diff --git a/android/LICENSE b/android/LICENSE
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/android/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/android/README.md b/android/README.md
new file mode 100644
index 0000000..f48f4fc
--- /dev/null
+++ b/android/README.md
@@ -0,0 +1,8 @@
+# Tinelix IRC Client (Legacy edition)
+**Minimal Android version:** Android 2.0 Eclair (API level 5) and higher
+
+**IMPORTANT!** Until May 1, 2024 all files from this repository will be moved to https://github.com/tinelix/irc-client-legacy.
+
+See https://github.com/tinelix/irc-client/issues/14#issue-2225137465.
+
+
diff --git a/android/TinelixIRCLegacy.iml b/android/TinelixIRCLegacy.iml
new file mode 100644
index 0000000..2a02201
--- /dev/null
+++ b/android/TinelixIRCLegacy.iml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/app.iml b/android/app/app.iml
new file mode 100644
index 0000000..f782803
--- /dev/null
+++ b/android/app/app.iml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/build.gradle b/android/app/build.gradle
new file mode 100644
index 0000000..fe8c81a
--- /dev/null
+++ b/android/app/build.gradle
@@ -0,0 +1,24 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 21
+ buildToolsVersion "21.1.2"
+ defaultConfig {
+ applicationId "dev.tinelix.irc.android.legacy"
+ minSdkVersion 5 // Android 2.0 Eclair
+ targetSdkVersion 21
+ versionCode 22
+ versionName '0.4.0_beta_20220506'
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ debug {
+ debuggable true
+ }
+ }
+ productFlavors {
+ }
+}
diff --git a/android/app/build/readme.txt b/android/app/build/readme.txt
new file mode 100644
index 0000000..292c28c
--- /dev/null
+++ b/android/app/build/readme.txt
@@ -0,0 +1 @@
+'build' - folder for output build
diff --git a/android/app/libs/readme.txt b/android/app/libs/readme.txt
new file mode 100644
index 0000000..4e9d86a
--- /dev/null
+++ b/android/app/libs/readme.txt
@@ -0,0 +1 @@
+'libs' - folder for Gradle libs
\ No newline at end of file
diff --git a/android/app/readme.txt b/android/app/readme.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/android/app/readme.txt
@@ -0,0 +1 @@
+
diff --git a/android/app/src/androidTest/java/dev/tinelix/irc/android/ExampleInstrumentedTest.java b/android/app/src/androidTest/java/dev/tinelix/irc/android/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..0257a09
--- /dev/null
+++ b/android/app/src/androidTest/java/dev/tinelix/irc/android/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package dev.tinelix.irc;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("dev.tinelix.irc", appContext.getPackageName());
+ }
+}
diff --git a/android/app/src/androidTest/java/dev/tinelix/irc/android/legacy/ExampleInstrumentedTest.java b/android/app/src/androidTest/java/dev/tinelix/irc/android/legacy/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..596443b
--- /dev/null
+++ b/android/app/src/androidTest/java/dev/tinelix/irc/android/legacy/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package dev.tinelix.irc.android;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("dev.tinelix.irc.android", appContext.getPackageName());
+ }
+}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..85d0030
--- /dev/null
+++ b/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/AboutApplicationActivity.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/AboutApplicationActivity.java
new file mode 100644
index 0000000..a639303
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/AboutApplicationActivity.java
@@ -0,0 +1,213 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.text.method.LinkMovementMethod;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.Locale;
+
+public class AboutApplicationActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ setCustomTheme(global_prefs);
+ setContentView(R.layout.about_application_activity);
+ setColorStyle(global_prefs);
+ Button repoButton = (Button) findViewById(R.id.repo_button);
+ Button websiteButton = (Button) findViewById(R.id.website_button);
+
+ repoButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Uri uri = Uri.parse("https://github.com/tinelix/irc-client-for-android");
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ startActivity(intent);
+ }
+ });
+ websiteButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Uri uri = Uri.parse("http://tinelix.downmail.ru/web1/pages/tinelix/irc-client_utf8.html");
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ startActivity(intent);
+ }
+ });
+ if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ websiteButton.setVisibility(View.GONE);
+ }
+ TextView license_label = (TextView) findViewById(R.id.license_label);
+ license_label.setMovementMethod(LinkMovementMethod.getInstance());
+ TextView version_label = (TextView) findViewById(R.id.version_label);
+ version_label.setText(getResources().getString(R.string.version_str, ((IRCClientApp) getApplicationContext()).version, ((IRCClientApp) getApplicationContext()).build_date));
+ };
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
+ if(id == android.R.id.home) {
+ onBackPressed();
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onBackPressed() {
+ finish();
+ }
+
+ private void setColorStyle(SharedPreferences global_prefs) {
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.activity_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ TextView app_title2 = (TextView) findViewById(R.id.app_title_label);
+ app_title2.setTextColor(getResources().getColor(R.color.black));
+ ((TextView) findViewById(R.id.license_label)).setTextColor(Color.DKGRAY);
+ } else {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.title_v11_transparent));
+ TextView app_title = (TextView) findViewById(R.id.activity_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ TextView app_title2 = (TextView) findViewById(R.id.app_title_label);
+ app_title2.setTextColor(getResources().getColor(R.color.white));
+ ((TextView) findViewById(R.id.license_label)).setTextColor(Color.LTGRAY);
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ TextView app_title2 = (TextView) findViewById(R.id.app_title_label);
+ app_title2.setTextColor(getResources().getColor(R.color.black));
+ } else {
+ TextView app_title2 = (TextView) findViewById(R.id.app_title_label);
+ app_title2.setTextColor(getResources().getColor(R.color.white));
+ }
+ }
+ } else {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.title_v11_transparent));
+ TextView app_title = (TextView) findViewById(R.id.activity_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ TextView app_title2 = (TextView) findViewById(R.id.app_title_label);
+ app_title2.setTextColor(getResources().getColor(R.color.white));
+ ((TextView) findViewById(R.id.license_label)).setTextColor(Color.LTGRAY);
+ } else {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.activity_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ TextView app_title2 = (TextView) findViewById(R.id.app_title_label);
+ app_title2.setTextColor(getResources().getColor(R.color.black));
+ ((TextView) findViewById(R.id.license_label)).setTextColor(Color.DKGRAY);
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ TextView app_title2 = (TextView) findViewById(R.id.app_title_label);
+ app_title2.setTextColor(getResources().getColor(R.color.white));
+ } else {
+ TextView app_title2 = (TextView) findViewById(R.id.app_title_label);
+ app_title2.setTextColor(getResources().getColor(R.color.black));
+ }
+ }
+ }
+ }
+
+ private void setCustomTheme(SharedPreferences global_prefs) {
+ if (global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if (global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ config.locale = locale;
+ config.setLayoutDirection(locale);
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ config.locale = locale;
+ config.setLayoutDirection(locale);
+ }
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if (global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ config.locale = locale;
+ config.setLayoutDirection(locale);
+ }
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ config.locale = locale;
+ config.setLayoutDirection(locale);
+ }
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ }
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient_Light);
+ } else {
+ setTheme(R.style.IRCClient);
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient);
+ } else {
+ setTheme(R.style.IRCClient_Light);
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/ConnectionManagerActivity.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/ConnectionManagerActivity.java
new file mode 100644
index 0000000..2a14466
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/ConnectionManagerActivity.java
@@ -0,0 +1,590 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.os.Bundle;
+import android.app.DialogFragment;
+import android.preference.PreferenceManager;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+
+public class ConnectionManagerActivity extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {
+ public List profilesArray = new ArrayList();
+ ArrayList profilesList = new ArrayList();
+ ProfileAdapter profilesAdapter;
+ public String selected_profile_name;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ setCustomTheme(global_prefs);
+ setContentView(R.layout.activity_connection_manager);
+ setColorStyle(global_prefs);
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ ImageButton menu_button = (ImageButton) findViewById(R.id.menu_button);
+ menu_button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ openOptionsMenu();
+ }
+ });
+ } else {
+ getActionBar().setTitle(getResources().getString(R.string.connection_manager_title));
+ }
+ profilesAdapter = new ProfileAdapter(this, profilesList);
+ String package_name = getApplicationContext().getPackageName();
+ String profile_path = "/data/data/" + package_name + "/shared_prefs";
+ File prefs_directory = new File(profile_path);
+ File[] prefs_files = prefs_directory.listFiles();
+ ListView profilesListView = (ListView) findViewById(R.id.profiles_list);
+ LinearLayout profilesLinearLayout = (LinearLayout) findViewById(R.id.empty_profiles_list_layout);
+ profilesArray = new LinkedList();
+ String file_extension;
+ Context context = getApplicationContext();
+ try {
+ for (int i = 0; i < prefs_files.length; i++) {
+ if(prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)).startsWith(getApplicationInfo().packageName + "_preferences"))
+ {
+ } else {
+ SharedPreferences prefs = context.getSharedPreferences(prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)), 0);
+ file_extension = prefs_files[i].getName().substring((int) (prefs_files[i].getName().length() - 4));
+ if (file_extension.contains(".xml") && file_extension.length() == 4) {
+ profilesList.add(new Profile(prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)),
+ prefs.getString("server", ""), prefs.getInt("port", 0), false, false));
+ }
+ }
+ }
+ if(prefs_files == null || profilesList.size() == 0) {
+ profilesListView.setVisibility(View.GONE);
+ profilesLinearLayout.setVisibility(View.VISIBLE);
+ } else {
+ profilesListView.setVisibility(View.VISIBLE);
+ profilesLinearLayout.setVisibility(View.GONE);
+ }
+ ArrayAdapter profilesAdapter2 = new ArrayAdapter(this,
+ android.R.layout.simple_list_item_1, profilesArray);
+ profilesListView.setAdapter(profilesAdapter);
+ profilesListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
+ Toast.makeText(getApplicationContext(), ((TextView)view.findViewById(R.id.profile_item_label)).getText(), Toast.LENGTH_LONG).show();
+ }
+ });
+ } catch(Exception ex) {
+ ex.printStackTrace();
+ }
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+ FragmentManager fragmentManager = null;
+ fragmentManager = getFragmentManager();
+ FragmentTransaction fragmentTransaction = null;
+ fragmentTransaction = fragmentManager.beginTransaction();
+ CreateItemFragm ci_fragment = new CreateItemFragm();
+ fragmentTransaction.add(R.id.create_item_layout2, ci_fragment);
+ fragmentTransaction.commit();
+ } else {
+ LinearLayout add_item_ll = (LinearLayout) findViewById(R.id.add_item_ll);
+ add_item_ll.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ showEnterTextDialog();
+ }
+ });
+ }
+ };
+
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.connection_manager_menu, menu);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ getActionBar().setHomeButtonEnabled(true);
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+
+ //noinspection SimplifiableIfStatement
+ if (id == R.id.add_item) {
+ return showEnterTextDialog();
+ }
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
+ if(id == android.R.id.home) {
+ onBackPressed();
+ }
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ public boolean showEnterTextDialog() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment enterTextDialogFragm = new EnterTextDialogFragm();
+ enterTextDialogFragm.show(getFragmentManager(), "enter_text_dlg");
+ } else {
+ final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
+ LayoutInflater inflater = this.getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.enter_text_activity, null);
+ TextView dialog_title = (TextView) dialogView.findViewById(R.id.dialog_title);
+ dialog_title.setText(getString(R.string.enter_the_pfn_title));
+ final EditText profile_name = (EditText) dialogView.findViewById(R.id.profile_name_text);
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ dialogBuilder.setView(dialogView);
+ dialogBuilder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ profileNameOkClicked(profile_name.getText().toString());
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+
+ }
+ });
+ final AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+ profile_name.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ if(profile_name.getText().toString().contains("/")) {
+ profile_name.setError(getResources().getString(R.string.text_field_wrong_characters));
+ ((AlertDialog) alertDialog).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
+ } else {
+ ((AlertDialog) alertDialog).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+
+ }
+ });
+ alertDialog.show();
+
+ Button dialogButton;
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return false;
+ };
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ profilesAdapter = new ProfileAdapter(this, profilesList);
+ String package_name = getApplicationContext().getPackageName();
+ String profile_path = "/data/data/" + package_name + "/shared_prefs";
+ File prefs_directory = new File(profile_path);
+ File[] prefs_files = prefs_directory.listFiles();
+ profilesList.clear();
+ profilesArray.clear();
+ String file_extension;
+ Context context = getApplicationContext();
+ ListView profilesListView = (ListView) findViewById(R.id.profiles_list);
+ LinearLayout profilesLinearLayout = (LinearLayout) findViewById(R.id.empty_profiles_list_layout);
+ try {
+ for (int i = 0; i < prefs_files.length; i++) {
+ if(prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)).startsWith(getApplicationInfo().packageName + "_preferences"))
+ {
+ } else {
+ SharedPreferences prefs = context.getSharedPreferences(prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)), 0);
+ file_extension = prefs_files[i].getName().substring((int) (prefs_files[i].getName().length() - 4));
+ if (file_extension.contains(".xml") && file_extension.length() == 4) {
+ profilesList.add(new Profile(prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)),
+ prefs.getString("server", ""), prefs.getInt("port", 0), false, false));
+ }
+ }
+ }
+ if(prefs_files == null || profilesList.size() == 0) {
+ profilesListView.setVisibility(View.GONE);
+ profilesLinearLayout.setVisibility(View.VISIBLE);
+ } else {
+ profilesListView.setVisibility(View.VISIBLE);
+ profilesLinearLayout.setVisibility(View.GONE);
+ }
+ ArrayAdapter profilesAdapter2 = new ArrayAdapter(this,
+ android.R.layout.simple_list_item_1, profilesArray);
+ profilesListView.setAdapter(profilesAdapter);
+ } catch(Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public void profileNameOkClicked(String profile_name) {
+ profilesArray.clear();
+ profilesList.clear();
+ profilesAdapter = new ProfileAdapter(this, profilesList);
+ String package_name = getApplicationContext().getPackageName();
+ String profile_path = "/data/data/" + package_name + "/shared_prefs";
+ File prefs_directory = new File(profile_path);
+ File[] prefs_files = prefs_directory.listFiles();
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("name", profile_name);
+ editor.putString("auth_method", "Disabled");
+ editor.putString("hide_ip", "Disabled");
+ editor.putString("quit_message", getString(R.string.default_quit_msg));
+ editor.putBoolean("connected", false);
+ editor.commit();
+ Intent intent = new Intent(this, ProfileSettingsActivity.class);
+ intent.putExtra("profile_name", profile_name);
+ intent.putExtra("package_name", getApplicationContext().getPackageName());
+ startActivity(intent);
+ }
+
+ public void selectProfile(View v) {
+ }
+
+ public void connectProfile(int position) {
+ Context context = getApplicationContext();
+ Intent intent = new Intent(context, ThreadActivity.class);
+ Intent parentIntent = new Intent();
+ Profile profile_item = null;
+ profile_item = (Profile) profilesAdapter.getItem(position);
+ intent.putExtra("profile_name", profile_item.name);
+ SharedPreferences prefs = context.getSharedPreferences(profile_item.name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean("connected", true);
+ editor.commit();
+ SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if(prefs.getString("nicknames", "").length() > 0) {
+ if (global_prefs.getBoolean("connected", false) == false) {
+ editor = global_prefs.edit();
+ editor.putBoolean("connected", true);
+ editor.commit();
+ setResult(RESULT_OK, parentIntent);
+ intent.setAction(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ startActivity(intent);
+ } else {
+ if(prefs.getBoolean("connected", false)) {
+ Toast.makeText(getApplicationContext(), getResources().getString(R.string.first_end_session), Toast.LENGTH_LONG).show();
+ }
+ }
+ finish();
+ } else {
+ Toast.makeText(getApplicationContext(), getResources().getString(R.string.forgot_nicknames), Toast.LENGTH_LONG).show();
+ }
+ }
+
+ public void editProfile(int position) {
+ Context context = getApplicationContext();
+ Intent intent = new Intent(context, ProfileSettingsActivity.class);
+ Profile profile_item = null;
+ profile_item = (Profile) profilesAdapter.getItem(position);
+ intent.putExtra("profile_name", profile_item.name);
+ intent.putExtra("package_name", getApplicationContext().getPackageName());
+ startActivity(intent);
+ }
+
+ public void deleteProfile(int position) {
+ profilesAdapter = new ProfileAdapter(this, profilesList);
+ String package_name = getApplicationContext().getPackageName();
+ Profile profile_item = null;
+ profile_item = (Profile) profilesAdapter.getItem(position);
+ profilesArray.clear();
+ profilesList.clear();
+ String profile_path = "/data/data/" + package_name + "/shared_prefs/" + profile_item.name + ".xml";
+ File file = new File(profile_path);
+ file.delete();
+ profilesAdapter = new ProfileAdapter(this, profilesList);
+ package_name = getApplicationContext().getPackageName();
+ profile_path = "/data/data/" + package_name + "/shared_prefs";
+ File prefs_directory = new File(profile_path);
+ File[] prefs_files = prefs_directory.listFiles();
+ profilesList.clear();
+ profilesArray.clear();
+ String file_extension;
+ Context context = getApplicationContext();
+ ListView profilesListView = (ListView) findViewById(R.id.profiles_list);
+ LinearLayout profilesLinearLayout = (LinearLayout) findViewById(R.id.empty_profiles_list_layout);
+ try {
+ for (int i = 0; i < prefs_files.length; i++) {
+ if(prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)).startsWith(getApplicationInfo().packageName + "_preferences"))
+ {
+ } else {
+ SharedPreferences prefs = context.getSharedPreferences(prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)), 0);
+ file_extension = prefs_files[i].getName().substring((int) (prefs_files[i].getName().length() - 4));
+ if (file_extension.contains(".xml") && file_extension.length() == 4) {
+ profilesList.add(new Profile(prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)),
+ prefs.getString("server", ""), prefs.getInt("port", 0), false, false));
+ }
+ }
+ }
+ if(prefs_files == null || profilesList.size() == 0) {
+ profilesListView.setVisibility(View.GONE);
+ profilesLinearLayout.setVisibility(View.VISIBLE);
+ } else {
+ profilesListView.setVisibility(View.VISIBLE);
+ profilesLinearLayout.setVisibility(View.GONE);
+ }
+ ArrayAdapter profilesAdapter2 = new ArrayAdapter(this,
+ android.R.layout.simple_list_item_1, profilesArray);
+ profilesListView.setAdapter(profilesAdapter);
+ profilesListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
+ Toast.makeText(getApplicationContext(), ((TextView)view.findViewById(R.id.profile_item_label)).getText(), Toast.LENGTH_LONG).show();
+ }
+ });
+ } catch(Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+
+ }
+
+ private void setColorStyle(SharedPreferences global_prefs) {
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ } else {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.title_v11_transparent));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ }
+ }
+ } else {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.title_v11_transparent));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ } else {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ }
+ }
+ }
+ }
+
+ private void setCustomTheme(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ }
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient_Light);
+ } else {
+ setTheme(R.style.IRCClient);
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient);
+ } else {
+ setTheme(R.style.IRCClient_Light);
+ }
+ }
+ }
+
+ private void customizeDialogStyle(Button dialogButton, SharedPreferences global_prefs, AlertDialog alertDialog) {
+ if(global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/CreateItemFragm.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/CreateItemFragm.java
new file mode 100644
index 0000000..5802b86
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/CreateItemFragm.java
@@ -0,0 +1,46 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.TargetApi;
+import android.app.Fragment;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import java.util.Locale;
+
+@TargetApi(Build.VERSION_CODES.HONEYCOMB)
+public class CreateItemFragm extends Fragment {
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ View view = inflater.inflate(R.layout.create_item,
+ container, false);
+ if(global_prefs.getString("theme", "Dark").contains("Light")) {
+ TextView add_item_label = (TextView) view.findViewById(R.id.add_item_label);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ add_item_label.setTextColor(getResources().getColor(android.R.color.holo_blue_light));
+ } else {
+ add_item_label.setTextColor(getResources().getColor(R.color.orange));
+ }
+ }
+ Button create_item_button = (Button) view.findViewById(R.id.create_item_button);
+ create_item_button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ ((ConnectionManagerActivity) getActivity()).showEnterTextDialog();
+ }
+ }
+ });
+
+ return view;
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/CreateItemFragm2.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/CreateItemFragm2.java
new file mode 100644
index 0000000..5f9f135
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/CreateItemFragm2.java
@@ -0,0 +1,44 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.SuppressLint;
+import android.app.Fragment;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+@SuppressLint("NewApi")
+public class CreateItemFragm2 extends Fragment {
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ View view = inflater.inflate(R.layout.create_item2,
+ container, false);
+ if(global_prefs.getString("theme", "Dark").contains("Light")) {
+ TextView add_item_label = (TextView) view.findViewById(R.id.add_item_label);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ add_item_label.setTextColor(getResources().getColor(android.R.color.holo_blue_light));
+ } else {
+ add_item_label.setTextColor(getResources().getColor(R.color.orange));
+ }
+ }
+ Button create_item_button = (Button) view.findViewById(R.id.create_item_button2);
+ create_item_button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ ((CustomNicknamesActivity) getActivity()).showEnterTextDialog();
+ }
+ }
+ });
+
+ return view;
+ }
+
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/CustomNicknamesActivity.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/CustomNicknamesActivity.java
new file mode 100644
index 0000000..86d0be3
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/CustomNicknamesActivity.java
@@ -0,0 +1,403 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceManager;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+
+public class CustomNicknamesActivity extends Activity {
+
+ List nicknamesArray = new ArrayList();
+ String nicknamesString;
+ String old_profile_name;
+ public String current_parameter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ setCustomTheme(global_prefs);
+ setContentView(R.layout.custom_nicknames_activity);
+ setColorStyle(global_prefs);
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ getActionBar().setHomeButtonEnabled(true);
+ }
+ getActionBar().setTitle(getResources().getString(R.string.nicknames_manager_title));
+ }
+ current_parameter = "creating_nickname";
+ if (savedInstanceState == null) {
+ Bundle extras = getIntent().getExtras();
+ if(extras == null) {
+ old_profile_name = null;
+ } else {
+ old_profile_name = extras.getString("profile_name");
+ }
+ } else {
+ old_profile_name = (String) savedInstanceState.getSerializable("profile_name");
+ };
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ nicknamesArray = new LinkedList(Arrays.asList(prefs.getString("nicknames", "").split(", ")));
+ if(nicknamesArray.size() == 1 && nicknamesArray.get(0).length() == 0) {
+ nicknamesArray.remove(0);
+ }
+ ListView nicknamesList = (ListView) findViewById(R.id.nicknames_list);
+ ArrayAdapter nicknamesAdapter = new ArrayAdapter(this,
+ android.R.layout.simple_list_item_1, nicknamesArray);
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ LinearLayout add_item_ll = (LinearLayout) findViewById(R.id.create_item_layout2);
+ add_item_ll.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ showEnterTextDialog();
+ }
+ });
+ }
+
+ nicknamesList.setAdapter(nicknamesAdapter);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.nicknames_manager_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+
+ //noinspection SimplifiableIfStatement
+ if(id == R.id.add_nickname_item) {
+ showEnterTextDialog();
+ } else if (id == R.id.clear_nicknames_item) {
+ nicknamesArray.clear();
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("nicknames", "");
+ editor.commit();
+ ListView nicknamesList = (ListView) findViewById(R.id.nicknames_list);
+ ArrayAdapter nicknamesAdapter = new ArrayAdapter(this,
+ android.R.layout.simple_list_item_1, nicknamesArray);
+ nicknamesList.setAdapter(nicknamesAdapter);
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ public void onCreatingNicknames(String parameter, String value) {
+ if(parameter == "creating_nickname") {
+ StringBuilder nicknames_sb = new StringBuilder();
+ if(value.length() > 0) {
+
+ nicknamesArray.add(value);
+ };
+ for (int i = 0; i < nicknamesArray.size(); i++) {
+ if(i < nicknamesArray.size() - 1 && nicknamesArray.get(i).length() > 0) {
+ nicknames_sb.append(nicknamesArray.get(i)).append(", ");
+ } else if(nicknamesArray.get(i).length() > 0) {
+ nicknames_sb.append(nicknamesArray.get(i));
+ }
+ };
+ ListView nicknamesList = (ListView) findViewById(R.id.nicknames_list);
+ ArrayAdapter nicknamesAdapter = new ArrayAdapter(this,
+ android.R.layout.simple_list_item_1, nicknamesArray);
+ nicknamesList.setAdapter(nicknamesAdapter);
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("nicknames", nicknames_sb.toString());
+ editor.commit();
+ }
+ }
+
+ public String getCurrentParameter() {
+ return current_parameter;
+ }
+
+ public boolean showEnterTextDialog() {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment enterTextDialogFragm = new EnterTextDialogFragm3();
+ enterTextDialogFragm.show(getFragmentManager(), "enter_text_dlg");
+ } else {
+ AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(CustomNicknamesActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(CustomNicknamesActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(CustomNicknamesActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(CustomNicknamesActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.enter_text_activity, null);
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ dialogBuilder.setView(dialogView);
+ dialogBuilder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) dialogView.findViewById(R.id.profile_name_text);
+ onCreatingNicknames(current_parameter, profile_name.getText().toString());
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+
+ }
+ });
+ TextView textAreaTitle = (TextView) dialogView.findViewById(R.id.profile_name_label);
+ textAreaTitle.setText(R.string.your_nickname);
+ TextView dialog_title = (TextView) dialogView.findViewById(R.id.dialog_title);
+ dialog_title.setText(getString(R.string.enter_the_nick_title));
+ AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+ alertDialog.show();
+ Button dialogButton;
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return false;
+ };
+
+ private void setColorStyle(SharedPreferences global_prefs) {
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ } else {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.title_v11_transparent));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ }
+ }
+ } else {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.title_v11_transparent));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ } else {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ }
+ }
+ }
+ }
+
+ private void setCustomTheme(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ }
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient_Light);
+ } else {
+ setTheme(R.style.IRCClient);
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient);
+ } else {
+ setTheme(R.style.IRCClient_Light);
+ }
+ }
+ }
+ private void customizeDialogStyle(Button dialogButton, SharedPreferences global_prefs, AlertDialog alertDialog) {
+ if(global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/CustomSpinnerAdapter.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/CustomSpinnerAdapter.java
new file mode 100644
index 0000000..f250f78
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/CustomSpinnerAdapter.java
@@ -0,0 +1,78 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+public class CustomSpinnerAdapter extends BaseAdapter {
+ Context ctx;
+ LayoutInflater inflater;
+ ArrayList objects;
+
+ CustomSpinnerAdapter(Context context, ArrayList products) {
+ ctx = context;
+ objects = products;
+ inflater = (LayoutInflater) ctx
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ public int getCount() {
+ return objects.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return objects.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ CustomSpinnerItem getProfile(int position) {
+ return ((CustomSpinnerItem) getItem(position));
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view = convertView;
+ if (view == null) {
+ view = inflater.inflate(R.layout.custom_spinner_item, parent, false);
+ }
+
+ CustomSpinnerItem p = getProfile(position);
+ ((TextView) view.findViewById(R.id.spinner_item_text)).setText(p.name);
+ TextView item_name = (TextView) view.findViewById(R.id.spinner_item_text);
+ SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ item_name.setTextColor(ctx.getResources().getColor(R.color.black));
+ } else {
+ item_name.setTextColor(ctx.getResources().getColor(R.color.white));
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ item_name.setTextColor(ctx.getResources().getColor(R.color.white));
+ } else {
+ item_name.setTextColor(ctx.getResources().getColor(R.color.black));
+ }
+ }
+ return view;
+ }
+
+ public class ViewHolder {
+ public TextView profile_name;
+ public TextView server;
+ }
+
+
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/CustomSpinnerItem.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/CustomSpinnerItem.java
new file mode 100644
index 0000000..8da2f6d
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/CustomSpinnerItem.java
@@ -0,0 +1,10 @@
+package dev.tinelix.irc.android.legacy;
+
+public class CustomSpinnerItem {
+
+ String name;
+
+ CustomSpinnerItem(String _describe) {
+ name = _describe;
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/DebugLogsActivity.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/DebugLogsActivity.java
new file mode 100644
index 0000000..ac4bd9d
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/DebugLogsActivity.java
@@ -0,0 +1,369 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.preference.PreferenceManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+
+public class DebugLogsActivity extends Activity {
+
+ public EditText debug_log_text;
+ public String log_text;
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ setCustomTheme(global_prefs);
+ setContentView(R.layout.debug_log_activity);
+ setColorStyle(global_prefs);
+ try {
+ Process process = Runtime.getRuntime().exec("logcat -d");
+ BufferedReader bufferedReader = new BufferedReader(
+ new InputStreamReader(process.getInputStream()));
+
+ StringBuilder log = new StringBuilder();
+ String line = "";
+ while ((line = bufferedReader.readLine()) != null) {
+ log.append(line + "\r\n");
+ }
+ final EditText debug_log_text = (EditText) findViewById(R.id.debug_log_text);
+ log_text = log.toString();
+ debug_log_text.setText(log_text);
+ debug_log_text.setKeyListener(null);
+ debug_log_text.setTypeface(Typeface.MONOSPACE);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ debug_log_text.setTextIsSelectable(true);
+ }
+ if(global_prefs.getInt("font_size", 0) >= 12) {
+ debug_log_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, global_prefs.getInt("font_size", 0));
+ }
+ } catch (IOException e) {
+ // Handle Exception
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ getActionBar().setHomeButtonEnabled(true);
+ }
+ Button save_log_btn = (Button) findViewById(R.id.save_log_btn);
+ save_log_btn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+
+ File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "Tinelix");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+
+ directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Tinelix", "IRC Client");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+ directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Tinelix/IRC Client", "App Logs");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+
+ try {
+ Date dt = new Date(System.currentTimeMillis());
+ Log.d("App", "Attempting creating log file...");
+ File file = new File(directory, "LOG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(dt) + ".log");
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ Log.d("App", "Log file created!");
+ FileWriter writer = new FileWriter(file);
+ writer.append(log_text);
+ writer.flush();
+ writer.close();
+ Toast.makeText(getApplicationContext(), getResources().getString(R.string.saved_log, "Tinelix/IRC Client/App Logs"), Toast.LENGTH_LONG).show();
+ } catch (Exception e) {
+ Log.e("App", "Could not save log to file: " + e.getMessage());
+ }
+ }
+ });
+ }
+
+ private void showMissingPermssionDialog() {
+ AlertDialog dialog;
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(getResources().getString(R.string.allow_permisssion_in_storage_title));
+ builder.setMessage(getResources().getString(R.string.allow_permisssion_in_storage));
+ builder.setPositiveButton(getResources().getString(R.string.open_button), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ Uri uri = Uri.fromParts("package", getPackageName(), null);
+ intent.setData(uri);
+ startActivity(intent);
+ }
+ });
+ builder.setNegativeButton(getResources().getString(R.string.cancel_button), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ dialog = builder.create();
+ dialog.show();
+ }
+
+ private void setCustomTheme(SharedPreferences global_prefs) {
+ if (global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if (global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ config.locale = locale;
+ config.setLayoutDirection(locale);
+ }
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ config.locale = locale;
+ config.setLayoutDirection(locale);
+ }
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if (global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ config.locale = locale;
+ config.setLayoutDirection(locale);
+ }
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ config.locale = locale;
+ config.setLayoutDirection(locale);
+ }
+ getApplicationContext().getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ }
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient_Light);
+ } else {
+ setTheme(R.style.IRCClient);
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient);
+ } else {
+ setTheme(R.style.IRCClient_Light);
+ }
+ }
+ }
+
+ private void customizeDialogStyle(Button dialogButton, SharedPreferences global_prefs, AlertDialog alertDialog) {
+ if(global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ }
+ }
+
+ private void setColorStyle(SharedPreferences global_prefs) {
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ ListView main_menu = (ListView) findViewById(R.id.mainmenu);
+ debug_log_text = (EditText) findViewById(R.id.debug_log_text);
+ debug_log_text.setBackgroundColor(getResources().getColor(R.color.white_90));
+ } else {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.title_v11_transparent));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ListView main_menu = (ListView) findViewById(R.id.mainmenu);
+ debug_log_text = (EditText) findViewById(R.id.debug_log_text);
+ debug_log_text.setBackgroundColor(getResources().getColor(R.color.gray_v2));
+ }
+ }
+ } else {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.title_v11_transparent));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ debug_log_text = (EditText) findViewById(R.id.debug_log_text);
+ debug_log_text.setBackgroundColor(getResources().getColor(R.color.gray_v2));
+ } else {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ debug_log_text = (EditText) findViewById(R.id.debug_log_text);
+ debug_log_text.setBackgroundColor(getResources().getColor(R.color.white_90));
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterPasswordDialogFragm.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterPasswordDialogFragm.java
new file mode 100644
index 0000000..3359497
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterPasswordDialogFragm.java
@@ -0,0 +1,87 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+
+import java.util.Locale;
+
+@SuppressLint("NewApi")
+public class EnterPasswordDialogFragm extends DialogFragment {
+
+ public String current_parameter;
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ setLocale(global_prefs);
+ current_parameter = ((ProfileSettingsActivity) getActivity()).getCurrentParameter();
+ String current_value;
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ if(current_parameter == "setting_password") {
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ final View view = inflater.inflate(R.layout.enter_password_activity, null);
+ builder.setView(view);
+ builder.setTitle(R.string.enter_the_password_title);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) view.findViewById(R.id.password_text);
+ ((ProfileSettingsActivity) getActivity()).onChangingValues(current_parameter, profile_name.getText().toString());
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ };
+ return builder.create();
+ }
+
+ private void setLocale(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterTextDialogFragm.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterTextDialogFragm.java
new file mode 100644
index 0000000..b91dc60
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterTextDialogFragm.java
@@ -0,0 +1,105 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.app.DialogFragment;
+import android.preference.PreferenceManager;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.util.Locale;
+
+@SuppressLint("NewApi")
+public class EnterTextDialogFragm extends DialogFragment {
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ setLocale(global_prefs);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ final View view = inflater.inflate(R.layout.enter_text_activity, null);
+ final EditText profile_name = (EditText) view.findViewById(R.id.profile_name_text);
+ profile_name.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ if(profile_name.getText().toString().contains("/")) {
+ profile_name.setError(getResources().getString(R.string.text_field_wrong_characters));
+ ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
+ } else {
+ ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+
+ }
+ });
+ builder.setView(view);
+ builder.setTitle(R.string.enter_the_pfn_title);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ ((ConnectionManagerActivity) getActivity()).profileNameOkClicked(profile_name.getText().toString());
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ return builder.create();
+ }
+
+ private void setLocale(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterTextDialogFragm2.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterTextDialogFragm2.java
new file mode 100644
index 0000000..3faf38d
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterTextDialogFragm2.java
@@ -0,0 +1,227 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.util.Locale;
+
+@SuppressLint("NewApi")
+public class EnterTextDialogFragm2 extends DialogFragment {
+
+ public String current_parameter;
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ setLocale(global_prefs);
+ current_parameter = ((ProfileSettingsActivity) getActivity()).getCurrentParameter();
+ String current_value;
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ if(current_parameter == "changing_profile_name") {
+ current_value = ((ProfileSettingsActivity) getActivity()).getCurrentValue(current_parameter);
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ final View view = inflater.inflate(R.layout.enter_text_activity, null);
+ final EditText profile_name = (EditText) view.findViewById(R.id.profile_name_text);
+ profile_name.setText(current_value);
+ profile_name.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ if(profile_name.getText().toString().contains("/")) {
+ profile_name.setError(getResources().getString(R.string.text_field_wrong_characters));
+ ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
+ } else {
+ ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+
+ }
+ });
+ builder.setView(view);
+ builder.setTitle(R.string.enter_the_pfn_title);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) view.findViewById(R.id.profile_name_text);
+ ((ProfileSettingsActivity) getActivity()).onChangingValues(current_parameter, profile_name.getText().toString());
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ } else if(current_parameter == "changing_auth_method") {
+ current_value = ((ProfileSettingsActivity) getActivity()).getCurrentValue(current_parameter);
+ String[] auth_methods = getResources().getStringArray(R.array.auth_method);
+ builder.setTitle(R.string.auth_method);
+ if(current_value.contains("NickServ")) {
+ builder.setSingleChoiceItems(auth_methods, 1,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ String value;
+ if(item == 0) {
+ value = "Disabled";
+ } else {
+ value = "NickServ";
+ }
+ ((ProfileSettingsActivity) getActivity()).onChangingValues(current_parameter, value);
+ }
+ });
+ } else {
+ builder.setSingleChoiceItems(auth_methods, 0,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ String value;
+ if(item == 0) {
+ value = "Disabled";
+ } else {
+ value = "NickServ";
+ }
+ ((ProfileSettingsActivity) getActivity()).onChangingValues(current_parameter, value);
+ }
+ });
+ }
+ builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ }
+ });
+ } else if(current_parameter == "changing_realname") {
+ current_value = ((ProfileSettingsActivity) getActivity()).getCurrentValue(current_parameter);
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ final View view = inflater.inflate(R.layout.enter_text_activity, null);
+ builder.setView(view);
+ builder.setTitle(R.string.enter_the_realname_title);
+ TextView realname_label = (TextView) view.findViewById(R.id.profile_name_label);
+ realname_label.setText(R.string.realname);
+ EditText realname_text = (EditText) view.findViewById(R.id.profile_name_text);
+ realname_text.setText(current_value);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) view.findViewById(R.id.profile_name_text);
+ ((ProfileSettingsActivity) getActivity()).onChangingValues(current_parameter, profile_name.getText().toString());
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ } else if(current_parameter == "changing_hostname") {
+ current_value = ((ProfileSettingsActivity) getActivity()).getCurrentValue(current_parameter);
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ final View view = inflater.inflate(R.layout.enter_text_activity, null);
+ builder.setView(view);
+ builder.setTitle(R.string.enter_the_hostname_title);
+ TextView realname_label = (TextView) view.findViewById(R.id.profile_name_label);
+ realname_label.setText(R.string.hostname);
+ EditText realname_text = (EditText) view.findViewById(R.id.profile_name_text);
+ realname_text.setText(current_value);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) view.findViewById(R.id.profile_name_text);
+ ((ProfileSettingsActivity) getActivity()).onChangingValues(current_parameter, profile_name.getText().toString());
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ } else if(current_parameter == "changing_quitmsg") {
+ current_value = ((ProfileSettingsActivity) getActivity()).getCurrentValue(current_parameter);
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ final View view = inflater.inflate(R.layout.enter_text_activity, null);
+ builder.setView(view);
+ builder.setTitle(R.string.enter_the_quiting_message);
+ TextView quitmsgname_label = (TextView) view.findViewById(R.id.profile_name_label);
+ quitmsgname_label.setText(R.string.quit_message);
+ EditText quitmsgname_text = (EditText) view.findViewById(R.id.profile_name_text);
+ quitmsgname_text.setText(current_value);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) view.findViewById(R.id.profile_name_text);
+ ((ProfileSettingsActivity) getActivity()).onChangingValues(current_parameter, profile_name.getText().toString());
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ }
+ return builder.create();
+ }
+
+ private void setLocale(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterTextDialogFragm3.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterTextDialogFragm3.java
new file mode 100644
index 0000000..bb01a9a
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/EnterTextDialogFragm3.java
@@ -0,0 +1,90 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.util.Locale;
+
+@SuppressLint("NewApi")
+public class EnterTextDialogFragm3 extends DialogFragment {
+
+ public String current_parameter;
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ setLocale(global_prefs);
+ current_parameter = ((CustomNicknamesActivity) getActivity()).getCurrentParameter();
+ String current_value;
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ if(current_parameter == "creating_nickname") {
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ final View view = inflater.inflate(R.layout.enter_text_activity, null);
+ TextView text_area_title = (TextView) view.findViewById(R.id.profile_name_label);
+ text_area_title.setText(R.string.your_nickname);
+ builder.setView(view);
+ builder.setTitle(R.string.enter_the_nick_title);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) view.findViewById(R.id.profile_name_text);
+ ((CustomNicknamesActivity) getActivity()).onCreatingNicknames(current_parameter, profile_name.getText().toString());
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ };
+ return builder.create();
+ }
+
+ private void setLocale(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/IRCClientApp.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/IRCClientApp.java
new file mode 100644
index 0000000..e95d0ba
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/IRCClientApp.java
@@ -0,0 +1,58 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+public class IRCClientApp extends Application {
+ ArrayList profilesList = new ArrayList();
+
+ public String version = "0.4.0 Beta";
+ public String build_date = "2022-05-06";
+
+ @Override
+ public void onCreate() {
+ String package_name = getApplicationContext().getPackageName();
+ String profile_path = "/data/data/" + package_name + "/shared_prefs";
+ File prefs_directory = new File(profile_path);
+ File[] prefs_files = prefs_directory.listFiles();
+ SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ SharedPreferences.Editor editor = global_prefs.edit();
+ if(prefs_files != null) {
+ String file_extension;
+ Context context = getApplicationContext();
+ for (int i = 0; i < prefs_files.length; i++) {
+ if (prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)).startsWith(getApplicationInfo().packageName + "_preferences")) {
+ } else {
+ SharedPreferences prefs = context.getSharedPreferences(prefs_files[i].getName().substring(0, (int) (prefs_files[i].getName().length() - 4)), 0);
+ file_extension = prefs_files[i].getName().substring((int) (prefs_files[i].getName().length() - 4));
+ if (file_extension.contains(".xml") && file_extension.length() == 4) {
+ editor = prefs.edit();
+ editor.putBoolean("connected", false);
+ editor.commit();
+ }
+ }
+ }
+ }
+ editor = global_prefs.edit();
+ editor.putBoolean("connected", false);
+ editor.putBoolean("theme_requires_restart", false);
+ editor.putBoolean("language_requires_restart", false);
+ if(global_prefs.contains("theme") == false) {
+ editor.putString("theme", "Dark");
+ }
+ if(global_prefs.contains("language") == false) {
+ editor.putString("language", "OS dependent");
+ }
+ if(global_prefs.contains("show_msg_timestamps") == false) {
+ editor.putBoolean("show_msg_timestamps", false);
+ }
+ editor.commit();
+ super.onCreate();
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/IRCParser.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/IRCParser.java
new file mode 100644
index 0000000..13ec2c4
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/IRCParser.java
@@ -0,0 +1,269 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.app.PendingIntent;
+import android.util.Log;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+public class IRCParser {
+ public String parseString(String raw, boolean showTimestamp) {
+ String[] array = raw.split(" ");
+ String[] member_msgs_array = array[0].split("!");
+ StringBuilder stringBuilder = new StringBuilder();
+ String parsed = new String();
+ if(raw.startsWith("PING")) {
+ Log.w("Tinelix IRC Parser", "PING messages ignored.");
+ parsed = "";
+ } else if(array[1].startsWith("372")) {
+ for(int index = 3; index < array.length; index++) {
+ if(index == 3) {
+ stringBuilder.append(array[index].replace(":",""));
+ } else {
+ stringBuilder.append(" " + array[index]);
+ }
+ }
+ parsed = "MOTD: " + stringBuilder.toString();
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("371")) {
+ for(int index = 3; index < array.length; index++) {
+ if(index == 3) {
+ stringBuilder.append(array[index].replace(":",""));
+ } else {
+ stringBuilder.append(" " + array[index]);
+ }
+ }
+ parsed = "Info: " + stringBuilder.toString();
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("671")) {
+ parsed = array[3] + " using a TLS/SSL connection.";
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("318")) {
+ Log.w("Tinelix IRC Parser", "Messages with \"318\" code ignored.");
+ parsed = "";
+ } else if(array[1].startsWith("321")) {
+ Log.w("Tinelix IRC Parser", "Messages with \"321\" code ignored.");
+ parsed = "";
+ } else if(array[1].startsWith("374")) {
+ Log.w("Tinelix IRC Parser", "Messages with \"374\" code ignored.");
+ parsed = "";
+ } else if(array[1].startsWith("374")) {
+ Log.w("Tinelix IRC Parser", "Messages with \"374\" code ignored.");
+ parsed = "";
+ } else if(array[1].startsWith("366")) {
+ Log.w("Tinelix IRC Parser", "Messages with \"366\" code ignored.");
+ parsed = "";
+ } else if(array[1].startsWith("376")) {
+ Log.w("Tinelix IRC Parser", "Messages with \"376\" code ignored.");
+ parsed = "";
+ } else if(array[1].startsWith("JOIN")) {
+ parsed = member_msgs_array[0].replace(":", "") + " joined on the " + array[2].replace(":", "") + " channel.";
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("PART")) {
+ parsed = member_msgs_array[0].replace(":", "") + " left the " + array[2].replace(":", "") + " channel.";
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("QUIT")) {
+ if(array.length > 3) {
+ for(int index = 2; index < array.length; index++) {
+ if(index == 2) {
+ stringBuilder.append(array[index].substring(1).replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ } else {
+ stringBuilder.append(" " + array[index]);
+ }
+ }
+ parsed = member_msgs_array[0].replace(":", "") + " quited with reason: " + stringBuilder;
+ } else {
+ parsed = member_msgs_array[0].replace(":", "") + " quited.";
+ }
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("PRIVMSG")) {
+ for(int index = 3; index < array.length; index++) {
+ if(index == 3) {
+ stringBuilder.append(array[index].substring(1).replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ } else {
+ stringBuilder.append(" " + array[index]);
+ }
+ }
+ parsed = member_msgs_array[0].replace(":", "") + ": " + stringBuilder.toString();
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("NOTICE")) {
+ if(array.length > 4) {
+ for(int index = 3; index < array.length; index++) {
+ if(index == 3) {
+ stringBuilder.append(array[index].substring(1).replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ } else {
+ stringBuilder.append(" " + array[index]);
+ }
+ }
+ parsed = member_msgs_array[0].replace(":", "") + " sent a notification: " + stringBuilder;
+ }
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("NICK")) {
+ parsed = member_msgs_array[0].replace(":", "") + " changed nickname to " + array[2].replace(":", "");
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("353")) {
+ if(array.length > 5) {
+ for (int index = 5; index < array.length; index++) {
+ if (index == 5) {
+ stringBuilder.append(array[index].substring(1).replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ } else {
+ stringBuilder.append(", " + array[index]);
+ }
+ }
+ parsed = "Members (" + (int)(array.length - 5) + "): " + stringBuilder;
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ }
+ } else if(array[1].startsWith("TOPIC")) {
+ if(array.length > 3) {
+ for (int index = 3; index < array.length; index++) {
+ if (index == 3) {
+ stringBuilder.append(array[index].substring(1).replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ } else {
+ stringBuilder.append(" " + array[index]);
+ }
+ }
+ parsed = "Topic: " + stringBuilder;
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ }
+ } else if(array[1].startsWith("311")) {
+ if(array.length > 7) {
+ for (int index = 7; index < array.length; index++) {
+ if (index == 7) {
+ stringBuilder.append(array[index].substring(1).replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ } else {
+ stringBuilder.append(" " + array[index].replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ }
+ }
+ parsed = array[3] + " (" + array[4] + "@" + array[5] + ")\r\nReal name: " + stringBuilder + "\r\n------------------------------";
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ }
+ } else if(array[1].startsWith("319")) {
+ if(array.length > 4) {
+ for (int index = 4; index < array.length; index++) {
+ if (index == 4) {
+ stringBuilder.append(array[index].substring(1).replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ } else {
+ stringBuilder.append(" " + array[index].replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ }
+ }
+ parsed = "Mutual channels: " + stringBuilder;
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ }
+ } else if(array[1].startsWith("317")) {
+ if(array.length > 4) {
+ try {
+ Date idle_time = new Date(TimeUnit.SECONDS.toMillis(Integer.parseInt(array[4])));
+ Date logon_time = new Date(TimeUnit.SECONDS.toMillis(Integer.parseInt(array[5])));
+ parsed = new SimpleDateFormat("HH:mm:ss").format(idle_time) + " idle, last logon time - " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(logon_time);
+ } catch(Exception e) {
+ e.printStackTrace();
+ parsed = "";
+ }
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]\r\nDate: " + System.currentTimeMillis());
+ }
+ } else if(array[1].startsWith("MODE")) {
+ if(array.length > 3) {
+ for (int index = 3; index < array.length; index++) {
+ if (index == 3) {
+ stringBuilder.append(array[index].substring(1).replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ } else {
+ stringBuilder.append(" " + array[index]);
+ }
+ }
+ parsed = "Enabled user modes for " + member_msgs_array[0].substring(1) + ": " + stringBuilder;
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ }
+ } else {
+ try {
+ if(array.length > 3) {
+ for (int index = 3; index < array.length; index++) {
+ if (index == 3) {
+ stringBuilder.append(array[index].substring(1).replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ } else {
+ stringBuilder.append(" " + array[index]);
+ }
+ }
+ parsed = "Code " + Integer.parseInt(array[1]) + ": " + stringBuilder.toString();
+ }
+ } catch(NumberFormatException nfe) {
+ parsed = raw;
+ }
+ }
+ if(showTimestamp == true && parsed.length() > 0 && array[1].startsWith("317") == false &&
+ array[1].startsWith("319") == false && array[1].startsWith("311") == false && array[1].startsWith("TOPIC") == false) {
+ Date time = new java.util.Date(System.currentTimeMillis());
+ parsed = parsed + " (" + new SimpleDateFormat("HH:mm:ss").format(time) + ")";
+ }
+ return parsed;
+ }
+
+
+
+ public String getMessageBody(String raw) {
+ String[] array = raw.split(" ");
+ String[] member_msgs_array = array[0].split("!");
+ StringBuilder stringBuilder = new StringBuilder();
+ String parsed = new String();
+ if(array[1].startsWith("PRIVMSG")) {
+ for(int index = 3; index < array.length; index++) {
+ if(index == 3) {
+ stringBuilder.append(array[index].substring(1).replace("http//", "http://")
+ .replace("https//", "https://").replace("ftp//", "ftp://"));
+ } else {
+ stringBuilder.append(" " + array[index]);
+ }
+ }
+ parsed = stringBuilder.toString();
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else {
+ parsed = "";
+ }
+ return parsed;
+ }
+
+ public String getMessageAuthor(String raw) {
+ String[] array = raw.split(" ");
+ String[] member_msgs_array = array[0].split("!");
+ StringBuilder stringBuilder = new StringBuilder();
+ String parsed = new String();
+ if(array[1].startsWith("PRIVMSG")) {
+ parsed = member_msgs_array[0].substring(1);
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else {
+ parsed = "";
+ }
+ return parsed;
+ }
+
+ public String getChannel(String raw) {
+ String[] array = raw.split(" ");
+ String[] member_msgs_array = array[0].split("!");
+ StringBuilder stringBuilder = new StringBuilder();
+ String parsed = new String();
+ if(array[1].startsWith("JOIN")) {
+ parsed = array[2].substring(1);
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("PRIVMSG")) {
+ parsed = array[2];
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else if(array[1].startsWith("PART")) {
+ parsed = array[2];
+ Log.i("Tinelix IRC Parser", "\r\nDone!\r\n\r\nOriginal string: [" + raw + "]\r\nCode: [" + array[1] + "]");
+ } else {
+ parsed = "";
+ }
+ return parsed;
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/MainActivity.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/MainActivity.java
new file mode 100644
index 0000000..31fd414
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/MainActivity.java
@@ -0,0 +1,233 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.os.Bundle;
+
+import android.content.Intent;
+import android.preference.PreferenceManager;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.Locale;
+
+public class MainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if(global_prefs.getBoolean("connected", false) == true) {
+ finish();
+ return;
+ }
+ setTitle(R.string.app_name);
+ setCustomTheme(global_prefs);
+ setContentView(R.layout.activity_main);
+ setColorStyle(global_prefs);
+ String[] mainMenu = getResources().getStringArray(R.array.main_menu_array);
+ ListView mainMenuList = (ListView) findViewById(R.id.mainmenu);
+
+ ArrayAdapter mainMenuAdapter = new ArrayAdapter(this,
+ android.R.layout.simple_list_item_1, mainMenu);
+
+ mainMenuList.setAdapter(mainMenuAdapter);
+
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ ImageButton menu_button = (ImageButton) findViewById(R.id.menu_button);
+ menu_button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ openOptionsMenu();
+ }
+ });
+ }
+
+ mainMenuList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
+ if(i == 0) {
+ showConnectionManager();
+ } else if(i == 1) {
+ showMainSettings();
+ } else if(i == 2) {
+ showAboutApplication();
+ } else if(i == 3) {
+ finish();
+ System.exit(0);
+ }
+ }
+ });
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ ImageButton menu_button = (ImageButton) findViewById(R.id.menu_button);
+ menu_button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ openOptionsMenu();
+ }
+ });
+ }
+
+ }
+
+ private void showMainSettings() {
+ Intent intent = new Intent(this, MainSettingsActivity.class);
+ startActivity(intent);
+ }
+
+ private void showAboutApplication() {
+ Intent intent = new Intent(this, AboutApplicationActivity.class);
+ startActivity(intent);
+ }
+
+ private void showConnectionManager() {
+ Intent intent = new Intent(this, ConnectionManagerActivity.class);
+ startActivity(intent);
+ }
+
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu)
+ {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.main_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+
+ //noinspection SimplifiableIfStatement
+ if (id == R.id.about_application_item) {
+ showAboutApplication();
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void setColorStyle(SharedPreferences global_prefs) {
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ ListView main_menu = (ListView) findViewById(R.id.mainmenu);
+ main_menu.setBackgroundColor(getResources().getColor(R.color.white));
+ main_menu.setCacheColorHint(getResources().getColor(R.color.white));
+ } else {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.title_v11_transparent));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ListView main_menu = (ListView) findViewById(R.id.mainmenu);
+ main_menu.setBackgroundColor(getResources().getColor(R.color.black));
+ main_menu.setCacheColorHint(getResources().getColor(R.color.black));
+ }
+ }
+ } else {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.title_v11_transparent));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ ListView main_menu = (ListView) findViewById(R.id.mainmenu);
+ main_menu.setBackgroundColor(getResources().getColor(R.color.black));
+ main_menu.setCacheColorHint(getResources().getColor(R.color.black));
+ } else {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ ListView main_menu = (ListView) findViewById(R.id.mainmenu);
+ main_menu.setBackgroundColor(getResources().getColor(R.color.white));
+ main_menu.setCacheColorHint(getResources().getColor(R.color.white));
+ }
+ }
+ }
+ }
+
+ private void setCustomTheme(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ }
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient_Light);
+ } else {
+ setTheme(R.style.IRCClient);
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient);
+ } else {
+ setTheme(R.style.IRCClient_Light);
+ }
+ }
+ }
+
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/MainSettingsActivity.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/MainSettingsActivity.java
new file mode 100644
index 0000000..bfedb35
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/MainSettingsActivity.java
@@ -0,0 +1,773 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.AlertDialog;
+import android.app.DialogFragment;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.preference.CheckBoxPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceManager;
+import android.provider.Settings;
+import android.text.Html;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import org.w3c.dom.Text;
+
+import java.io.File;
+import java.util.Locale;
+
+public class MainSettingsActivity extends PreferenceActivity {
+
+ public String package_name;
+ public String current_parameter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ setCustomTheme(global_prefs);
+ setColorStyle(global_prefs);
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.main_settings);
+ setContentView(R.layout.custom_preferences_layout);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ getActionBar().setHomeButtonEnabled(true);
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ } else {
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setText(R.string.settings_title);
+ }
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ final Preference ui_language = findPreference("interface_language");
+ ui_language.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ setResult(Activity.RESULT_OK);
+ current_parameter = "setting_language";
+ final String current_value;
+ final String[] value = {new String()};
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment setFontSizeDialogFragm = new SettingsItemsDialogFragm();
+ setFontSizeDialogFragm.show(getFragmentManager(), "settings_items");
+ } else {
+ current_value = getCurrentValue(current_parameter);
+ final String[] languages = getResources().getStringArray(R.array.ui_language);
+ final String[] requires_reboot_app = getResources().getStringArray(R.array.ui_language_app_restart_toast);
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ final AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.interface_language_item) + ""));
+ } else {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.interface_language_item) + ""));
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.interface_language_item) + ""));
+ } else {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.interface_language_item) + ""));
+ }
+ }
+ if(current_value.contains("OS dependent")) {
+ dialogBuilder.setSingleChoiceItems(languages, 0,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if(item == 0) {
+ value[0] = "OS dependent";
+ } else if(item == 1) {
+ value[0] = "English";
+ } else {
+ value[0] = "Russian";
+ }
+ }
+ });
+ } else if(current_value.contains("English")) {
+ dialogBuilder.setSingleChoiceItems(languages, 1,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if(item == 0) {
+ value[0] = "OS dependent";
+ } else if(item == 1) {
+ value[0] = "English";
+ } else {
+ value[0] = "Russian";
+ }
+ }
+ });
+ } else {
+ dialogBuilder.setSingleChoiceItems(languages, 2,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if(item == 0) {
+ value[0] = "OS dependent";
+ } else if(item == 1) {
+ value[0] = "English";
+ } else {
+ value[0] = "Russian";
+ }
+ }
+ });
+ }
+ dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ onChangingValues(current_parameter, value[0]);
+ SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if(global_prefs.getBoolean("connected", false) == false) {
+ Intent mainActivity = new Intent(getApplicationContext(), this.getClass());
+ int pendingIntentId = 1;
+ PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), pendingIntentId, mainActivity, PendingIntent.FLAG_CANCEL_CURRENT);
+ AlarmManager mgr = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+ mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent);
+ System.exit(0);
+ } else {
+ if(current_value.contains("Russian")) {
+ Toast.makeText(getApplicationContext(), requires_reboot_app[1], Toast.LENGTH_LONG).show();
+ } else {
+ Toast.makeText(getApplicationContext(), requires_reboot_app[0], Toast.LENGTH_LONG).show();
+ }
+ }
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ }
+ });
+ AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+
+ alertDialog.show();
+ Button dialogButton;
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return true;
+ }
+ });
+ String[] languages = getResources().getStringArray(R.array.ui_language);
+ if (global_prefs.getBoolean("language_requires_restart", false) == false) {
+ if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ ui_language.setSummary(languages[1]);
+ } else if (global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ ui_language.setSummary(languages[2]);
+ } else {
+ ui_language.setSummary(languages[0]);
+ }
+ } else {
+ ui_language.setSummary(R.string.need_to_restart);
+ ui_language.setEnabled(false);
+ }
+ final Preference app_theme = findPreference("interface_theme");
+ final String[] value = {new String()};
+ app_theme.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ setResult(Activity.RESULT_OK);
+ current_parameter = "setting_theme";
+ final String current_value;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment setFontSizeDialogFragm = new SettingsItemsDialogFragm();
+ setFontSizeDialogFragm.show(getFragmentManager(), "settings_items");
+ } else {
+ current_value = getCurrentValue(current_parameter);
+ final String[] requires_reboot_app = getResources().getStringArray(R.array.ui_language_app_restart_toast);
+ final String[] themes = getResources().getStringArray(R.array.themes);
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ final AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.interface_theme_item) + ""));
+ } else {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.interface_theme_item) + ""));
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.interface_theme_item) + ""));
+ } else {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.interface_theme_item) + ""));
+ }
+ }
+ if(current_value.contains("Light")) {
+ dialogBuilder.setSingleChoiceItems(themes, 1,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if(item == 0) {
+ value[0] = "Dark";
+ } else {
+ value[0] = "Light";
+ }
+ }
+ });
+ } else {
+ dialogBuilder.setSingleChoiceItems(themes, 0,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if(item == 0) {
+ value[0] = "Dark";
+ } else {
+ value[0] = "Light";
+ }
+ }
+ });
+ }
+ dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ onChangingValues(current_parameter, value[0]);
+ if(global_prefs.getBoolean("connected", false) == false) {
+ Intent mainActivity = new Intent(getApplicationContext(), this.getClass());
+ int pendingIntentId = 1;
+ PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), pendingIntentId, mainActivity, PendingIntent.FLAG_CANCEL_CURRENT);
+ AlarmManager mgr = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+ mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent);
+ System.exit(0);
+ } else {
+ if(current_value.contains("Russian")) {
+ Toast.makeText(getApplicationContext(), requires_reboot_app[0], Toast.LENGTH_LONG).show();
+ } else {
+ Toast.makeText(getApplicationContext(), requires_reboot_app[1], Toast.LENGTH_LONG).show();
+ }
+ }
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ app_theme.setSummary(themes[1]);
+ } else {
+ app_theme.setSummary(themes[0]);
+ }
+ } else {
+ app_theme.setSummary(R.string.need_to_restart);
+ app_theme.setEnabled(false);
+ }
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ }
+ });
+ AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+
+ alertDialog.show();
+ Button dialogButton;
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return true;
+ }
+ });
+ String[] themes = getResources().getStringArray(R.array.themes);
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ app_theme.setSummary(themes[1]);
+ } else {
+ app_theme.setSummary(themes[0]);
+ }
+ } else {
+ app_theme.setSummary(R.string.need_to_restart);
+ app_theme.setEnabled(false);
+ }
+
+ Preference setFontSizePref = findPreference("font_size");
+ setFontSizePref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ setResult(Activity.RESULT_OK);
+ current_parameter = "setting_fontsize";
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment setFontSizeDialogFragm = new SetFontSizeDialogFragm();
+ setFontSizeDialogFragm.show(getFragmentManager(), "set_font_size");
+ } else {
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ final AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(MainSettingsActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.set_font_size_activity, null);
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ final SeekBar font_size_seekbar = (SeekBar) dialogView.findViewById(R.id.font_size_seekbar);
+ final EditText preview_text = (EditText) dialogView.findViewById(R.id.preview_text);
+ final TextView value_label = (TextView) dialogView.findViewById(R.id.value_label);
+ dialogBuilder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt("font_size", font_size_seekbar.getProgress() + 12);
+ editor.commit();
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ preview_text.setKeyListener(null);
+ font_size_seekbar.setMax((60 - 12) / 1);
+ font_size_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+ preview_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, i + 12);
+ value_label.setText(getString(R.string.value_in_px, i + 12));
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+ if(prefs.getInt("font_size", 0) < 12) {
+ float text_size_in_sp = (int) preview_text.getTextSize() / getResources().getDisplayMetrics().scaledDensity;
+ font_size_seekbar.setProgress((int) text_size_in_sp - 12);
+ value_label.setText(getString(R.string.value_in_px, (int)text_size_in_sp));
+ preview_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, text_size_in_sp);
+ } else {
+ font_size_seekbar.setProgress(prefs.getInt("font_size", 0) - 12);
+ value_label.setText(getString(R.string.value_in_px, prefs.getInt("font_size", 0)));
+ preview_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, prefs.getInt("font_size", 0));
+ }
+ TextView dialog_title = (TextView) dialogView.findViewById(R.id.dialog_title);
+ dialog_title.setText(getString(R.string.changing_font_label));
+ dialogBuilder.setView(dialogView);
+ AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+
+ alertDialog.show();
+ Button dialogButton;
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return true;
+ }
+ });
+ setFontSizePref.setSummary(getString(R.string.value_in_px, prefs.getInt("font_size", 18)));
+
+ final CheckBoxPreference save_msg_history = (CheckBoxPreference) findPreference("save_msg_history");
+
+ save_msg_history.setChecked(global_prefs.getBoolean("save_msg_history", false));
+
+ File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
+ if (!directory.canWrite() && !directory.canRead()) {
+ save_msg_history.setChecked(false);
+ onChangingBooleanValues("setting_saving_msg_history", false);
+ save_msg_history.setEnabled(false);
+ save_msg_history.setSummary(R.string.device_memory_restricted);
+ }
+
+ save_msg_history.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ if(save_msg_history.isChecked() == true) {
+ save_msg_history.setSummary(getResources().getString(R.string.saved_messages_history, "Tinelix/IRC Client/Messages Logs"));
+ }
+
+ current_parameter = "setting_saving_msg_history";
+ onChangingBooleanValues(current_parameter, save_msg_history.isChecked());
+ return false;
+ }
+ });
+ Preference debug_logs = findPreference("debug_logs");
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ debug_logs.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ showDebugLogsActivity();
+ return false;
+ }
+ });
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ CheckBoxPreference save_msg_history = (CheckBoxPreference) findPreference("save_msg_history");
+ SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(MainSettingsActivity.this);
+ File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
+ if (!directory.canWrite() && !directory.canRead()) {
+ save_msg_history.setChecked(false);
+ save_msg_history.setEnabled(false);
+ save_msg_history.setSummary(R.string.device_memory_restricted);
+ } else {
+ save_msg_history.setChecked(global_prefs.getBoolean("save_msg_history", false));
+ save_msg_history.setSummary(getResources().getString(R.string.saved_messages_history, "Tinelix/IRC Client/Messages Logs"));
+ }
+ super.onResume();
+ }
+
+ private void showMissingPermssionDialog() {
+ AlertDialog dialog;
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(getResources().getString(R.string.allow_permisssion_in_storage_title));
+ builder.setMessage(getResources().getString(R.string.allow_permisssion_in_storage));
+ builder.setPositiveButton(getResources().getString(R.string.open_button), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ Uri uri = Uri.fromParts("package", getPackageName(), null);
+ intent.setData(uri);
+ startActivity(intent);
+ }
+ });
+ builder.setNegativeButton(getResources().getString(R.string.cancel_button), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ CheckBoxPreference save_msg_history = (CheckBoxPreference) findPreference("save_msg_history");
+ save_msg_history.setChecked(false);
+ onChangingBooleanValues(current_parameter, save_msg_history.isChecked());
+ return;
+ }
+ });
+ dialog = builder.create();
+ dialog.show();
+ }
+
+ private void showDebugLogsActivity() {
+ Intent intent = new Intent(this, DebugLogsActivity.class);
+ startActivity(intent);
+ }
+
+ public String getCurrentParameter() {
+ return current_parameter;
+ }
+
+ public String getCurrentValue(String current_parameter) {
+ String value;
+ if(current_parameter == "setting_language") {
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ value = prefs.getString("language", "OS dependent");
+ } else if(current_parameter == "setting_theme") {
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ value = prefs.getString("theme", "Dark");
+ } else {
+ value = "";
+ }
+ return value;
+ }
+
+ public void onChangingValues(String current_parameter, String value) {
+ if(current_parameter == "setting_language") {
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("language", value);
+ editor.putBoolean("language_requires_restart", true);
+ editor.commit();
+ Preference ui_language = findPreference("interface_language");
+ final String[] languages = getResources().getStringArray(R.array.ui_language);
+ if(prefs.getBoolean("language_requires_restart", false) == false) {
+ if (prefs.getString("language", "OS dependent").contains("English")) {
+ ui_language.setSummary(languages[1]);
+ } else if (prefs.getString("language", "OS dependent").contains("Russian")) {
+ ui_language.setSummary(languages[2]);
+ } else {
+ ui_language.setSummary(languages[0]);
+ }
+ } else {
+ ui_language.setSummary(R.string.need_to_restart);
+ ui_language.setEnabled(false);
+ }
+ } else if(current_parameter == "setting_theme") {
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("theme", value);
+ editor.putBoolean("theme_requires_restart", true);
+ editor.commit();
+ Preference theme = findPreference("interface_theme");
+ final String[] themes = getResources().getStringArray(R.array.themes);
+ if(prefs.getBoolean("theme_requires_restart", false) == false) {
+ if (prefs.getString("theme", "Dark").contains("Light")) {
+ theme.setSummary(themes[1]);
+ } else {
+ theme.setSummary(themes[0]);
+ }
+ } else {
+ theme.setSummary(R.string.need_to_restart);
+ theme.setEnabled(false);
+ }
+ }
+ }
+
+ private void onChangingBooleanValues(String current_parameter, boolean value) {
+ if(current_parameter == "setting_saving_msg_history") {
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean("save_msg_history", value);
+ editor.commit();
+ }
+ }
+
+ public void showDebugLogActivity() {
+ Intent intent = new Intent(this, ConnectionManagerActivity.class);
+ startActivity(intent);
+ }
+
+ public void setColorStyle(SharedPreferences global_prefs) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ getListView().setBackgroundColor(getResources().getColor(R.color.white));
+ getListView().setCacheColorHint(getResources().getColor(R.color.white));
+ } else {
+ getListView().setBackgroundColor(getResources().getColor(R.color.black));
+ getListView().setCacheColorHint(getResources().getColor(R.color.black));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ getListView().setBackgroundColor(getResources().getColor(R.color.black));
+ getListView().setCacheColorHint(getResources().getColor(R.color.black));
+ } else {
+ getListView().setBackgroundColor(getResources().getColor(R.color.white));
+ getListView().setCacheColorHint(getResources().getColor(R.color.white));
+ }
+ }
+ }
+ }
+
+ private void setCustomTheme(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ }
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient_Light);
+ } else {
+ setTheme(R.style.IRCClient);
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient);
+ } else {
+ setTheme(R.style.IRCClient_Light);
+ }
+ }
+ }
+
+ private void customizeDialogStyle(Button dialogButton, SharedPreferences global_prefs, AlertDialog alertDialog) {
+ if(global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+ if(id == android.R.id.home) {
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
+ onBackPressed();
+ } else {
+ finish();
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/NotificationActivity.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/NotificationActivity.java
new file mode 100644
index 0000000..582ad3a
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/NotificationActivity.java
@@ -0,0 +1,52 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+
+import java.util.Locale;
+
+public class NotificationActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ }
+ setContentView(R.layout.notification_activity);
+ }
+
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/Profile.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/Profile.java
new file mode 100644
index 0000000..89de209
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/Profile.java
@@ -0,0 +1,18 @@
+package dev.tinelix.irc.android.legacy;
+
+public class Profile {
+
+ String name;
+ String server;
+ int port;
+ boolean isConnected;
+ boolean isSelected;
+
+ Profile(String _describe, String _server, int _port, boolean _isConnected, boolean _isSelected) {
+ name = _describe;
+ server = _server;
+ port = _port;
+ isConnected = _isConnected;
+ isSelected = _isSelected;
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/ProfileAdapter.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/ProfileAdapter.java
new file mode 100644
index 0000000..d46f2af
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/ProfileAdapter.java
@@ -0,0 +1,144 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.app.Activity;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+
+public class ProfileAdapter extends BaseAdapter {
+ Context ctx;
+ LayoutInflater inflater;
+ ArrayList objects;
+
+ ProfileAdapter(Context context, ArrayList products) {
+ ctx = context;
+ objects = products;
+ inflater = (LayoutInflater) ctx
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ public int getCount() {
+ return objects.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return objects.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ Profile getProfile(int position) {
+ return ((Profile) getItem(position));
+ }
+
+ @Override
+ public View getView(final int position, View convertView, final ViewGroup parent) {
+ View view = convertView;
+ if (view == null) {
+ view = inflater.inflate(R.layout.profile_item, parent, false);
+ }
+
+ Profile p = getProfile(position);
+ ((TextView) view.findViewById(R.id.profile_item_label)).setText(p.name);
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(view.getContext());
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ ((TextView) view.findViewById(R.id.profile_item_label)).setTextColor(view.getResources().getColor(R.color.black));
+ } else {
+ ((TextView) view.findViewById(R.id.profile_item_label)).setTextColor(view.getResources().getColor(R.color.white));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ ((TextView) view.findViewById(R.id.profile_item_label)).setTextColor(view.getResources().getColor(R.color.white));
+ } else {
+ ((TextView) view.findViewById(R.id.profile_item_label)).setTextColor(view.getResources().getColor(R.color.black));
+ }
+ }
+ SharedPreferences prefs = view.getContext().getSharedPreferences(p.name, 0);
+ if(prefs.getBoolean("connected", false) == true) {
+ view.findViewById(R.id.state_indicator).setVisibility(View.VISIBLE);
+ ImageButton edit_btn = (ImageButton) view.findViewById(R.id.edit_btn);
+ edit_btn.setVisibility(View.GONE);
+ ImageButton delete_btn = (ImageButton) view.findViewById(R.id.delete_btn);
+ delete_btn.setVisibility(View.GONE);
+ } else {
+ view.findViewById(R.id.state_indicator).setVisibility(View.GONE);
+ }
+ ((TextView) view.findViewById(R.id.profile_server_label)).setText(p.server + ":" + p.port);
+ ImageButton edit_btn = (ImageButton) view.findViewById(R.id.edit_btn);
+ edit_btn.setTag(position);
+ edit_btn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ for (int pos = 0; pos < getCount(); pos++) {
+ if(pos == position) {
+ ((Profile) getItem(pos)).isSelected = true;
+ ((ConnectionManagerActivity) ctx).editProfile(pos);
+ } else {
+ ((Profile) getItem(pos)).isSelected = false;
+ }
+ }
+ }
+ });
+ ImageButton delete_btn = (ImageButton) view.findViewById(R.id.delete_btn);
+ delete_btn.setTag(position);
+ delete_btn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ for (int pos = 0; pos < getCount(); pos++) {
+ if(pos == position) {
+ ((Profile) getItem(pos)).isSelected = true;
+ ((ConnectionManagerActivity) ctx).deleteProfile(pos);
+ } else {
+ ((Profile) getItem(pos)).isSelected = false;
+ }
+ }
+ }
+ });
+ ImageButton connect_btn = (ImageButton) view.findViewById(R.id.connect_btn);
+ connect_btn.setTag(position);
+ connect_btn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ for (int pos = 0; pos < getCount(); pos++) {
+ if(pos == position) {
+ ((Profile) getItem(pos)).isSelected = true;
+ ((Profile) getItem(pos)).isConnected = true;
+ ((ConnectionManagerActivity) ctx).connectProfile(pos);
+ } else {
+ ((Profile) getItem(pos)).isSelected = false;
+ }
+ }
+ }
+ });
+ return view;
+ }
+
+ public class ViewHolder {
+ public TextView profile_name;
+ public TextView server;
+ }
+
+
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/ProfileSettingsActivity.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/ProfileSettingsActivity.java
new file mode 100644
index 0000000..de1148d
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/ProfileSettingsActivity.java
@@ -0,0 +1,1100 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceManager;
+import android.text.Editable;
+import android.text.Html;
+import android.text.TextWatcher;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import org.w3c.dom.Text;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+
+public class ProfileSettingsActivity extends PreferenceActivity
+{
+ public String old_profile_name;
+ public String package_name;
+ public String current_parameter;
+ public String auth_method_string;
+ public String server_name;
+ public int server_port;
+ public String realname_string;
+ public String hostname_string;
+ public String quitmsg_string;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ setCustomTheme(global_prefs);
+ setColorStyle(global_prefs);
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.profile_settings);
+ setContentView(R.layout.custom_preferences_layout);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ getActionBar().setHomeButtonEnabled(true);
+ getActionBar().setTitle(getResources().getString(R.string.connection_manager_title));
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ } else {
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setText(R.string.connection_manager_title);
+ }
+
+ if (savedInstanceState == null) {
+ Bundle extras = getIntent().getExtras();
+ if(extras == null) {
+ old_profile_name = null;
+ package_name = null;
+ } else {
+ old_profile_name = extras.getString("profile_name");
+ package_name = extras.getString("package_name");
+ }
+ } else {
+ old_profile_name = (String) savedInstanceState.getSerializable("profile_name");
+ package_name = (String) savedInstanceState.getSerializable("package_name");
+ }
+ final Preference prof_name = (Preference) findPreference("prof_name");
+ prof_name.setSummary(old_profile_name);
+ prof_name.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener()
+ {
+ public boolean onPreferenceClick(Preference pref)
+ {
+ setResult(Activity.RESULT_OK);
+ current_parameter = "changing_profile_name";
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment enterTextDialogFragm = new EnterTextDialogFragm2();
+ enterTextDialogFragm.show(getFragmentManager(), "enter_text_dlg");
+ } else {
+ final AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ String old_profile_name = getCurrentValue(current_parameter);
+ LayoutInflater inflater = getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.enter_text_activity, null);
+ final EditText profile_name = (EditText) dialogView.findViewById(R.id.profile_name_text);
+ profile_name.setText(old_profile_name);
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ dialogBuilder.setView(dialogView);
+ dialogBuilder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) dialogView.findViewById(R.id.profile_name_text);
+ onChangingValues(current_parameter, profile_name.getText().toString());
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+
+ }
+ });
+ TextView dialog_title = (TextView) dialogView.findViewById(R.id.dialog_title);
+ dialog_title.setText(getString(R.string.enter_the_pfn_title));
+ final AlertDialog alertDialog = dialogBuilder.create();
+ profile_name.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ if(profile_name.getText().toString().contains("/")) {
+ profile_name.setError(getResources().getString(R.string.text_field_wrong_characters));
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
+ } else {
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+
+ }
+ });
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+ alertDialog.show();
+ Button dialogButton = null;
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return true;
+ }
+ });
+ Preference auth_method = (Preference) findPreference("auth_method");
+ auth_method.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener()
+ {
+ public boolean onPreferenceClick(Preference pref)
+ {
+ setResult(Activity.RESULT_OK);
+ current_parameter = "changing_auth_method";
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment enterTextDialogFragm = new EnterTextDialogFragm2();
+ enterTextDialogFragm.show(getFragmentManager(), "enter_text_dlg");
+ } else {
+ final AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ String current_value = getCurrentValue(current_parameter);
+ String[] auth_methods = getResources().getStringArray(R.array.auth_method);
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.auth_method) + ""));
+ } else {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.auth_method) + ""));
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.auth_method) + ""));
+ } else {
+ dialogBuilder.setTitle(Html.fromHtml("" + getString(R.string.auth_method) + ""));
+ }
+ }
+ if(current_value.contains("NickServ")) {
+ dialogBuilder.setSingleChoiceItems(auth_methods, 1,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ String value;
+ if(item == 0) {
+ value = "Disabled";
+ } else {
+ value = "NickServ";
+ }
+ onChangingValues(current_parameter, value);
+ }
+ });
+ } else {
+ dialogBuilder.setSingleChoiceItems(auth_methods, 0,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ String value;
+ if(item == 0) {
+ value = "Disabled";
+ } else {
+ value = "NickServ";
+ }
+ onChangingValues(current_parameter, value);
+ }
+ });
+ }
+ dialogBuilder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+
+ }
+ });
+ AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+ alertDialog.show();
+ Button dialogButton = null;
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return true;
+ }
+ });
+ Preference nicknames = (Preference) findPreference("nicknames");
+ nicknames.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener()
+ {
+ public boolean onPreferenceClick(Preference pref)
+ {
+ showNicknamesActivity(old_profile_name);
+ return true;
+ }
+ });
+ Preference password = (Preference) findPreference("password");
+ password.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener()
+ {
+ public boolean onPreferenceClick(Preference pref)
+ {
+ setResult(Activity.RESULT_OK);
+ current_parameter = "setting_password";
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment enterPasswordDialogFragm = new EnterPasswordDialogFragm();
+ enterPasswordDialogFragm.show(getFragmentManager(), "enter_password_dlg");
+ } else {
+ final AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.enter_password_activity, null);
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ dialogBuilder.setView(dialogView);
+ dialogBuilder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) dialogView.findViewById(R.id.password_text);
+ onChangingValues(current_parameter, profile_name.getText().toString());
+ }
+ });
+
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+
+ }
+ });
+ TextView dialog_title = (TextView) dialogView.findViewById(R.id.dialog_title);
+ dialog_title.setText(getString(R.string.enter_the_password_title));
+ AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+ alertDialog.show();
+ Button dialogButton = null;
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return true;
+ }
+ });
+ Preference server_settings = (Preference) findPreference("server_settings");
+ server_settings.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener()
+ {
+ public boolean onPreferenceClick(Preference pref)
+ {
+ setResult(Activity.RESULT_OK);
+ current_parameter = "setting_server";
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment serverSettingsDialogFragm = new ServerSettingsDialogFragm();
+ serverSettingsDialogFragm.show(getFragmentManager(), "server_settings_dlg");
+ } else {
+ final AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.enter_server_activity, null);
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ dialogBuilder.setView(dialogView);
+ final Spinner encoding_spinner = (Spinner) dialogView.findViewById(R.id.encoding_spinner);
+ final EditText server_name = (EditText) dialogView.findViewById(R.id.server_text);
+ final EditText port_number = (EditText) dialogView.findViewById(R.id.port_numb);
+ final CheckBox hide_ip_cb = (CheckBox) dialogView.findViewById(R.id.hide_ip_checkbox);
+ final CheckBox force_ssl_cb = (CheckBox) dialogView.findViewById(R.id.force_ssl_checkbox);
+ dialogBuilder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ String[] encoding_array = getResources().getStringArray(R.array.encoding_array);
+ String encoding = new String();
+ String force_ssl = new String();
+ if(encoding_spinner.getSelectedItemPosition() == 0) {
+ encoding = "utf-8";
+ } else if(encoding_spinner.getSelectedItemPosition() == 1) {
+ encoding = "cp866";
+ } else if(encoding_spinner.getSelectedItemPosition() == 2) {
+ encoding = "windows-1251";
+ } else if(encoding_spinner.getSelectedItemPosition() == 3) {
+ encoding = "koi8_r";
+ } else if(encoding_spinner.getSelectedItemPosition() == 4) {
+ encoding = "koi8_u";
+ };
+ String hide_ip = new String();
+ if(hide_ip_cb.isChecked() == true) {
+ hide_ip = "Enabled";
+ } else {
+ hide_ip = "Disabled";
+ }
+ if(force_ssl_cb.isChecked() == true) {
+ force_ssl = "Enabled";
+ } else {
+ force_ssl = "Disabled";
+ }
+ onSettingServer(server_name.getText().toString(),
+ port_number.getText().toString(), encoding, hide_ip, force_ssl);
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+
+ }
+ });
+
+ String[] encoding_array = getResources().getStringArray(R.array.encoding_array);
+ String server_parameter = new String();
+ String current_value = new String();
+ server_parameter = "changing_server";
+ current_value = getCurrentValue(server_parameter);
+ final EditText server_text = (EditText) dialogView.findViewById(R.id.server_text);
+ server_text.setText(current_value);
+ server_parameter = "changing_port";
+ current_value = getCurrentValue(server_parameter);
+ EditText port_numb = (EditText) dialogView.findViewById(R.id.port_numb);
+ port_numb.setText(current_value);
+ server_parameter = "changing_encoding";
+ current_value = getCurrentValue(server_parameter);
+ if(current_value.contains("utf-8")) {
+ encoding_spinner.setSelection(0);
+ } else if(current_value.contains("cp866")) {
+ encoding_spinner.setSelection(1);
+ } else if(current_value.contains("windows-1251")) {
+ encoding_spinner.setSelection(2);
+ } else if(current_value.contains("koi8_r")) {
+ encoding_spinner.setSelection(3);
+ } else if(current_value.contains("koi8_u")) {
+ encoding_spinner.setSelection(4);
+ }
+
+ server_parameter = "hide_ip";
+ current_value = getCurrentValue(server_parameter);
+ if(current_value.contains("Disabled")) {
+ hide_ip_cb.setChecked(false);
+ } else {
+ hide_ip_cb.setChecked(true);
+ }
+
+ server_parameter = "force_ssl";
+ current_value = getCurrentValue(server_parameter);
+ if(current_value.contains("Disabled")) {
+ force_ssl_cb.setChecked(false);
+ } else {
+ force_ssl_cb.setChecked(true);
+ }
+
+ customizeServerSettingsDialog(global_prefs, dialogView);
+ TextView dialog_title = (TextView) dialogView.findViewById(R.id.dialog_title);
+ dialog_title.setText(getString(R.string.server_settings));
+ Spinner spinner = (Spinner) dialogView.findViewById(R.id.encoding_spinner);
+
+ ArrayList spinnerArray = new ArrayList();
+ spinnerArray.clear();
+ for (int i = 0; i < 5; i++) {
+ spinnerArray.add(new CustomSpinnerItem(getResources().getStringArray(R.array.encoding_array)[i]));
+ }
+ CustomSpinnerAdapter customSpinnerAdapter = new CustomSpinnerAdapter(dialogView.getContext(), spinnerArray);
+ spinner.setAdapter(customSpinnerAdapter);
+ final AlertDialog alertDialog = dialogBuilder.create();
+ server_text.addTextChangedListener(new TextWatcher() {
+
+ public void afterTextChanged(Editable s) { }
+
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ if(server_text.getText().toString().contains(":")) {
+ server_text.setError(getResources().getString(R.string.text_field_wrong_characters));
+ ((AlertDialog) alertDialog).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
+ } else {
+ ((AlertDialog) alertDialog).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
+ }
+ }
+ });
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+ alertDialog.show();
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ server_name.setTextColor(getResources().getColor(R.color.black));
+ port_number.setTextColor(getResources().getColor(R.color.black));
+ } else {
+ server_name.setTextColor(getResources().getColor(R.color.white));
+ port_number.setTextColor(getResources().getColor(R.color.white));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ server_name.setTextColor(getResources().getColor(R.color.white));
+ port_number.setTextColor(getResources().getColor(R.color.white));
+ } else {
+ server_name.setTextColor(getResources().getColor(R.color.black));
+ port_number.setTextColor(getResources().getColor(R.color.black));
+ }
+ }
+ if(getResources().getDisplayMetrics().density == 0.75) {
+ server_name.setPadding(6, 0, 6, 0);
+ port_number.setPadding(6, 0, 6, 0);
+ } else {
+ server_name.setPadding(12, 0, 12, 0);
+ port_number.setPadding(12, 0, 12, 0);
+ }
+ Button dialogButton = null;
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return true;
+ }
+ });
+ Preference realname = (Preference) findPreference("realname");
+ realname.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener()
+ {
+ public boolean onPreferenceClick(Preference pref)
+ {
+ setResult(Activity.RESULT_OK);
+ current_parameter = "changing_realname";
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ realname_string = prefs.getString("realname", "");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment enterTextDialogFragm = new EnterTextDialogFragm2();
+ enterTextDialogFragm.show(getFragmentManager(), "enter_text_dlg");
+ } else {
+ final AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.enter_text_activity, null);
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ dialogBuilder.setView(dialogView);
+ dialogBuilder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) dialogView.findViewById(R.id.profile_name_text);
+ onChangingValues(current_parameter, profile_name.getText().toString());
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+
+ }
+ });
+ TextView textAreaTitle = (TextView) dialogView.findViewById(R.id.profile_name_label);
+ TextView dialog_title = (TextView) dialogView.findViewById(R.id.dialog_title);
+ EditText dialog_value = (EditText) dialogView.findViewById(R.id.profile_name_text);
+ dialog_value.setText(realname_string);
+ dialog_title.setText(getString(R.string.enter_the_realname_title));
+ AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+ alertDialog.show();
+ Button dialogButton = null;
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return true;
+ }
+ });
+ Preference hostname = (Preference) findPreference("hostname");
+ hostname.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener()
+ {
+ public boolean onPreferenceClick(Preference pref)
+ {
+ setResult(Activity.RESULT_OK);
+ current_parameter = "changing_hostname";
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ hostname_string = prefs.getString("hostname", "");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment enterTextDialogFragm = new EnterTextDialogFragm2();
+ enterTextDialogFragm.show(getFragmentManager(), "enter_text_dlg");
+ } else {
+ final AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.enter_text_activity, null);
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ dialogBuilder.setView(dialogView);
+ dialogBuilder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) dialogView.findViewById(R.id.profile_name_text);
+ onChangingValues(current_parameter, profile_name.getText().toString());
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+
+ }
+ });
+ TextView textAreaTitle = (TextView) dialogView.findViewById(R.id.profile_name_label);
+ textAreaTitle.setText(R.string.hostname);
+ TextView dialog_title = (TextView) dialogView.findViewById(R.id.dialog_title);
+ dialog_title.setText(getString(R.string.enter_the_hostname_title));
+ EditText dialog_value = (EditText) dialogView.findViewById(R.id.profile_name_text);
+ dialog_value.setText(hostname_string);
+ AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+ alertDialog.show();
+ Button dialogButton = null;
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return true;
+ }
+ });
+ Preference quit_msg = (Preference) findPreference("quit_message");
+ quit_msg.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener()
+ {
+ public boolean onPreferenceClick(Preference pref)
+ {
+ setResult(Activity.RESULT_OK);
+ current_parameter = "changing_quitmsg";
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ quitmsg_string = prefs.getString("quit_message", "");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment enterTextDialogFragm = new EnterTextDialogFragm2();
+ enterTextDialogFragm.show(getFragmentManager(), "enter_text_dlg");
+ } else {
+ final AlertDialog.Builder dialogBuilder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient));
+ } else {
+ dialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(ProfileSettingsActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.enter_text_activity, null);
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ dialogBuilder.setView(dialogView);
+ dialogBuilder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText profile_name = (EditText) dialogView.findViewById(R.id.profile_name_text);
+ onChangingValues(current_parameter, profile_name.getText().toString());
+ }
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+
+ }
+ });
+ TextView textAreaTitle = (TextView) dialogView.findViewById(R.id.profile_name_label);
+ textAreaTitle.setText(R.string.quit_message);
+ TextView dialog_title = (TextView) dialogView.findViewById(R.id.dialog_title);
+ dialog_title.setText(getString(R.string.enter_the_quiting_message));
+ EditText dialog_value = (EditText) dialogView.findViewById(R.id.profile_name_text);
+ dialog_value.setText(quitmsg_string);
+ AlertDialog alertDialog = dialogBuilder.create();
+ alertDialog.getWindow().setGravity(Gravity.BOTTOM);
+ alertDialog.show();
+ Button dialogButton = null;
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ return true;
+ }
+ });
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ auth_method_string = prefs.getString("auth_method", "");
+ if(auth_method_string.contains("NickServ")) {
+ auth_method.setSummary("NickServ");
+ password.setEnabled(true);
+ } else {
+ String[] auth_methods = getResources().getStringArray(R.array.auth_method);
+ auth_method.setSummary(auth_methods[0]);
+ password.setEnabled(false);
+ };
+ server_name = prefs.getString("server", "");
+ server_port = prefs.getInt("port", 0);
+ if(server_name.length() > 0 && server_port > 0) {
+ server_settings.setSummary(server_name + ":" + Integer.toString(server_port));
+ };
+ realname_string = prefs.getString("realname", "");
+ hostname_string = prefs.getString("hostname", "");
+ quitmsg_string = prefs.getString("quit_message", "");
+ realname.setSummary(realname_string);
+ hostname.setSummary(hostname_string);
+ quit_msg.setSummary(quitmsg_string);
+ }
+
+ private void customizeServerSettingsDialog(SharedPreferences global_prefs, View dialogView) {
+ EditText server_name = (EditText) dialogView.findViewById(R.id.server_text);
+ EditText port_edit = (EditText) dialogView.findViewById(R.id.port_numb);
+ Spinner spinner = (Spinner) dialogView.findViewById(R.id.encoding_spinner);
+
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ server_name.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_textarea_light));
+ server_name.setTextColor(getResources().getColor(R.color.black));
+ server_name.setTextAppearance(ProfileSettingsActivity.this, R.style.IRCClient_Light_TextArea);
+ } else {
+ server_name.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_textarea));
+ server_name.setTextColor(getResources().getColor(R.color.white));
+ server_name.setTextAppearance(ProfileSettingsActivity.this, R.style.IRCClient_TextArea);
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ server_name.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_textarea));
+ server_name.setTextColor(getResources().getColor(R.color.white));
+ server_name.setTextAppearance(ProfileSettingsActivity.this, R.style.IRCClient_TextArea);
+ } else {
+ server_name.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_textarea_light));
+ server_name.setTextColor(getResources().getColor(R.color.black));
+ server_name.setTextAppearance(ProfileSettingsActivity.this, R.style.IRCClient_Light_TextArea);
+ }
+ }
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ port_edit.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_textarea_light));
+ port_edit.setTextColor(getResources().getColor(R.color.black));
+ port_edit.setTextAppearance(ProfileSettingsActivity.this, R.style.IRCClient_Light_TextArea);
+ } else {
+ port_edit.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_textarea));
+ port_edit.setTextColor(getResources().getColor(R.color.white));
+ port_edit.setTextAppearance(ProfileSettingsActivity.this, R.style.IRCClient_TextArea);
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ port_edit.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_textarea));
+ port_edit.setTextColor(getResources().getColor(R.color.white));
+ port_edit.setTextAppearance(ProfileSettingsActivity.this, R.style.IRCClient_TextArea);
+ } else {
+ port_edit.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_textarea_light));
+ port_edit.setTextColor(getResources().getColor(R.color.black));
+ port_edit.setTextAppearance(ProfileSettingsActivity.this, R.style.IRCClient_Light_TextArea);
+ }
+ }
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner_light));
+ } else {
+ spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner));
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner));
+ } else {
+ spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner_light));
+ }
+ }
+ }
+
+ private void setCustomTheme(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ }
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient_Light);
+ } else {
+ setTheme(R.style.IRCClient);
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient);
+ } else {
+ setTheme(R.style.IRCClient_Light);
+ }
+ }
+ }
+
+ private void customizeDialogStyle(Button dialogButton, SharedPreferences global_prefs, AlertDialog alertDialog) {
+ if(global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ }
+ }
+
+ private void showNicknamesActivity(String profile_name) {
+ Intent intent = new Intent(this, CustomNicknamesActivity.class);
+ intent.putExtra("profile_name", profile_name);
+ startActivity(intent);
+ }
+
+ public void onChangingValues(String parameter, String value) {
+ Preference prof_name = (Preference) findPreference("prof_name");
+ Preference nicknames = (Preference) findPreference("nicknames");
+ if (parameter == "changing_profile_name") {
+ Context context = getApplicationContext();
+ String profile_path = "/data/data/" + package_name + "/shared_prefs/" + old_profile_name + ".xml";
+ File file = new File(profile_path);
+ file.delete();
+ SharedPreferences prefs = context.getSharedPreferences(value, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("name", value);
+ editor.commit();
+ old_profile_name = value;
+ prof_name.setSummary(old_profile_name);
+ } else if(parameter == "changing_auth_method") {
+ Preference auth_method = (Preference) findPreference("auth_method");
+ Preference password = (Preference) findPreference("password");
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ String[] auth_methods = getResources().getStringArray(R.array.auth_method);
+ editor.putString("auth_method", value);
+ if(value == "Disabled") {
+ auth_method.setSummary(auth_methods[0]);
+ password.setEnabled(false);
+ } else {
+ auth_method.setSummary(value);
+ password.setEnabled(true);
+ }
+ editor.commit();
+ } else if (parameter == "changing_nicknames") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("nicknames", value);
+ editor.commit();
+ nicknames.setSummary(value);
+ } else if (parameter == "setting_password") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("password", value);
+ editor.commit();
+ } else if (parameter == "changing_realname") {
+ Preference realname = (Preference) findPreference("realname");
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("realname", value);
+ editor.commit();
+ realname.setSummary(value);
+ } else if (parameter == "changing_hostname") {
+ Preference hostname = (Preference) findPreference("hostname");
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("hostname", value);
+ editor.commit();
+ hostname.setSummary(value);
+ } else if (parameter == "changing_quitmsg") {
+ Preference quit_msg = (Preference) findPreference("quit_message");
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("quit_message", value);
+ editor.commit();
+ quit_msg.setSummary(value);
+ }
+ }
+
+ public String getCurrentParameter() {
+ return current_parameter;
+ }
+
+ public String getCurrentValue(String parameter) {
+ String value;
+ if(parameter == "changing_profile_name") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ value = old_profile_name;
+ } else if(parameter == "changing_auth_method") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ value = prefs.getString("auth_method", "");
+ } else if(parameter == "changing_realname") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ value = prefs.getString("realname", "");
+ } else if(parameter == "changing_hostname") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ value = prefs.getString("hostname", "");
+ } else if(parameter == "changing_server") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ value = prefs.getString("server", "");
+ } else if(parameter == "changing_port") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ value = "" + prefs.getInt("port", 0);
+ } else if(parameter == "changing_encoding") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ value = prefs.getString("encoding", "");
+ } else if(parameter == "hide_ip") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ value = prefs.getString("hide_ip", "");
+ } else if(parameter == "force_ssl") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ value = prefs.getString("force_ssl", "");
+ } else if(parameter == "changing_quitmsg") {
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ value = prefs.getString("quit_message", "");
+ } else {
+ value = "";
+ };
+ return value;
+ }
+
+ public void onSettingServer(String server, String port, String encoding, String hide_ip, String force_ssl) {
+ Preference server_settings = (Preference) findPreference("server_settings");
+ Context context = getApplicationContext();
+ SharedPreferences prefs = context.getSharedPreferences(old_profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString("server", server);
+ editor.putInt("port", Integer.parseInt(port));
+ if(server.length() > 0 && port.length() > 0) {
+ server_settings.setSummary(server + ":" + port);
+ }
+ editor.putString("encoding", encoding);
+ editor.putString("hide_ip", hide_ip);
+ editor.putString("force_ssl", force_ssl);
+ editor.commit();
+ }
+
+ public void setColorStyle(SharedPreferences global_prefs) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ getListView().setBackgroundColor(getResources().getColor(R.color.white));
+ getListView().setCacheColorHint(getResources().getColor(R.color.white));
+ } else {
+ getListView().setBackgroundColor(getResources().getColor(R.color.black));
+ getListView().setCacheColorHint(getResources().getColor(R.color.black));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ getListView().setBackgroundColor(getResources().getColor(R.color.black));
+ getListView().setCacheColorHint(getResources().getColor(R.color.black));
+ } else {
+ getListView().setBackgroundColor(getResources().getColor(R.color.white));
+ getListView().setCacheColorHint(getResources().getColor(R.color.white));
+ }
+ }
+ }
+ }
+
+
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
+ if(id == android.R.id.home) {
+ onBackPressed();
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/ServerSettingsDialogFragm.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/ServerSettingsDialogFragm.java
new file mode 100644
index 0000000..654ea60
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/ServerSettingsDialogFragm.java
@@ -0,0 +1,196 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.text.Editable;
+import android.text.Html;
+import android.text.SpannableStringBuilder;
+import android.text.TextWatcher;
+import android.text.method.KeyListener;
+import android.text.style.ForegroundColorSpan;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import java.util.Locale;
+
+@SuppressLint("NewApi")
+public class ServerSettingsDialogFragm extends DialogFragment {
+
+ public String current_parameter;
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ setLocale(global_prefs);
+ current_parameter = ((ProfileSettingsActivity) getActivity()).getCurrentParameter();
+ String current_value;
+ String server_parameter;
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ if(current_parameter == "setting_server") {
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ final View view = inflater.inflate(R.layout.enter_server_activity, null);
+ final Spinner encoding_spinner = (Spinner) view.findViewById(R.id.encoding_spinner);
+ Context context = view.getContext();
+ ArrayAdapter> adapter =
+ ArrayAdapter.createFromResource(context, R.array.encoding_array,
+ android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ encoding_spinner.setAdapter(adapter);
+ builder.setView(view);
+ builder.setTitle(R.string.server_settings);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ EditText server_name = (EditText) view.findViewById(R.id.server_text);
+ EditText port_number = (EditText) view.findViewById(R.id.port_numb);
+ CheckBox hide_ip_cb = (CheckBox) view.findViewById(R.id.hide_ip_checkbox);
+ CheckBox force_ssl_cb = (CheckBox) view.findViewById(R.id.force_ssl_checkbox);
+ String[] encoding_array = getResources().getStringArray(R.array.encoding_array);
+ String encoding = new String();
+ String force_ssl = new String();
+ if(encoding_spinner.getSelectedItemPosition() == 0) {
+ encoding = "utf-8";
+ } else if(encoding_spinner.getSelectedItemPosition() == 1) {
+ encoding = "cp866";
+ } else if(encoding_spinner.getSelectedItemPosition() == 2) {
+ encoding = "windows-1251";
+ } else if(encoding_spinner.getSelectedItemPosition() == 3) {
+ encoding = "koi8_r";
+ } else if(encoding_spinner.getSelectedItemPosition() == 4) {
+ encoding = "koi8_u";
+ };
+ String hide_ip = new String();
+ if(hide_ip_cb.isChecked() == true) {
+ hide_ip = "Enabled";
+ } else {
+ hide_ip = "Disabled";
+ }
+ if(force_ssl_cb.isChecked() == true) {
+ force_ssl = "Enabled";
+ } else {
+ force_ssl = "Disabled";
+ }
+ ((ProfileSettingsActivity) getActivity()).onSettingServer(server_name.getText().toString(),
+ port_number.getText().toString(), encoding, hide_ip, force_ssl);
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ String[] encoding_array = getResources().getStringArray(R.array.encoding_array);
+ server_parameter = "changing_server";
+ current_value = ((ProfileSettingsActivity) getActivity()).getCurrentValue(server_parameter);
+ final EditText server_text = (EditText) view.findViewById(R.id.server_text);
+ server_text.setText(current_value);
+ server_text.addTextChangedListener(new TextWatcher() {
+
+ public void afterTextChanged(Editable s) { }
+
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ if(s.toString().contains(":")) {
+ server_text.setError(getResources().getString(R.string.text_field_wrong_characters));
+ ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
+ } else {
+ ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
+ }
+ }
+ });
+ server_parameter = "changing_port";
+ current_value = ((ProfileSettingsActivity) getActivity()).getCurrentValue(server_parameter);
+ EditText port_numb = (EditText) view.findViewById(R.id.port_numb);
+ port_numb.setText(current_value);
+ ArrayAdapter> encoding_adapter =
+ ArrayAdapter.createFromResource(view.getContext(), R.array.encoding_array,
+ android.R.layout.simple_spinner_item);
+ encoding_spinner.setAdapter(encoding_adapter);
+ server_parameter = "changing_encoding";
+ current_value = ((ProfileSettingsActivity) getActivity()).getCurrentValue(server_parameter);
+ if(current_value.contains("utf-8")) {
+ encoding_spinner.setSelection(0);
+ } else if(current_value.contains("cp866")) {
+ encoding_spinner.setSelection(1);
+ } else if(current_value.contains("windows-1251")) {
+ encoding_spinner.setSelection(2);
+ } else if(current_value.contains("koi8_r")) {
+ encoding_spinner.setSelection(3);
+ } else if(current_value.contains("koi8_u")) {
+ encoding_spinner.setSelection(4);
+ }
+ server_parameter = "hide_ip";
+ current_value = ((ProfileSettingsActivity) getActivity()).getCurrentValue(server_parameter);
+ CheckBox hide_ip_cb = (CheckBox) view.findViewById(R.id.hide_ip_checkbox);
+ if(current_value.contains("Disabled")) {
+ hide_ip_cb.setChecked(false);
+ } else {
+ hide_ip_cb.setChecked(true);
+ }
+
+ server_parameter = "force_ssl";
+ current_value = ((ProfileSettingsActivity) getActivity()).getCurrentValue(server_parameter);
+ CheckBox force_ssl_cb = (CheckBox) view.findViewById(R.id.force_ssl_checkbox);
+ if(current_value.contains("Disabled")) {
+ force_ssl_cb.setChecked(false);
+ } else {
+ force_ssl_cb.setChecked(true);
+ }
+ };
+ return builder.create();
+ }
+
+ private void setLocale(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/SetFontSizeDialogFragm.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/SetFontSizeDialogFragm.java
new file mode 100644
index 0000000..3682b55
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/SetFontSizeDialogFragm.java
@@ -0,0 +1,138 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import java.util.Locale;
+
+@SuppressLint("NewApi")
+public class SetFontSizeDialogFragm extends DialogFragment {
+ public String current_parameter;
+
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ setLocale(global_prefs);
+ current_parameter = ((MainSettingsActivity) getActivity()).getCurrentParameter();
+ String current_value;
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ if(current_parameter == "setting_fontsize") {
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ final View view = inflater.inflate(R.layout.set_font_size_activity, null);
+ final SeekBar font_size_seekbar = (SeekBar) view.findViewById(R.id.font_size_seekbar);
+ final EditText preview_text = (EditText) view.findViewById(R.id.preview_text);
+ final TextView value_label = (TextView) view.findViewById(R.id.value_label);
+ if(global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ preview_text.setTextColor(getResources().getColor(R.color.black));
+ } else {
+ preview_text.setTextColor(getResources().getColor(R.color.white));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ preview_text.setTextColor(getResources().getColor(R.color.white));
+ } else {
+ preview_text.setTextColor(getResources().getColor(R.color.black));
+ }
+ }
+ builder.setView(view);
+ builder.setTitle(R.string.changing_font_label);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt("font_size", font_size_seekbar.getProgress() + 12);
+ editor.commit();
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ preview_text.setKeyListener(null);
+ font_size_seekbar.setMax((60 - 12) / 1);
+ font_size_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+ preview_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, i + 12);
+ value_label.setText(getString(R.string.value_in_px, i + 12));
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+ if(prefs.getInt("font_size", 0) < 12) {
+ float text_size_in_sp = (int) preview_text.getTextSize() / getResources().getDisplayMetrics().scaledDensity;
+ font_size_seekbar.setProgress((int) text_size_in_sp - 12);
+ value_label.setText(getString(R.string.value_in_px, (int)text_size_in_sp));
+ preview_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, text_size_in_sp);
+ } else {
+ font_size_seekbar.setProgress(prefs.getInt("font_size", 0) - 12);
+ value_label.setText(getString(R.string.value_in_px, prefs.getInt("font_size", 0)));
+ preview_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, prefs.getInt("font_size", 0));
+ }
+ };
+ return builder.create();
+ }
+
+ private void setLocale(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/SettingsItemsDialogFragm.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/SettingsItemsDialogFragm.java
new file mode 100644
index 0000000..6dfbe12
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/SettingsItemsDialogFragm.java
@@ -0,0 +1,203 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.SuppressLint;
+import android.app.AlarmManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.ContextThemeWrapper;
+import android.widget.Toast;
+
+import java.util.Locale;
+
+@SuppressLint("NewApi")
+public class SettingsItemsDialogFragm extends DialogFragment {
+ public String current_parameter;
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ current_parameter = ((MainSettingsActivity) getActivity()).getCurrentParameter();
+ final String current_value;
+ final String[] value = new String[1];
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ if(current_parameter == "setting_language") {
+ current_value = ((MainSettingsActivity) getActivity()).getCurrentValue(current_parameter);
+ final String[] languages = getResources().getStringArray(R.array.ui_language);
+ builder.setTitle(R.string.interface_language_item);
+ if(current_value.contains("OS dependent")) {
+ builder.setSingleChoiceItems(languages, 0,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if(item == 0) {
+ value[0] = "OS dependent";
+ } else if(item == 1) {
+ value[0] = "English";
+ } else {
+ value[0] = "Russian";
+ }
+ }
+ });
+ } else if(current_value.contains("English")) {
+ builder.setSingleChoiceItems(languages, 1,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if(item == 0) {
+ value[0] = "OS dependent";
+ } else if(item == 1) {
+ value[0] = "English";
+ } else {
+ value[0] = "Russian";
+ }
+ }
+ });
+ } else {
+ builder.setSingleChoiceItems(languages, 2,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if(item == 0) {
+ value[0] = "OS dependent";
+ } else if(item == 1) {
+ value[0] = "English";
+ } else {
+ value[0] = "Russian";
+ }
+ }
+ });
+ }
+ builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ ((MainSettingsActivity) getActivity()).onChangingValues(current_parameter, value[0]);
+ SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ final String[] requires_reboot_app = getResources().getStringArray(R.array.ui_language_app_restart_toast);
+ if(global_prefs.getBoolean("connected", false) == false) {
+ Intent mainActivity = new Intent(getActivity(), this.getClass());
+ int pendingIntentId = 1;
+ PendingIntent pendingIntent;
+ pendingIntent = PendingIntent.getActivity(getActivity(), pendingIntentId, mainActivity, PendingIntent.FLAG_CANCEL_CURRENT);
+ AlarmManager mgr = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
+ mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent);
+ System.exit(0);
+ } else {
+ if(current_value.contains("Russian")) {
+ Toast.makeText(getActivity(), requires_reboot_app[1], Toast.LENGTH_LONG).show();
+ } else {
+ Toast.makeText(getActivity(), requires_reboot_app[0], Toast.LENGTH_LONG).show();
+ }
+ }
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ }
+ });
+ } else if(current_parameter == "setting_theme") {
+ current_value = ((MainSettingsActivity) getActivity()).getCurrentValue(current_parameter);
+ String[] themes = getResources().getStringArray(R.array.themes);
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ builder.setTitle(getString(R.string.interface_theme_item));
+ if(current_value.contains("Dark")) {
+ builder.setSingleChoiceItems(themes, 0,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if(item == 0) {
+ value[0] = "Dark";
+ } else {
+ value[0] = "Light";
+ }
+ }
+ });
+ } else {
+ builder.setSingleChoiceItems(themes, 1,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if(item == 0) {
+ value[0] = "Dark";
+ } else {
+ value[0] = "Light";
+ }
+ }
+ });
+ }
+ builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ ((MainSettingsActivity) getActivity()).onChangingValues(current_parameter, value[0]);
+ SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ final String[] requires_reboot_app = getResources().getStringArray(R.array.ui_language_app_restart_toast);
+ if(global_prefs.getBoolean("connected", false) == false) {
+ Intent mainActivity = new Intent(getActivity(), this.getClass());
+ int pendingIntentId = 1;
+ PendingIntent pendingIntent;
+ pendingIntent = PendingIntent.getActivity(getActivity(), pendingIntentId, mainActivity, PendingIntent.FLAG_CANCEL_CURRENT);
+ AlarmManager mgr = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
+ mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent);
+ System.exit(0);
+ } else {
+ if(current_value.contains("Russian")) {
+ Toast.makeText(getActivity(), requires_reboot_app[0], Toast.LENGTH_LONG).show();
+ } else {
+ Toast.makeText(getActivity(), requires_reboot_app[1], Toast.LENGTH_LONG).show();
+ }
+ }
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ }
+ });
+ }
+ return builder.create();
+ }
+
+ private void setLocale(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ }
+ }
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/StatisticsFragm.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/StatisticsFragm.java
new file mode 100644
index 0000000..5a15e5f
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/StatisticsFragm.java
@@ -0,0 +1,207 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.math.RoundingMode;
+import java.text.DecimalFormat;
+import java.util.Locale;
+import java.util.Timer;
+import java.util.TimerTask;
+
+@SuppressLint("NewApi")
+public class StatisticsFragm extends DialogFragment {
+ public int sended_bytes;
+ public int received_bytes;
+ public int total_bytes;
+ public Timer statsTimer;
+ public TextView sended_bytes_label;
+ public TextView received_bytes_label;
+ public TextView total_bytes_label;
+ public View view;
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ setLocale(global_prefs);
+ sended_bytes = ((ThreadActivity) getActivity()).getSendedBytes();
+ received_bytes = ((ThreadActivity) getActivity()).getReceivedBytes();
+ total_bytes = sended_bytes + received_bytes;
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.statistics_item);
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ view = inflater.inflate(R.layout.statistics_activity, null);
+ builder.setView(view);
+ sended_bytes_label = (TextView) view.findViewById(R.id.sended_label2);
+ received_bytes_label = (TextView) view.findViewById(R.id.received_label2);
+ total_bytes_label = (TextView) view.findViewById(R.id.total_label2);
+ TextView session_label = (TextView) view.findViewById(R.id.session_label);
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ session_label.setTextColor(getResources().getColor(R.color.black));
+ } else {
+ session_label.setTextColor(getResources().getColor(R.color.white));
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ session_label.setTextColor(getResources().getColor(R.color.white));
+ } else {
+ session_label.setTextColor(getResources().getColor(R.color.black));
+ }
+ }
+ DecimalFormat dF = new DecimalFormat("#.##");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
+ dF.setRoundingMode(RoundingMode.DOWN);
+ }
+ if (sended_bytes > 1073741824) {
+ String sended_bytes_rounded = dF.format((float)(sended_bytes / 1073741824));
+ sended_bytes_label.setText(getString(R.string.gbytes_stats, sended_bytes_rounded));
+ } else if(sended_bytes > 1048576) {
+ String sended_bytes_rounded = dF.format((float)(sended_bytes / 1048576));
+ sended_bytes_label.setText(getString(R.string.mbytes_stats, sended_bytes_rounded));
+ } else if(sended_bytes > 1024) {
+ String sended_bytes_rounded = dF.format((float)(sended_bytes / 1024));
+ sended_bytes_label.setText(getString(R.string.kbytes_stats, sended_bytes_rounded));
+ } else {
+ sended_bytes_label.setText(getString(R.string.bytes_stats, Integer.toString(sended_bytes)));
+ }
+ if (received_bytes > 1073741824) {
+ String received_bytes_rounded = dF.format((float)(received_bytes / 1073741824));
+ received_bytes_label.setText(getString(R.string.gbytes_stats, received_bytes_rounded));
+ } else if(received_bytes > 1048576) {
+ String received_bytes_rounded = dF.format((float)(received_bytes / 1048576));
+ received_bytes_label.setText(getString(R.string.mbytes_stats, received_bytes_rounded));
+ } else if(received_bytes > 1024) {
+ String received_bytes_rounded = dF.format((float)(received_bytes / 1024));
+ received_bytes_label.setText(getString(R.string.kbytes_stats, received_bytes_rounded));
+ } else {
+ received_bytes_label.setText(getString(R.string.bytes_stats, Integer.toString(received_bytes)));
+ }
+ if (total_bytes > 1073741824) {
+ String total_bytes_rounded = dF.format((float)(total_bytes / 1073741824));
+ total_bytes_label.setText(getString(R.string.gbytes_stats, total_bytes_rounded));
+ } else if(total_bytes > 1048576) {
+ String total_bytes_rounded = dF.format((float)(total_bytes / 1048576));
+ total_bytes_label.setText(getString(R.string.mbytes_stats, total_bytes_rounded));
+ } else if(total_bytes > 1024) {
+ String total_bytes_rounded = dF.format((float)(total_bytes / 1024));
+ total_bytes_label.setText(getString(R.string.kbytes_stats, total_bytes_rounded));
+ } else {
+ total_bytes_label.setText(getString(R.string.bytes_stats, Integer.toString(total_bytes)));
+ }
+ final Handler updateHandler = new Handler();
+ statsTimer = new Timer();
+ statsTimer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ sended_bytes = ((ThreadActivity) getActivity()).getSendedBytes();
+ received_bytes = ((ThreadActivity) getActivity()).getReceivedBytes();
+ total_bytes = sended_bytes + received_bytes;
+ updateHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ DecimalFormat dF = new DecimalFormat("#.##");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
+ dF.setRoundingMode(RoundingMode.DOWN);
+ }
+ if (sended_bytes > 1073741824) {
+ String sended_bytes_rounded = dF.format((float)(sended_bytes / 1073741824));
+ sended_bytes_label.setText(getString(R.string.gbytes_stats, sended_bytes_rounded));
+ } else if(sended_bytes > 1048576) {
+ String sended_bytes_rounded = dF.format((float)(sended_bytes / 1048576));
+ sended_bytes_label.setText(getString(R.string.mbytes_stats, sended_bytes_rounded));
+ } else if(sended_bytes > 1024) {
+ String sended_bytes_rounded = dF.format((float)(sended_bytes / 1024));
+ sended_bytes_label.setText(getString(R.string.kbytes_stats, sended_bytes_rounded));
+ } else {
+ sended_bytes_label.setText(getString(R.string.bytes_stats, Integer.toString(sended_bytes)));
+ }
+ if (received_bytes > 1073741824) {
+ String received_bytes_rounded = dF.format((float)(received_bytes / 1073741824));
+ received_bytes_label.setText(getString(R.string.gbytes_stats, received_bytes_rounded));
+ } else if(received_bytes > 1048576) {
+ String received_bytes_rounded = dF.format((float)(received_bytes / 1048576));
+ received_bytes_label.setText(getString(R.string.mbytes_stats, received_bytes_rounded));
+ } else if(received_bytes > 1024) {
+ String received_bytes_rounded = dF.format((float)(received_bytes / 1024));
+ received_bytes_label.setText(getString(R.string.kbytes_stats, received_bytes_rounded));
+ } else {
+ received_bytes_label.setText(getString(R.string.bytes_stats, Integer.toString(received_bytes)));
+ }
+ if (total_bytes > 1073741824) {
+ String total_bytes_rounded = dF.format((float)(total_bytes / 1073741824));
+ total_bytes_label.setText(getString(R.string.gbytes_stats, total_bytes_rounded));
+ } else if(total_bytes > 1048576) {
+ String total_bytes_rounded = dF.format((float)(total_bytes / 1048576));
+ total_bytes_label.setText(getString(R.string.mbytes_stats, total_bytes_rounded));
+ } else if(total_bytes > 1024) {
+ String total_bytes_rounded = dF.format((float)(total_bytes / 1024));
+ total_bytes_label.setText(getString(R.string.kbytes_stats, total_bytes_rounded));
+ } else {
+ total_bytes_label.setText(getString(R.string.bytes_stats, Integer.toString(total_bytes)));
+ }
+ }
+ });
+ }
+ }, 1000, 1000);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ statsTimer.cancel();
+ statsTimer = null;
+ return;
+ }
+ });
+ return builder.create();
+ }
+
+ private void setLocale(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getActivity().getResources().updateConfiguration(config,
+ getActivity().getResources().getDisplayMetrics());
+ }
+ }
+ }
+
+}
diff --git a/android/app/src/main/java/dev/tinelix/irc/android/legacy/ThreadActivity.java b/android/app/src/main/java/dev/tinelix/irc/android/legacy/ThreadActivity.java
new file mode 100644
index 0000000..375b607
--- /dev/null
+++ b/android/app/src/main/java/dev/tinelix/irc/android/legacy/ThreadActivity.java
@@ -0,0 +1,1856 @@
+package dev.tinelix.irc.android.legacy;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.DialogFragment;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;import android.preference.PreferenceManager;
+import android.text.Editable;
+import android.text.Html;
+import android.text.InputType;
+import android.text.method.KeyListener;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextMenu;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+import android.widget.Spinner;
+import android.widget.TabHost;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.math.RoundingMode;
+import java.net.ConnectException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
+import java.nio.channels.IllegalBlockingModeException;
+import java.security.KeyStore;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.zip.Inflater;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import static java.lang.System.out;
+import static java.lang.Thread.sleep;
+
+public class ThreadActivity extends Activity {
+
+ public Socket socket;
+ public SSLSocket sslSocket;
+ public boolean isConnected;
+ public InputStream input;
+ public OutputStream output;
+ Handler updateConversationHandler;
+ public String profile_name;
+ public String server;
+ public String nicknames;
+ public String hostname;
+ public String realname;
+ public StringBuilder msg;
+ public int received_bytes;
+ public int sended_bytes;
+ public List channelsArray = new ArrayList();
+ public List outputMsgArray = new ArrayList();
+ public byte[] socket_data_bytes;
+ public int port;
+ private EditText socks_msg_text;
+ public EditText output_msg_text;
+ public byte[] socket_data = new byte[1<<12];
+ public String socket_data_string;
+ public String raw_socket_data_string;
+ private Timer timer;
+ private UpdateUITask updateUITask;
+ public String state;
+ public String encoding;
+ public String channel;
+ public String current_channel;
+ public String password;
+ public String auth_method;
+ public String hide_ip;
+ public String quit_msg;
+ public String force_ssl;
+ public int sended_bytes_count;
+ public int received_bytes_count;
+ public String messageAuthor;
+ public String messageBody;
+ public boolean isMentioned;
+ public String sendingMsgText;
+ public AlertDialog connectionDialog;
+ public Date dt;
+ public boolean autoscroll_needed;
+ public Menu thread_menu;
+ public TabHost tabHost;
+ public List channels_sb = new LinkedList();
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ setCustomTheme(global_prefs);
+ setContentView(R.layout.thread_activity);
+ setColorStyle(global_prefs);
+ dt = new Date(System.currentTimeMillis());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ getActionBar().setHomeButtonEnabled(true);
+ }
+ channel = new String();
+ current_channel = new String();
+ for (int ch_index = 0; ch_index < 128; ch_index++) {
+ channels_sb.add(ch_index, new StringBuilder());
+ }
+ autoscroll_needed = true;
+ socks_msg_text = (EditText) findViewById(R.id.sock_msg_text);
+ socks_msg_text.setKeyListener(null);
+ socks_msg_text.setLongClickable(true);
+ socks_msg_text.setTypeface(Typeface.MONOSPACE);
+ socks_msg_text.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ switch (motionEvent.getAction()) {
+ case MotionEvent.ACTION_SCROLL:
+ autoscroll_needed = false;
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ MenuItem go_down = thread_menu.findItem(R.id.go_down_item);
+ go_down.setVisible(true);
+ } else {
+ Button go_down_btn = (Button) findViewById(R.id.go_down_button);
+ go_down_btn.setVisibility(View.VISIBLE);
+ }
+ }
+ return false;
+ }
+ });
+ socks_msg_text.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View view) {
+ autoscroll_needed = false;
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ MenuItem go_down = thread_menu.findItem(R.id.go_down_item);
+ go_down.setVisible(true);
+ } else {
+ Button go_down_btn = (Button) findViewById(R.id.go_down_button);
+ go_down_btn.setVisibility(View.VISIBLE);
+ }
+ Toast.makeText(getApplicationContext(), getResources().getString(R.string.autoscroll_is_disabled), Toast.LENGTH_LONG).show();
+ return false;
+ }
+ });
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ socks_msg_text.setTextIsSelectable(true);
+ }
+ if(global_prefs.getInt("font_size", 0) >= 12) {
+ socks_msg_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, global_prefs.getInt("font_size", 0));
+ }
+ EditText channel_socks_msg = (EditText) findViewById(R.id.channels_msg_text);
+ channel_socks_msg.setKeyListener(null);
+ channel_socks_msg.setLongClickable(true);
+ channel_socks_msg.setTypeface(Typeface.MONOSPACE);
+ channel_socks_msg.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ switch (motionEvent.getAction()) {
+ case MotionEvent.ACTION_SCROLL:
+ autoscroll_needed = false;
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ MenuItem go_down = thread_menu.findItem(R.id.go_down_item);
+ go_down.setVisible(true);
+ } else {
+ Button go_down_btn = (Button) findViewById(R.id.go_down_button);
+ go_down_btn.setVisibility(View.VISIBLE);
+ }
+ }
+ return false;
+ }
+ });
+ channel_socks_msg.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View view) {
+ autoscroll_needed = false;
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ MenuItem go_down = thread_menu.findItem(R.id.go_down_item);
+ go_down.setVisible(true);
+ Toast.makeText(getApplicationContext(), getResources().getString(R.string.autoscroll_is_disabled), Toast.LENGTH_LONG).show();
+ } else {
+ Button go_down_btn = (Button) findViewById(R.id.go_down_button);
+ go_down_btn.setVisibility(View.VISIBLE);
+ }
+ return false;
+ }
+ });
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ channel_socks_msg.setTextIsSelectable(true);
+ }
+ if(global_prefs.getInt("font_size", 0) >= 12) {
+ channel_socks_msg.setTextSize(TypedValue.COMPLEX_UNIT_SP, global_prefs.getInt("font_size", 0));
+ }
+ output_msg_text = (EditText) findViewById(R.id.output_msg_text);
+ Spinner channels_spinner = (Spinner) findViewById(R.id.channels_spinner);
+
+ if (savedInstanceState == null) {
+ Bundle extras = getIntent().getExtras();
+ if(extras == null) {
+ profile_name = null;
+ } else {
+ profile_name = extras.getString("profile_name");
+ }
+ } else {
+ profile_name = (String) savedInstanceState.getSerializable("profile_name");
+ };
+ SharedPreferences prefs = getApplicationContext().getSharedPreferences(profile_name, 0);
+ if (timer != null) {
+ timer.cancel();
+ }
+ if(profile_name == null) {
+ socket = null;
+ finish();
+ return;
+ }
+
+ updateUITask = new UpdateUITask();
+ sendingMsgText = new String();
+
+ final Context context = getApplicationContext();
+ server = prefs.getString("server", "");
+ port = prefs.getInt("port", 0);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ getActionBar().setSubtitle(server + ":" + port);
+ } else {
+ Log.i("Client", "\r\nProfile Info:\r\n\r\nPROFILE NAME: [" + profile_name + "]\r\nSERVER: [" + server + "]\r\nPORT: " + port);
+ }
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ TextView app_summary = (TextView) findViewById(R.id.app_summary_text);
+ app_summary.setText(server + ":" + port);
+ final Button go_down_btn = (Button) findViewById(R.id.go_down_button);
+ go_down_btn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ autoscroll_needed = true;
+ if(tabHost.getCurrentTab() == 0) {
+ socks_msg_text.setSelection(socks_msg_text.getText().length());
+ } else if(tabHost.getCurrentTab() == 1) {
+ EditText channel_socks_msg = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_msg_text);
+ channel_socks_msg.setSelection(channel_socks_msg.getText().length());
+ }
+ go_down_btn.setVisibility(View.GONE);
+ }
+ });
+ }
+ nicknames = prefs.getString("nicknames", "");
+ auth_method = prefs.getString("auth_method", "");
+ password = prefs.getString("password", "");
+ hostname = prefs.getString("hostname", "");
+ realname = prefs.getString("realname", "");
+ encoding = prefs.getString("encoding", "");
+ hide_ip = prefs.getString("hide_ip", "");
+ quit_msg = prefs.getString("quit_message", "");
+ force_ssl = prefs.getString("force_ssl", "Disabled");
+ if(hostname.length() <= 2) {
+ hostname = nicknames.split(", ")[0];
+ }
+ if(realname.length() <= 2) {
+ realname = "Member";
+ }
+
+ tabHost = (TabHost) findViewById(R.id.thread_tabs_host);
+ tabHost.setup();
+ TabHost.TabSpec tabSpec = tabHost.newTabSpec("thread");
+ tabSpec.setContent(R.id.thread_tab);
+ tabSpec.setIndicator(getResources().getString(R.string.thread_category));
+ tabHost.addTab(tabSpec);
+ tabHost.setCurrentTab(0);
+ tabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
+ @Override
+ public void onTabChanged(String s) {
+ tabHost.setCurrentTab(tabHost.getCurrentTab());
+ }
+ });
+
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ View view = tabHost.getTabWidget().getChildAt(0);
+ view.setBackgroundResource(R.drawable.tabwidget);
+ if (view != null) {
+ tabHost.getTabWidget().getChildAt(0).getLayoutParams().height = (int) (30 * getResources().getDisplayMetrics().density);
+ View tabImage = view.findViewById(android.R.id.icon);
+ if (tabImage != null) {
+ tabImage.setVisibility(View.GONE);
+ Log.d("Client", "TabIcon View");
+ } else {
+ Log.e("Client", "TabImage View is null");
+ }
+ TextView tabTitle = (TextView) view.findViewById(android.R.id.title);
+ if (tabTitle != null) {
+ Log.d("Client", "TabTitle View");
+ tabTitle.setGravity(Gravity.CENTER);
+ ViewGroup parent = (ViewGroup) tabTitle.getParent();
+ parent.removeView(tabTitle);
+ parent.addView(tabTitle);
+ ViewGroup.LayoutParams params = tabTitle.getLayoutParams();
+ params.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ } else {
+ }
+ } else {
+ }
+ }
+
+ tabSpec = tabHost.newTabSpec("thread");
+ if(force_ssl.equals("Enabled")) {
+ new Thread(new sslIrcThread()).start();
+ } else {
+ new Thread(new ircThread()).start();
+ }
+ ImageButton send_btn = (ImageButton) findViewById(R.id.send_button);
+ send_btn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (output_msg_text.getText().toString().length() > 0) {
+ EditText output_msg_text = (EditText) findViewById(R.id.output_msg_text);
+ Thread send_msg_thread = new Thread(new SendSocketMsg());
+ new Thread(new SendSocketMsg()).start();
+ socks_msg_text.setText(socks_msg_text.getText() + "You: " + output_msg_text.getText() + "\r\n");
+ socks_msg_text.setSelection(socks_msg_text.getText().length());
+ } else {
+ Toast emptyMessageAttempting = Toast.makeText(context, getString(R.string.empty_message_sending_attempt), Toast.LENGTH_SHORT);
+ emptyMessageAttempting.show();
+ }
+ }
+ });
+
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ ImageButton menu_button = (ImageButton) findViewById(R.id.menu_button);
+ menu_button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ openOptionsMenu();
+ }
+ });
+ }
+ AlertDialog.Builder builder;
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ builder = new AlertDialog.Builder(this);
+ } else {
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient_Light));
+ } else {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient));
+ } else {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.progress_activity, null);
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ }
+ TextView progressText = (TextView) dialogView.findViewById(R.id.progress_text);
+ progressText.setText(getString(R.string.connection_progress, server + ":" + port));
+ builder.setView(dialogView);
+ connectionDialog = builder.create();
+ connectionDialog.setCancelable(false);
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ connectionDialog.getWindow().setGravity(Gravity.BOTTOM);
+ }
+ connectionDialog.show();
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ Button dialogButton;
+ dialogButton = connectionDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if(dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = connectionDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if(dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = connectionDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if(dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ }
+
+ private void setColorStyle(SharedPreferences global_prefs) {
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ EditText socks_msg_text = (EditText) findViewById(R.id.sock_msg_text);
+ socks_msg_text.setTextColor(getResources().getColor(R.color.black));
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ LinearLayout app_title_bar = (LinearLayout) findViewById(R.id.app_title_bar);
+ app_title_bar.setBackgroundColor(getResources().getColor(R.color.white_75));
+ TextView app_title = (TextView) findViewById(R.id.app_title_label);
+ app_title.setBackgroundColor(getResources().getColor(R.color.white_75));
+ ImageView app_icon = (ImageView) findViewById(R.id.app_icon_view);
+ app_icon.setBackgroundColor(getResources().getColor(R.color.white_75));
+ LinearLayout activity_ll = (LinearLayout) findViewById(R.id.activity_ll);
+ activity_ll.setBackgroundColor(getResources().getColor(R.color.white));
+ socks_msg_text.setBackgroundColor(getResources().getColor(R.color.white_75));
+ EditText sended_msg_area = (EditText) findViewById(R.id.output_msg_text);
+ sended_msg_area.setTextColor(getResources().getColor(R.color.black));
+ Spinner channels_spinner = (Spinner) findViewById(R.id.channels_spinner);
+ channels_spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner_light));
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if(global_prefs.getInt("font_size", 0) >= 12) {
+ socks_msg_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, global_prefs.getInt("font_size", 0));
+ }
+ super.onResume();
+ }
+
+ @Override
+ public void onBackPressed() {
+ AlertDialog alertDialog;
+ AlertDialog.Builder builder;
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ builder = new AlertDialog.Builder(this);
+ builder.setTitle(getResources().getString(R.string.quit_session_title));
+ builder.setMessage(getResources().getString(R.string.quit_session_msg));
+ } else {
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient_Light));
+ builder.setTitle(Html.fromHtml("" + getResources().getString(R.string.quit_session_title) + ""));
+ builder.setMessage(Html.fromHtml("" + getResources().getString(R.string.quit_session_msg) + ""));
+ } else {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient));
+ builder.setTitle(Html.fromHtml("" + getResources().getString(R.string.quit_session_title) + ""));
+ builder.setMessage(Html.fromHtml("" + getResources().getString(R.string.quit_session_msg) + ""));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient));
+ builder.setTitle(Html.fromHtml("" + getResources().getString(R.string.quit_session_title) + ""));
+ builder.setMessage(Html.fromHtml("" + getResources().getString(R.string.quit_session_msg) + ""));
+ } else {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient_Light));
+ builder.setTitle(Html.fromHtml("" + getResources().getString(R.string.quit_session_title) + ""));
+ builder.setMessage(Html.fromHtml("" + getResources().getString(R.string.quit_session_msg) + ""));
+ }
+ }
+ }
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ sendQuitMessage();
+ }
+ });
+ builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ return;
+ }
+ });
+ alertDialog = builder.create();
+ alertDialog.show();
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ Button dialogButton = null;
+ customizeDialogStyle(dialogButton, global_prefs, alertDialog);
+ }
+ }
+
+ private void sendQuitMessage() {
+ if(tabHost.getCurrentTab() == 0) {
+ output_msg_text.setText("/quit");
+ } else {
+ EditText channel_output_msg = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_output_msg_text);
+ channel_output_msg.setText("/quit");
+ }
+ sendingMsgText = "/quit";
+ state = "sending_message";
+ new Thread(new SendSocketMsg()).start();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.thread_menu, menu);
+ thread_menu = menu;
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+
+ //noinspection SimplifiableIfStatement
+ if (id == R.id.statistics_item) {
+ showStatisticsDialog();
+ return true;
+ } else if (id == R.id.about_application_item) {
+ showAboutApplication();
+ } else if (id == R.id.connection_manager_item) {
+ showConnectionManager();
+ } else if (id == R.id.settings_item) {
+ showMainSettings();
+ } else if(id == R.id.disconnect_item) {
+ onBackPressed();
+ } else if(id == R.id.go_down_item) {
+ if(tabHost.getCurrentTab() == 0) {
+ socks_msg_text.setSelection(socks_msg_text.getText().length());
+ } else if(tabHost.getCurrentTab() == 1) {
+ EditText channel_socks_msg = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_msg_text);
+ channel_socks_msg.setSelection(channel_socks_msg.getText().length());
+ }
+ autoscroll_needed = true;
+ MenuItem go_down = thread_menu.findItem(R.id.go_down_item);
+ go_down.setVisible(false);
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void showConnectionManager() {
+ Intent intent = new Intent(ThreadActivity.this, ConnectionManagerActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ }
+
+ private void showAboutApplication() {
+ Intent intent = new Intent(ThreadActivity.this, AboutApplicationActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ }
+
+ private void showStatisticsDialog() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ DialogFragment statsDialogFragm = new StatisticsFragm();
+ statsDialogFragm.show(getFragmentManager(), "stats_dialog");
+ } else {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ AlertDialog.Builder builder;
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient_Light));
+ } else {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient));
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient));
+ } else {
+ builder = new AlertDialog.Builder(new ContextThemeWrapper(ThreadActivity.this, R.style.IRCClient_Light));
+ }
+ }
+ LayoutInflater inflater = getLayoutInflater();
+ final View dialogView = inflater.inflate(R.layout.statistics_activity, null);
+ TextView session_label = (TextView) dialogView.findViewById(R.id.session_label);
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ session_label.setTextColor(getResources().getColor(R.color.black));
+ } else {
+ session_label.setTextColor(getResources().getColor(R.color.white));
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ session_label.setTextColor(getResources().getColor(R.color.white));
+ } else {
+ session_label.setTextColor(getResources().getColor(R.color.black));
+ }
+ }
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ dialogView.setMinimumWidth(metrics.widthPixels);
+ builder.setView(dialogView);
+ builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+
+ }
+ });
+ sended_bytes = getSendedBytes();
+ received_bytes = getReceivedBytes();
+ int total_bytes = sended_bytes + received_bytes;
+ TextView sended_bytes_label = (TextView) dialogView.findViewById(R.id.sended_label2);
+ TextView received_bytes_label = (TextView) dialogView.findViewById(R.id.received_label2);
+ TextView total_bytes_label = (TextView) dialogView.findViewById(R.id.total_label2);
+ TextView dialog_title = (TextView) dialogView.findViewById(R.id.dialog_title);
+ dialog_title.setText(getString(R.string.statistics_item));
+ DecimalFormat dF = new DecimalFormat("#.00");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
+ dF.setRoundingMode(RoundingMode.DOWN);
+ }
+ if (sended_bytes > 1073741824) {
+ String sended_bytes_rounded = dF.format((sended_bytes / 1073741824));
+ sended_bytes_label.setText(getString(R.string.gbytes_stats, sended_bytes_rounded));
+ } else if(sended_bytes > 1048576) {
+ String sended_bytes_rounded = dF.format((sended_bytes / 1048576));
+ sended_bytes_label.setText(getString(R.string.mbytes_stats, sended_bytes_rounded));
+ } else if(sended_bytes > 1024) {
+ String sended_bytes_rounded = dF.format((sended_bytes / 1024));
+ sended_bytes_label.setText(getString(R.string.kbytes_stats, sended_bytes_rounded));
+ } else {
+ sended_bytes_label.setText(getString(R.string.bytes_stats, Integer.toString(sended_bytes)));
+ }
+ if (received_bytes > 1073741824) {
+ String received_bytes_rounded = dF.format((received_bytes / 1073741824));
+ received_bytes_label.setText(getString(R.string.gbytes_stats, received_bytes_rounded));
+ } else if(received_bytes > 1048576) {
+ String received_bytes_rounded = dF.format((received_bytes / 1048576));
+ received_bytes_label.setText(getString(R.string.mbytes_stats, received_bytes_rounded));
+ } else if(received_bytes > 1024) {
+ String received_bytes_rounded = dF.format((received_bytes / 1024));
+ received_bytes_label.setText(getString(R.string.kbytes_stats, received_bytes_rounded));
+ } else {
+ received_bytes_label.setText(getString(R.string.bytes_stats, Integer.toString(received_bytes)));
+ }
+ if (total_bytes > 1073741824) {
+ String total_bytes_rounded = dF.format((total_bytes / 1073741824));
+ total_bytes_label.setText(getString(R.string.gbytes_stats, total_bytes_rounded));
+ } else if(total_bytes > 1048576) {
+ String total_bytes_rounded = dF.format((total_bytes / 1048576));
+ total_bytes_label.setText(getString(R.string.mbytes_stats, total_bytes_rounded));
+ } else if(total_bytes > 1024) {
+ String total_bytes_rounded = dF.format((total_bytes / 1024));
+ total_bytes_label.setText(getString(R.string.kbytes_stats, total_bytes_rounded));
+ } else {
+ total_bytes_label.setText(getString(R.string.bytes_stats, Integer.toString(total_bytes)));
+ }
+ AlertDialog statisticsDlg = builder.create();
+ statisticsDlg.getWindow().setGravity(Gravity.BOTTOM);
+ statisticsDlg.show();
+
+ Button dialogButton = null;
+ customizeDialogStyle(dialogButton, global_prefs, statisticsDlg);
+ }
+ }
+
+ private void setCustomTheme(SharedPreferences global_prefs) {
+ if(global_prefs.getString("language", "OS dependent").contains("Russian")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ } else if (global_prefs.getString("language", "OS dependent").contains("English")) {
+ if(global_prefs.getBoolean("language_requires_restart", false) == false) {
+ Locale locale = new Locale("en_US");
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ } else {
+ Locale locale = new Locale("ru");
+ Locale.setDefault(locale);
+ Configuration config = getResources().getConfiguration();
+ config.locale = locale;
+ getResources().updateConfiguration(config,
+ getApplicationContext().getResources().getDisplayMetrics());
+ }
+ }
+ if (global_prefs.getString("theme", "Light").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient_Light);
+ } else {
+ setTheme(R.style.IRCClient);
+ }
+ } else {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ setTheme(R.style.IRCClient);
+ } else {
+ setTheme(R.style.IRCClient_Light);
+ }
+ }
+ }
+
+ private void customizeDialogStyle(Button dialogButton, SharedPreferences global_prefs, AlertDialog alertDialog) {
+ if(global_prefs.getString("theme", "Dark").contains("Light")) {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ } else {
+ if(global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.title_v11_full_transparent));
+ dialogButton.setTextColor(getResources().getColor(R.color.white));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ } else {
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.black));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ dialogButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (dialogButton != null) {
+ dialogButton.setBackgroundColor(getResources().getColor(R.color.white));
+ dialogButton.setTextColor(getResources().getColor(R.color.orange));
+ dialogButton.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ }
+ }
+ }
+ }
+
+ private void showMainSettings() {
+ Intent intent = new Intent(ThreadActivity.this, MainSettingsActivity.class);
+ startActivity(intent);
+ }
+
+ @Override
+ protected void onDestroy() {
+ if(profile_name != null) {
+ SharedPreferences prefs = getApplicationContext().getSharedPreferences(profile_name, 0);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean("connected", false);
+ editor.commit();
+ SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ editor = global_prefs.edit();
+ editor.putBoolean("connected", false);
+ editor.commit();
+ }
+ super.onDestroy();
+ }
+
+ public int getSendedBytes() {
+ return sended_bytes_count;
+ }
+
+ public int getReceivedBytes() {
+ return received_bytes_count;
+ }
+
+ class ircThread implements Runnable {
+ @Override
+ public void run() {
+ try {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ socket = new Socket();
+ state = "connecting";
+ Log.d("Client", "Getting IP address from " + server + ":" + port + "...");
+ InetAddress serverAddr = InetAddress.getByName(server);
+ SocketAddress socketAddress = new InetSocketAddress(serverAddr, port);
+ Log.d("Client", "Connecting to " + server + ":" + port + "...");
+ socket.connect(socketAddress, 30000);
+ socket.setKeepAlive(true);
+ while(state == "connecting") {
+ if (socket.isConnected()) {
+ updateUITask.run();
+ sleep(50);
+ }
+ }
+ input = socket.getInputStream();
+ output = socket.getOutputStream();
+ output.write(("USER " + nicknames.split(", ")[0] + " " +
+ hostname + " " + nicknames.split(", ")[0] + " :" +
+ realname + "\r\n").getBytes(encoding));
+ output.flush();
+ sended_bytes_count += ("USER " + nicknames.split(", ")[0] + " " +
+ hostname + " " + nicknames.split(", ")[0] + " :" +
+ realname + "\r\n").getBytes(encoding).length;
+ output.write(("NICK " + nicknames.split(", ")[0] + "\r\n").getBytes(encoding));
+ output.flush();
+ sended_bytes_count += ("NICK " + nicknames.split(", ")[0] + "\r\n").getBytes(encoding).length;
+ if(password.length() > 0 && auth_method.startsWith("NickServ")) {
+ output.write(("NICKSERV identify " + password + "\r\n").getBytes(encoding));
+ output.flush();
+ sended_bytes_count += ("NICKSERV identify " + password + "\r\n").getBytes(encoding).length;
+ }
+ if(hide_ip.startsWith("Enabled")) {
+ output.write(("MODE " + nicknames.split(", ")[0] + " +x\r\n").getBytes(encoding));
+ output.flush();
+ sended_bytes_count += ("MODE " + nicknames.split(", ")[0] + " +x\r\n").getBytes(encoding).length;
+ }
+ BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), encoding));
+ String response;
+ messageAuthor = new String();
+ messageBody = new String();
+ messageBody = "";
+ String nick = nicknames.split(", ")[0];
+ IRCParser parser = new IRCParser();
+ msg = new StringBuilder();
+ while(socket.isConnected() == true) {
+ if(in.ready() == true) {
+ sleep(10);
+ response = in.readLine();
+ raw_socket_data_string = response;
+ received_bytes_count += response.length();
+ if (response.startsWith("PING")) {
+ output.write(("PONG " + response.split(" ")[1]).getBytes(encoding));
+ output.flush();
+ sended_bytes_count += ("PONG " + response.split(" ")[1]).getBytes(encoding).length;
+ }
+ if(response != null) {
+ String parsedString;
+ if(global_prefs.getBoolean("show_msg_timestamps", true) == true) {
+ parsedString = parser.parseString(response, true);
+ } else {
+ parsedString = parser.parseString(response, false);
+ }
+ messageBody = parser.getMessageBody(response);
+ messageAuthor = parser.getMessageAuthor(response);
+ current_channel = parser.getChannel(response);
+ if(parsedString.length() > 0) {
+ msg.append(parsedString).append("\n");
+ socket_data_string = msg.toString();
+ msg.setLength(0);
+ if(messageBody.contains(nicknames.split(", ")[0])) {
+ state = "getting_data_with_mention";
+ } else {
+ state = "getting_data";
+ }
+ updateUITask.run();
+ };
+ }
+ };
+ }
+ socket.close();
+ socket = null;
+ state = "connection_lost";
+ updateUITask.run();
+ } catch (UnknownHostException uhEx) {
+ Log.e("Socket", "UnknownHostException");
+ try {
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ socket = null;
+ state = "no_connection";
+ updateUITask.run();
+ } catch(SocketTimeoutException timeoutEx) {
+ Log.e("Socket", "SocketTimeoutException");
+ try {
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ socket = null;
+ state = "timeout";
+ updateUITask.run();
+ } catch (IllegalBlockingModeException ibmEx) {
+ Log.e("Socket", "IllegalBlockingModeException");
+ try {
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ socket = null;
+ state = "no_connection";
+ updateUITask.run();
+ } catch (IllegalArgumentException iaEx) {
+ Log.e("Socket", "IllegalArgumentException");
+ try {
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ socket = null;
+ state = "no_connection";
+ updateUITask.run();
+ } catch (ConnectException Ex) {
+ Log.e("Socket", "ConnectException");
+ try {
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ socket = null;
+ state = "no_connection";
+ updateUITask.run();
+ } catch (IOException ioEx) {
+ ioEx.printStackTrace();
+ } catch (Exception ex) {
+ try {
+ if(socket != null) {
+ socket.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ socket = null;
+ state = "disconnected";
+ updateUITask.run();
+ }
+ }
+ }
+
+ class sslIrcThread implements Runnable {
+ @Override
+ public void run() {
+ try {
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ final TrustManager[] trustAllCerts = new TrustManager[]{
+ new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
+ }
+
+ @Override
+ public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
+ }
+
+ @Override
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return new java.security.cert.X509Certificate[]{};
+ }
+ }
+ };
+
+ final SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
+ SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory();
+ Log.d("Client", "Getting IP address from " + server + ":" + port + "...");
+ InetAddress serverAddr = InetAddress.getByName(server);
+
+ state = "connecting";
+ Log.d("Client", "Connecting to " + server + ":" + port + "... (Secured)");
+ SocketAddress socketAddress = new InetSocketAddress(serverAddr, port);
+ sslSocket = (SSLSocket) ssf.createSocket(serverAddr, port);
+
+ while(state == "connecting") {
+ if (sslSocket.isConnected()) {
+ updateUITask.run();
+ sleep(50);
+ }
+ }
+ input = sslSocket.getInputStream();
+ output = sslSocket.getOutputStream();
+ output.write(("USER " + nicknames.split(", ")[0] + " " +
+ hostname + " " + nicknames.split(", ")[0] + " :" +
+ realname + "\r\n").getBytes(encoding));
+ output.flush();
+ sended_bytes_count += ("USER " + nicknames.split(", ")[0] + " " +
+ hostname + " " + nicknames.split(", ")[0] + " :" +
+ realname + "\r\n").getBytes(encoding).length;
+ output.write(("NICK " + nicknames.split(", ")[0] + "\r\n").getBytes(encoding));
+ output.flush();
+ sended_bytes_count += ("NICK " + nicknames.split(", ")[0] + "\r\n").getBytes(encoding).length;
+ if(password.length() > 0 && auth_method.startsWith("NickServ")) {
+ output.write(("NICKSERV identify " + password + "\r\n").getBytes(encoding));
+ output.flush();
+ sended_bytes_count += ("NICKSERV identify " + password + "\r\n").getBytes(encoding).length;
+ }
+ if(hide_ip.startsWith("Enabled")) {
+ output.write(("MODE " + nicknames.split(", ")[0] + " +x\r\n").getBytes(encoding));
+ output.flush();
+ sended_bytes_count += ("MODE " + nicknames.split(", ")[0] + " +x\r\n").getBytes(encoding).length;
+ }
+ BufferedReader in = new BufferedReader(new InputStreamReader(sslSocket.getInputStream(), encoding));
+ String response;
+ messageAuthor = new String();
+ messageBody = new String();
+ messageBody = "";
+ String nick = nicknames.split(", ")[0];
+ IRCParser parser = new IRCParser();
+ msg = new StringBuilder();
+ while(sslSocket.isConnected() == true) {
+ sleep(10);
+ response = in.readLine();
+ raw_socket_data_string = response;
+ received_bytes_count += response.length();
+ if (response.startsWith("PING")) {
+ output.write(("PONG " + response.split(" ")[1]).getBytes(encoding));
+ output.flush();
+ sended_bytes_count += ("PONG " + response.split(" ")[1]).getBytes(encoding).length;
+ }
+ if(response != null) {
+ String parsedString;
+ if(global_prefs.getBoolean("show_msg_timestamps", true) == true) {
+ parsedString = parser.parseString(response, true);
+ } else {
+ parsedString = parser.parseString(response, false);
+ }
+ messageBody = parser.getMessageBody(response);
+ messageAuthor = parser.getMessageAuthor(response);
+ current_channel = parser.getChannel(response);
+ if(parsedString.length() > 0) {
+ msg.append(parsedString).append("\n");
+ socket_data_string = msg.toString();
+ msg.setLength(0);
+ if(messageBody.contains(nicknames.split(", ")[0])) {
+ state = "getting_data_with_mention";
+ } else {
+ state = "getting_data";
+ }
+ updateUITask.run();
+ };
+ }
+ }
+ sslSocket.close();
+ sslSocket = null;
+ state = "connection_lost";
+ updateUITask.run();
+ } catch (UnknownHostException uhEx) {
+ Log.e("Socket", "UnknownHostException");
+ try {
+ sslSocket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ sslSocket = null;
+ state = "no_connection";
+ updateUITask.run();
+ } catch(SocketTimeoutException timeoutEx) {
+ Log.e("Socket", "SocketTimeoutException");
+ try {
+ sslSocket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ sslSocket = null;
+ state = "timeout";
+ updateUITask.run();
+ } catch (IllegalBlockingModeException ibmEx) {
+ Log.e("Socket", "IllegalBlockingModeException");
+ try {
+ sslSocket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ sslSocket = null;
+ state = "no_connection";
+ updateUITask.run();
+ } catch (IllegalArgumentException iaEx) {
+ Log.e("Socket", "IllegalArgumentException");
+ try {
+ sslSocket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ sslSocket = null;
+ state = "no_connection";
+ updateUITask.run();
+ } catch (ConnectException Ex) {
+ Log.e("Socket", "ConnectException");
+ try {
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ sslSocket = null;
+ state = "no_connection";
+ updateUITask.run();
+ } catch (IOException ioEx) {
+ ioEx.printStackTrace();
+ } catch (Exception ex) {
+ try {
+ if(socket != null) {
+ socket.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ sslSocket = null;
+ state = "disconnected";
+ updateUITask.run();
+ }
+ }
+ }
+
+ class SendSocketMsg implements Runnable {
+ @Override
+ public void run() {
+ if (socket != null || sslSocket != null) {
+ state = "sending_message";
+ while(state == "sending_message") {
+ updateUITask.run();
+ try {
+ sleep(50);
+ state = "finishing_sending_message";
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ if(sendingMsgText.length() > 0) {
+ try {
+ if(sendingMsgText.startsWith("QUIT")) {
+ Timer shutdownTimer = new Timer();
+ shutdownTimer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ if(force_ssl.equals("Enabled")) {
+ if (sslSocket != null) {
+ sslSocket.close();
+ sslSocket = null;
+ }
+ } else {
+ if (socket != null) {
+ socket.close();
+ socket = null;
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ finish();
+ }
+ }, 1000);
+ }
+ if(force_ssl.equals("Enabled")) {
+ if (sslSocket.isConnected() == true && state == "finishing_sending_message") {
+ PrintWriter out;
+ out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(output, encoding)));
+ Log.i("Client", "Sending message...\r\n\r\nMESSAGE: [" + sendingMsgText.replace("\r", "\\r").replace("\n", "\\n") + "]");
+ out.println(new String((sendingMsgText).getBytes(encoding), encoding));
+ Log.i("Client", "Clearing output stream...");
+ out.flush();
+ Log.i("Client", "\r\nSended message!");
+ state = "sended_message";
+ updateUITask.run();
+ }
+ } else {
+ if (socket.isConnected() == true && state == "finishing_sending_message") {
+ PrintWriter out;
+ out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(output, encoding)));
+ Log.i("Client", "Sending message...\r\n\r\nMESSAGE: [" + sendingMsgText.replace("\r", "\\r").replace("\n", "\\n") + "]");
+ out.println(new String((sendingMsgText).getBytes(encoding), encoding));
+ Log.i("Client", "Clearing output stream...");
+ out.flush();
+ Log.i("Client", "\r\nSended message!");
+ state = "sended_message";
+ updateUITask.run();
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ } else {
+ Log.e("Socket", "Socket not created");
+ }
+ }
+ }
+
+ class UpdateUITask extends TimerTask {
+ @Override
+ public void run() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if(current_channel.length() > 0 && channelsArray.size() > 0 && tabHost.getTabWidget().getTabCount() > 1) {
+ socks_msg_text = (EditText) findViewById(R.id.sock_msg_text);
+ for(int ch_index = 0; ch_index < channelsArray.size(); ch_index++) {
+ if(channelsArray.get(ch_index).equals(current_channel)) {
+ View tab = tabHost.getTabWidget().getChildTabViewAt(0);
+ if(tab == null) {
+ Log.e("Client", "TabView is null");
+ }
+ socks_msg_text = (EditText) tab.findViewById(R.id.sock_msg_text);
+ if(socks_msg_text == null) {
+ socks_msg_text = (EditText) findViewById(R.id.sock_msg_text);
+ }
+ }
+ }
+ } else {
+ socks_msg_text = (EditText) findViewById(R.id.sock_msg_text);
+ }
+ final SharedPreferences global_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if(state == "getting_data") {
+ if(socket_data_string.length() > 0) {
+ if(global_prefs.getBoolean("save_msg_history", false) == true) {
+ File directory;
+ directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "Tinelix");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+
+ directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Tinelix", "IRC Client");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+ directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Tinelix/IRC Client", "Messages Logs");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+
+ try {
+ Log.d("App", "Attempting creating log file...");
+ File file = new File(directory, "LOG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(dt) + ".log");
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ Log.d("App", "Log file created!");
+ FileWriter writer = new FileWriter(file);
+ writer.append(socks_msg_text.getText() + socket_data_string);
+ writer.flush();
+ writer.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ int cursor_pos = socks_msg_text.getSelectionStart();
+ int current_ch_index = -1;
+ for (int ch_index = 0; ch_index < channelsArray.size(); ch_index++) {
+ if(current_channel.length() > 0 && current_channel.equals(channelsArray.get(ch_index))) {
+ current_ch_index = ch_index;
+ }
+ }
+ if(current_ch_index > -1 && channels_sb.size() > current_ch_index && channelsArray.size() > current_ch_index) {
+ channels_sb.get(current_ch_index).append(socket_data_string);
+ }
+ if(tabHost.getTabWidget().getTabCount() == 1) {
+ socks_msg_text.setText(socks_msg_text.getText() + socket_data_string);
+ } else if(tabHost.getTabWidget().getTabCount() > 1) {
+ try {
+ if(current_ch_index > -1) {
+ Spinner channel_spinner = (Spinner) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_spinner);
+ if (channel_spinner.getSelectedItemPosition() == current_ch_index) {
+ EditText channel_socks_msg = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_msg_text);
+ channel_socks_msg.setText(channels_sb.get(current_ch_index));
+ }
+ } else {
+ socks_msg_text.setText(socks_msg_text.getText() + socket_data_string);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if(autoscroll_needed == true) {
+ if(tabHost.getCurrentTab() == 0) {
+ socks_msg_text.setSelection(socks_msg_text.getText().length());
+ } else if(tabHost.getCurrentTab() == 1) {
+ if(current_ch_index > -1) {
+ EditText channel_socks_msg = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_msg_text);
+ channel_socks_msg.setSelection(channel_socks_msg.getText().length());
+ } else {
+ socks_msg_text.setSelection(socks_msg_text.getText().length());
+ }
+
+ }
+ } else {
+ if (tabHost.getCurrentTab() == 0) {
+ cursor_pos = socks_msg_text.getSelectionStart();
+ socks_msg_text.setSelection(socks_msg_text.getSelectionStart());
+ } else if (tabHost.getCurrentTab() == 1) {
+ EditText channel_socks_msg = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_msg_text);
+ cursor_pos = channel_socks_msg.getSelectionStart();
+ channel_socks_msg.setSelection(cursor_pos);
+ }
+ }
+ Log.d("Client", "Position 2: " + socks_msg_text.getSelectionStart());
+ socket_data_string = "";
+ }
+ } else if(state == "getting_data_with_mention") {
+ int cursor_pos = socks_msg_text.getSelectionStart();
+ int current_ch_index = -1;
+ if(socket_data_string.length() > 0) {
+ for (int ch_index = 0; ch_index < channelsArray.size(); ch_index++) {
+ if(current_channel.length() > 0 && current_channel.equals(channelsArray.get(ch_index))) {
+ current_ch_index = ch_index;
+ }
+ }
+ if(current_ch_index > -1 && channels_sb.size() > current_ch_index && channelsArray.size() > current_ch_index) {
+ channels_sb.get(current_ch_index).append(socket_data_string);
+ }
+ if(tabHost.getTabWidget().getTabCount() == 1) {
+ socks_msg_text.setText(socks_msg_text.getText() + socket_data_string);
+ } else if(tabHost.getTabWidget().getTabCount() > 1) {
+ try {
+ if(current_ch_index > -1) {
+ Spinner channel_spinner = (Spinner) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_spinner);
+ if (channel_spinner.getSelectedItemPosition() == current_ch_index) {
+ EditText channel_socks_msg = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_msg_text);
+ channel_socks_msg.setText(channels_sb.get(current_ch_index));
+ }
+ } else {
+ socks_msg_text.setText(socks_msg_text.getText() + socket_data_string);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ socket_data_string = "";
+ Context context = getApplicationContext();
+ if(messageBody.length() > 0 && nicknames.split(", ")[0].length() > 0) {
+ if(global_prefs.getBoolean("save_msg_history", false) == true) {
+ File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "Tinelix");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+
+ directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Tinelix", "IRC Client");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+ directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Tinelix/IRC Client", "App Logs");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+
+ try {
+ Log.d("App", "Attempting creating log file...");
+ File file = new File(directory, "LOG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(dt) + ".log");
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ Log.d("App", "Log file created!");
+ FileWriter writer = new FileWriter(file);
+ writer.append(socks_msg_text.getText() + socket_data_string);
+ writer.flush();
+ writer.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ Notification.Builder notificationBuilder = null;
+ notificationBuilder = new Notification.Builder(context);
+ notificationBuilder
+ .setSmallIcon(R.drawable.ic_notification_icon)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle(getString(R.string.mention_notification_title, messageAuthor))
+ .setContentText(messageBody);
+ notificationManager.notify(1, notificationBuilder.build());
+ } else {
+ Notification notification = new Notification(R.drawable.ic_notification_icon, getString(R.string.mention_notification_title, messageAuthor), System.currentTimeMillis());
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.notification_activity);
+ contentView.setTextViewText(R.id.notification_title, getString(R.string.mention_notification_title, messageAuthor));
+ contentView.setTextViewText(R.id.notification_text, messageBody);
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ notification.contentView = contentView;
+ ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
+ List tasks = am.getRunningTasks(1);
+ ActivityManager.RunningTaskInfo task = tasks.get(0); // Should be my task
+ Intent notificationIntent = new Intent(context, ThreadActivity.class);
+ notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ notificationIntent.setAction(Intent.ACTION_MAIN);
+ notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ notification.flags |= Notification.FLAG_AUTO_CANCEL;
+ PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);
+ notification.contentIntent = contentIntent;
+ notificationManager.notify(R.layout.notification_activity, notification);
+ }
+ }
+ }
+ } else if(state == "disconnected") {
+ Toast.makeText(getApplicationContext(), R.string.connection_lost_msg, Toast.LENGTH_SHORT).show();
+ socks_msg_text.setSelection(socks_msg_text.getText().length());
+ connectionDialog.cancel();
+ finish();
+ } else if(state == "connection_lost") {
+ Toast.makeText(getApplicationContext(), R.string.connection_lost_msg, Toast.LENGTH_SHORT).show();
+ socks_msg_text.setSelection(socks_msg_text.getText().length());
+ connectionDialog.cancel();
+ finish();
+ } else if(state == "timeout") {
+ Toast.makeText(getApplicationContext(), R.string.connection_timeout_msg, Toast.LENGTH_SHORT).show();
+ socks_msg_text.setSelection(socks_msg_text.getText().length());
+ connectionDialog.cancel();
+ finish();
+ } else if(state == "no_connection") {
+ Toast.makeText(getApplicationContext(), R.string.no_connection_msg, Toast.LENGTH_SHORT).show();
+ socks_msg_text.setSelection(socks_msg_text.getText().length());
+ connectionDialog.cancel();
+ finish();
+ } else if(state == "sending_message") {
+ if (socket != null || sslSocket != null) {
+ EditText output_msg_text;
+ if(tabHost.getCurrentTab() == 1) {
+ output_msg_text = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_output_msg_text);
+ } else {
+ output_msg_text = (EditText) findViewById(R.id.output_msg_text);
+ }
+ outputMsgArray = new LinkedList(Arrays.asList(output_msg_text.getText().toString().split(" ")));
+ Log.i("Client", "\r\nSending message...\r\n\r\nMESSAGE: [" + output_msg_text.getText().toString() + "]");
+ if (outputMsgArray.get(0).startsWith("/join") && outputMsgArray.size() > 1 && outputMsgArray.get(1).startsWith("#")) {
+ try {
+ channelsArray.add(outputMsgArray.get(1));
+ sendingMsgText = ("JOIN " + outputMsgArray.get(1) + "\r\n");
+ sended_bytes_count += ("JOIN " + outputMsgArray.get(1) + "\r\n").getBytes(encoding).length;
+ if(tabHost.getTabWidget().getTabCount() < 2) {
+ TabHost.TabSpec tabSpec = tabHost.newTabSpec("channels");
+ tabSpec.setContent(R.id.channels_tab);
+ tabSpec.setIndicator(getResources().getString(R.string.channels_tab_item));
+ tabHost.addTab(tabSpec);
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ View view = tabHost.getTabWidget().getChildAt(1);
+ view.setBackgroundResource(R.drawable.tabwidget);
+ if (view != null) {
+ Log.d("Client", "TabWidget View");
+ tabHost.getTabWidget().getChildAt(1).getLayoutParams().height = (int) (30 * getResources().getDisplayMetrics().density);
+ View tabImage = view.findViewById(android.R.id.icon);
+ if (tabImage != null) {
+ tabImage.setVisibility(View.GONE);
+ Log.d("Client", "TabIcon View");
+ } else {
+ Log.e("Client", "TabImage View is null");
+ }
+ TextView tabTitle = (TextView) view.findViewById(android.R.id.title);
+ if (tabTitle != null) {
+ Log.d("Client", "TabTitle View");
+ tabTitle.setGravity(Gravity.CENTER);
+ ViewGroup parent = (ViewGroup) tabTitle.getParent();
+ parent.removeView(tabTitle);
+ parent.addView(tabTitle);
+ ViewGroup.LayoutParams params = tabTitle.getLayoutParams();
+ params.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ } else {
+ Log.e("Client", "TabTitle View is null");
+ }
+ } else {
+ Log.e("Client", "TabWidget View is null");
+ }
+ }
+ }
+ tabHost.setCurrentTab(1);
+ final Spinner channels_spinner = (Spinner) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_spinner);
+ final EditText channels_socks_text = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_msg_text);
+ final EditText channels_output_text = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_output_msg_text);
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ channels_spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner_light));
+ } else {
+ channels_spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner));
+ }
+ } else if (global_prefs.getString("theme", "Dark").contains("Dark")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ channels_spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner));
+ } else {
+ channels_spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner_light));
+ }
+ }
+ channels_spinner.setPadding(2, 0, 2, 0);
+ ArrayList spinnerArray = new ArrayList();
+ spinnerArray.clear();
+ for (int i = 0; i < channelsArray.size(); i++) {
+ spinnerArray.add(new CustomSpinnerItem(channelsArray.get(i)));
+ }
+ CustomSpinnerAdapter customSpinnerAdapter = new CustomSpinnerAdapter(getApplicationContext(), spinnerArray);
+ channels_spinner.setAdapter(customSpinnerAdapter);
+ } else {
+ ArrayList spinnerArray = new ArrayList();
+ spinnerArray.clear();
+ for (int i = 0; i < channelsArray.size(); i++) {
+ spinnerArray.add(new CustomSpinnerItem(channelsArray.get(i)));
+ }
+ CustomSpinnerAdapter customSpinnerAdapter = new CustomSpinnerAdapter(getApplicationContext(), spinnerArray);
+ channels_spinner.setAdapter(customSpinnerAdapter);
+ }
+ ImageButton channels_send_btn = (ImageButton) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_send_button);
+ channels_send_btn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (channels_output_text.getText().toString().length() > 0) {
+ sendingMsgText = channels_output_text.getText().toString();
+ Thread send_msg_thread = new Thread(new SendSocketMsg());
+ new Thread(new SendSocketMsg()).start();
+ channels_socks_text.setText(channels_socks_text.getText() + "You: " + channels_output_text.getText() + "\r\n");
+ channels_socks_text.setSelection(channels_socks_text.getText().length());
+ channels_sb.get(channels_spinner.getSelectedItemPosition()).append("You: " + channels_output_text.getText() + "\r\n");
+ } else {
+ Toast emptyMessageAttempting = Toast.makeText(getApplicationContext(), getString(R.string.empty_message_sending_attempt), Toast.LENGTH_SHORT);
+ emptyMessageAttempting.show();
+ }
+ }
+ });
+ channels_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
+ try {
+ channels_socks_text.setText(channels_sb.get(i).toString());
+ } catch(IndexOutOfBoundsException ioofe) {
+ ioofe.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView) {
+
+ }
+ });
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else if (outputMsgArray.get(0).startsWith("/join") && outputMsgArray.size() > 1 && !outputMsgArray.get(1).startsWith("#")) {
+ try {
+ channelsArray.add(outputMsgArray.get(1));
+ sendingMsgText = ("JOIN " + outputMsgArray.get(1) + "\r\n");
+ sended_bytes_count += ("JOIN " + outputMsgArray.get(1) + "\r\n").getBytes(encoding).length;
+ if(tabHost.getTabWidget().getTabCount() < 2) {
+ TabHost.TabSpec tabSpec = tabHost.newTabSpec("channels");
+ tabSpec.setContent(R.id.channels_tab);
+ tabSpec.setIndicator(getResources().getString(R.string.channels_tab_item));
+ tabHost.addTab(tabSpec);
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ View view = tabHost.getTabWidget().getChildAt(1);
+ view.setBackgroundResource(R.drawable.tabwidget);
+ if (view != null) {
+ tabHost.getTabWidget().getChildAt(1).getLayoutParams().height = (int) (30 * getResources().getDisplayMetrics().density);
+ View tabImage = view.findViewById(android.R.id.icon);
+ if (tabImage != null) {
+ tabImage.setVisibility(View.GONE);
+ Log.d("Client", "TabIcon View");
+ } else {
+ Log.e("Client", "TabImage View is null");
+ }
+ TextView tabTitle = (TextView) view.findViewById(android.R.id.title);
+ if (tabTitle != null) {
+ Log.d("Client", "TabTitle View");
+ tabTitle.setGravity(Gravity.CENTER);
+ ViewGroup parent = (ViewGroup) tabTitle.getParent();
+ parent.removeView(tabTitle);
+ parent.addView(tabTitle);
+ ViewGroup.LayoutParams params = tabTitle.getLayoutParams();
+ params.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ } else {
+ Log.e("Client", "TabTitle View is null");
+ }
+ } else {
+ Log.e("Client", "TabWidget View is null");
+ }
+ }
+ }
+ tabHost.setCurrentTab(1);
+ final Spinner channels_spinner = (Spinner) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_spinner);
+ final EditText channels_socks_text = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_msg_text);
+ final EditText channels_output_text = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_output_msg_text);
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ if (global_prefs.getString("theme", "Dark").contains("Light")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ channels_spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner_light));
+ } else {
+ channels_spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner));
+ }
+ } else if (global_prefs.getString("theme", "Dark").contains("Dark")) {
+ if (global_prefs.getBoolean("theme_requires_restart", false) == false) {
+ channels_spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner));
+ } else {
+ channels_spinner.setBackgroundDrawable(getResources().getDrawable(R.drawable.dialog_spinner_light));
+ }
+ }
+ channels_spinner.setPadding(2, 0, 2, 0);
+ ArrayList spinnerArray = new ArrayList();
+ spinnerArray.clear();
+ for (int i = 0; i < channelsArray.size(); i++) {
+ spinnerArray.add(new CustomSpinnerItem(channelsArray.get(i)));
+ }
+ CustomSpinnerAdapter customSpinnerAdapter = new CustomSpinnerAdapter(getApplicationContext(), spinnerArray);
+ channels_spinner.setAdapter(customSpinnerAdapter);
+ } else {
+ ArrayList spinnerArray = new ArrayList();
+ spinnerArray.clear();
+ for (int i = 0; i < channelsArray.size(); i++) {
+ spinnerArray.add(new CustomSpinnerItem(channelsArray.get(i)));
+ }
+ CustomSpinnerAdapter customSpinnerAdapter = new CustomSpinnerAdapter(getApplicationContext(), spinnerArray);
+ channels_spinner.setAdapter(customSpinnerAdapter);
+ }
+ ImageButton channels_send_btn = (ImageButton) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_send_button);
+ channels_send_btn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (channels_output_text.getText().toString().length() > 0) {
+ sendingMsgText = channels_output_text.getText().toString();
+ Thread send_msg_thread = new Thread(new SendSocketMsg());
+ new Thread(new SendSocketMsg()).start();
+ channels_socks_text.setText(channels_socks_text.getText() + "You: " + channels_output_text.getText() + "\r\n");
+ channels_socks_text.setSelection(channels_socks_text.getText().length());
+ channels_sb.get(channels_spinner.getSelectedItemPosition()).append("You: " + channels_output_text.getText() + "\r\n");
+ } else {
+ Toast emptyMessageAttempting = Toast.makeText(getApplicationContext(), getString(R.string.empty_message_sending_attempt), Toast.LENGTH_SHORT);
+ emptyMessageAttempting.show();
+ }
+ }
+ });
+ channels_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
+ try {
+ channels_socks_text.setText(channels_sb.get(i).toString());
+ } catch(IndexOutOfBoundsException ioofe) {
+ ioofe.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView) {
+
+ }
+ });
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else if (outputMsgArray.get(0).startsWith("/mode") && outputMsgArray.size() > 1) {
+ try {
+ StringBuilder message_sb = new StringBuilder();
+ for (int i = 1; i < outputMsgArray.size(); i++) {
+ if (i < outputMsgArray.size() - 1 && outputMsgArray.get(i).length() > 0) {
+ message_sb.append(outputMsgArray.get(i)).append(" ");
+ } else if (outputMsgArray.get(i).length() > 0) {
+ message_sb.append(outputMsgArray.get(i));
+ }
+ }
+ sendingMsgText = ("MODE " + message_sb.toString() + "\r\n");
+ sended_bytes_count += ("MODE " + message_sb.toString() + "\r\n").getBytes(encoding).length;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else if (outputMsgArray.get(0).startsWith("/nick") && outputMsgArray.size() > 1) {
+ try {
+ sendingMsgText = ("NICK " + outputMsgArray.get(1) + "\r\n");
+ sended_bytes_count += ("NICK " + outputMsgArray.get(1) + "\r\n").getBytes(encoding).length;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else if (outputMsgArray.get(0).startsWith("/quit")) {
+ try {
+ sendingMsgText = ("QUIT :" + quit_msg + "\r\n");
+ sended_bytes_count += ("QUIT :" + quit_msg + "\r\n").getBytes(encoding).length;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else if (outputMsgArray.get(0).startsWith("/")) {
+ try {
+ StringBuilder message_sb = new StringBuilder();
+ for (int i = 0; i < outputMsgArray.size(); i++) {
+ if (i < outputMsgArray.size() - 1 && outputMsgArray.get(i).length() > 0) {
+ message_sb.append(outputMsgArray.get(i)).append(" ");
+ } else if (outputMsgArray.get(i).length() > 0) {
+ message_sb.append(outputMsgArray.get(i));
+ }
+ }
+ sendingMsgText = (message_sb.toString().substring(1) + "\r\n");
+ sended_bytes_count += (message_sb.toString().substring(1) + "\r\n").getBytes(encoding).length;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else if (!outputMsgArray.get(0).startsWith("/")) {
+ try {
+ if (channelsArray.size() > 0) {
+ if(tabHost.getCurrentTab() == 1) {
+ Spinner channels_spinner = (Spinner) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_spinner);
+ EditText channels_socks_msg = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_msg_text);
+ EditText channels_output_msg = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_output_msg_text);
+ sendingMsgText = ("PRIVMSG " + channelsArray.get(channels_spinner.getSelectedItemPosition()) + " :" + channels_output_msg.getText().toString() + "\r\n");
+ sended_bytes_count += ("PRIVMSG " + channelsArray.get(channels_spinner.getSelectedItemPosition()) + " :" + channels_output_msg.getText().toString() + "\r\n").getBytes(encoding).length;
+ } else {
+
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if(tabHost.getCurrentTab() == 1) {
+ output_msg_text.setText("");
+ EditText ch_output_msg_text = (EditText) tabHost.getTabContentView().getChildAt(1).findViewById(R.id.channels_output_msg_text);
+ ch_output_msg_text.setText("");
+ } else {
+ output_msg_text.setText("");
+ }
+ if(global_prefs.getBoolean("save_msg_history", false) == true) {
+ File directory;
+ directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "Tinelix");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+
+ directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Tinelix", "IRC Client");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+ directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Tinelix/IRC Client", "Messages Logs");
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+
+ try {
+ Log.d("App", "Attempting creating log file...");
+ File file = new File(directory, "LOG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(dt) + ".log");
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ Log.d("App", "Log file created!");
+ FileWriter writer = new FileWriter(file);
+ writer.append(socks_msg_text.getText() + socket_data_string);
+ writer.flush();
+ writer.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ } else {
+ Log.e("Socket", "Socket not created");
+ }
+ } else if(state == "connecting") {
+ connectionDialog.cancel();
+ state = "connected";
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/android/app/src/main/res/drawable-anydpi/button_bottom_border.png b/android/app/src/main/res/drawable-anydpi/button_bottom_border.png
new file mode 100644
index 0000000..ec3e42e
Binary files /dev/null and b/android/app/src/main/res/drawable-anydpi/button_bottom_border.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/ic_menu_btn_add.png b/android/app/src/main/res/drawable-hdpi/ic_menu_btn_add.png
new file mode 100644
index 0000000..444e8a5
Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_menu_btn_add.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/ic_menu_delete.png b/android/app/src/main/res/drawable-hdpi/ic_menu_delete.png
new file mode 100644
index 0000000..24d8f6a
Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_menu_delete.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/ic_menu_edit.png b/android/app/src/main/res/drawable-hdpi/ic_menu_edit.png
new file mode 100644
index 0000000..9bdba1b
Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_menu_edit.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png b/android/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644
index 0000000..2abc458
Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/ic_menu_send.png b/android/app/src/main/res/drawable-hdpi/ic_menu_send.png
new file mode 100644
index 0000000..d94e692
Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_menu_send.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png
new file mode 100644
index 0000000..4967c45
Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/ic_stat_name.png b/android/app/src/main/res/drawable-hdpi/ic_stat_name.png
new file mode 100644
index 0000000..cf6d39f
Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_stat_name.png differ
diff --git a/android/app/src/main/res/drawable-ldpi/checkbox_checked.png b/android/app/src/main/res/drawable-ldpi/checkbox_checked.png
new file mode 100644
index 0000000..44b36cd
Binary files /dev/null and b/android/app/src/main/res/drawable-ldpi/checkbox_checked.png differ
diff --git a/android/app/src/main/res/drawable-ldpi/checkbox_checked_disabled.png b/android/app/src/main/res/drawable-ldpi/checkbox_checked_disabled.png
new file mode 100644
index 0000000..00dff69
Binary files /dev/null and b/android/app/src/main/res/drawable-ldpi/checkbox_checked_disabled.png differ
diff --git a/android/app/src/main/res/drawable-ldpi/checkbox_disabled.png b/android/app/src/main/res/drawable-ldpi/checkbox_disabled.png
new file mode 100644
index 0000000..7b14ad9
Binary files /dev/null and b/android/app/src/main/res/drawable-ldpi/checkbox_disabled.png differ
diff --git a/android/app/src/main/res/drawable-ldpi/checkbox_unchecked.png b/android/app/src/main/res/drawable-ldpi/checkbox_unchecked.png
new file mode 100644
index 0000000..d2525ce
Binary files /dev/null and b/android/app/src/main/res/drawable-ldpi/checkbox_unchecked.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/ic_menu_btn_add.png b/android/app/src/main/res/drawable-mdpi/ic_menu_btn_add.png
new file mode 100644
index 0000000..361c7c4
Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_menu_btn_add.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/ic_menu_delete.png b/android/app/src/main/res/drawable-mdpi/ic_menu_delete.png
new file mode 100644
index 0000000..e2c8700
Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_menu_delete.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/ic_menu_edit.png b/android/app/src/main/res/drawable-mdpi/ic_menu_edit.png
new file mode 100644
index 0000000..d0314e9
Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_menu_edit.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png b/android/app/src/main/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644
index 0000000..ba704b6
Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/ic_menu_send.png b/android/app/src/main/res/drawable-mdpi/ic_menu_send.png
new file mode 100644
index 0000000..06b4717
Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_menu_send.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png
new file mode 100644
index 0000000..c5afcba
Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png differ
diff --git a/android/app/src/main/res/drawable-mdpi/ic_stat_name.png b/android/app/src/main/res/drawable-mdpi/ic_stat_name.png
new file mode 100644
index 0000000..fa7096c
Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_stat_name.png differ
diff --git a/android/app/src/main/res/drawable-nodpi/checkbox_checked.png b/android/app/src/main/res/drawable-nodpi/checkbox_checked.png
new file mode 100644
index 0000000..d414117
Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/checkbox_checked.png differ
diff --git a/android/app/src/main/res/drawable-nodpi/checkbox_checked_disabled.png b/android/app/src/main/res/drawable-nodpi/checkbox_checked_disabled.png
new file mode 100644
index 0000000..46c50e9
Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/checkbox_checked_disabled.png differ
diff --git a/android/app/src/main/res/drawable-nodpi/checkbox_disabled.png b/android/app/src/main/res/drawable-nodpi/checkbox_disabled.png
new file mode 100644
index 0000000..6f88c9c
Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/checkbox_disabled.png differ
diff --git a/android/app/src/main/res/drawable-nodpi/checkbox_unchecked.png b/android/app/src/main/res/drawable-nodpi/checkbox_unchecked.png
new file mode 100644
index 0000000..3332669
Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/checkbox_unchecked.png differ
diff --git a/android/app/src/main/res/drawable-nodpi/full_application_icon.png b/android/app/src/main/res/drawable-nodpi/full_application_icon.png
new file mode 100644
index 0000000..4615929
Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/full_application_icon.png differ
diff --git a/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog.png b/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog.png
new file mode 100644
index 0000000..1cecc4f
Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog.png differ
diff --git a/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog_hovered.png b/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog_hovered.png
new file mode 100644
index 0000000..aa86c96
Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog_hovered.png differ
diff --git a/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog_light.png b/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog_light.png
new file mode 100644
index 0000000..b25e21b
Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog_light.png differ
diff --git a/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog_pressed.png b/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog_pressed.png
new file mode 100644
index 0000000..82c35bc
Binary files /dev/null and b/android/app/src/main/res/drawable-nodpi/spinner_arrow_dialog_pressed.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/ic_menu_btn_add.png b/android/app/src/main/res/drawable-xhdpi/ic_menu_btn_add.png
new file mode 100644
index 0000000..7d498a9
Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_menu_btn_add.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/ic_menu_delete.png b/android/app/src/main/res/drawable-xhdpi/ic_menu_delete.png
new file mode 100644
index 0000000..65b9cae
Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_menu_delete.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/ic_menu_edit.png b/android/app/src/main/res/drawable-xhdpi/ic_menu_edit.png
new file mode 100644
index 0000000..fcdd71e
Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_menu_edit.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_dark.png b/android/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644
index 0000000..a92fb1d
Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_dark.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/ic_menu_send.png b/android/app/src/main/res/drawable-xhdpi/ic_menu_send.png
new file mode 100644
index 0000000..6e5ec78
Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_menu_send.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png
new file mode 100644
index 0000000..fd58378
Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/ic_stat_name.png b/android/app/src/main/res/drawable-xhdpi/ic_stat_name.png
new file mode 100644
index 0000000..ffe95a3
Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_stat_name.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png
new file mode 100644
index 0000000..1d5a932
Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png b/android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png
new file mode 100644
index 0000000..04ba4a3
Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png
new file mode 100644
index 0000000..c66029f
Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png b/android/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png
new file mode 100644
index 0000000..482376a
Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png differ
diff --git a/android/app/src/main/res/drawable/checkbox.xml b/android/app/src/main/res/drawable/checkbox.xml
new file mode 100644
index 0000000..bdce318
--- /dev/null
+++ b/android/app/src/main/res/drawable/checkbox.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/dialog_spinner.xml b/android/app/src/main/res/drawable/dialog_spinner.xml
new file mode 100644
index 0000000..9e46a9b
--- /dev/null
+++ b/android/app/src/main/res/drawable/dialog_spinner.xml
@@ -0,0 +1,20 @@
+
+
+
+ -
+
-
+
+
+
+
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/dialog_spinner_light.xml b/android/app/src/main/res/drawable/dialog_spinner_light.xml
new file mode 100644
index 0000000..01a9b3b
--- /dev/null
+++ b/android/app/src/main/res/drawable/dialog_spinner_light.xml
@@ -0,0 +1,20 @@
+
+
+
+ -
+
-
+
+
+
+
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/dialog_textarea.xml b/android/app/src/main/res/drawable/dialog_textarea.xml
new file mode 100644
index 0000000..0cb075c
--- /dev/null
+++ b/android/app/src/main/res/drawable/dialog_textarea.xml
@@ -0,0 +1,14 @@
+
+
+
+ -
+
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/dialog_textarea_light.xml b/android/app/src/main/res/drawable/dialog_textarea_light.xml
new file mode 100644
index 0000000..a7faf8a
--- /dev/null
+++ b/android/app/src/main/res/drawable/dialog_textarea_light.xml
@@ -0,0 +1,14 @@
+
+
+
+ -
+
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/successfully_state_shape.xml b/android/app/src/main/res/drawable/successfully_state_shape.xml
new file mode 100644
index 0000000..8ca0924
--- /dev/null
+++ b/android/app/src/main/res/drawable/successfully_state_shape.xml
@@ -0,0 +1,11 @@
+
+
+ -
+
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/tabwidget.xml b/android/app/src/main/res/drawable/tabwidget.xml
new file mode 100644
index 0000000..df9df9b
--- /dev/null
+++ b/android/app/src/main/res/drawable/tabwidget.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/tabwidget_default.xml b/android/app/src/main/res/drawable/tabwidget_default.xml
new file mode 100644
index 0000000..989948b
--- /dev/null
+++ b/android/app/src/main/res/drawable/tabwidget_default.xml
@@ -0,0 +1,13 @@
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/tabwidget_selected.xml b/android/app/src/main/res/drawable/tabwidget_selected.xml
new file mode 100644
index 0000000..5753c6c
--- /dev/null
+++ b/android/app/src/main/res/drawable/tabwidget_selected.xml
@@ -0,0 +1,14 @@
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/textarea.xml b/android/app/src/main/res/drawable/textarea.xml
new file mode 100644
index 0000000..12e2e38
--- /dev/null
+++ b/android/app/src/main/res/drawable/textarea.xml
@@ -0,0 +1,14 @@
+
+
+
+ -
+
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-ldpi/checkbox_prefw.xml b/android/app/src/main/res/layout-ldpi/checkbox_prefw.xml
new file mode 100644
index 0000000..fb96fb9
--- /dev/null
+++ b/android/app/src/main/res/layout-ldpi/checkbox_prefw.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/about_application_activity.xml b/android/app/src/main/res/layout-v11/about_application_activity.xml
new file mode 100644
index 0000000..84cdecd
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/about_application_activity.xml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/activity_connection_manager.xml b/android/app/src/main/res/layout-v11/activity_connection_manager.xml
new file mode 100644
index 0000000..18140b0
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/activity_connection_manager.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/activity_main.xml b/android/app/src/main/res/layout-v11/activity_main.xml
new file mode 100644
index 0000000..a7d068e
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/activity_main.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/create_item.xml b/android/app/src/main/res/layout-v11/create_item.xml
new file mode 100644
index 0000000..c000315
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/create_item.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/create_item2.xml b/android/app/src/main/res/layout-v11/create_item2.xml
new file mode 100644
index 0000000..a58d778
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/create_item2.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/custom_nicknames_activity.xml b/android/app/src/main/res/layout-v11/custom_nicknames_activity.xml
new file mode 100644
index 0000000..17a1dd9
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/custom_nicknames_activity.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/custom_preferences_layout.xml b/android/app/src/main/res/layout-v11/custom_preferences_layout.xml
new file mode 100644
index 0000000..489889a
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/custom_preferences_layout.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/layout-v11/debug_log_activity.xml b/android/app/src/main/res/layout-v11/debug_log_activity.xml
new file mode 100644
index 0000000..1aba17c
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/debug_log_activity.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/enter_password_activity.xml b/android/app/src/main/res/layout-v11/enter_password_activity.xml
new file mode 100644
index 0000000..ea77159
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/enter_password_activity.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/enter_server_activity.xml b/android/app/src/main/res/layout-v11/enter_server_activity.xml
new file mode 100644
index 0000000..439f4e8
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/enter_server_activity.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/enter_text_activity.xml b/android/app/src/main/res/layout-v11/enter_text_activity.xml
new file mode 100644
index 0000000..1c8447a
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/enter_text_activity.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/profile_item.xml b/android/app/src/main/res/layout-v11/profile_item.xml
new file mode 100644
index 0000000..a139863
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/profile_item.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/set_font_size_activity.xml b/android/app/src/main/res/layout-v11/set_font_size_activity.xml
new file mode 100644
index 0000000..d2bbc2d
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/set_font_size_activity.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/statistics_activity.xml b/android/app/src/main/res/layout-v11/statistics_activity.xml
new file mode 100644
index 0000000..ed3791b
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/statistics_activity.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout-v11/thread_activity.xml b/android/app/src/main/res/layout-v11/thread_activity.xml
new file mode 100644
index 0000000..bd2766f
--- /dev/null
+++ b/android/app/src/main/res/layout-v11/thread_activity.xml
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/about_application_activity.xml b/android/app/src/main/res/layout/about_application_activity.xml
new file mode 100644
index 0000000..277e6e6
--- /dev/null
+++ b/android/app/src/main/res/layout/about_application_activity.xml
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_connection_manager.xml b/android/app/src/main/res/layout/activity_connection_manager.xml
new file mode 100644
index 0000000..c59f868
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_connection_manager.xml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..61faa6a
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/checkbox_prefw.xml b/android/app/src/main/res/layout/checkbox_prefw.xml
new file mode 100644
index 0000000..5fa685b
--- /dev/null
+++ b/android/app/src/main/res/layout/checkbox_prefw.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/custom_nicknames_activity.xml b/android/app/src/main/res/layout/custom_nicknames_activity.xml
new file mode 100644
index 0000000..cea8d99
--- /dev/null
+++ b/android/app/src/main/res/layout/custom_nicknames_activity.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/custom_preferences_layout.xml b/android/app/src/main/res/layout/custom_preferences_layout.xml
new file mode 100644
index 0000000..972ec87
--- /dev/null
+++ b/android/app/src/main/res/layout/custom_preferences_layout.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/custom_spinner_item.xml b/android/app/src/main/res/layout/custom_spinner_item.xml
new file mode 100644
index 0000000..0984e9c
--- /dev/null
+++ b/android/app/src/main/res/layout/custom_spinner_item.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/debug_log_activity.xml b/android/app/src/main/res/layout/debug_log_activity.xml
new file mode 100644
index 0000000..8c25c5d
--- /dev/null
+++ b/android/app/src/main/res/layout/debug_log_activity.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/enter_password_activity.xml b/android/app/src/main/res/layout/enter_password_activity.xml
new file mode 100644
index 0000000..a84f6c3
--- /dev/null
+++ b/android/app/src/main/res/layout/enter_password_activity.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/enter_server_activity.xml b/android/app/src/main/res/layout/enter_server_activity.xml
new file mode 100644
index 0000000..e11357f
--- /dev/null
+++ b/android/app/src/main/res/layout/enter_server_activity.xml
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/enter_text_activity.xml b/android/app/src/main/res/layout/enter_text_activity.xml
new file mode 100644
index 0000000..b1855dc
--- /dev/null
+++ b/android/app/src/main/res/layout/enter_text_activity.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/notification_activity.xml b/android/app/src/main/res/layout/notification_activity.xml
new file mode 100644
index 0000000..408cbfa
--- /dev/null
+++ b/android/app/src/main/res/layout/notification_activity.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/pref_widget.xml b/android/app/src/main/res/layout/pref_widget.xml
new file mode 100644
index 0000000..37450a9
--- /dev/null
+++ b/android/app/src/main/res/layout/pref_widget.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/profile_item.xml b/android/app/src/main/res/layout/profile_item.xml
new file mode 100644
index 0000000..9c4ba2b
--- /dev/null
+++ b/android/app/src/main/res/layout/profile_item.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/progress_activity.xml b/android/app/src/main/res/layout/progress_activity.xml
new file mode 100644
index 0000000..4c3ccef
--- /dev/null
+++ b/android/app/src/main/res/layout/progress_activity.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/set_font_size_activity.xml b/android/app/src/main/res/layout/set_font_size_activity.xml
new file mode 100644
index 0000000..8b0ba35
--- /dev/null
+++ b/android/app/src/main/res/layout/set_font_size_activity.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/statistics_activity.xml b/android/app/src/main/res/layout/statistics_activity.xml
new file mode 100644
index 0000000..707d0bb
--- /dev/null
+++ b/android/app/src/main/res/layout/statistics_activity.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/thread_activity.xml b/android/app/src/main/res/layout/thread_activity.xml
new file mode 100644
index 0000000..aabb45e
--- /dev/null
+++ b/android/app/src/main/res/layout/thread_activity.xml
@@ -0,0 +1,252 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/connection_manager_menu.xml b/android/app/src/main/res/menu/connection_manager_menu.xml
new file mode 100644
index 0000000..a2f6816
--- /dev/null
+++ b/android/app/src/main/res/menu/connection_manager_menu.xml
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/main.xml b/android/app/src/main/res/menu/main.xml
new file mode 100644
index 0000000..c820ac1
--- /dev/null
+++ b/android/app/src/main/res/menu/main.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/main_menu.xml b/android/app/src/main/res/menu/main_menu.xml
new file mode 100644
index 0000000..593b086
--- /dev/null
+++ b/android/app/src/main/res/menu/main_menu.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/nicknames_manager_menu.xml b/android/app/src/main/res/menu/nicknames_manager_menu.xml
new file mode 100644
index 0000000..83485d6
--- /dev/null
+++ b/android/app/src/main/res/menu/nicknames_manager_menu.xml
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/thread_menu.xml b/android/app/src/main/res/menu/thread_menu.xml
new file mode 100644
index 0000000..5d1c103
--- /dev/null
+++ b/android/app/src/main/res/menu/thread_menu.xml
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..d3d1108
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..c5f2168
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a0ab5b5
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..ec3ce47
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..123f876
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..3fc83b2
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6aeab8c
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..263a0cf
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4615929
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..e9847ff
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/values-ldpi-v11/styles.xml b/android/app/src/main/res/values-ldpi-v11/styles.xml
new file mode 100644
index 0000000..db35d31
--- /dev/null
+++ b/android/app/src/main/res/values-ldpi-v11/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values-ldpi/styles.xml b/android/app/src/main/res/values-ldpi/styles.xml
new file mode 100644
index 0000000..bb077a3
--- /dev/null
+++ b/android/app/src/main/res/values-ldpi/styles.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values-ru/arrays.xml b/android/app/src/main/res/values-ru/arrays.xml
new file mode 100644
index 0000000..be21ea6
--- /dev/null
+++ b/android/app/src/main/res/values-ru/arrays.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ - Без аутентификации
+ - NickServ
+
+
+ - ЗавиÑимый от ОС
+ - English
+ - РуÑÑкий
+
+
+ - ТемнаÑ
+ - СветлаÑ
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000..25898da
--- /dev/null
+++ b/android/app/src/main/res/values-ru/strings.xml
@@ -0,0 +1,100 @@
+
+
+
+ - Ðачать общение
+ - ÐаÑтройки
+ - О приложении
+ - Выход
+
+ Менеджер подключений
+ Добавить
+ ПодключитьÑÑ
+ Изменить
+ Удалить
+ Ð˜Ð¼Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ:
+ Открыть
+ Отмена
+ Ввод имени профилÑ
+ Ввод никнейма
+ Ввод паролÑ
+ Ввод наÑтоÑщего имени
+ Ввод имени хоÑта
+ Ð˜Ð¼Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ
+ Ðикнейм
+ Общие
+ Метод аутентификации
+ Добавить никнейм
+ Создать профиль
+ Менеджер никнеймов
+ Ðикнеймы
+ ОчиÑтить
+ Пароль
+ ÐаÑтоÑщее имÑ
+ Ð˜Ð¼Ñ Ñ…Ð¾Ñта
+ Сервер
+ ÐаÑтройки Ñервера
+ ИдентификациÑ
+ Порт
+ Только SSL/TLS
+ Соединение потерÑно.
+ Ð’Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¿Ñ€ÐµÐ²Ñ‹ÑˆÐµÐ½Ð¾. Повторите позже.
+ Ðе удалоÑÑŒ подключитьÑÑ Ðº Ñерверу.
+ Кодировка:
+ Профиль удален
+ Выход из ÑеанÑа
+ ОтÑоединитьÑÑ Ð¾Ñ‚ Ñервера?
+ О приложении
+ ВерÑÐ¸Ñ %1$s (%2$s)
+ Ðто Ñвободное программное обеÑпечение Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом, раÑпроÑтранÑемое в ÑоответÑтвии Ñ ÑƒÑловиÑми GNU General Public License 3.0 (прочитать лицензию).\n\nБЕЗ КÐКИХ-ЛИБО ГÐÐ ÐÐТИЙ, ВКЛЮЧÐЯ КОММЕРЧЕСКУЮ ЦЕÐÐОСТЬ.
+ Репозиторий
+ Сообщение
+ СтатиÑтика
+ Отправлено:
+ Получено:
+ Итого:
+ %1$s байт
+ %1$s кБ
+ %1$s МБ
+ %1$s ГБ
+ СеанÑ
+ ОтÑоединитьÑÑ
+ Скрывать IP-адреÑ
+ %1$s упомÑнул(a) ваÑ
+ Ð’Ñ‹ не можете отправить пуÑтое Ñообщение.
+ Меню
+ Соединение к %1$s...
+ Сообщение о выходе
+ Сообщение о выходе:
+ Ввод ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾ выходе
+ ИнтерфейÑ
+ Язык (Language)
+ Тема оформлениÑ
+ Поток
+ Размер шрифта
+ Размер шрифта:
+ Изменение размера шрифта
+ ПредпроÑмотр:
+ ÐаÑтройки
+ %1$d пикÑ.
+ ПОДКЛЮЧЕÐО
+ Сайт
+ Ðеобходима перезагрузка приложениÑ
+ СпиÑок пуÑÑ‚\n\nÐ’Ñ‹ можете Ñоздать Ñвой профиль Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº IRC-Ñерверам.
+ Приложение
+ Отладочный журнал
+ Сохранить журнал
+ Отладочный журнал Ñохранен в ПамÑÑ‚ÑŒ уÑтройÑтва/%1$s
+ СохранÑетÑÑ Ð² ПамÑÑ‚ÑŒ уÑтройÑтва/%1$s
+ ТребуютÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ
+ Ð”Ð»Ñ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… в памÑÑ‚ÑŒ уÑтройÑтва приложению нужны Ñпециальные разрешениÑ.\n\nОткрыть раздел ÑиÑтемных наÑтроек \"О приложении\"?
+ Сохр. иÑторию Ñообщений
+ ПамÑÑ‚ÑŒ уÑтройÑтва недоÑтупна
+ Вниз
+ Ð’Ñ‹ забыли указать первый никнейм в наÑтройках профилÑ.
+ Сначала завершите запущенное Ñоединение нажатием кнопки \"Ðазад\".
+ Ðто текÑтовое поле не должно Ñодержать Ñпециальные Ñимволы
+ Пока не работает в текущей верÑии Android
+ Ðвтопрокрутка отключена. Включить можно Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ кнопки \"Вниз\".
+ Показывать Ð²Ñ€ÐµÐ¼Ñ Ð² Ñообщ.
+ Каналы
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values-v11/styles.xml b/android/app/src/main/res/values-v11/styles.xml
new file mode 100644
index 0000000..db35d31
--- /dev/null
+++ b/android/app/src/main/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values/arrays.xml b/android/app/src/main/res/values/arrays.xml
new file mode 100644
index 0000000..41123c8
--- /dev/null
+++ b/android/app/src/main/res/values/arrays.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ - Without authentification
+ - NickServ
+
+
+
+ - UTF-8
+ - DOS (866)
+ - Windows-1251
+ - KOI8-R
+ - KOI8-U
+
+
+ - OS dependent
+ - English
+ - РуÑÑкий
+
+
+ - Dark
+ - Light
+
+
+ - Changes will take effect only after restarting the application.
+ - Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²ÑтупÑÑ‚ в Ñилу только поÑле перезагрузки приложениÑ.
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..259683d
--- /dev/null
+++ b/android/app/src/main/res/values/colors.xml
@@ -0,0 +1,21 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #000000
+ #ffffff
+ #e1e1e1
+ #222222
+ #ff7700
+ #a14b00
+ #4aff7700
+ #16ffffff
+ #00ffffff
+ #2f2f2f
+ #3affffff
+ #d2d2d2
+ #119f3f
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..59a0b0c
--- /dev/null
+++ b/android/app/src/main/res/values/dimens.xml
@@ -0,0 +1,3 @@
+
+ 16dp
+
diff --git a/android/app/src/main/res/values/ic_launcher_background.xml b/android/app/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..266123a
--- /dev/null
+++ b/android/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #272727
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..fafa360
--- /dev/null
+++ b/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,107 @@
+
+
+
+ - Start chatting
+ - Settings
+ - About application
+ - Quit
+
+ Tinelix IRC Client
+ Tinelix IRC
+ Connection manager
+ Add
+ Connect
+ Change
+ Delete
+ Profile name:
+ OK
+ Open
+ Cancel
+ Enter profile name
+ Enter nickname
+ Enter password
+ Enter real name
+ Enter hostname
+ Nickname
+ Profile name
+ Main
+ Authentication method
+ Add nickname
+ Create profile
+ Nicknames
+ Nicknames manager
+ add
+ Clear
+ Password
+ Real name
+ Server
+ Server settings
+ Identification
+ Hostname
+ Port
+ Only SSL/TLS
+ Connection lost.
+ Connection time is exceeded. Try again later.
+ Could not connect to the server.
+ Encoding:
+ Profile deleted
+ Quit session
+ Disconnect from server?
+ About application
+ Version %1$s (%2$s)
+ This is free software with open source, distributed under the terms of the GNU General Public License 3.0 (read license).\n\nWITHOUT ANY WARRANTY, NOT EVEN FOR MERCHANTABILITY.
+ Repository
+ Copyright © 2022 Dmitry Tretyakov (aka. Tinelix)
+ Message
+ Statistics
+ Sended:
+ Received:
+ Total:
+ %1$s bytes
+ %1$s kB
+ %1$s MB
+ %1$s GB
+ Session
+ Disconnect
+ Hide IP address
+ %1$s mentioned you
+ You cannot send empty message.
+ Menu
+ Connecting to %1$s...
+ Quiting message
+ Quiting message:
+ Tinelix IRC Client ver. 0.3.1 Beta for Android (2022-04-08)
+ Enter quiting message
+ Interface
+ Language
+ Theme
+ Thread
+ Font size
+ Font size:
+ Preview:
+ Changing font size
+ tinelix: Hello everyone (11:00:12)\nshortn: hello (11:00:13)\nlong_nick: hi\nsuper_long_nick: Hello, Dmitry! (11:00:13)\ntinelix: How are you? (11:00:16)
+ Settings
+ %1$d px
+ CONNECTED
+ Website
+ Application needs to be restarted
+ The list is empty\n\nYou can create your own profile to connect to IRC servers.
+ Application
+ Debug log
+ Save log
+ Debug log saved to Device Memory/%1$s
+ Saving to Device Memory/%1$s
+ Permissions required
+ To save data to the Device Memory, application needs special permissions.\n\nOpen the \"About application\" system settings section?
+ Save messages history
+ Device Memory is not available
+ Go down
+ You forgot to enter the first nickname in Profile Settings.
+ First end the running connection by pressing the Back button.
+ This text field must not contain special characters!
+ Doesn\'t work in current Android version yet
+ Autoscrolling is disabled. You can enable using the \"Go down\" button.
+ Show timestamps in messages
+ Channels
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..9e78c1c
--- /dev/null
+++ b/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/xml-v11/main_settings.xml b/android/app/src/main/res/xml-v11/main_settings.xml
new file mode 100644
index 0000000..b1dc084
--- /dev/null
+++ b/android/app/src/main/res/xml-v11/main_settings.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/xml-v16/main_settings.xml b/android/app/src/main/res/xml-v16/main_settings.xml
new file mode 100644
index 0000000..851446b
--- /dev/null
+++ b/android/app/src/main/res/xml-v16/main_settings.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/xml/main_settings.xml b/android/app/src/main/res/xml/main_settings.xml
new file mode 100644
index 0000000..e3e5329
--- /dev/null
+++ b/android/app/src/main/res/xml/main_settings.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/xml/profile_settings.xml b/android/app/src/main/res/xml/profile_settings.xml
new file mode 100644
index 0000000..2275160
--- /dev/null
+++ b/android/app/src/main/res/xml/profile_settings.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/test/java/dev/tinelix/irc/android/ExampleUnitTest.java b/android/app/src/test/java/dev/tinelix/irc/android/ExampleUnitTest.java
new file mode 100644
index 0000000..85fbc5d
--- /dev/null
+++ b/android/app/src/test/java/dev/tinelix/irc/android/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package dev.tinelix.irc;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/test/java/dev/tinelix/irc/android/legacy/ExampleUnitTest.java b/android/app/src/test/java/dev/tinelix/irc/android/legacy/ExampleUnitTest.java
new file mode 100644
index 0000000..4638e99
--- /dev/null
+++ b/android/app/src/test/java/dev/tinelix/irc/android/legacy/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package dev.tinelix.irc.android;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..6356aab
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,19 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.0.0'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
diff --git a/android/gradle.properties b/android/gradle.properties
new file mode 100644
index 0000000..1d3591c
--- /dev/null
+++ b/android/gradle.properties
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
\ No newline at end of file
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..0c71e76
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
diff --git a/android/gradlew b/android/gradlew
new file mode 100644
index 0000000..91a7e26
--- /dev/null
+++ b/android/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/android/gradlew.bat b/android/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/android/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/android/settings.gradle b/android/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/windows/win16/.gitignore b/windows/win16/.gitignore
new file mode 100644
index 0000000..3a98cf0
--- /dev/null
+++ b/windows/win16/.gitignore
@@ -0,0 +1,17 @@
+# Ignore compiler output
+*.bsc
+*.crf
+*.bnd
+*.exe
+*.lk1
+*.map
+*.obj
+*.pdb
+*.res
+*.sbr
+*.sym
+
+# Ignore Visual Studio files
+*.aps
+*.vcw
+*.wsp
\ No newline at end of file
diff --git a/windows/win16/LICENSE b/windows/win16/LICENSE
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/windows/win16/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/windows/win16/TLX_IRC.MAK b/windows/win16/TLX_IRC.MAK
new file mode 100644
index 0000000..fffaec1
--- /dev/null
+++ b/windows/win16/TLX_IRC.MAK
@@ -0,0 +1,160 @@
+# Microsoft Visual C++ generated build script - Do not modify
+
+PROJ = TLX_IRC
+DEBUG = 1
+PROGTYPE = 0
+CALLER =
+ARGS =
+DLLS =
+D_RCDEFINES = /d_DEBUG
+R_RCDEFINES = /dNDEBUG
+ORIGIN = MSVC
+ORIGIN_VER = 1.00
+PROJPATH = C:\HOME\TLX_IRC\
+USEMFC = 0
+CC = cl
+CPP = cl
+CXX = cl
+CCREATEPCHFLAG =
+CPPCREATEPCHFLAG =
+CUSEPCHFLAG =
+CPPUSEPCHFLAG =
+FIRSTC = ABOUTDLG.C
+FIRSTCPP =
+RC = rc
+CFLAGS_D_WEXE = /nologo /G2 /W3 /Zi /AM /Od /D "_DEBUG" /FR /GA /Fd"TLX_IRC.PDB"
+CFLAGS_R_WEXE = /nologo /W3 /Gf /O1 /D "WINVER"="0x0300" /D "NDEBUG" /FR /GA /GEs /GEm
+LFLAGS_D_WEXE = /NOLOGO /NOD /PACKC:61440 /STACK:10240 /ALIGN:16 /ONERROR:NOEXE /CO
+LFLAGS_R_WEXE = /NOLOGO /NOD /PACKC:61440 /ALIGN:16 /ONERROR:NOEXE
+LIBS_D_WEXE = oldnames libw mlibcew winsock.lib commdlg.lib olecli.lib olesvr.lib shell.lib
+LIBS_R_WEXE = oldnames libw slibcew commdlg.lib olecli.lib olesvr.lib shell.lib
+RCFLAGS = /nologo
+RESFLAGS = /nologo /30
+RUNFLAGS =
+DEFFILE = SRC\TLX_IRC.DEF
+OBJS_EXT =
+LIBS_EXT =
+!if "$(DEBUG)" == "1"
+CFLAGS = $(CFLAGS_D_WEXE)
+LFLAGS = $(LFLAGS_D_WEXE)
+LIBS = $(LIBS_D_WEXE)
+MAPFILE = nul
+RCDEFINES = $(D_RCDEFINES)
+!else
+CFLAGS = $(CFLAGS_R_WEXE)
+LFLAGS = $(LFLAGS_R_WEXE)
+LIBS = $(LIBS_R_WEXE)
+MAPFILE = nul
+RCDEFINES = $(R_RCDEFINES)
+!endif
+!if [if exist MSVC.BND del MSVC.BND]
+!endif
+SBRS = ABOUTDLG.SBR \
+ APP.SBR \
+ MAINWND.SBR \
+ CONNMDLG.SBR \
+ ETEXTDLG.SBR \
+ PRFSTDLG.SBR \
+ IRCCLNT.SBR
+
+
+ABOUTDLG_DEP = c:\home\tlx_irc\src\aboutdlg.h \
+ c:\home\tlx_irc\src\globals.h
+
+
+APP_DEP = c:\home\tlx_irc\src\globals.h \
+ c:\home\tlx_irc\src\mainwnd.h \
+ c:\programs\msvc\include\winsock.h
+
+
+MAINWND_DEP = c:\home\tlx_irc\src\aboutdlg.h \
+ c:\home\tlx_irc\src\etextdlg.h \
+ c:\home\tlx_irc\src\globals.h \
+ c:\home\tlx_irc\src\mainwnd.h \
+ c:\home\tlx_irc\src\connmdlg.h \
+ c:\home\tlx_irc\src\ircclnt.h
+
+
+RESOURCE_RCDEP = c:\home\tlx_irc\src\tlx_irc.ver
+
+
+CONNMDLG_DEP = c:\home\tlx_irc\src\connmdlg.h \
+ c:\home\tlx_irc\src\etextdlg.h \
+ c:\home\tlx_irc\src\globals.h
+
+
+ETEXTDLG_DEP = c:\home\tlx_irc\src\etextdlg.h \
+ c:\home\tlx_irc\src\prfstdlg.h \
+ c:\home\tlx_irc\src\globals.h
+
+
+PRFSTDLG_DEP = c:\home\tlx_irc\src\prfstdlg.h \
+ c:\home\tlx_irc\src\globals.h
+
+
+IRCCLNT_DEP = c:\programs\msvc\include\winsock.h \
+ c:\home\tlx_irc\src\ircclnt.h
+
+
+all: $(PROJ).EXE $(PROJ).BSC
+
+ABOUTDLG.OBJ: SRC\ABOUTDLG.C $(ABOUTDLG_DEP)
+ $(CC) $(CFLAGS) $(CCREATEPCHFLAG) /c SRC\ABOUTDLG.C
+
+APP.OBJ: SRC\APP.C $(APP_DEP)
+ $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SRC\APP.C
+
+MAINWND.OBJ: SRC\MAINWND.C $(MAINWND_DEP)
+ $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SRC\MAINWND.C
+
+RESOURCE.RES: SRC\RESOURCE.RC $(RESOURCE_RCDEP)
+ $(RC) $(RCFLAGS) $(RCDEFINES) -r -FoC:\HOME\TLX_IRC\RESOURCE.RES SRC\RESOURCE.RC
+
+CONNMDLG.OBJ: SRC\CONNMDLG.C $(CONNMDLG_DEP)
+ $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SRC\CONNMDLG.C
+
+ETEXTDLG.OBJ: SRC\ETEXTDLG.C $(ETEXTDLG_DEP)
+ $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SRC\ETEXTDLG.C
+
+PRFSTDLG.OBJ: SRC\PRFSTDLG.C $(PRFSTDLG_DEP)
+ $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SRC\PRFSTDLG.C
+
+IRCCLNT.OBJ: SRC\IRCCLNT.C $(IRCCLNT_DEP)
+ $(CC) $(CFLAGS) $(CUSEPCHFLAG) /c SRC\IRCCLNT.C
+
+
+$(PROJ).EXE:: RESOURCE.RES
+
+$(PROJ).EXE:: ABOUTDLG.OBJ APP.OBJ MAINWND.OBJ CONNMDLG.OBJ ETEXTDLG.OBJ PRFSTDLG.OBJ \
+ IRCCLNT.OBJ $(OBJS_EXT) $(DEFFILE)
+ echo >NUL @<<$(PROJ).CRF
+ABOUTDLG.OBJ +
+APP.OBJ +
+MAINWND.OBJ +
+CONNMDLG.OBJ +
+ETEXTDLG.OBJ +
+PRFSTDLG.OBJ +
+IRCCLNT.OBJ +
+$(OBJS_EXT)
+$(PROJ).EXE
+$(MAPFILE)
+c:\programs\msvc\lib\+
+c:\programs\msvc\mfc\lib\+
+$(LIBS)
+$(DEFFILE);
+<<
+ link $(LFLAGS) @$(PROJ).CRF
+ $(RC) $(RESFLAGS) RESOURCE.RES $@
+ @copy $(PROJ).CRF MSVC.BND
+
+$(PROJ).EXE:: RESOURCE.RES
+ if not exist MSVC.BND $(RC) $(RESFLAGS) RESOURCE.RES $@
+
+run: $(PROJ).EXE
+ $(PROJ) $(RUNFLAGS)
+
+
+$(PROJ).BSC: $(SBRS)
+ bscmake @<<
+/o$@ $(SBRS)
+<<
diff --git a/windows/win16/src/AboutDlg.c b/windows/win16/src/AboutDlg.c
new file mode 100644
index 0000000..8716d2e
--- /dev/null
+++ b/windows/win16/src/AboutDlg.c
@@ -0,0 +1,56 @@
+#include "AboutDlg.h"
+#include "Globals.h"
+#include "Resource.h"
+
+/* Dialog procedure for our "about" dialog */
+BOOL CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ {
+ WORD id = wParam;
+
+ switch (id)
+ {
+ case IDOK:
+ case IDCANCEL:
+ {
+ EndDialog(hwndDlg, id);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ case WM_INITDIALOG:
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* Show our "about" dialog */
+void ShowAboutDialog(HWND owner)
+{
+ HWND hWnd = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_ABOUTDIALOG), owner, AboutDialogProc);
+ if(hWnd) {
+ HWND appNameHwnd = GetDlgItem(hWnd, IDC_APPNAME);
+ SetAboutUiFont(hWnd);
+ SetWindowText(appNameHwnd, AppName);
+ ShowWindow(hWnd, SW_SHOW);
+ }
+}
+
+void SetAboutUiFont(HWND hWnd) {
+ HFONT defaultFont;
+ LOGFONT fontAttrib;
+ defaultFont = (HFONT)CreateFont(13, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET,
+ OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
+ "Helv");
+
+ SendDlgItemMessage(hWnd, IDOK, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_CORYRIGHT, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_GITHUB_LINK, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+}
diff --git a/windows/win16/src/AboutDlg.h b/windows/win16/src/AboutDlg.h
new file mode 100644
index 0000000..fbb464f
--- /dev/null
+++ b/windows/win16/src/AboutDlg.h
@@ -0,0 +1,15 @@
+#ifndef ABOUTDLG_H
+#define ABOUTDLG_H
+
+#include
+
+
+/* Dialog procedure for our "about" dialog */
+BOOL CALLBACK __export AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+/* Show our "about" dialog */
+void ShowAboutDialog(HWND owner);
+
+void SetAboutUiFont(HWND hWnd);
+
+#endif
diff --git a/windows/win16/src/App.c b/windows/win16/src/App.c
new file mode 100644
index 0000000..dc81296
--- /dev/null
+++ b/windows/win16/src/App.c
@@ -0,0 +1,63 @@
+#include
+#include "Globals.h"
+#include "MainWnd.h"
+#include "Resource.h"
+#include
+
+/* Global instance handle */
+HINSTANCE g_hInstance = NULL;
+WSADATA WSAData;
+
+/* Our application entry point */
+int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+ HWND hWnd;
+ HACCEL hAccelerators;
+ MSG msg;
+ int status;
+
+ /* Assign global HINSTANCE */
+ g_hInstance = hInstance;
+
+ /* Register our main window class, or error */
+ if (!hPrevInstance && !RegisterMainWindowClass())
+ {
+ FatalAppExit(0, "Window class registration failed.");
+ return 0;
+ }
+
+ /* Create our main window, or error */
+ if (!(hWnd = CreateMainWindow()))
+ {
+ FatalAppExit(0, "Window creating failed.");
+ return 0;
+ }
+
+ /* Load accelerators */
+ hAccelerators = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR));
+
+ /* Show main window and force a paint */
+ ShowWindow(hWnd, nCmdShow);
+ UpdateWindow(hWnd);
+ status = WSAStartup(101, &WSAData);
+ if(status != 0) {
+ FatalAppExit(0, "WinSock initialization failed. Application cannot be started.");
+ return 0;
+ }
+
+ /* Main message loop */
+ while (GetMessage(&msg, NULL, 0, 0) > 0)
+ {
+ if (!TranslateAccelerator(hWnd, hAccelerators, &msg) && !IsDialogMessage(hWnd, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ return (int)msg.wParam;
+}
+
+void QuitApp() {
+ WSACleanup(WSAData);
+}
diff --git a/windows/win16/src/App.ico b/windows/win16/src/App.ico
new file mode 100644
index 0000000..2ca7e94
Binary files /dev/null and b/windows/win16/src/App.ico differ
diff --git a/windows/win16/src/CONNMDLG.C b/windows/win16/src/CONNMDLG.C
new file mode 100644
index 0000000..9e19d3c
--- /dev/null
+++ b/windows/win16/src/CONNMDLG.C
@@ -0,0 +1,79 @@
+#include "ConnMDlg.h"
+#include "ETextDlg.h"
+#include "Globals.h"
+#include "Resource.h"
+#include
+
+char ini_path[256];
+
+BOOL CALLBACK ConnManDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ {
+ WORD id = wParam;
+
+ switch (id)
+ {
+ case IDOK: {
+ EndDialog(hwndDlg, id);
+ return TRUE;
+ }
+ case IDC_CREATE_PROFILE_BTN: {
+ ShowEnterTextDialog(hwndDlg, "profile_name");
+ return TRUE;
+ }
+ case IDCANCEL:
+ {
+ EndDialog(hwndDlg, id);
+ return TRUE;
+ }
+ }
+ break;
+ }
+
+ case WM_INITDIALOG:
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void ShowConnManDialog(HWND owner)
+{
+ HWND hWnd = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_CONNMANDIALOG), owner, ConnManDialogProc);
+ SetConnManUiFont(hWnd);
+}
+
+void SetConnManUiFont(HWND hWnd) {
+ HFONT defaultFont;
+ LOGFONT fontAttrib;
+ int main_settings_index;
+ HWND listBoxHwnd = GetDlgItem(hWnd, IDC_PROFILELIST);
+ defaultFont = (HFONT)CreateFont(13, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET,
+ OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
+ "Helv");
+ GetModuleFileName(g_hInstance, ini_path, 256);
+ *(strrchr(ini_path, '\\')+1) = '\0';
+ strcat(ini_path, "*.ini");
+
+ if(LOBYTE(LOWORD(GetVersion())) >= 3 && HIBYTE(LOWORD(GetVersion())) >= 1) {
+ // Windows 3.0 moment
+ DlgDirList(hWnd, ini_path, IDC_PROFILELIST, IDC_PROFILELIST, 0);
+ }
+ // Next...
+
+ main_settings_index = SendMessage(listBoxHwnd, LB_FINDSTRING, 0, (LPARAM)"client.ini");
+ if(main_settings_index >= 0) {
+ SendMessage(listBoxHwnd, LB_DELETESTRING, main_settings_index, 0);
+ };
+ SendDlgItemMessage(hWnd, IDC_PROFILELIST, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDOK, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_CREATE_PROFILE_BTN, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_CONNECT_BTN, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_EDIT_PROFILE_BTN, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_DELETE_PROFILE_BTN, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+}
diff --git a/windows/win16/src/CONNMDLG.H b/windows/win16/src/CONNMDLG.H
new file mode 100644
index 0000000..8806951
--- /dev/null
+++ b/windows/win16/src/CONNMDLG.H
@@ -0,0 +1,14 @@
+#ifndef CONNMDLG_H
+#define CONNMDLG_H
+
+#include
+
+/* Dialog procedure for our "about" dialog */
+BOOL CALLBACK __export ConnManDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+/* Show our "about" dialog */
+void ShowConnManDialog(HWND owner);
+
+void SetConnManUiFont(HWND hWnd);
+
+#endif
diff --git a/windows/win16/src/ETEXTDLG.C b/windows/win16/src/ETEXTDLG.C
new file mode 100644
index 0000000..0dd4ef0
--- /dev/null
+++ b/windows/win16/src/ETEXTDLG.C
@@ -0,0 +1,80 @@
+#include "ETextDlg.h"
+#include "PrfStDlg.h"
+#include "Globals.h"
+#include "Resource.h"
+#include
+
+char* key;
+char* value;
+
+BOOL CALLBACK EnterTextDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ {
+ WORD id = wParam;
+
+ switch (id)
+ {
+ case IDOK: {
+ HWND editText = GetDlgItem(hwndDlg, IDC_ENTERTEXTBOX);
+ GetWindowText(editText, value, 256);
+ if(!strcmp(key, "profile_name")) {
+ if(strlen(value) > 8) {
+ MessageBox(hwndDlg, "Profile name must not exceed 8 characters.", "Error", MB_ICONSTOP|MB_OK);
+ return FALSE;
+ }
+ if(!strcmp(value, "client")) {
+ MessageBox(hwndDlg, "This name is already reserved. Try choosing a different name.", "Error", MB_ICONSTOP|MB_OK);
+ return FALSE;
+ }
+ ShowProfileSettingsDialog(hwndDlg, value);
+ }
+ EndDialog(hwndDlg, id);
+ return TRUE;
+ }
+ case IDCANCEL:
+ {
+ EndDialog(hwndDlg, id);
+ return TRUE;
+ }
+ }
+ break;
+ }
+
+ case WM_INITDIALOG:
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void ShowEnterTextDialog(HWND owner, char* _key)
+{
+ HWND hWnd = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_ENTERTEXTDIALOG), owner, EnterTextDialogProc);
+ if(hWnd) {
+ ShowWindow(hWnd, SW_SHOW);
+ key = _key;
+ if(!strcmp(_key, "profile_name")) {
+ HWND editTextLabel = GetDlgItem(hWnd, IDC_ENTERTEXTLABEL);
+ SetWindowText(editTextLabel, "Profile name:");
+ }
+ SetEnterTextUiFont(hWnd);
+ }
+}
+
+void SetEnterTextUiFont(HWND hWnd) {
+ HFONT defaultFont;
+ LOGFONT fontAttrib;
+ defaultFont = (HFONT)CreateFont(13, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET,
+ OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
+ "Helv");
+
+ SendDlgItemMessage(hWnd, IDOK, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDCANCEL, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_ENTERTEXTLABEL, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_ENTERTEXTBOX, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+}
diff --git a/windows/win16/src/ETEXTDLG.H b/windows/win16/src/ETEXTDLG.H
new file mode 100644
index 0000000..aa91348
--- /dev/null
+++ b/windows/win16/src/ETEXTDLG.H
@@ -0,0 +1,14 @@
+#ifndef ETEXTDLG_H
+#define ETEXTDLG_H
+
+#include
+
+/* Dialog procedure for our "about" dialog */
+BOOL CALLBACK __export EnterTextDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+/* Show our "about" dialog */
+void ShowEnterTextDialog(HWND owner, char* _key);
+
+void SetEnterTextUiFont(HWND hWnd);
+
+#endif
diff --git a/windows/win16/src/Globals.h b/windows/win16/src/Globals.h
new file mode 100644
index 0000000..8651f8e
--- /dev/null
+++ b/windows/win16/src/Globals.h
@@ -0,0 +1,17 @@
+#ifndef GLOBALS_H
+#define GLOBALS_H
+
+#include
+
+static char* AppName = "Tinelix IRC";
+static char* BuildDate = "2022-12-04";
+static char* DevState = "Alpha";
+static char* AppVersion = "0.0.0-alpha_win16";
+
+/* Global instance handle */
+extern HINSTANCE g_hInstance;
+
+static UINT WM_SOCKMSG = 0xAFFF;
+
+
+#endif
diff --git a/windows/win16/src/IRCCLNT.C b/windows/win16/src/IRCCLNT.C
new file mode 100644
index 0000000..ff12ba6
--- /dev/null
+++ b/windows/win16/src/IRCCLNT.C
@@ -0,0 +1,82 @@
+#include
+#include
+#include "IRCClnt.h"
+#include "Globals.h"
+#include "resource.h"
+
+char nicknames[256];
+char password[20];
+char realname[256];
+char server[256];
+char port[5];
+SOCKET sock;
+
+void CreateConnectionSession(char server[256], char port[5], HWND hWnd) {
+ SOCKADDR_IN client_param;
+ HOSTENT* host;
+ int conn_status;
+ int wsa_async_result;
+ char connection_status[512];
+ int connection_status_count = 0;
+ /*GetPrivateProfileString("Main", "Nicknames", "", nicknames, 256, ini_path);
+ GetPrivateProfileString("Main", "Password", "", password, 20, ini_path);
+ GetPrivateProfileString("Main", "Realname", "", realname, 256, ini_path);*/
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if(sock == SOCKET_ERROR) {
+ char error_msg_text[512];
+ int error_code = WSAGetLastError();
+ sprintf(error_msg_text, "Could not start WinSock with error code: %d", error_code);
+ MessageBox(NULL, error_msg_text, "Error", MB_OK|MB_ICONSTOP);
+ return;
+ }
+
+ client_param.sin_family = AF_INET;
+
+ connection_status_count = sprintf(connection_status, "Connecting to %s:%s...\r\n", server, port);
+ SetWindowText(GetDlgItem(hWnd, IDC_MSGINPUT_EDIT), connection_status);
+
+ host = gethostbyname(server);
+ if(host == NULL) {
+ if(WSAGetLastError() != 0) {
+ connection_status_count += sprintf(connection_status + connection_status_count, "Failed to get the IP for this hostname.\r\nError code: %d (%s)",
+ WSAGetLastError(), strerror(WSAGetLastError()));
+ SetWindowText(GetDlgItem(hWnd, IDC_MSGINPUT_EDIT), connection_status);
+ MessageBox(NULL, "Failed to get the IP for this hostname.", "Error", MB_OK|MB_ICONSTOP);
+ return;
+ }
+ } else {
+ client_param.sin_addr.s_addr = inet_addr((char*)inet_ntoa(**(IN_ADDR**)host->h_addr_list));
+ }
+ client_param.sin_port = htons(atoi(port));
+ conn_status = connect(sock, (struct sockaddr*)&client_param, sizeof(client_param));
+ if(conn_status == SOCKET_ERROR || conn_status == INVALID_SOCKET) {
+ char error_msg_text[512];
+ int error_code = WSAGetLastError();
+ closesocket(sock);
+ if(error_code == 10060) {
+ connection_status_count += sprintf(connection_status + connection_status_count, "Connection timed out.\r\n", server, port);
+ sprintf(error_msg_text, "Connection timed out.");
+ } else {
+ connection_status_count += sprintf(connection_status + connection_status_count, "Connection failed with error code: %d (%s)\r\n", error_code, strerror(error_code));
+ sprintf(error_msg_text, "Connection failed with error code: %d (%s)", error_code, strerror(error_code));
+ }
+ SetWindowText(GetDlgItem(hWnd, IDC_MSGINPUT_EDIT), connection_status);
+ MessageBox(NULL, error_msg_text, "Error", MB_OK|MB_ICONSTOP);
+ return;
+ }
+ wsa_async_result = WSAAsyncSelect(sock, hWnd, WM_SOCKMSG, FD_READ|FD_WRITE);
+ if(wsa_async_result > 0) {
+ char error_msg_text[512];
+ int error_code = WSAGetLastError();
+ if(error_code == 10060) {
+ connection_status_count += sprintf(connection_status + connection_status_count, "Connection timed out.\r\n", server, port);
+ sprintf(error_msg_text, "Connection timed out.");
+ } else {
+ connection_status_count += sprintf(connection_status + connection_status_count, "Could not start WinSock with error code: %d (%s)\r\n",
+ error_code, strerror(error_code));
+ sprintf(error_msg_text, "Could not start WinSock with error code: %d (%s)", error_code, strerror(error_code));
+ }
+ SetWindowText(GetDlgItem(hWnd, IDC_MSGINPUT_EDIT), connection_status);
+ MessageBox(NULL, error_msg_text, "Error", MB_OK|MB_ICONSTOP);
+ }
+}
\ No newline at end of file
diff --git a/windows/win16/src/IRCCLNT.H b/windows/win16/src/IRCCLNT.H
new file mode 100644
index 0000000..1280289
--- /dev/null
+++ b/windows/win16/src/IRCCLNT.H
@@ -0,0 +1,7 @@
+#ifndef IRCCLNT_H
+#define IRCCLNT_H
+
+
+void CreateConnectionSession(char server[256], char port[5], HWND hWnd);
+
+#endif
diff --git a/windows/win16/src/MainWnd.c b/windows/win16/src/MainWnd.c
new file mode 100644
index 0000000..6d59f1a
--- /dev/null
+++ b/windows/win16/src/MainWnd.c
@@ -0,0 +1,161 @@
+#include "AboutDlg.h"
+#include "ETextDlg.h"
+#include "Globals.h"
+#include "MainWnd.h"
+#include "ConnMDlg.h"
+#include "Resource.h"
+#include "Commdlg.h"
+#include "IRCClnt.h"
+#include
+
+/* Main window class and title */
+static const char MainWndClass[] = "Main Window";
+
+BOOL file_opened;
+char ini_path[];
+char nicknames[256];
+char password[20];
+char realname[256];
+char server[256];
+char port[5];
+int recv_status;
+char sock_buffer[4096] = {0};
+
+LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if(msg == WM_COMMAND) {
+ WORD id = wParam;
+
+ switch (id)
+ {
+ case ID_ABOUT:
+ {
+ ShowAboutDialog(hWnd);
+ return 0;
+ }
+ case ID_CONNECT:
+ {
+ if(file_opened == FALSE) {
+ MessageBox(hWnd, "First you need to open the profile file.", "Tinelix IRC", MB_ICONASTERISK|MB_OK);
+ } else {
+ CreateConnectionSession(server, port, hWnd);
+ }
+ return 0;
+ }
+ case ID_NEW_PROFILE:
+ {
+ ShowEnterTextDialog(hWnd, "profile_name");
+ return 0;
+ }
+ case ID_OPEN_PROFILE:
+ {
+ OPENFILENAME ofn;
+ char fileTitle[256];
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hWnd;
+ ofn.lpstrFilter = "Profile file (*.ini; *.cfg)\0*.ini;*.cfg\0All files\0*.*\0";
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = ini_path;
+ ofn.nMaxFile = 256;
+ ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+ if(GetOpenFileName(&ofn)) {
+ file_opened = TRUE;
+ sprintf(ini_path, "%s", ofn.lpstrFile);
+ GetPrivateProfileString("Main", "Nicknames", "", nicknames, 256, ofn.lpstrFile);
+ GetPrivateProfileString("Main", "Password", "", password, 20, ofn.lpstrFile);
+ GetPrivateProfileString("Main", "Realname", "", realname, 256, ofn.lpstrFile);
+ GetPrivateProfileString("Connection", "Server", "", server, 256, ofn.lpstrFile);
+ GetPrivateProfileString("Connection", "Port", "", port, 5, ofn.lpstrFile);
+ };
+ return 0;
+ }
+ case IDOK:
+ case IDCANCEL:
+ {
+ DestroyWindow(hWnd);
+ return 0;
+ }
+ }
+ } else if(msg == WM_SYSCOMMAND) {
+ WORD id = wParam;
+
+ switch (id)
+ {
+ /* Show "about" dialog on about system menu item */
+ case ID_ABOUT:
+ {
+ ShowAboutDialog(hWnd);
+ return 0;
+ }
+ }
+ } else if(msg == WM_CREATE) {
+ HWND dummyWnd;
+ RECT rect;
+
+ dummyWnd = CreateWindowEx(0, "STATIC", "STATIC", 0, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, g_hInstance,
+ NULL);
+ GetWindowRect(dummyWnd, &rect);
+ DestroyWindow(dummyWnd);
+
+ SetWindowPos(hWnd, 0, rect.left, rect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+
+ return 0;
+ } else if(msg == WM_SOCKMSG) {
+ recv_status = recv((SOCKET)wParam, (char*)&sock_buffer, 4095, 0);
+ if(recv_status == SOCKET_ERROR) {
+ char error_msg_text[512];
+ sprintf(error_msg_text, "Socket error: %d", WSAGetLastError());
+ MessageBox(hWnd, error_msg_text, "Error", MB_OK|MB_ICONSTOP);
+ }
+ SetWindowText(hWnd, "Tinelix IRC Client | Connected");
+ if(recv_status == 0) {
+ MessageBox(hWnd, "Connection lost.", "Tinelix IRC", MB_OK|MB_ICONASTERISK);
+ closesocket((SOCKET)wParam);
+ }
+ } else if(msg == WM_DESTROY) {
+ QuitApp();
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+BOOL RegisterMainWindowClass()
+{
+
+ WNDCLASS wc;
+
+ wc.style = 0;
+ wc.lpfnWndProc = &MainWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = DLGWINDOWEXTRA;
+ wc.hInstance = g_hInstance;
+ wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_APPICON));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = MainWndClass;
+
+ return (RegisterClass(&wc)) ? TRUE : FALSE;
+}
+
+HWND CreateMainWindow()
+{
+ HWND hWnd = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_MAINDIALOG), NULL, NULL);
+
+ if (hWnd)
+ {
+ HMENU hMenu;
+ HMENU hSysMenu;
+ hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_APPMENU));
+ hSysMenu = GetSystemMenu(hWnd, FALSE);
+ InsertMenu(hSysMenu, 5, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
+ InsertMenu(hSysMenu, 6, MF_BYPOSITION, ID_ABOUT, "About...");
+ SetMenu(hWnd, hMenu);
+ SetWindowText(hWnd, AppName);
+ }
+
+ return hWnd;
+}
diff --git a/windows/win16/src/MainWnd.h b/windows/win16/src/MainWnd.h
new file mode 100644
index 0000000..d3ede22
--- /dev/null
+++ b/windows/win16/src/MainWnd.h
@@ -0,0 +1,15 @@
+#ifndef MAINWND_H
+#define MAINWND_H
+
+#include
+
+/* Window procedure for our main window */
+LRESULT CALLBACK __export MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+/* Register a class for our main window */
+BOOL RegisterMainWindowClass(void);
+
+/* Create an instance of our main window */
+HWND CreateMainWindow(void);
+
+#endif
diff --git a/windows/win16/src/PRFSTDLG.C b/windows/win16/src/PRFSTDLG.C
new file mode 100644
index 0000000..ac5217e
--- /dev/null
+++ b/windows/win16/src/PRFSTDLG.C
@@ -0,0 +1,205 @@
+#include "PrfStDlg.h"
+#include "Globals.h"
+#include "Resource.h"
+#include
+#include
+
+HWND pageViewerHwnd;
+HWND parentHwnd;
+WNDPROC prstPagesCallback;
+char ini_path[256];
+char profile_name[8];
+char current_page[32];
+
+BOOL CALLBACK ProfileSettingsDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ {
+ WORD id = wParam;
+
+ switch (id)
+ {
+ case IDOK:
+ {
+ if(!strcmp(current_page, "main")) {
+ char nicknames[256];
+ char password[20];
+ char realname[256];
+ HWND editText = GetDlgItem(pageViewerHwnd, IDC_NICKNAMES_EDIT);
+ GetWindowText(editText, nicknames, 256);
+ editText = GetDlgItem(pageViewerHwnd, IDC_PASSWORD_EDIT);
+ GetWindowText(editText, password, 20);
+ editText = GetDlgItem(pageViewerHwnd, IDC_REALNAME_EDIT);
+ GetWindowText(editText, realname, 20);
+ WritePrivateProfileString("Main", "Nicknames", nicknames, ini_path);
+ WritePrivateProfileString("Main", "Password", password, ini_path);
+ WritePrivateProfileString("Main", "Realname", realname, ini_path);
+ } else if(!strcmp(current_page, "connection")) {
+ char server[256];
+ char port[5];
+ HWND editText = GetDlgItem(pageViewerHwnd, IDC_PROFILE_SERVER_EDIT);
+ GetWindowText(editText, server, 256);
+ editText = GetDlgItem(pageViewerHwnd, IDC_PROFILE_PORT_EDIT);
+ GetWindowText(editText, port, 5);
+ WritePrivateProfileString("Main", "Server", server, ini_path);
+ WritePrivateProfileString("Main", "Port", port, ini_path);
+ }
+ }
+ case IDCANCEL:
+ {
+ EndDialog(hwndDlg, id);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ case WM_INITDIALOG:
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+LRESULT CALLBACK PrStPagesComboProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ if(uMsg == WM_COMMAND) {
+ WORD id = wParam;
+ if(id == 1000) {
+ char debug_str[40];
+ int index = SendMessage(hWnd, (UINT) CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0);
+ if(!strcmp(current_page, "main")) {
+ char nicknames[256];
+ char password[20];
+ char realname[256];
+ HWND editText = GetDlgItem(pageViewerHwnd, IDC_NICKNAMES_EDIT);
+ GetWindowText(editText, nicknames, 256);
+ editText = GetDlgItem(pageViewerHwnd, IDC_PASSWORD_EDIT);
+ GetWindowText(editText, password, 20);
+ editText = GetDlgItem(pageViewerHwnd, IDC_REALNAME_EDIT);
+ GetWindowText(editText, realname, 20);
+ WritePrivateProfileString("Main", "Nicknames", nicknames, ini_path);
+ WritePrivateProfileString("Main", "Password", password, ini_path);
+ WritePrivateProfileString("Main", "Realname", realname, ini_path);
+ } else if(!strcmp(current_page, "connection")) {
+ char server[256];
+ char port[5];
+ HWND editText = GetDlgItem(pageViewerHwnd, IDC_PROFILE_SERVER_EDIT);
+ GetWindowText(editText, server, 256);
+ editText = GetDlgItem(pageViewerHwnd, IDC_PROFILE_PORT_EDIT);
+ GetWindowText(editText, port, 5);
+ WritePrivateProfileString("Main", "Server", server, ini_path);
+ WritePrivateProfileString("Main", "Port", port, ini_path);
+ }
+ EndDialog(pageViewerHwnd, 0);
+ if(index == 0) {
+ pageViewerHwnd = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_PCONN_STGSPAGE), parentHwnd, NULL);
+ ShowWindow(pageViewerHwnd, SW_SHOWNORMAL);
+ SetProfileSettingsUiFont(hWnd, pageViewerHwnd, "connection");
+ } else {
+ pageViewerHwnd = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_PMAIN_STGSPAGE), parentHwnd, NULL);
+ ShowWindow(pageViewerHwnd, SW_SHOWNORMAL);
+ SetProfileSettingsUiFont(hWnd, pageViewerHwnd, "main");
+ }
+ }
+ }
+ return CallWindowProc(prstPagesCallback, hWnd, uMsg, wParam, lParam);
+}
+
+void ShowProfileSettingsDialog(HWND owner, char _profile_name[])
+{
+ int ini_path_length = 0;
+ sprintf(profile_name, _profile_name);
+ GetModuleFileName(g_hInstance, ini_path, 256);
+ *(strrchr(ini_path, '\\')+1) = '\0';
+ strcat(ini_path, profile_name);
+ strcat(ini_path, ".ini");
+ if(_access(ini_path, 0) != 0) {
+ WritePrivateProfileString("Main", "Nicknames", "", ini_path);
+ WritePrivateProfileString("Main", "Password", "", ini_path);
+ WritePrivateProfileString("Main", "Realname", "", ini_path);
+ WritePrivateProfileString("Connection", "Server", "", ini_path);
+ WritePrivateProfileString("Connection", "Port", "6667", ini_path);
+ }
+ if((LOBYTE(LOWORD(GetVersion())) == 3 && HIBYTE(LOWORD(GetVersion())) >= 10)
+ || LOBYTE(LOWORD(GetVersion())) > 3) {
+ HWND hWnd = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_PROFILESETTINGSDIALOG), owner, ProfileSettingsDialogProc);
+ parentHwnd = hWnd;
+
+ if(hWnd) {
+ pageViewerHwnd = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_PMAIN_STGSPAGE), hWnd, NULL);
+ ShowWindow(hWnd, SW_SHOW);
+ ShowWindow(pageViewerHwnd, SW_SHOWNORMAL);
+ SetProfileSettingsUiFont(hWnd, pageViewerHwnd, "main");
+ prstPagesCallback = (WNDPROC) SetWindowLong((HWND)GetDlgItem(hWnd, IDC_PAGESCOMBO), GWL_WNDPROC, (long)&PrStPagesComboProc);
+ UpdateWindow(pageViewerHwnd);
+ } else {
+ MessageBox(hWnd, "Something wen\'t wrong", "Error", MB_ICONSTOP|MB_OK);
+ }
+ } else {
+ char msg_text[512];
+ sprintf(msg_text, "Profile created at: %s. Use a text editor.", ini_path);
+ MessageBox(NULL, msg_text, "Tinelix IRC", MB_ICONASTERISK|MB_OK);
+ }
+}
+
+void SetProfileSettingsUiFont(HWND hwndParent, HWND hWnd, char* page_name) {
+ HFONT defaultFont;
+ LOGFONT fontAttrib;
+ char Pages[2][20] = {
+ "Main", "Connection"
+ };
+ int i = 0;
+ sprintf(current_page, page_name);
+ defaultFont = (HFONT)CreateFont(13, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET,
+ OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
+ "Helv");
+ SendDlgItemMessage(hwndParent, IDOK, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hwndParent, IDCANCEL, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hwndParent, IDC_PAGESCOMBO, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ for(i = 0; i < 2; i++) {
+ SendMessage((HWND)GetDlgItem(hwndParent, IDC_PAGESCOMBO), CB_ADDSTRING, (WPARAM) 0, (LPARAM) Pages[i]);
+ }
+ SendMessage((HWND)GetDlgItem(hwndParent, IDC_PAGESCOMBO), CB_SETCURSEL, (WPARAM) 1, (LPARAM) 0);
+ if(!strcmp(page_name, "main")) {
+ char nicknames[256];
+ char password[20];
+ char realname[256];
+ HWND editText;
+ SendDlgItemMessage(hWnd, IDC_PROFILE_NAME_LABEL, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_PROFILE_NAME_EDIT, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_NICKNAMES_LABEL, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_NICKNAMES_EDIT, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_PASSWORD_LABEL, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_PASSWORD_EDIT, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_REALNAME_LABEL, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_REALNAME_EDIT, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ GetPrivateProfileString("Main", "Nicknames", "", nicknames, 256, ini_path);
+ GetPrivateProfileString("Main", "Password", "", password, 20, ini_path);
+ GetPrivateProfileString("Main", "Realname", "", realname, 256, ini_path);
+ editText = GetDlgItem(hWnd, IDC_PROFILE_NAME_EDIT);
+ SetWindowText(editText, profile_name);
+ editText = GetDlgItem(hWnd, IDC_NICKNAMES_EDIT);
+ SetWindowText(editText, nicknames);
+ editText = GetDlgItem(hWnd, IDC_PASSWORD_EDIT);
+ SetWindowText(editText, password);
+ editText = GetDlgItem(hWnd, IDC_REALNAME_EDIT);
+ SetWindowText(editText, realname);
+ } else if(!strcmp(page_name, "connection")) {
+ char server[256];
+ char port[5];
+ HWND editText;
+ SendDlgItemMessage(hWnd, IDC_PROFILE_SERVER_LABEL, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_PROFILE_SERVER_EDIT, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_PROFILE_PORT_LABEL, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ SendDlgItemMessage(hWnd, IDC_PROFILE_PORT_EDIT, WM_SETFONT, (WPARAM)defaultFont, TRUE);
+ GetPrivateProfileString("Connection", "Server", "", server, 256, ini_path);
+ GetPrivateProfileString("Connection", "Port", "", port, 5, ini_path);
+ editText = GetDlgItem(hWnd, IDC_PROFILE_SERVER_EDIT);
+ SetWindowText(editText, server);
+ editText = GetDlgItem(hWnd, IDC_PROFILE_PORT_EDIT);
+ SetWindowText(editText, port);
+ }
+}
diff --git a/windows/win16/src/PRFSTDLG.H b/windows/win16/src/PRFSTDLG.H
new file mode 100644
index 0000000..cb57a75
--- /dev/null
+++ b/windows/win16/src/PRFSTDLG.H
@@ -0,0 +1,17 @@
+#ifndef PRFSTDLG_H
+#define PRFSTDLG_H
+
+#include
+
+
+/* Dialog procedure for our "about" dialog */
+BOOL CALLBACK __export ProfileSettingsDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+long CALLBACK PagesComboProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+/* Show our "about" dialog */
+void ShowProfileSettingsDialog(HWND owner, char _profile_name[]);
+
+void SetProfileSettingsUiFont(HWND hwndParent, HWND hWnd, char* page_name);
+
+#endif
diff --git a/windows/win16/src/RESOURCE.H b/windows/win16/src/RESOURCE.H
new file mode 100644
index 0000000..4b5c05d
--- /dev/null
+++ b/windows/win16/src/RESOURCE.H
@@ -0,0 +1,70 @@
+//{{NO_DEPENDENCIES}}
+// App Studio generated include file.
+// Used by RESOURCE.RC
+//
+#define IDI_APPICON 100
+#define IDR_ACCELERATOR 101
+#define IDD_MAINDIALOG 102
+#define IDD_ABOUTDIALOG 103
+#define IDR_APPMENU 104
+#define IDD_CONNMANDIALOG 105
+#define IDD_ENTERTEXTDIALOG 106
+#define IDD_PROFILESTGSDIALOG 107
+#define IDD_PROFILESETTINGSDIALOG 107
+#define IDD_PMAIN_STGSPAGE 108
+#define IDD_PCONN_STGSPAGE 109
+#define ID_HELP_ABOUT 200
+#define ID_CONNECT 201
+#define ID_QUIT 202
+#define ID_ABOUT 204
+#define ID_NEW_PROFILE 205
+#define ID_OPEN_PROFILE 207
+#define ID_EDIT_PROFILE 208
+#define ID_DELETE_PROFILE 209
+#define IDC_MSGINPUT 1002
+#define IDC_MSGINPUT_EDIT 1002
+#define IDC_EDIT2 1003
+#define IDC_MSG_EDIT 1003
+#define IDC_SENDBTN 1004
+#define IDC_SENDMSG_BTN 1004
+#define IDC_CORYRIGHT 1005
+#define IDC_PROFILELIST 1007
+#define IDC_CREATE_PROFILE_BTN 1008
+#define IDC_CONNECT_BTN 1009
+#define IDC_EDIT_PROFILE_BTN 1010
+#define IDC_ENTERTEXTLABEL 1010
+#define IDC_DELETE_PROFILE_BTN 1011
+#define IDC_ENTERTEXTBOX 1011
+#define IDC_PROFILES_GROUP 1012
+#define IDC_APPNAME 1013
+#define IDC_GITHUB_LINK 1014
+#define IDC_COMBO1 1015
+#define IDC_PAGESCOMBO 1015
+#define IDC_PAGE_LABEL 1016
+#define IDC_PROFILE_NAME_LABEL 1018
+#define IDC_PROFILE_NAME_EDIT 1019
+#define IDC_NICKNAME_LABEL 1020
+#define IDC_PROFILE_SERVER_LABEL 1020
+#define IDC_NICKNAMES_LABEL 1020
+#define IDC_NICKNAME_EDIT 1021
+#define IDC_PROFILE_SERVER_EDIT 1021
+#define IDC_NICKNAMES_EDIT 1021
+#define IDC_PASSWORD_LABEL 1022
+#define IDC_PROFILE_PORT_LABEL 1022
+#define IDC_PASSWORD_EDIT 1023
+#define IDC_PROFILE_PORT_EDIT 1023
+#define IDC_REALNAME_LABEL 1024
+#define IDC_REALNAME_EDIT 1025
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NEXT_RESOURCE_VALUE 110
+#define _APS_NEXT_COMMAND_VALUE 210
+#define _APS_NEXT_CONTROL_VALUE 1022
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/windows/win16/src/RESOURCE.RC b/windows/win16/src/RESOURCE.RC
new file mode 100644
index 0000000..517619d
--- /dev/null
+++ b/windows/win16/src/RESOURCE.RC
@@ -0,0 +1,189 @@
+//Microsoft App Studio generated resource script.
+//
+#include "Resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTDIALOG DIALOG DISCARDABLE 0, 0, 201, 88
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About"
+FONT 8, "Helv"
+BEGIN
+ ICON 100,IDC_STATIC,7,7,18,20
+ LTEXT "Tinelix IRC Client (Win16)",IDC_APPNAME,34,7,131,8
+ CONTROL "\251 2022 Dmitry Tretyakov (aka. Tinelix)",
+ IDC_CORYRIGHT,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,34,
+ 17,135,8
+ DEFPUSHBUTTON "OK",IDOK,153,69,42,14,WS_GROUP
+ LTEXT "https://github.com/tinelix/irc-client-win16",
+ IDC_GITHUB_LINK,5,73,142,10
+END
+
+IDD_MAINDIALOG DIALOG DISCARDABLE 0, 0, 274, 167
+STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU |
+ WS_THICKFRAME
+CAPTION "Tinelix IRC for Win16"
+CLASS "Main Window"
+FONT 8, "Helv"
+BEGIN
+ EDITTEXT IDC_MSGINPUT_EDIT,1,1,272,136,ES_MULTILINE |
+ ES_AUTOHSCROLL | ES_READONLY
+ EDITTEXT IDC_MSG_EDIT,1,139,227,15,ES_AUTOHSCROLL | WS_DISABLED
+ PUSHBUTTON "Send",IDC_SENDMSG_BTN,230,139,43,15,WS_DISABLED
+END
+
+IDD_CONNMANDIALOG DIALOG DISCARDABLE 0, 0, 211, 162
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Connection Manager"
+FONT 8, "Helv"
+BEGIN
+ PUSHBUTTON "OK",IDOK,166,143,40,14
+ LISTBOX IDC_PROFILELIST,10,16,191,98,LBS_SORT |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Create",IDC_CREATE_PROFILE_BTN,10,116,47,15
+ PUSHBUTTON "Connect",IDC_CONNECT_BTN,58,116,47,15
+ PUSHBUTTON "Edit",IDC_EDIT_PROFILE_BTN,106,116,47,15
+ PUSHBUTTON "Delete",IDC_DELETE_PROFILE_BTN,154,116,47,15
+ GROUPBOX "Profiles",IDC_PROFILES_GROUP,5,2,201,134
+END
+
+IDD_ENTERTEXTDIALOG DIALOG DISCARDABLE 0, 0, 185, 55
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Enter text"
+FONT 8, "Helv"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,92,36,44,14
+ PUSHBUTTON "Cancel",IDCANCEL,137,36,44,14
+ LTEXT "Text:",IDC_ENTERTEXTLABEL,4,5,177,9
+ EDITTEXT IDC_ENTERTEXTBOX,4,17,177,12,ES_AUTOHSCROLL
+END
+
+IDD_PROFILESETTINGSDIALOG DIALOG DISCARDABLE 0, 0, 185, 167
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Profile Settings"
+FONT 8, "Helv"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,99,148,40,14
+ PUSHBUTTON "Cancel",IDCANCEL,140,148,40,14
+ COMBOBOX IDC_PAGESCOMBO,123,4,57,63,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ RTEXT "PAGE",IDC_PAGE_LABEL,80,7,39,9
+END
+
+IDD_PMAIN_STGSPAGE DIALOG DISCARDABLE 5, 20, 174, 124
+STYLE WS_CHILD | WS_BORDER
+FONT 8, "Helv"
+BEGIN
+ LTEXT "Profile name:",IDC_PROFILE_NAME_LABEL,3,4,50,9
+ EDITTEXT IDC_PROFILE_NAME_EDIT,53,3,117,12,ES_AUTOHSCROLL
+ LTEXT "Nicknames:",IDC_NICKNAMES_LABEL,3,19,50,9
+ EDITTEXT IDC_NICKNAMES_EDIT,53,17,117,12,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_PASSWORD_LABEL,3,34,50,9
+ EDITTEXT IDC_PASSWORD_EDIT,53,32,117,12,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ LTEXT "Realname:",IDC_REALNAME_LABEL,3,48,50,9
+ EDITTEXT IDC_REALNAME_EDIT,53,46,117,12,ES_AUTOHSCROLL
+END
+
+IDD_PCONN_STGSPAGE DIALOG DISCARDABLE 5, 20, 174, 124
+STYLE WS_CHILD | WS_VISIBLE | WS_BORDER
+FONT 8, "Helv"
+BEGIN
+ RTEXT "Server:",IDC_PROFILE_SERVER_LABEL,4,7,30,9
+ EDITTEXT IDC_PROFILE_SERVER_EDIT,37,5,75,12,ES_AUTOHSCROLL
+ RTEXT "Port:",IDC_PROFILE_PORT_LABEL,118,7,23,9
+ EDITTEXT IDC_PROFILE_PORT_EDIT,143,5,26,12,ES_AUTOHSCROLL
+END
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCELERATOR ACCELERATORS DISCARDABLE
+BEGIN
+ "a", ID_ABOUT, ASCII, ALT, NOINVERT
+END
+
+#ifdef APSTUDIO_INVOKED
+//////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "Resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""tlx_irc.ver""\0"
+END
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // APSTUDIO_INVOKED
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_APPMENU MENU DISCARDABLE
+BEGIN
+ POPUP "Client"
+ BEGIN
+ MENUITEM "&Connect", ID_CONNECT
+ MENUITEM SEPARATOR
+ MENUITEM "&Quit...", ID_QUIT
+ END
+ POPUP "Profile"
+ BEGIN
+ MENUITEM "New...", ID_NEW_PROFILE
+ MENUITEM "Open...", ID_OPEN_PROFILE
+ MENUITEM SEPARATOR
+ MENUITEM "Edit", ID_EDIT_PROFILE, GRAYED
+ MENUITEM "Delete", ID_DELETE_PROFILE, GRAYED
+ END
+ POPUP "Help"
+ BEGIN
+ MENUITEM "&About...", ID_ABOUT
+ END
+END
+
+
+#ifndef APSTUDIO_INVOKED
+////////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "tlx_irc.ver"
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/windows/win16/src/tlx_irc.def b/windows/win16/src/tlx_irc.def
new file mode 100644
index 0000000..3b288fe
--- /dev/null
+++ b/windows/win16/src/tlx_irc.def
@@ -0,0 +1,9 @@
+NAME WIN16DLG
+DESCRIPTION 'Win16 Dialog Application'
+EXETYPE WINDOWS 3.00
+REALMODE
+STUB 'WINSTUB.EXE'
+CODE MOVEABLE PRELOAD DISCARDABLE
+DATA MOVEABLE PRELOAD MULTIPLE
+HEAPSIZE 1024
+STACKSIZE 4096
diff --git a/windows/win16/src/tlx_irc.ver b/windows/win16/src/tlx_irc.ver
new file mode 100644
index 0000000..f327ee8
--- /dev/null
+++ b/windows/win16/src/tlx_irc.ver
@@ -0,0 +1,35 @@
+#include
+
+/* Executable version information */
+VS_VERSION_INFO VERSIONINFO DISCARDABLE
+FILEVERSION 0,0,0,0
+PRODUCTVERSION 0,0,0,0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG | VS_FF_PRERELEASE
+#else
+ FILEFLAGS 0
+#endif
+FILEOS VOS_DOS_WINDOWS16
+FILETYPE VFT_APP
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904E4"
+ BEGIN
+ VALUE "CompanyName", "Tinelix\0"
+ VALUE "FileDescription", "Tinelix IRC for Win16\0"
+ VALUE "FileVersion", "0.0.0\0"
+ VALUE "InternalName", "Tinelix IRC\0"
+ VALUE "LegalCopyright", "\2512022 Dmitry Tretyakov (aka. Tinelix)\0"
+ VALUE "OriginalFilename", "tlx_irc.exe\0"
+ VALUE "ProductName", "2022 Dmitry Tretyakov (aka. Tinelix)\0"
+ VALUE "ProductVersion", "0.0.0\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x809, 1252
+ END
+END
diff --git a/windows/win32s/LICENSE.TXT b/windows/win32s/LICENSE.TXT
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/windows/win32s/LICENSE.TXT
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/windows/win32s/README.md b/windows/win32s/README.md
new file mode 100644
index 0000000..dda440f
--- /dev/null
+++ b/windows/win32s/README.md
@@ -0,0 +1,11 @@
+# Tinelix IRC Client for Win32
+Tinelix IRC client written on Microsoft Visual C++ 4.0 and designed for Windows 3.1x with Win32s.
+
+**IMPORTANT!** Until May 1, 2024 all files from this repository will be moved to https://github.com/tinelix/irc-client-legacy.
+
+See https://github.com/tinelix/irc-client/issues/14#issue-2225137465.
+
+### Status
+Alpha / Under construction
+### License
+GPLv3 (or later version)
diff --git a/windows/win32s/StdAfx.cpp b/windows/win32s/StdAfx.cpp
new file mode 100644
index 0000000..47d2e0d
--- /dev/null
+++ b/windows/win32s/StdAfx.cpp
@@ -0,0 +1,6 @@
+// stdafx.cpp : source file that includes just the standard includes
+// Tinelix IRC.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
diff --git a/windows/win32s/StdAfx.h b/windows/win32s/StdAfx.h
new file mode 100644
index 0000000..49a2dde
--- /dev/null
+++ b/windows/win32s/StdAfx.h
@@ -0,0 +1,16 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include // MFC core and standard components
+#include // MFC extensions
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include // MFC support for Windows 95 Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+
+
+
diff --git a/windows/win32s/Tinelix IRC.aps b/windows/win32s/Tinelix IRC.aps
new file mode 100644
index 0000000..522c6a7
Binary files /dev/null and b/windows/win32s/Tinelix IRC.aps differ
diff --git a/windows/win32s/Tinelix IRC.clw b/windows/win32s/Tinelix IRC.clw
new file mode 100644
index 0000000..0881c16
--- /dev/null
+++ b/windows/win32s/Tinelix IRC.clw
@@ -0,0 +1,208 @@
+; CLW file contains information for the MFC ClassWizard
+
+[General Info]
+Version=1
+LastClass=CAboutDlg
+LastTemplate=CDialog
+NewFileInclude1=#include "stdafx.h"
+NewFileInclude2=#include "Tinelix IRC.h"
+
+ClassCount=8
+Class1=CIRCApplication
+Class2=CMainDlg
+
+ResourceCount=11
+Resource1=IDD_TABTHREAD
+Resource2=IDR_MAINFRAME
+Resource3=IDD_TINELIXIRC_DIALOG
+Resource4=IDD_TEXTDIALOG
+Resource5=IDR_MAINMENU (English (U.S.))
+Resource6=IDD_TABCHAT
+Class3=CAboutDlg
+Class4=CAppThreadTab
+Resource7=IDD_MAINDIALOG
+Resource8=IDD_CONNMANDIALOG
+Class5=CConnManDlg
+Resource9=IDD_STATSDIALOG
+Class6=CProgressDlg
+Resource10=IDD_CONNECTION_PROGRESS
+Class7=CStatisticsDlg
+Class8=CTextBoxDlg
+Resource11=IDD_ABOUTBOX
+
+[CLS:CIRCApplication]
+Type=0
+HeaderFile=Tinelix IRC.h
+ImplementationFile=Tinelix IRC.cpp
+Filter=N
+LastObject=CIRCApplication
+
+[CLS:CMainDlg]
+Type=0
+HeaderFile=dialogs\maindlg.h
+ImplementationFile=dialogs\maindlg.cpp
+BaseClass=CDialog
+Filter=D
+VirtualFilter=dWC
+LastObject=CMainDlg
+
+[DLG:IDD_TINELIXIRC_DIALOG]
+Type=1
+ControlCount=3
+Control1=IDOK,button,1342242817
+Control2=IDCANCEL,button,1342242816
+Control3=IDC_STATIC,static,1342308352
+Class=CMainDlg
+
+[MNU:IDR_MAINMENU (English (U.S.))]
+Type=1
+Class=CMainDlg
+Command1=ID_FILE_CONNECT
+Command2=ID_FILE_QUIT
+Command3=ID_CONNECTION_STATISTICS
+Command4=ID_CHANNEL_JOIN
+Command5=ID_CHANNEL_LEAVE
+Command6=ID_ABOUT
+CommandCount=6
+
+[CLS:CAboutDlg]
+Type=0
+HeaderFile=dialogs\aboutdlg.h
+ImplementationFile=dialogs\aboutdlg.cpp
+BaseClass=CDialog
+Filter=D
+VirtualFilter=dWC
+LastObject=CAboutDlg
+
+[DLG:IDD_ABOUTBOX]
+Type=1
+Class=CAboutDlg
+ControlCount=8
+Control1=IDC_STATIC,static,1342177283
+Control2=IDC_STATIC,static,1342308480
+Control3=IDC_STATIC,static,1342308352
+Control4=IDOK,button,1342373889
+Control5=IDC_LICENSE,static,1342308352
+Control6=IDC_LICENSE2,static,1342308352
+Control7=IDC_SRC_CODE_ADDR,edit,1350633600
+Control8=IDC_SRC_CODE,static,1342308352
+
+[DLG:IDD_TABCHAT]
+Type=1
+ControlCount=4
+Control1=IDC_CHAT_INPUT,edit,1352730692
+Control2=IDC_CHAT_OUTPUT,edit,1350631424
+Control3=IDC_CHAT_SEND_MSG,button,1342242816
+Control4=IDC_CHAT_MEMBERS,listbox,1352728835
+
+[DLG:IDD_TABTHREAD]
+Type=1
+Class=CAppThreadTab
+ControlCount=3
+Control1=IDC_CHAT_INPUT,edit,1352730692
+Control2=IDC_CHAT_OUTPUT,edit,1484849152
+Control3=IDC_CHAT_SEND_MSG,button,1476460544
+
+[DLG:IDD_MAINDIALOG]
+Type=1
+Class=CMainDlg
+ControlCount=1
+Control1=IDC_MAINDLG_TABS,SysTabControl32,1342177280
+
+[CLS:CAppThreadTab]
+Type=0
+HeaderFile=tabs\appthreadtab.h
+ImplementationFile=tabs\appthreadtab.cpp
+BaseClass=CDialog
+Filter=D
+LastObject=IDCANCEL
+VirtualFilter=dWC
+
+[DLG:IDD_CONNMANDIALOG]
+Type=1
+Class=CConnManDlg
+ControlCount=7
+Control1=IDOK,button,1342242817
+Control2=IDCANCEL,button,1342242816
+Control3=IDC_CREATE_PROFILE,button,1342242816
+Control4=IDC_REMOVE_PROFILE,button,1342242816
+Control5=IDC_EDIT_PROFILE,button,1342242816
+Control6=IDC_PROFILES_GROUP,button,1342177287
+Control7=IDC_PROFILE_LIST,listbox,1352728835
+
+[DLG:IDD_TEXTDIALOG]
+Type=1
+Class=CTextBoxDlg
+ControlCount=4
+Control1=IDOK,button,1342242817
+Control2=IDCANCEL,button,1342242816
+Control3=IDC_EDITTEXT,static,1342308352
+Control4=IDC_EDITTEXTAREA,edit,1350631552
+
+[CLS:CConnManDlg]
+Type=0
+HeaderFile=dialogs\ConnManDlg.h
+ImplementationFile=dialogs\ConnManDlg.cpp
+BaseClass=CDialog
+Filter=D
+LastObject=IDC_PROFILE_LIST
+VirtualFilter=dWC
+
+[DLG:IDD_CONNECTION_PROGRESS]
+Type=1
+Class=CProgressDlg
+ControlCount=2
+Control1=IDC_PROGRESS,msctls_progress32,1350565888
+Control2=IDC_STATUS,static,1342308352
+
+[CLS:CProgressDlg]
+Type=0
+HeaderFile=dialogs\ProgressDlg.h
+ImplementationFile=dialogs\ProgressDlg.cpp
+BaseClass=CDialog
+Filter=D
+LastObject=CProgressDlg
+VirtualFilter=dWC
+
+[DLG:IDD_STATSDIALOG]
+Type=1
+Class=CStatisticsDlg
+ControlCount=19
+Control1=IDOK,button,1342242817
+Control2=IDC_PACKETS_GROUP,button,1342177287
+Control3=IDC_PACKETS_SENT_LABEL,static,1342308352
+Control4=IDC_PACKETS_SENT_VALUE,static,1342308354
+Control5=IDC_PACKETS_READ_LABEL,static,1342308352
+Control6=IDC_PACKETS_READ_VALUE,static,1342308354
+Control7=IDC_BYTES_SENT_LABEL,static,1342308352
+Control8=IDC_BYTES_SENT_VALUE,static,1342308354
+Control9=IDC_READ_BYTES_LABEL,static,1342308352
+Control10=IDC_BYTES_READ_VALUE,static,1342308354
+Control11=IDC_TOTAL_BYTES_LABEL2,static,1342308352
+Control12=IDC_TOTAL_BYTES_VALUE,static,1342308354
+Control13=IDC_DATA_GROUP,button,1342177287
+Control14=IDC_TOTAL_PACKETS_LABEL,static,1342308352
+Control15=IDC_TOTAL_PACKETS_VALUE,static,1342308354
+Control16=IDC_CONNECTION_GROUP,button,1342177287
+Control17=IDC_CONNQUALITY_LABEL,static,1342308352
+Control18=IDC_PING_STRENGTH,msctls_progress32,1350565888
+Control19=IDC_CONNQUALITY_VALUE,static,1342308354
+
+[CLS:CStatisticsDlg]
+Type=0
+HeaderFile=dialogs\StatisticsDlg.h
+ImplementationFile=dialogs\StatisticsDlg.cpp
+BaseClass=CDialog
+Filter=D
+LastObject=CStatisticsDlg
+VirtualFilter=dWC
+
+[CLS:CTextBoxDlg]
+Type=0
+HeaderFile=dialogs\TextBoxDlg.h
+ImplementationFile=dialogs\TextBoxDlg.cpp
+BaseClass=CDialog
+Filter=D
+VirtualFilter=dWC
+LastObject=CTextBoxDlg
+
diff --git a/windows/win32s/Tinelix IRC.cpp b/windows/win32s/Tinelix IRC.cpp
new file mode 100644
index 0000000..689d45c
--- /dev/null
+++ b/windows/win32s/Tinelix IRC.cpp
@@ -0,0 +1,129 @@
+// Tinelix IRC.cpp : Defines the class behaviors for the application.
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+#include "stdafx.h"
+#include "afxdisp.h"
+#include "Tinelix IRC.h"
+#include "dialogs\MainDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CIRCApplication
+
+BEGIN_MESSAGE_MAP(CIRCApplication, CWinApp)
+ //{{AFX_MSG_MAP(CIRCApplication)
+ // NOTE - the ClassWizard will add and remove mapping macros here.
+ // DO NOT EDIT what you see in these blocks of generated code!
+ //}}AFX_MSG
+ ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CIRCApplication construction
+
+CIRCApplication::CIRCApplication()
+{
+ // TODO: add construction code here,
+ // Place all significant initialization in InitInstance
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CIRCApplication object
+
+CIRCApplication theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CIRCApplication initialization
+
+BOOL CIRCApplication::InitInstance()
+{
+ // Standard initialization
+ // If you are not using these features and wish to reduce the size
+ // of your final executable, you should remove from the following
+ // the specific initialization routines you do not need.
+
+#ifdef _AFXDLL
+ Enable3dControls(); // Call this when using MFC in a shared DLL
+#else
+ Enable3dControlsStatic(); // Call this when linking to MFC statically
+#endif
+
+ int nResponse = 0;
+ CMainDlg dlg;
+ m_pMainWnd = &dlg;
+ nResponse = dlg.DoModal();
+
+ if (nResponse == IDOK)
+ {
+ // TODO: Place code here to handle when the dialog is
+ // dismissed with OK
+ }
+ else if (nResponse == IDCANCEL)
+ {
+ // TODO: Place code here to handle when the dialog is
+ // dismissed with Cancel
+ }
+
+ // Since the dialog has been closed, return FALSE so that we exit the
+ // application, rather than start the application's message pump.
+ return FALSE;
+}
+
+BOOL CIRCApplication::CheckIsWin32s() {
+ BOOL is_win32s = FALSE;
+
+ if(GetVersion() & 0x80000000 && (GetVersion() & 0xFF) == 3) {
+ is_win32s = TRUE;
+ } else {
+ is_win32s = FALSE;
+ }
+
+ return is_win32s;
+}
+
+char* CIRCApplication::GetAppPath() {
+ char exe_path[MAX_PATH];
+ GetModuleFileName(NULL, exe_path, MAX_PATH);
+ char* token;
+ char path_array[64][256];
+ int path_count = 0;
+ int path_index;
+ token = strtok(exe_path, "\\");
+ char app_path[480];
+
+ while(token != NULL) {
+ sprintf(path_array[path_count], token);
+ path_count++;
+ token = strtok(NULL, "\\");
+ }
+
+ for(int i = 0; i < path_count - 1; i++) {
+ if(i == 0) {
+ path_index = sprintf(app_path, path_array[i]);
+ } else {
+ path_index += sprintf(app_path + path_index, "\\%s", path_array[i]);
+ }
+ }
+ return app_path;
+}
diff --git a/windows/win32s/Tinelix IRC.h b/windows/win32s/Tinelix IRC.h
new file mode 100644
index 0000000..66ee78b
--- /dev/null
+++ b/windows/win32s/Tinelix IRC.h
@@ -0,0 +1,55 @@
+// Tinelix IRC.h : main header file for the Tinelix IRC application
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // main symbols
+
+/////////////////////////////////////////////////////////////////////////////
+// CIRCApplication:
+// See Tinelix IRC.cpp for the implementation of this class
+//
+
+class CIRCApplication : public CWinApp
+{
+public:
+ CIRCApplication();
+ BOOL CheckIsWin32s();
+ char* GetAppPath();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CIRCApplication)
+ public:
+ virtual BOOL InitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+
+ //{{AFX_MSG(CIRCApplication)
+ // NOTE - the ClassWizard will add and remove member functions here.
+ // DO NOT EDIT what you see in these blocks of generated code !
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/windows/win32s/Tinelix IRC.mak b/windows/win32s/Tinelix IRC.mak
new file mode 100644
index 0000000..fccdf6a
--- /dev/null
+++ b/windows/win32s/Tinelix IRC.mak
@@ -0,0 +1,434 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+!IF "$(CFG)" == ""
+CFG=Tinelix IRC - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to Tinelix IRC - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "Tinelix IRC - Win32 Release" && "$(CFG)" !=\
+ "Tinelix IRC - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Tinelix IRC.mak" CFG="Tinelix IRC - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Tinelix IRC - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "Tinelix IRC - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "Tinelix IRC - Win32 Debug"
+CPP=cl.exe
+RSC=rc.exe
+MTL=mktyplib.exe
+
+!IF "$(CFG)" == "Tinelix IRC - Win32 Release"
+
+# PROP BASE Use_MFC 5
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 5
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(OUTDIR)\tlx_irc.exe"
+
+CLEAN :
+ -@erase ".\Release\tlx_irc.exe"
+ -@erase ".\Release\ConnManDlg.obj"
+ -@erase ".\Release\Tinelix IRC.pch"
+ -@erase ".\Release\Tinelix IRC.obj"
+ -@erase ".\Release\TextBoxDlg.obj"
+ -@erase ".\Release\ProgressDlg.obj"
+ -@erase ".\Release\AboutDlg.obj"
+ -@erase ".\Release\AppThreadTab.obj"
+ -@erase ".\Release\StatisticsDlg.obj"
+ -@erase ".\Release\StdAfx.obj"
+ -@erase ".\Release\MainDlg.obj"
+ -@erase ".\Release\Tinelix IRC.res"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /c
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D\
+ "_MBCS" /Fp"$(INTDIR)/Tinelix IRC.pch" /Yu"stdafx.h" /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\Release/
+CPP_SBRS=
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+RSC_PROJ=/l 0x419 /fo"$(INTDIR)/Tinelix IRC.res" /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/Tinelix IRC.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
+# ADD LINK32 /nologo /subsystem:windows /machine:I386 /out:"Release/tlx_irc.exe"
+# SUBTRACT LINK32 /pdb:none
+LINK32_FLAGS=/nologo /subsystem:windows /incremental:no\
+ /pdb:"$(OUTDIR)/tlx_irc.pdb" /machine:I386 /out:"$(OUTDIR)/tlx_irc.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/ConnManDlg.obj" \
+ "$(INTDIR)/Tinelix IRC.obj" \
+ "$(INTDIR)/TextBoxDlg.obj" \
+ "$(INTDIR)/ProgressDlg.obj" \
+ "$(INTDIR)/AboutDlg.obj" \
+ "$(INTDIR)/AppThreadTab.obj" \
+ "$(INTDIR)/StatisticsDlg.obj" \
+ "$(INTDIR)/StdAfx.obj" \
+ "$(INTDIR)/MainDlg.obj" \
+ "$(INTDIR)/Tinelix IRC.res"
+
+"$(OUTDIR)\tlx_irc.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "Tinelix IRC - Win32 Debug"
+
+# PROP BASE Use_MFC 5
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 5
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(OUTDIR)\tlx_irc.exe"
+
+CLEAN :
+ -@erase ".\Debug\vc40.pdb"
+ -@erase ".\Debug\Tinelix IRC.pch"
+ -@erase ".\Debug\vc40.idb"
+ -@erase ".\Debug\tlx_irc.exe"
+ -@erase ".\Debug\Tinelix IRC.obj"
+ -@erase ".\Debug\TextBoxDlg.obj"
+ -@erase ".\Debug\AboutDlg.obj"
+ -@erase ".\Debug\AppThreadTab.obj"
+ -@erase ".\Debug\ProgressDlg.obj"
+ -@erase ".\Debug\ConnManDlg.obj"
+ -@erase ".\Debug\MainDlg.obj"
+ -@erase ".\Debug\StatisticsDlg.obj"
+ -@erase ".\Debug\StdAfx.obj"
+ -@erase ".\Debug\Tinelix IRC.res"
+ -@erase ".\Debug\tlx_irc.ilk"
+ -@erase ".\Debug\tlx_irc.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /c
+CPP_PROJ=/nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\
+ /D "_MBCS" /Fp"$(INTDIR)/Tinelix IRC.pch" /Yu"stdafx.h" /Fo"$(INTDIR)/"\
+ /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+RSC_PROJ=/l 0x419 /fo"$(INTDIR)/Tinelix IRC.res" /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/Tinelix IRC.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386
+# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /out:"Debug/tlx_irc.exe"
+# SUBTRACT LINK32 /pdb:none
+LINK32_FLAGS=/nologo /subsystem:windows /incremental:yes\
+ /pdb:"$(OUTDIR)/tlx_irc.pdb" /debug /machine:I386 /out:"$(OUTDIR)/tlx_irc.exe"
+LINK32_OBJS= \
+ "$(INTDIR)/Tinelix IRC.obj" \
+ "$(INTDIR)/TextBoxDlg.obj" \
+ "$(INTDIR)/AboutDlg.obj" \
+ "$(INTDIR)/AppThreadTab.obj" \
+ "$(INTDIR)/ProgressDlg.obj" \
+ "$(INTDIR)/ConnManDlg.obj" \
+ "$(INTDIR)/MainDlg.obj" \
+ "$(INTDIR)/StatisticsDlg.obj" \
+ "$(INTDIR)/StdAfx.obj" \
+ "$(INTDIR)/Tinelix IRC.res"
+
+"$(OUTDIR)\tlx_irc.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+################################################################################
+# Begin Target
+
+# Name "Tinelix IRC - Win32 Release"
+# Name "Tinelix IRC - Win32 Debug"
+
+!IF "$(CFG)" == "Tinelix IRC - Win32 Release"
+
+!ELSEIF "$(CFG)" == "Tinelix IRC - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=".\Tinelix IRC.cpp"
+DEP_CPP_TINEL=\
+ ".\dialogs\..\stdafx.h"\
+ ".\tabs\..\Tinelix IRC.h"\
+ ".\tabs\..\dialogs\MainDlg.h"\
+
+
+"$(INTDIR)\Tinelix IRC.obj" : $(SOURCE) $(DEP_CPP_TINEL) "$(INTDIR)"\
+ "$(INTDIR)\Tinelix IRC.pch"
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+DEP_CPP_STDAF=\
+ ".\dialogs\..\stdafx.h"\
+
+
+!IF "$(CFG)" == "Tinelix IRC - Win32 Release"
+
+# ADD CPP /Yc"stdafx.h"
+
+BuildCmds= \
+ $(CPP) /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS"\
+ /Fp"$(INTDIR)/Tinelix IRC.pch" /Yc"stdafx.h" /Fo"$(INTDIR)/" /c $(SOURCE) \
+
+
+"$(INTDIR)\StdAfx.obj" : $(SOURCE) $(DEP_CPP_STDAF) "$(INTDIR)"
+ $(BuildCmds)
+
+"$(INTDIR)\Tinelix IRC.pch" : $(SOURCE) $(DEP_CPP_STDAF) "$(INTDIR)"
+ $(BuildCmds)
+
+!ELSEIF "$(CFG)" == "Tinelix IRC - Win32 Debug"
+
+# ADD CPP /Yc"stdafx.h"
+
+BuildCmds= \
+ $(CPP) /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\
+ /D "_MBCS" /Fp"$(INTDIR)/Tinelix IRC.pch" /Yc"stdafx.h" /Fo"$(INTDIR)/"\
+ /Fd"$(INTDIR)/" /c $(SOURCE) \
+
+
+"$(INTDIR)\StdAfx.obj" : $(SOURCE) $(DEP_CPP_STDAF) "$(INTDIR)"
+ $(BuildCmds)
+
+"$(INTDIR)\Tinelix IRC.pch" : $(SOURCE) $(DEP_CPP_STDAF) "$(INTDIR)"
+ $(BuildCmds)
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=".\Tinelix IRC.rc"
+DEP_RSC_TINELI=\
+ ".\res\Tinelix IRC.ico"\
+ ".\res\Tinelix IRC.rc2"\
+
+
+"$(INTDIR)\Tinelix IRC.res" : $(SOURCE) $(DEP_RSC_TINELI) "$(INTDIR)"
+ $(RSC) $(RSC_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\dialogs\AboutDlg.cpp
+DEP_CPP_ABOUT=\
+ ".\tabs\..\Tinelix IRC.h"\
+ ".\dialogs\AboutDlg.h"\
+
+NODEP_CPP_ABOUT=\
+ ".\dialogs\stdafx.h"\
+
+
+"$(INTDIR)\AboutDlg.obj" : $(SOURCE) $(DEP_CPP_ABOUT) "$(INTDIR)"\
+ "$(INTDIR)\Tinelix IRC.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\dialogs\MainDlg.cpp
+DEP_CPP_MAIND=\
+ {$(INCLUDE)}"\sys\TYPES.H"\
+ {$(INCLUDE)}"\sys\TIMEB.H"\
+ ".\tabs\..\Tinelix IRC.h"\
+ ".\dialogs\..\tabs\AppThreadTab.h"\
+ ".\dialogs\AboutDlg.h"\
+ ".\tabs\..\dialogs\MainDlg.h"\
+ ".\dialogs\ConnManDlg.h"\
+ ".\dialogs\ProgressDlg.h"\
+ ".\dialogs\StatisticsDlg.h"\
+
+NODEP_CPP_MAIND=\
+ ".\dialogs\stdafx.h"\
+
+
+"$(INTDIR)\MainDlg.obj" : $(SOURCE) $(DEP_CPP_MAIND) "$(INTDIR)"\
+ "$(INTDIR)\Tinelix IRC.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\tabs\AppThreadTab.cpp
+DEP_CPP_APPTH=\
+ ".\tabs\..\Tinelix IRC.h"\
+ ".\tabs\..\dialogs\MainDlg.h"\
+ ".\dialogs\..\tabs\AppThreadTab.h"\
+
+NODEP_CPP_APPTH=\
+ ".\tabs\stdafx.h"\
+
+
+"$(INTDIR)\AppThreadTab.obj" : $(SOURCE) $(DEP_CPP_APPTH) "$(INTDIR)"\
+ "$(INTDIR)\Tinelix IRC.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\dialogs\ConnManDlg.cpp
+DEP_CPP_CONNM=\
+ ".\tabs\..\Tinelix IRC.h"\
+ ".\tabs\..\dialogs\MainDlg.h"\
+ ".\dialogs\ConnManDlg.h"\
+ ".\dialogs\TextBoxDlg.h"\
+
+NODEP_CPP_CONNM=\
+ ".\dialogs\stdafx.h"\
+
+
+"$(INTDIR)\ConnManDlg.obj" : $(SOURCE) $(DEP_CPP_CONNM) "$(INTDIR)"\
+ "$(INTDIR)\Tinelix IRC.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\dialogs\ProgressDlg.cpp
+DEP_CPP_PROGR=\
+ ".\tabs\..\Tinelix IRC.h"\
+ ".\dialogs\ProgressDlg.h"\
+
+NODEP_CPP_PROGR=\
+ ".\dialogs\stdafx.h"\
+
+
+"$(INTDIR)\ProgressDlg.obj" : $(SOURCE) $(DEP_CPP_PROGR) "$(INTDIR)"\
+ "$(INTDIR)\Tinelix IRC.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\dialogs\StatisticsDlg.cpp
+DEP_CPP_STATI=\
+ ".\tabs\..\Tinelix IRC.h"\
+ ".\tabs\..\dialogs\MainDlg.h"\
+ ".\dialogs\StatisticsDlg.h"\
+
+NODEP_CPP_STATI=\
+ ".\dialogs\stdafx.h"\
+
+
+"$(INTDIR)\StatisticsDlg.obj" : $(SOURCE) $(DEP_CPP_STATI) "$(INTDIR)"\
+ "$(INTDIR)\Tinelix IRC.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\dialogs\TextBoxDlg.cpp
+DEP_CPP_TEXTB=\
+ ".\tabs\..\Tinelix IRC.h"\
+ ".\dialogs\TextBoxDlg.h"\
+
+NODEP_CPP_TEXTB=\
+ ".\dialogs\stdafx.h"\
+
+
+"$(INTDIR)\TextBoxDlg.obj" : $(SOURCE) $(DEP_CPP_TEXTB) "$(INTDIR)"\
+ "$(INTDIR)\Tinelix IRC.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/windows/win32s/Tinelix IRC.mdp b/windows/win32s/Tinelix IRC.mdp
new file mode 100644
index 0000000..5ef59cf
Binary files /dev/null and b/windows/win32s/Tinelix IRC.mdp differ
diff --git a/windows/win32s/Tinelix IRC.ncb b/windows/win32s/Tinelix IRC.ncb
new file mode 100644
index 0000000..86328c9
Binary files /dev/null and b/windows/win32s/Tinelix IRC.ncb differ
diff --git a/windows/win32s/Tinelix IRC.rc b/windows/win32s/Tinelix IRC.rc
new file mode 100644
index 0000000..2e24f46
--- /dev/null
+++ b/windows/win32s/Tinelix IRC.rc
@@ -0,0 +1,402 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1251)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_APPICON ICON DISCARDABLE "res\\Tinelix IRC.ico"
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+#ifdef _WIN32
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+ "#ifdef _WIN32\r\n"
+ "LANGUAGE 9, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#endif\r\n"
+ "#include ""res\\Tinelix IRC.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""afxres.rc"" // Standard components\r\n"
+ "#endif\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOGEX 0, 0, 241, 156
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About Tinelix IRC"
+FONT 8, "MS Sans Serif"
+BEGIN
+ ICON IDR_APPICON,IDC_STATIC,5,6,21,20
+ LTEXT "Tinelix IRC Client 0.2.0-b002 for Win32s",IDC_STATIC,35,
+ 6,156,8,SS_NOPREFIX
+ LTEXT "Copyright © 2023 Dmitry Tretyakov (Tinelix)",IDC_STATIC,
+ 35,17,170,10
+ DEFPUSHBUTTON "OK",IDOK,190,137,46,14,WS_GROUP
+ LTEXT "This is free software: you can 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.",
+ IDC_LICENSE,35,36,201,36
+ LTEXT "Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.",
+ IDC_LICENSE2,35,74,201,36
+ EDITTEXT IDC_SRC_CODE_ADDR,93,115,137,12,ES_AUTOHSCROLL |
+ ES_READONLY,WS_EX_TRANSPARENT
+ LTEXT "Source code:",IDC_SRC_CODE,35,117,53,10
+END
+
+IDD_TABTHREAD DIALOG DISCARDABLE 0, 0, 266, 147
+STYLE WS_CHILD | WS_VISIBLE
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_CHAT_INPUT,4,4,258,121,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | WS_VSCROLL
+ EDITTEXT IDC_CHAT_OUTPUT,4,129,214,14,WS_DISABLED
+ PUSHBUTTON "Send",IDC_CHAT_SEND_MSG,221,129,41,14,WS_DISABLED
+END
+
+IDD_TABCHAT DIALOG DISCARDABLE 0, 0, 266, 147
+STYLE WS_CHILD | WS_DISABLED | WS_BORDER
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_CHAT_INPUT,4,4,184,121,ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_READONLY | WS_VSCROLL
+ EDITTEXT IDC_CHAT_OUTPUT,4,129,214,14
+ PUSHBUTTON "Send",IDC_CHAT_SEND_MSG,221,129,41,14
+ LISTBOX IDC_CHAT_MEMBERS,190,4,72,121,LBS_SORT |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_MAINDIALOG DIALOG DISCARDABLE 0, 0, 274, 166
+STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU |
+ WS_THICKFRAME
+CAPTION "Dialog"
+MENU IDR_MAINMENU
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "Tab1",IDC_MAINDLG_TABS,"SysTabControl32",0x0,2,2,270,
+ 162
+END
+
+IDD_CONNMANDIALOG DIALOG DISCARDABLE 0, 0, 199, 153
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Connection Manager"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,92,134,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,144,134,50,14
+ PUSHBUTTON "Create...",IDC_CREATE_PROFILE,11,110,58,14
+ PUSHBUTTON "Remove",IDC_REMOVE_PROFILE,71,110,58,14
+ PUSHBUTTON "Edit",IDC_EDIT_PROFILE,131,110,58,14
+ GROUPBOX "Profiles",IDC_PROFILES_GROUP,5,5,189,125
+ LISTBOX IDC_PROFILE_LIST,12,17,176,90,LBS_SORT |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_TEXTDIALOG DIALOG DISCARDABLE 0, 0, 183, 55
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Enter the text..."
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,74,36,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,128,36,50,14
+ LTEXT "Enter the text...",IDC_EDITTEXT,5,5,173,9
+ EDITTEXT IDC_EDITTEXTAREA,5,16,173,13,ES_AUTOHSCROLL
+END
+
+IDD_CONNECTION_PROGRESS DIALOG DISCARDABLE 0, 0, 189, 38
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
+CAPTION "Please wait..."
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,
+ 20,175,11
+ LTEXT "Connecting with [server]...",IDC_STATUS,7,7,175,10
+END
+
+IDD_STATSDIALOG DIALOG DISCARDABLE 0, 0, 147, 149
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Statistics"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,92,130,50,14
+ GROUPBOX "Packets",IDC_PACKETS_GROUP,5,5,137,45
+ LTEXT "Sent:",IDC_PACKETS_SENT_LABEL,13,16,50,8
+ RTEXT "N/A",IDC_PACKETS_SENT_VALUE,76,16,58,8
+ LTEXT "Read:",IDC_PACKETS_READ_LABEL,13,26,50,8
+ RTEXT "N/A",IDC_PACKETS_READ_VALUE,76,26,58,8
+ LTEXT "Sent:",IDC_BYTES_SENT_LABEL,13,64,50,8
+ RTEXT "N/A",IDC_BYTES_SENT_VALUE,76,64,58,8
+ LTEXT "Received:",IDC_READ_BYTES_LABEL,13,74,50,8
+ RTEXT "N/A",IDC_BYTES_READ_VALUE,76,74,58,8
+ LTEXT "Total:",IDC_TOTAL_BYTES_LABEL2,13,84,50,8
+ RTEXT "N/A",IDC_TOTAL_BYTES_VALUE,76,84,58,8
+ GROUPBOX "Data",IDC_DATA_GROUP,5,53,137,44
+ LTEXT "Total:",IDC_TOTAL_PACKETS_LABEL,13,36,50,8
+ RTEXT "N/A",IDC_TOTAL_PACKETS_VALUE,76,36,58,8
+ GROUPBOX "Connection",IDC_CONNECTION_GROUP,5,101,137,25
+ LTEXT "Quality:",IDC_CONNQUALITY_LABEL,13,112,38,8
+ CONTROL "Progress1",IDC_PING_STRENGTH,"msctls_progress32",
+ WS_BORDER,55,111,50,9
+ RTEXT "0%",IDC_CONNQUALITY_VALUE,109,112,25,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_ABOUTBOX, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 236
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 151
+ END
+
+ IDD_TABTHREAD, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 262
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 143
+ END
+
+ IDD_TABCHAT, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 262
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 143
+ END
+
+ IDD_MAINDIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 272
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 164
+ END
+
+ IDD_CONNMANDIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 194
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 148
+ END
+
+ IDD_TEXTDIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 178
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 50
+ END
+
+ IDD_CONNECTION_PROGRESS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 182
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 31
+ END
+
+ IDD_STATSDIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 142
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 144
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // Russian resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,2,0,2
+ PRODUCTVERSION 0,2,0,2
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x23L
+#else
+ FILEFLAGS 0x22L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080004e4"
+ BEGIN
+ VALUE "Comments", "Tinelix IRC Client compatible version with Win32s, Windows 95/98, Windows NT and 64-bit (AMD64) Windows editions.\0"
+ VALUE "CompanyName", "Tinelix\0"
+ VALUE "FileDescription", "Tinelix IRC\0"
+ VALUE "FileVersion", "0.2.0-b002\0"
+ VALUE "InternalName", "Tinelix IRC for Win32s\0"
+ VALUE "LegalCopyright", "Copyright © 2023 Dmitry Tretyakov (aka. tretdm). Licensed under GPLv3.\0"
+ VALUE "OriginalFilename", "tlx_irc.exe\0"
+ VALUE "ProductName", "Tinelix IRC for Win32s\0"
+ VALUE "ProductVersion", "0.2.0-b002\0"
+ VALUE "SpecialBuild", "Source code: https://github.com/tinelix/irc-client-win32s\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x800, 1252
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MAINMENU MENU DISCARDABLE
+BEGIN
+ POPUP "File"
+ BEGIN
+ MENUITEM "Connect...", ID_FILE_CONNECT
+ MENUITEM SEPARATOR
+ MENUITEM "Quit", ID_FILE_QUIT
+ END
+ POPUP "Connection"
+ BEGIN
+ MENUITEM "Statistics...", ID_CONNECTION_STATISTICS
+ END
+ POPUP "Channel", GRAYED
+ BEGIN
+ MENUITEM "Join...", ID_CHANNEL_JOIN
+ MENUITEM "Leave", ID_CHANNEL_LEAVE
+ END
+ POPUP "Help"
+ BEGIN
+ MENUITEM "About...", ID_ABOUT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_ABOUTBOX "&About..."
+ IDS_CONNECTION_FAILED_1 "Connection to server failed."
+ IDS_TABS_THREAD "Thread"
+ IDS_APP_NAME "Tinelix IRC Client (Win32s)"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif
+#include "res\Tinelix IRC.rc2" // non-Microsoft Visual C++ edited resources
+#include "afxres.rc" // Standard components
+#endif
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/windows/win32s/dialogs/AboutDlg.cpp b/windows/win32s/dialogs/AboutDlg.cpp
new file mode 100644
index 0000000..c64c6b2
--- /dev/null
+++ b/windows/win32s/dialogs/AboutDlg.cpp
@@ -0,0 +1,81 @@
+// AboutDlg.cpp : implementation file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+
+#include "stdafx.h"
+#include "..\Tinelix IRC.h"
+#include "AboutDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+CString src_code_repo;
+
+/////////////////////////////////////////////////////////////////////////////
+// CAboutDlg dialog
+
+
+CAboutDlg::CAboutDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CAboutDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CAboutDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+}
+
+
+void CAboutDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CAboutDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
+ //{{AFX_MSG_MAP(CAboutDlg)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CAboutDlg message handlers
+
+BOOL CAboutDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
+ DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
+ UINT nID, CCreateContext* pContext)
+{
+
+ return CDialog::Create(IDD, pParentWnd);
+}
+
+BOOL CAboutDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ src_code_repo = CString("https://github.com/tinelix/irc-client-win32s");
+ CEdit* source_code_addr = (CEdit*)GetDlgItem(IDC_SRC_CODE_ADDR);
+ source_code_addr->SetWindowText(src_code_repo);
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
diff --git a/windows/win32s/dialogs/AboutDlg.h b/windows/win32s/dialogs/AboutDlg.h
new file mode 100644
index 0000000..116cd7b
--- /dev/null
+++ b/windows/win32s/dialogs/AboutDlg.h
@@ -0,0 +1,53 @@
+// AboutDlg.h : header file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+/////////////////////////////////////////////////////////////////////////////
+// CAboutDlg dialog
+
+class CAboutDlg : public CDialog
+{
+// Construction
+public:
+ CAboutDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CAboutDlg)
+ enum { IDD = IDD_ABOUTBOX };
+ // NOTE: the ClassWizard will add data members here
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CAboutDlg)
+ public:
+ virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CAboutDlg)
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/windows/win32s/dialogs/ConnManDlg.cpp b/windows/win32s/dialogs/ConnManDlg.cpp
new file mode 100644
index 0000000..be8a4bf
--- /dev/null
+++ b/windows/win32s/dialogs/ConnManDlg.cpp
@@ -0,0 +1,171 @@
+// ConnManDlg.cpp : implementation file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+#include "stdafx.h"
+#include "..\Tinelix IRC.h"
+#include "MainDlg.h"
+#include "ConnManDlg.h"
+#include "TextBoxDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+WIN32_FIND_DATA ffd;
+
+int dir_error_code;
+
+/////////////////////////////////////////////////////////////////////////////
+// CConnManDlg dialog
+
+
+CConnManDlg::CConnManDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CConnManDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CConnManDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+}
+
+
+void CConnManDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CConnManDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CConnManDlg, CDialog)
+ //{{AFX_MSG_MAP(CConnManDlg)
+ ON_BN_CLICKED(IDC_CREATE_PROFILE, OnCreateProfileBtn)
+ ON_LBN_SELCHANGE(IDC_PROFILE_LIST, OnProfileListSelection)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CConnManDlg message handlers
+
+BOOL CConnManDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ LoadProfileList();
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CConnManDlg::OnOK()
+{
+ char* server = "";
+ CListBox* profileList = (CListBox*)GetDlgItem(IDC_PROFILE_LIST);
+ CMainDlg* parent = (CMainDlg*)AfxGetMainWnd();
+ char profile[256];
+ profileList->GetText(profileList->GetCurSel(), profile);
+ if(dir_error_code == 0 && profileList->GetCount() > 0) {
+ CDialog::OnOK();
+ parent->LoadProfileSettings(profile);
+ return;
+ } else {
+ char dir_path[460];
+ CIRCApplication* app = (CIRCApplication*)app;
+ sprintf(dir_path, app->GetAppPath());
+ if(app->CheckIsWin32s() == TRUE) {
+ strcat(dir_path, "\\PROFILES");
+ } else {
+ strcat(dir_path, "\\profiles");
+ }
+ char address[640] = {0};
+ OPENFILENAME ofna = {0};
+ ofna.lStructSize = sizeof(OPENFILENAME);
+ ofna.lpstrInitialDir = dir_path;
+ ofna.lpstrFile = address;
+ ofna.nMaxFile = 640;
+ ofna.lpstrFilter = "Config files (*.ini, *.cfg)\0*.ini;*.cfg\0All files\0*.*";
+ ofna.Flags |= OFN_FILEMUSTEXIST;
+ if(GetOpenFileName(&ofna)) {
+ sprintf(address, ofna.lpstrFile);
+ parent->LoadProfileSettingsF(address);
+ }
+ }
+ CDialog::OnOK();
+}
+
+void CConnManDlg::LoadProfileList() {
+ char dir_path[460];
+ char error_msg[1024];
+ CIRCApplication* app = (CIRCApplication*)app;
+ sprintf(dir_path, app->GetAppPath());
+ if(app->CheckIsWin32s() == TRUE) {
+ strcat(dir_path, "\\PROFILES");
+ } else {
+ strcat(dir_path, "\\profiles");
+ }
+ if(CreateDirectory(dir_path, NULL) > 0 || GetLastError() == ERROR_ALREADY_EXISTS) {
+ CListBox* profileList = (CListBox*)GetDlgItem(IDC_PROFILE_LIST);
+ HANDLE hFindProfiles = INVALID_HANDLE_VALUE;
+ char folder_list_path[460];
+ sprintf(folder_list_path, "%s\\*.ini", dir_path);
+ hFindProfiles = FindFirstFile(folder_list_path, &ffd);
+ CString strText = "";
+ int items_count;
+ if(hFindProfiles != INVALID_HANDLE_VALUE) {
+ try {
+ items_count++;
+ do {
+ if(strText.GetLength() > 4) {
+ strText.Format("%s", ffd.cFileName);
+ profileList->AddString(strText.Left(strText.GetLength() - 4));
+ items_count++;
+ }
+ } while (FindNextFile(hFindProfiles, &ffd) != 0);
+ FindClose(hFindProfiles);
+ } catch(...) {
+
+ }
+ }
+ if(profileList->GetCount() > 0) {
+ CButton* ok_btn = (CButton*)GetDlgItem(IDOK);
+ ok_btn->EnableWindow(FALSE);
+ }
+ } else {
+ dir_error_code = GetLastError();
+ sprintf(error_msg, "Invalid directory path.\r\n\r\nPath: %s\r\nError code: %d",
+ dir_path, dir_error_code);
+ MessageBox(error_msg, "Error", MB_OK|MB_ICONSTOP);
+ }
+
+}
+
+void CConnManDlg::OnCreateProfileBtn()
+{
+ CTextBoxDlg textBoxDlg;
+ textBoxDlg.SetAction(0);
+ textBoxDlg.DoModal();
+}
+
+void CConnManDlg::OnProfileListSelection()
+{
+ CButton* ok_btn = (CButton*)GetDlgItem(IDOK);
+ ok_btn->EnableWindow(TRUE);
+}
diff --git a/windows/win32s/dialogs/ConnManDlg.h b/windows/win32s/dialogs/ConnManDlg.h
new file mode 100644
index 0000000..fd2d0f0
--- /dev/null
+++ b/windows/win32s/dialogs/ConnManDlg.h
@@ -0,0 +1,68 @@
+// ConnManDlg.h : header file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+/////////////////////////////////////////////////////////////////////////////
+// CConnManDlg dialog
+
+class CConnManDlg : public CDialog
+{
+// Construction
+public:
+ CConnManDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CConnManDlg)
+ enum { IDD = IDD_CONNMANDIALOG };
+ // NOTE: the ClassWizard will add data members here
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CConnManDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ typedef struct _LV_ITEMA {
+ UINT mask;
+ int iItem;
+ int iSubItem;
+ UINT state;
+ UINT stateMask;
+ LPTSTR pszText;
+ int cchTextMax;
+ int iImage;
+ LPARAM lParam;
+ #if(_WIN32_IE >= 0x0300)
+ int iIndent;
+ #endif
+ } LVITEM, FAR *LPLVITEM;
+ void LoadProfileList();
+ // Generated message map functions
+ //{{AFX_MSG(CConnManDlg)
+ virtual void OnOK();
+ virtual BOOL OnInitDialog();
+ afx_msg void OnCreateProfileBtn();
+ afx_msg void OnProfileListSelection();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/windows/win32s/dialogs/MainDlg.cpp b/windows/win32s/dialogs/MainDlg.cpp
new file mode 100644
index 0000000..f23078f
--- /dev/null
+++ b/windows/win32s/dialogs/MainDlg.cpp
@@ -0,0 +1,560 @@
+// MainDlg.cpp : implementation file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+#include "stdafx.h"
+#include
+#include
+#include
+#include
+#include "..\Tinelix IRC.h"
+#include "..\tabs\AppThreadTab.h"
+#include "AboutDlg.h"
+#include "MainDlg.h"
+#include "ConnManDlg.h"
+#include "ProgressDlg.h"
+#include "StatisticsDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainDlg dialog
+
+CMainDlg::CMainDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CMainDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CMainDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+ // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
+ m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+}
+
+void CMainDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CMainDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
+ //{{AFX_MSG_MAP(CMainDlg)
+ ON_WM_SYSCOMMAND()
+ ON_WM_PAINT()
+ ON_WM_QUERYDRAGICON()
+ ON_COMMAND(ID_ABOUT, OnMenuHelpAbout)
+ ON_COMMAND(ID_FILE_CONNECT, OpenConnectionManager)
+ ON_WM_SIZE()
+ ON_COMMAND(ID_CONNECTION_STATISTICS, OnConnectionStatistics)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+// Global variables
+
+CAppThreadTab *thread_tab;
+HINSTANCE wsaWrap;
+HINSTANCE ircParser;
+CString thread_input;
+BOOL isWin3x;
+char* conn_server;
+char* app_name;
+int new_unread_messages;
+char g_address[256];
+char settings_ini_path[MAX_PATH];
+char profile_ini_path[MAX_PATH];
+char main_nick[20];
+int g_port;
+CProgressDlg progressDlg;
+CStatisticsDlg statisticsDlg;
+int until_pong;
+CIRCApplication* app;
+
+// WSAWrapper DLL functions;
+
+typedef void (WINAPI *EnableDebugging) (BOOL);
+typedef BOOL (WINAPI *EnableAsyncMessages) (HWND);
+typedef int (WINAPI *GetWSAError) ();
+typedef int (WINAPI *CreateAsyncConnection) (char*, int, int, int, HWND);
+typedef BOOL (WINAPI *SendSocketData) (char*);
+typedef char* (WINAPI *GetInputBuffer) (SOCKET s);
+typedef void (WINAPI *CloseConnection) ();
+
+EnableDebugging EnableDebug;
+CreateAsyncConnection WrapCreateConn;
+EnableAsyncMessages EnableAsyncMsgs;
+SendSocketData SendOutBuff;
+GetInputBuffer GetInBuff;
+GetWSAError GetWSAErrorFunc;
+CloseConnection WrapCloseConn;
+
+// Tinelix IRC Parser functions:
+
+typedef char* (WINAPI *ParseIRCPacketFunc) (char[4096]);
+typedef char* (WINAPI *ParseIRCSendingMessageFunc) (char*, char*);
+
+ParseIRCPacketFunc ParseIRCPacket;
+ParseIRCSendingMessageFunc ParseIRCSendingMsg;
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainDlg message handlers
+
+BOOL CMainDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ isWin3x = (GetVersion() & 0xFF) == 3; // check if it's Windows (or WinNT) 3.x
+
+ // Add "About..." menu item to system menu.
+
+ // IDM_ABOUTBOX must be in the system command range.
+ ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
+ ASSERT(IDM_ABOUTBOX < 0xF000);
+
+ char app_path[640];
+ sprintf(app_path, app->GetAppPath());
+
+ // Loading WSAWrapper library.
+ // Available in https://github.com/tinelix/WSAWrapper (LGPLv2.1+)
+ char wsawrap_path[640];
+ sprintf(wsawrap_path, "%s\\wsawrap.dll", app_path);
+ char ircpars_path[640];
+ sprintf(ircpars_path, "%s\\ircpars.dll", app_path);
+ wsaWrap = LoadLibrary(wsawrap_path);
+ conn_server = "";
+
+ if(!wsaWrap) {
+ MessageBox("wsawrap.dll loading error", "Error", MB_OK|MB_ICONSTOP);
+ EnableWindow(FALSE);
+ return FALSE;
+ }
+
+ ircParser = LoadLibrary(ircpars_path);
+ if(!ircParser) {
+ MessageBox("ircpars.dll loading error", "Error", MB_OK|MB_ICONSTOP);
+ EnableWindow(FALSE);
+ return FALSE;
+ }
+
+ ImportDllFunctions();
+ (EnableDebug)(TRUE);
+
+ CMenu* pSysMenu = GetSystemMenu(FALSE);
+ CString strAboutMenu;
+ strAboutMenu.LoadString(IDS_ABOUTBOX);
+ if (!strAboutMenu.IsEmpty())
+ {
+ pSysMenu->AppendMenu(MF_SEPARATOR);
+ pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
+ }
+
+ SetIcon(m_hIcon, TRUE);
+ SetIcon(m_hIcon, FALSE);
+
+ app_name = "Tinelix IRC (Win32s)"; // LoadString is buggy...
+ SetWindowText(app_name);
+ progressDlg.Create(CProgressDlg::IDD, this);
+ statisticsDlg.Create(CStatisticsDlg::IDD, this);
+ statisticsDlg.SetWSAWrapper(wsaWrap);
+
+ EnableWindow(TRUE);
+
+ CreateTabs();
+
+ app = (CIRCApplication*)AfxGetApp();
+
+ sprintf(settings_ini_path, "%s\\settings.ini", app->GetAppPath());
+ LoadSettings(settings_ini_path);
+
+ return TRUE;
+}
+
+
+void CMainDlg::CreateTabs() {
+ CTabCtrl* tabCtrl = (CTabCtrl*)GetDlgItem(IDC_MAINDLG_TABS);
+ TC_ITEM tabItem;
+ tabItem.mask = TCIF_TEXT;
+ char* tab_title = "Thread";
+ tabItem.pszText = tab_title;
+ tabCtrl->InsertItem(0, &tabItem);
+ thread_tab = new CAppThreadTab;
+ thread_tab->Create(IDD_TABTHREAD, this);
+ tabItem.lParam = (LPARAM)thread_tab;
+ thread_tab->SetWindowPos(NULL, 6, 24, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
+ thread_tab->ShowWindow(SW_SHOW);
+ CEdit* thread_input_box = (CEdit*)thread_tab->GetDlgItem(IDC_CHAT_INPUT);
+ font.CreateFont(11, 0, 0, 0, FW_REGULAR, FALSE, FALSE, 0, DEFAULT_CHARSET,
+ 0, 0, 0, 0, "Fixedsys");
+ thread_input_box->SetFont(&font);
+ thread_tab->SetParentWnd(this);
+
+}
+
+void CMainDlg::OnSysCommand(UINT nID, LPARAM lParam)
+{
+ if ((nID & 0xFFF0) == IDM_ABOUTBOX)
+ {
+ CAboutDlg aboutDlg;
+ aboutDlg.DoModal();
+ } else {
+ CDialog::OnSysCommand(nID, lParam);
+ }
+}
+
+void CMainDlg::OnPaint()
+{
+ if (IsIconic())
+ {
+ CPaintDC dc(this); // device context for painting
+
+ SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
+
+ // Center icon in client rectangle
+ int cxIcon = GetSystemMetrics(SM_CXICON);
+ int cyIcon = GetSystemMetrics(SM_CYICON);
+ CRect rect;
+ GetClientRect(&rect);
+ int x = (rect.Width() - cxIcon + 1) / 2;
+ int y = (rect.Height() - cyIcon + 1) / 2;
+
+ // Draw the icon
+ dc.DrawIcon(x, y, m_hIcon);
+ }
+ else
+ {
+ CDialog::OnPaint();
+ }
+}
+
+HCURSOR CMainDlg::OnQueryDragIcon()
+{
+ return (HCURSOR) m_hIcon;
+}
+
+BOOL CMainDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
+ DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
+ UINT nID, CCreateContext* pContext)
+{
+ // TODO: Add your specialized code here and/or call the base class
+
+ return CDialog::Create(IDD, pParentWnd);
+}
+
+void CMainDlg::OnMenuHelpAbout()
+{
+ CAboutDlg aboutDlg;
+ aboutDlg.DoModal();
+}
+
+BOOL CMainDlg::DestroyWindow()
+{
+ if(thread_tab != NULL && thread_tab->m_hWnd != NULL ) {
+ thread_tab->DestroyWindow();
+ delete thread_tab;
+ }
+
+ if(wsaWrap != NULL) {
+ FreeLibrary(wsaWrap);
+ }
+
+ return CDialog::DestroyWindow();
+}
+
+void CMainDlg::OpenConnectionManager()
+{
+ CConnManDlg connman;
+ connman.DoModal();
+}
+
+void CMainDlg::PrepareConnect(char* address, int port) {
+ sprintf(g_address, address);
+ g_port = port;
+ progressDlg.SetProgress(0);
+ sprintf(app_name, "Tinelix IRC (Win32s) | %s:%d", g_address, port); // LoadString is buggy...
+ sprintf(conn_server, "%s:%d", address, port);
+ progressDlg.CenterWindow();
+ progressDlg.ShowWindow(SW_SHOW);
+ int result = (*WrapCreateConn)(address, port, 0, 0xB001, m_hWnd);
+ if(result == 0) {
+ int error_code = ((*GetWSAErrorFunc)());
+ char error_msg[32];
+ sprintf(error_msg, "Connection error #%d", error_code);
+ MessageBox(error_msg, address, MB_OK|MB_ICONSTOP);
+ sprintf(app_name, "Tinelix IRC (Win32s)", address, port); // LoadString is buggy...
+ } else if(result == 1) {
+ IdentificateConnection();
+ EnableAsyncMsgs(m_hWnd);
+ SetWindowText(app_name);
+ }
+}
+
+void CMainDlg::PrepareConnect(int result) {
+ if(result == 0) {
+ int error_code = ((*GetWSAErrorFunc)());
+ char error_msg[32];
+ sprintf(error_msg, "Connection error #%d", error_code);
+ MessageBox(error_msg, g_address, MB_OK|MB_ICONSTOP);
+ sprintf(app_name, "Tinelix IRC (Win32s)"); // LoadString is buggy...
+ } else if(result == 1) {
+ if(progressDlg.m_hWnd) {
+ progressDlg.SetProgress(100);
+ }
+ IdentificateConnection();
+ EnableAsyncMsgs(m_hWnd);
+ SetWindowText(app_name);
+ }
+}
+
+void CMainDlg::ImportDllFunctions() {
+ // Running EnableDebugging function (#14) in WSAWrapper DLL
+ EnableDebug = (EnableDebugging)GetProcAddress(wsaWrap, MAKEINTRESOURCE(14));
+ // Running EnableAsyncMessages function (#15) in WSAWrapper DLL
+ EnableAsyncMsgs = (EnableAsyncMessages)GetProcAddress(wsaWrap, MAKEINTRESOURCE(15));
+ // Running GetWSAError function (#16) in WSAWrapper DLL
+ GetWSAErrorFunc = (GetWSAError)GetProcAddress(wsaWrap, MAKEINTRESOURCE(16));
+ // Running CreateAsyncConnection function (#18) in WSAWrapper DLL
+ WrapCreateConn = (CreateAsyncConnection)GetProcAddress(wsaWrap, MAKEINTRESOURCE(18));
+ // Running SendData function (#19) in WSAWrapper DLL
+ SendOutBuff = (SendSocketData)GetProcAddress(wsaWrap, MAKEINTRESOURCE(19));
+ // Running GetInputBuffer function (#20) in WSAWrapper DLL
+ GetInBuff = (GetInputBuffer)GetProcAddress(wsaWrap, MAKEINTRESOURCE(20));
+ // Running CloseConnection function (#21) in WSAWrapper DLL
+ WrapCloseConn = (CloseConnection)GetProcAddress(wsaWrap, MAKEINTRESOURCE(22));
+
+ ParseIRCPacket = (ParseIRCPacketFunc)GetProcAddress(ircParser, MAKEINTRESOURCE(2));
+ ParseIRCSendingMsg = (ParseIRCSendingMessageFunc)GetProcAddress(ircParser, MAKEINTRESOURCE(3));
+
+}
+
+void CMainDlg::IdentificateConnection() {
+ char* ident_str = "";
+ if(strlen(main_nick) == 0) {
+ sprintf(ident_str, "USER %s %s %s :Member\r\n",
+ "main_nick", "main_nick", "main_nick");
+ } else {
+ sprintf(ident_str, "USER %s %s %s :Member\r\n",
+ main_nick, main_nick, main_nick);
+ }
+ if(!(*SendOutBuff)(ident_str)) {
+ if(progressDlg.m_hWnd) {
+ progressDlg.Close();
+ EnableWindow(TRUE);
+ }
+ int error_code = ((*GetWSAErrorFunc)());
+ char error_msg[32];
+ sprintf(error_msg, "Identification error #%d", error_code);
+ MessageBox(error_msg, conn_server, MB_OK|MB_ICONSTOP);
+ return;
+ }
+ sprintf(ident_str, "NICK %s\r\n", main_nick);
+ BOOL result = (*SendOutBuff)(ident_str);
+ if(progressDlg.m_hWnd) {
+ progressDlg.Close();
+ EnableWindow(TRUE);
+ }
+ if(!result) {
+ int error_code = ((*GetWSAErrorFunc)());
+ char error_msg[32];
+ sprintf(error_msg, "Identification error #%d", error_code);
+ MessageBox(error_msg, conn_server, MB_OK|MB_ICONSTOP);
+ return;
+ } else {
+ CEdit* thread_output_box = (CEdit*)thread_tab->GetDlgItem(IDC_CHAT_OUTPUT);
+ thread_output_box->EnableWindow(TRUE);
+ CButton* thread_send_btn = (CButton*)thread_tab->GetDlgItem(IDC_CHAT_SEND_MSG);
+ thread_send_btn->EnableWindow(TRUE);
+ }
+}
+
+void CMainDlg::SendPing(CString ping_hexcode) {
+ CString ping_str = "";
+ ping_str.Format("PONG %s\r\n", ping_hexcode);
+ if((*SendOutBuff)(ping_str.GetBuffer(ping_str.GetLength()))) {
+ Sleep(5); // for real PONG effect
+ int after_pong = GetTickCount();
+ statisticsDlg.SetConnectionQuality(after_pong - until_pong - 5);
+ }
+}
+
+LRESULT CMainDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if(message == 0xB001) {
+ progressDlg.SetProgress(50);
+ int result = (*WrapCreateConn)("", 0, 1, 0xB001, m_hWnd);
+ PrepareConnect(result);
+ } else if(message == 0xAFFF) {
+ until_pong = GetTickCount();
+ new_unread_messages += 1;
+ char* sock_buffer;
+ sock_buffer = (*GetInBuff)((SOCKET)wParam);
+ CEdit* thread_input_box = (CEdit*)thread_tab->GetDlgItem(IDC_CHAT_INPUT);
+ CString sock_buff_str = CString(sock_buffer);
+ if(sock_buff_str == "[WSAWrapper] 0xE0001\r\n") {
+ char error_str[80];
+ int error_code = (*GetWSAErrorFunc)();
+ sprintf(error_str, "Connection with %s closed.\r\n\r\nError code: #%d",
+ conn_server, error_code);
+ MessageBox(error_str, conn_server, MB_OK|MB_ICONINFORMATION);
+ app_name = "Tinelix IRC (Win32s)";
+ conn_server = "";
+ SetWindowText(app_name);
+ } else if(sock_buff_str.GetLength() > 0) {
+ if(sock_buff_str.Left(4) == "PING") {
+ SendPing(sock_buff_str.Right(sock_buff_str.GetLength() - 3));
+ OutputDebugString(sock_buff_str.Right(sock_buff_str.GetLength() - 3));
+ } else {
+ if(ircParser != NULL) {
+ CString parsed_str = CString("");
+ parsed_str = CString(
+ (*ParseIRCPacket)(sock_buffer)
+ );
+ thread_input += parsed_str;
+ thread_input_box->SetWindowText(thread_input);
+ } else {
+ thread_input += sock_buff_str;
+ thread_input_box->SetWindowText(thread_input);
+ }
+ }
+ }
+ thread_input_box->SetSel(thread_input.GetLength(), thread_input.GetLength());
+ } else if(message == 0xAFFE) {
+ CEdit* thread_input_box = (CEdit*)thread_tab->GetDlgItem(IDC_CHAT_INPUT);
+ thread_input_box->Clear();
+ EnableWindow(FALSE);
+ char status[48];
+ sprintf(status, "Connecting with %s...", conn_server);
+ if(progressDlg.m_hWnd) {
+ progressDlg.ShowWindow(SW_SHOW);
+ progressDlg.SetStatus(CString(status));
+ }
+ } else if(message == 0xE0001) {
+ MessageBox("Connection closed", conn_server, MB_OK|MB_ICONINFORMATION);
+ app_name = "Tinelix IRC (Win32s)";
+ conn_server = "";
+ SetWindowText(app_name);
+ }
+
+ return CDialog::WindowProc(message, wParam, lParam);
+}
+
+void CMainDlg::OnSize(UINT nType, int cx, int cy)
+{
+ CDialog::OnSize(nType, cx, cy);
+
+ CRect rect;
+
+ GetWindowRect(&rect);
+
+ CTabCtrl* tabCtrl = (CTabCtrl*)GetDlgItem(IDC_MAINDLG_TABS);
+ if(tabCtrl != NULL) {
+ if(isWin3x) {
+ tabCtrl->MoveWindow(4, 3, rect.Width() - 16, rect.Height() - 54);
+ thread_tab->MoveWindow(6, 26, rect.Width() - 20, rect.Height() - 80);
+ } else {
+ tabCtrl->MoveWindow(4, 3, rect.Width() - 24, rect.Height() - 66);
+ thread_tab->MoveWindow(6, 26, rect.Width() - 28, rect.Height() - 92);
+ }
+ }
+
+ if(isWin3x) {
+ // Setting window title in Win3.x / WinNT3.x
+ // for greater compactness.
+ if(nType != SIZE_MINIMIZED) {
+ SetWindowText(app_name);
+ } else if(strlen(conn_server) > 0) {
+ SetWindowText(conn_server);
+ }
+ }
+}
+
+CString CMainDlg::ParseMessage(char* irc_packet) {
+ char* parsed_packet = "";
+ parsed_packet = (*ParseIRCPacket)(irc_packet);
+
+ return CString(parsed_packet);
+};
+
+void CMainDlg::OnConnectionStatistics()
+{
+ statisticsDlg.CenterWindow();
+ statisticsDlg.ShowWindow(SW_SHOW);
+}
+
+void CMainDlg::SendIRCMessage(CWnd* parent) {
+ CEdit* thread_input_box = (CEdit*)thread_tab->GetDlgItem(IDC_CHAT_INPUT);
+ CEdit* thread_output_box = (CEdit*)thread_tab->GetDlgItem(IDC_CHAT_OUTPUT);
+ CString command;
+ thread_output_box->GetWindowText(command);
+ char* parsed_message = (*ParseIRCSendingMsg)(command.GetBuffer(command.GetLength()), "");
+ if(command == "/quit") {
+ if((*SendOutBuff)(parsed_message)) {
+ thread_output_box->SetWindowText("");
+ thread_input = "";
+ thread_input_box->SetWindowText("");
+ parent->SetWindowText("Tinelix IRC (Win32s)");
+ CEdit* thread_output_box = (CEdit*)thread_tab->GetDlgItem(IDC_CHAT_OUTPUT);
+ thread_output_box->EnableWindow(FALSE);
+ CButton* thread_send_btn = (CButton*)thread_tab->GetDlgItem(IDC_CHAT_SEND_MSG);
+ thread_send_btn->EnableWindow(FALSE);
+ (*WrapCloseConn)();
+ }
+ } else {
+ if((*SendOutBuff)(parsed_message)) {
+ thread_output_box->SetWindowText("");
+ }
+ }
+}
+
+void CMainDlg::LoadSettings(char* ini_filename) {
+
+}
+
+void CMainDlg::LoadProfileSettings(char* ini_filename) {
+ char g_port_str[6];
+ char app_path[460];
+ sprintf(app_path, app->GetAppPath());
+ sprintf(profile_ini_path, "%s\\profiles\\%s.ini", app_path, ini_filename);
+ GetPrivateProfileString("Main", "Server", "irc.tinelix.ru", g_address,
+ MAX_PATH, profile_ini_path);
+ GetPrivateProfileString("Main", "Port", "6667", g_port_str,
+ 6, profile_ini_path);
+ GetPrivateProfileString("Main", "MainNick", "irc_member", main_nick,
+ 20, profile_ini_path);
+ if(isdigit(g_port_str[0])) {
+ g_port = atoi(g_port_str);
+ }
+ PrepareConnect(g_address, g_port);
+}
+
+void CMainDlg::LoadProfileSettingsF(char* address) {
+ char g_port_str[6];
+ GetPrivateProfileString("Main", "Server", "irc.tinelix.ru", g_address,
+ MAX_PATH, address);
+ GetPrivateProfileString("Main", "Port", "6667", g_port_str,
+ 6, address);
+ GetPrivateProfileString("Main", "MainNick", "irc_member", main_nick,
+ 20, address);
+ if(isdigit(g_port_str[0])) {
+ g_port = atoi(g_port_str);
+ }
+ PrepareConnect(g_address, g_port);
+}
\ No newline at end of file
diff --git a/windows/win32s/dialogs/MainDlg.h b/windows/win32s/dialogs/MainDlg.h
new file mode 100644
index 0000000..6b757f4
--- /dev/null
+++ b/windows/win32s/dialogs/MainDlg.h
@@ -0,0 +1,79 @@
+// MainDlg.h : header file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainDlg dialog
+
+#define WM_SOCKET_READ 0xAFFF;
+
+class CMainDlg : public CDialog
+{
+// Construction
+public:
+ BOOL is_connected;
+
+ void SendIRCMessage(CWnd* parent);
+
+ CMainDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CMainDlg)
+ enum { IDD = IDD_MAINDIALOG };
+ //}}AFX_DATA
+
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CMainDlg)
+ public:
+ virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
+ virtual BOOL DestroyWindow();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ HICON m_hIcon;
+ CFont font;
+ void CreateTabs();
+ void PrepareConnect(LPSTR address, int port);
+ void PrepareConnect(int result);
+ void ImportDllFunctions();
+ void IdentificateConnection();
+ void SendPing(CString ping_hexcode);
+ CString ParseMessage(char* irc_packet);
+ void LoadSettings(char* ini_filename);
+ void LoadProfileSettings(char* ini_filename);
+ void LoadProfileSettingsF(char* address);
+
+ // Generated message map functions
+ //{{AFX_MSG(CMainDlg)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
+ afx_msg void OnPaint();
+ afx_msg HCURSOR OnQueryDragIcon();
+ afx_msg void OnMenuHelpAbout();
+ afx_msg void OpenConnectionManager();
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+ afx_msg void OnConnectionStatistics();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+ friend class CConnManDlg;
+};
diff --git a/windows/win32s/dialogs/ProgressDlg.cpp b/windows/win32s/dialogs/ProgressDlg.cpp
new file mode 100644
index 0000000..8dde465
--- /dev/null
+++ b/windows/win32s/dialogs/ProgressDlg.cpp
@@ -0,0 +1,99 @@
+// ProgressDlg.cpp : implementation file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+#include "stdafx.h"
+#include "..\Tinelix IRC.h"
+#include "ProgressDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CProgressDlg dialog
+
+
+CProgressDlg::CProgressDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CProgressDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CProgressDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+}
+
+
+void CProgressDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CProgressDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CProgressDlg, CDialog)
+ //{{AFX_MSG_MAP(CProgressDlg)
+ ON_WM_SIZE()
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CProgressDlg message handlers
+
+void CProgressDlg::SetStatus(CString status) {
+ CWnd* status_label = (CWnd*)GetDlgItem(IDC_STATUS);
+ status_label->SetWindowText(status);
+}
+
+void CProgressDlg::SetProgress(int value) {
+ CProgressCtrl* status_label = (CProgressCtrl*)GetDlgItem(IDC_PROGRESS);
+ status_label->SetPos(value);
+}
+
+void CProgressDlg::OnOK()
+{
+ //CDialog::OnOK();
+}
+
+void CProgressDlg::Close() {
+ CDialog::OnOK();
+}
+
+void CProgressDlg::OnCancel()
+{
+ //CDialog::OnCancel();
+}
+
+BOOL CProgressDlg::DestroyWindow()
+{
+ return CDialog::DestroyWindow();
+}
+
+void CProgressDlg::OnSize(UINT nType, int cx, int cy)
+{
+ CDialog::OnSize(nType, cx, cy);
+}
+
+void CProgressDlg::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CDialog::OnShowWindow(bShow, nStatus);
+}
diff --git a/windows/win32s/dialogs/ProgressDlg.h b/windows/win32s/dialogs/ProgressDlg.h
new file mode 100644
index 0000000..a19950f
--- /dev/null
+++ b/windows/win32s/dialogs/ProgressDlg.h
@@ -0,0 +1,60 @@
+// ProgressDlg.h : header file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+/////////////////////////////////////////////////////////////////////////////
+// CProgressDlg dialog
+
+class CProgressDlg : public CDialog
+{
+// Construction
+public:
+ CProgressDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CProgressDlg)
+ enum { IDD = IDD_CONNECTION_PROGRESS };
+ // NOTE: the ClassWizard will add data members here
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CProgressDlg)
+ public:
+ virtual BOOL DestroyWindow();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+public:
+ void SetStatus(CString status);
+ void SetProgress(int value);
+ void Close();
+ // Generated message map functions
+ //{{AFX_MSG(CProgressDlg)
+ virtual void OnOK();
+ virtual void OnCancel();
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/windows/win32s/dialogs/StatisticsDlg.cpp b/windows/win32s/dialogs/StatisticsDlg.cpp
new file mode 100644
index 0000000..7e5cf07
--- /dev/null
+++ b/windows/win32s/dialogs/StatisticsDlg.cpp
@@ -0,0 +1,170 @@
+// StatisticsDlg.cpp : implementation file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+#include "stdafx.h"
+#include "..\Tinelix IRC.h"
+#include "MainDlg.h"
+#include "StatisticsDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CStatisticsDlg dialog
+
+
+CStatisticsDlg::CStatisticsDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CStatisticsDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CStatisticsDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+}
+
+
+void CStatisticsDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CStatisticsDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CStatisticsDlg, CDialog)
+ //{{AFX_MSG_MAP(CStatisticsDlg)
+ ON_WM_TIMER()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+HINSTANCE wsaWrapper;
+struct NetworkStatistics {
+ int packets_read;
+ int packets_sent;
+ int total_bytes_sent;
+ int total_bytes_read;
+ } NetworkStats;
+typedef NetworkStatistics (WINAPI *GetNetworkStatistics) ();
+NetworkStatistics stats;
+GetNetworkStatistics GetNetworkStats;
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CStatisticsDlg message handlers
+
+BOOL CStatisticsDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CStatisticsDlg::SetWSAWrapper(HINSTANCE wrapper) {
+ wsaWrapper = wrapper;
+ if(wsaWrapper) {
+ GetNetworkStats = (GetNetworkStatistics)GetProcAddress(wsaWrapper, MAKEINTRESOURCE(21));
+ stats = (NetworkStatistics)(*GetNetworkStats)();
+ SetStatisticsData(stats);
+ SetTimer(0x8A001, 1000, (TIMERPROC)NULL);
+ }
+}
+
+void CStatisticsDlg::SetStatisticsData(NetworkStatistics stats) {
+ int total_bytes = stats.total_bytes_sent + stats.total_bytes_read;
+ int total_packets = stats.packets_sent + stats.packets_read;
+
+ CWnd* packets_sent_counter = (CWnd*)GetDlgItem(IDC_PACKETS_SENT_VALUE);
+ CWnd* packets_read_counter = (CWnd*)GetDlgItem(IDC_PACKETS_READ_VALUE);
+ CWnd* total_packets_counter = (CWnd*)GetDlgItem(IDC_TOTAL_PACKETS_VALUE);
+
+ CWnd* bytes_sent_counter = (CWnd*)GetDlgItem(IDC_BYTES_SENT_VALUE);
+ CWnd* bytes_read_counter = (CWnd*)GetDlgItem(IDC_BYTES_READ_VALUE);
+ CWnd* total_bytes_counter = (CWnd*)GetDlgItem(IDC_TOTAL_BYTES_VALUE);
+
+ CString packets_sent = CString("");
+ CString packets_read = CString("");
+ CString total_packets_str = CString("");
+ CString bytes_sent = CString("");
+ CString bytes_read = CString("");
+ CString total_bytes_str = CString("");
+
+ packets_sent.Format("%d packet(s)", stats.packets_sent);
+ packets_read.Format("%d packet(s)", stats.packets_read);
+ total_packets_str.Format("%d packet(s)", total_packets);
+
+ if(total_bytes >= 1048576) {
+ bytes_sent.Format("%.2f MB", (float)(stats.total_bytes_sent) / 1048576);
+ bytes_read.Format("%.2f MB", (float)(stats.total_bytes_read) / 1048576);
+ total_bytes_str.Format("%.2f MB", (float)(total_bytes) / 1048576);
+ } else if(total_bytes >= 1024) {
+ bytes_sent.Format("%.2f kB", (float)(stats.total_bytes_sent) / 1024);
+ bytes_read.Format("%.2f kB", (float)(stats.total_bytes_read) / 1024);
+ total_bytes_str.Format("%.2f kB", (float)(total_bytes) / 1024);
+ } else {
+ bytes_sent.Format("%d bytes", stats.total_bytes_sent);
+ bytes_read.Format("%d bytes", stats.total_bytes_read);
+ total_bytes_str.Format("%d bytes", total_bytes);
+ }
+
+ packets_sent_counter->SetWindowText(packets_sent);
+ packets_read_counter->SetWindowText(packets_read);
+ total_packets_counter->SetWindowText(total_packets_str);
+
+ bytes_read_counter->SetWindowText(bytes_read);
+ bytes_sent_counter->SetWindowText(bytes_sent);
+ total_bytes_counter->SetWindowText(total_bytes_str);
+}
+
+void CStatisticsDlg::SetConnectionQuality(int ping_value) {
+ if(CIRCApplication::CheckIsWin32s) {
+ if(wsaWrapper) {
+ GetNetworkStats = (GetNetworkStatistics)GetProcAddress(wsaWrapper, MAKEINTRESOURCE(21));
+ stats = (NetworkStatistics)(*GetNetworkStats)();
+ SetStatisticsData(stats);
+ }
+ }
+ CString quality_percent = CString("");
+ int reserve_value = 10000 - ping_value;
+ if(reserve_value < 0) {
+ reserve_value = -reserve_value;
+ }
+ int ping_strength = reserve_value / 100;
+ CProgressCtrl* ping_strength_progress = (CProgressCtrl*)GetDlgItem(IDC_PING_STRENGTH);
+ ping_strength_progress->SetPos(ping_strength);
+ CWnd* ping_strength_counter = GetDlgItem(IDC_CONNQUALITY_VALUE);
+ quality_percent.Format("%d%%", ping_strength);
+ ping_strength_counter->SetWindowText(quality_percent);
+}
+
+void CStatisticsDlg::OnTimer(UINT nIDEvent)
+{
+ if(nIDEvent == 0x8A001) {
+ if(wsaWrapper) {
+ GetNetworkStats = (GetNetworkStatistics)GetProcAddress(wsaWrapper, MAKEINTRESOURCE(21));
+ stats = (NetworkStatistics)(*GetNetworkStats)();
+ SetStatisticsData(stats);
+ }
+ }
+
+ CDialog::OnTimer(nIDEvent);
+}
diff --git a/windows/win32s/dialogs/StatisticsDlg.h b/windows/win32s/dialogs/StatisticsDlg.h
new file mode 100644
index 0000000..c6671a5
--- /dev/null
+++ b/windows/win32s/dialogs/StatisticsDlg.h
@@ -0,0 +1,57 @@
+// StatisticsDlg.h : header file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+/////////////////////////////////////////////////////////////////////////////
+// CStatisticsDlg dialog
+
+class CStatisticsDlg : public CDialog
+{
+// Construction
+
+public:
+ CStatisticsDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CStatisticsDlg)
+ enum { IDD = IDD_STATSDIALOG };
+ // NOTE: the ClassWizard will add data members here
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CStatisticsDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+public:
+ void SetStatisticsData(struct NetworkStatistics stats);
+ void SetConnectionQuality(int ping_value);
+ void SetWSAWrapper(HINSTANCE wrapper);
+ // Generated message map functions
+ //{{AFX_MSG(CStatisticsDlg)
+ afx_msg void OnTimer(UINT nIDEvent);
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/windows/win32s/dialogs/TextBoxDlg.cpp b/windows/win32s/dialogs/TextBoxDlg.cpp
new file mode 100644
index 0000000..f065443
--- /dev/null
+++ b/windows/win32s/dialogs/TextBoxDlg.cpp
@@ -0,0 +1,93 @@
+// TextBoxDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "..\Tinelix IRC.h"
+#include "TextBoxDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CTextBoxDlg dialog
+
+
+CTextBoxDlg::CTextBoxDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CTextBoxDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CTextBoxDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+}
+
+
+void CTextBoxDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CTextBoxDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CTextBoxDlg, CDialog)
+ //{{AFX_MSG_MAP(CTextBoxDlg)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+int action;
+
+/////////////////////////////////////////////////////////////////////////////
+// CTextBoxDlg message handlers
+
+BOOL CTextBoxDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ if(action == 0) { // if creating profile
+ CWnd* title = (CWnd*)GetDlgItem(IDC_EDITTEXT);
+ title->SetWindowText("Profile name:");
+ }
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CTextBoxDlg::SetAction(int _action) {
+ action = _action;
+}
+
+void CTextBoxDlg::CreateProfile() {
+ CIRCApplication* app = (CIRCApplication*)AfxGetApp();
+ CEdit* text_area = (CEdit*)GetDlgItem(IDC_EDITTEXTAREA);
+ CString profile_name = "";
+ text_area->GetWindowText(profile_name);
+ char app_path[256];
+ sprintf(app_path, app->GetAppPath());
+ CString profile_path = "";
+ profile_path.Format("%s\\profiles\\%s.ini", app_path, profile_name);
+ WritePrivateProfileString("Main", "ProfileName", profile_name, profile_path);
+ WritePrivateProfileString("Main", "MainNick", "irc_member", profile_path);
+ WritePrivateProfileString("Main", "Server", "irc.tinelix.ru", profile_path);
+ WritePrivateProfileString("Main", "Port", "6667", profile_path);
+ if((UINT)ShellExecute(
+ NULL, "open", "notepad.exe", profile_path, NULL, SW_SHOWNORMAL) <= 32) {
+ MessageBox("Notepad not found. "
+ "Use another editor to modify this configuration file.",
+ "Error", MB_OK | MB_ICONSTOP);
+ }
+}
+
+void CTextBoxDlg::OnOK()
+{
+ if(action == 0) {
+ CreateProfile();
+ }
+
+ CDialog::OnOK();
+}
+
+
diff --git a/windows/win32s/dialogs/TextBoxDlg.h b/windows/win32s/dialogs/TextBoxDlg.h
new file mode 100644
index 0000000..c57865f
--- /dev/null
+++ b/windows/win32s/dialogs/TextBoxDlg.h
@@ -0,0 +1,37 @@
+// TextBoxDlg.h : header file
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CTextBoxDlg dialog
+
+class CTextBoxDlg : public CDialog
+{
+// Construction
+public:
+ CTextBoxDlg(CWnd* pParent = NULL); // standard constructor
+ void SetAction(int _action);
+
+// Dialog Data
+ //{{AFX_DATA(CTextBoxDlg)
+ enum { IDD = IDD_TEXTDIALOG };
+ // NOTE: the ClassWizard will add data members here
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CTextBoxDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ void CreateProfile();
+ // Generated message map functions
+ //{{AFX_MSG(CTextBoxDlg)
+ virtual void OnOK();
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/windows/win32s/libs/IRCParser/Debug/ircpars.dll b/windows/win32s/libs/IRCParser/Debug/ircpars.dll
new file mode 100644
index 0000000..bcababe
Binary files /dev/null and b/windows/win32s/libs/IRCParser/Debug/ircpars.dll differ
diff --git a/windows/win32s/libs/IRCParser/IRCParser.aps b/windows/win32s/libs/IRCParser/IRCParser.aps
new file mode 100644
index 0000000..ed238fa
Binary files /dev/null and b/windows/win32s/libs/IRCParser/IRCParser.aps differ
diff --git a/windows/win32s/libs/IRCParser/IRCParser.cpp b/windows/win32s/libs/IRCParser/IRCParser.cpp
new file mode 100644
index 0000000..66bcbf2
--- /dev/null
+++ b/windows/win32s/libs/IRCParser/IRCParser.cpp
@@ -0,0 +1,242 @@
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// Tinelix IRC Parser files is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+#include
+#include
+#include "IRCParser.h"
+
+BOOL is_win32s;
+int MAX_WORDS_COUNT = 512;
+
+int WINAPI DllMain(HINSTANCE hInst, DWORD fdReas, PVOID pvRes) {
+ switch(fdReas) {
+ case DLL_PROCESS_ATTACH:
+ // Checking if it's Win32s
+ if(GetVersion() & 0x80000000 && (GetVersion() & 0xFF) == 3) {
+ is_win32s = TRUE;
+ } else {
+ is_win32s = FALSE;
+ }
+ if(!is_win32s) {
+ OutputDebugString("\r\nTinelix IRC Parser - Win32 DLL"
+ "\r\nCopyright © 2023 Dmitry Tretyakov (aka. Tinelix)."
+ "\r\nLicensed as part of Tinelix IRC Client under GPLv3."
+ "\r\nSource code: "
+ "https://github.com/tinelix/irc-client-win32s\r\n");
+ }
+ break;
+ case DLL_PROCESS_DETACH:
+ if(!is_win32s) {
+ OutputDebugString("\r\nIRC Parser is shutting down...\r\n");
+ }
+ break;
+
+ }
+
+ return TRUE;
+}
+
+EXPORT char* CALLBACK ParseLine(char* original_line, int length) {
+ char* line = new char[length];
+ original_line[length] = 0;
+ strcpy(line, original_line);
+ char debug_parsed_line[4096];
+ char parsed_line[4096];
+ char words[512][512];
+ if(strlen(original_line) > 0) {
+ try {
+ char prefix[80];
+ char command[60];
+ char params[256];
+ char body[1536];
+ char* token = strtok(line, " ");
+ int spaces = 0;
+ int body_index;
+ while(token != NULL) {
+ if(token[0] == ':') {
+ sprintf(words[spaces], token + 1);
+ } else {
+ sprintf(words[spaces], token);
+ }
+ if(spaces == 0) {
+ sprintf(prefix, words[spaces]);
+ } else if(spaces == 1) {
+ sprintf(command, words[spaces]);
+ } else if(spaces == 2) {
+ sprintf(params, words[spaces]);
+ } else if(spaces == 3) {
+ sprintf(body, words[spaces]);
+ body_index = strlen(body);
+ } else {
+ body_index += sprintf(body + body_index, " %s", words[spaces]);
+ }
+ token = strtok(NULL, " ");
+ spaces++;
+ }
+ if(spaces > 2) {
+ if(strcmp(command, "372") == 0) {
+ if(original_line[0] == ':') {
+ sprintf(body, original_line +
+ strlen(prefix) + strlen(command) + strlen(params) + 5);
+ } else {
+ sprintf(body, original_line +
+ strlen(prefix) + strlen(command) + strlen(params) + 4);
+ }
+ body[strlen(original_line) -
+ (strlen(prefix) + strlen(command) + strlen(params) + 5)] = '\0';
+ sprintf(parsed_line, "[MOTD] %s\r\n", body);
+ } else if(strcmp(command, "396") == 0) {
+ sprintf(parsed_line, "[396] %s@%s\r\n", params, body);
+ } else if(strcmp(command, "001") == 0) {
+ sprintf(parsed_line, "[001] %s\r\n", body);
+ } else if(strcmp(command, "002") == 0) {
+ sprintf(parsed_line, "[002] %s\r\n", body);
+ } else if(strcmp(command, "003") == 0) {
+ sprintf(parsed_line, "[003] %s\r\n", body);
+ } else if(strcmp(command, "004") == 0) {
+ sprintf(parsed_line, "[004] %s\r\n", body);
+ } else if(strcmp(command, "005") == 0) {
+ sprintf(parsed_line, "[005] %s\r\n", body);
+ } else if(strcmp(command, "End") == 0) {
+ sprintf(parsed_line, "--------------------"
+ "------------------------------\r\n");
+ } else if(strcmp(prefix, "ERROR") == 0) {
+ sprintf(parsed_line, "[%s] %s %s\r\n", prefix, command, body);
+ } else if(strcmp(command, "PRIVMSG") == 0) {
+ for(int prefix_index = 0; prefix_index < strlen(prefix);
+ prefix_index++) {
+ if(prefix_index > 0) {
+ if(prefix[prefix_index] == '!') {
+ prefix[prefix_index] = '\0';
+ }
+ }
+ prefix_index++;
+ }
+ sprintf(parsed_line, "[%s] %s: %s\r\n", params, prefix, body);
+ } else if(strlen(command) == 3 && isdigit(command[0]) != 0
+ && isdigit(command[1]) != 0 && isdigit(command[2]) != 0) {
+ sprintf(parsed_line, "[%s] %s %s\r\n", command, params, body);
+ } else {
+ sprintf(parsed_line, "[%s] %s\r\n", command, body);
+ }
+ } else if(spaces > 0) {
+ sprintf(parsed_line, "[RAW] [%s]\r\n", original_line);
+ } else {
+ sprintf(parsed_line, "[Parsing error]\r\n");
+ }
+ return parsed_line;
+ } catch(...) {
+ sprintf(parsed_line, "[Parsing error]\r\n");
+ return parsed_line;
+ }
+ } else {
+ sprintf(parsed_line, "");
+ return parsed_line;
+ }
+}
+
+EXPORT char* CALLBACK ParsePacket(char original_packet[4096]) {
+ char* packet = "";
+ char* line = "";
+ char* token = "";
+ char debug_parsed_line[800];
+ int lines_count = 0;
+ int lines_index = 0;
+ int lnlen[64];
+ int parsed_lines_count = 0;
+ char lines[64][4096];
+ char parsed_lines[64][4096];
+ char parsed_packet[4096];
+ char* token_s = "";
+
+ for(int i = 0; i < strlen(original_packet); i++) {
+ if(original_packet[i] == '\r') {
+
+ } else if(original_packet[i] == '\n') {
+ lnlen[lines_count] = lines_index;
+ lines_count++;
+ lines_index = 0;
+ } else {
+ lines[lines_count][lines_index] = original_packet[i];
+ lines_index++;
+ }
+ }
+
+ for(int line_index = 0; line_index < lines_count; line_index++) {
+ char* line;
+ line = new char[lnlen[lines_count]];
+ line = lines[line_index];
+ if(line != NULL) {
+ if(line_index == 0) {
+ strcpy(parsed_packet, ParseLine(line, lnlen[line_index]));
+ } else {
+ strcat(parsed_packet, ParseLine(line, lnlen[line_index]));
+ }
+ }
+ }
+ return parsed_packet;
+}
+
+EXPORT char* CALLBACK ParseSendingMessage(char* message, char* channel) {
+ char line[4096];
+ strcpy(line, message);
+ char parsed_line[4096];
+ char debug_parsed_line[4096];
+ char words[512][256];
+ if(message != NULL && message[0] >= 0) {
+ try {
+ char command[60];
+ char params[4096];
+ char body[4096];
+ char* token = strtok(line, " ");
+ int spaces = 0;
+ int body_index;
+ while(token != NULL) {
+ if(spaces == 0) {
+ sprintf(command, words[spaces]);
+ } else if(spaces == 1) {
+ sprintf(params, words[spaces]);
+ } else if(spaces == 2) {
+ sprintf(body, words[spaces]);
+ body_index = strlen(body);
+ } else {
+ body_index += sprintf(body + body_index, " %s", words[spaces]);
+ }
+ token = strtok(NULL, " ");
+ spaces++;
+ }
+ if(spaces > 2) {
+ if(strcmp(command, "/join") == 0 || strcmp(command, "/JOIN") == 0) {
+ sprintf(parsed_line, "JOIN %s\r\n", params);
+ } else if(strcmp(command, "/privmsg") == 0
+ || strcmp(command, "/PRIVMSG") == 0) {
+ sprintf(parsed_line, "PRIVMSG %s :%s\r\n", params, body);
+ }
+ } else {
+ if((strlen(channel) > 0 && channel[0] >= 0) || message[0] != '/') {
+ sprintf(parsed_line, "PRIVMSG %s :%s\r\n", channel, message);
+ } else {
+ sprintf(parsed_line, "%s\r\n", message + 1);
+ }
+ }
+
+ } catch(...) {
+
+ }
+ }
+ return parsed_line;
+}
diff --git a/windows/win32s/libs/IRCParser/IRCParser.def b/windows/win32s/libs/IRCParser/IRCParser.def
new file mode 100644
index 0000000..0ca8bf3
--- /dev/null
+++ b/windows/win32s/libs/IRCParser/IRCParser.def
@@ -0,0 +1,7 @@
+LIBRARY "Tinelix IRC Parser"
+DESCRIPTION "IRC Parser special for Tinelix IRC"
+
+EXPORTS
+ParseLine @1
+ParsePacket @2
+ParseSendingMessage @3
\ No newline at end of file
diff --git a/windows/win32s/libs/IRCParser/IRCParser.h b/windows/win32s/libs/IRCParser/IRCParser.h
new file mode 100644
index 0000000..bc9d02f
--- /dev/null
+++ b/windows/win32s/libs/IRCParser/IRCParser.h
@@ -0,0 +1,21 @@
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// Tinelix IRC Parser files is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+#define EXPORT extern "C" __declspec (dllexport)
+
+EXPORT char* CALLBACK ParseLine(char* original_line, int length);
+EXPORT char* CALLBACK ParsePacket(char original_packet[4096]);
\ No newline at end of file
diff --git a/windows/win32s/libs/IRCParser/IRCParser.rc b/windows/win32s/libs/IRCParser/IRCParser.rc
new file mode 100644
index 0000000..11033ba
--- /dev/null
+++ b/windows/win32s/libs/IRCParser/IRCParser.rc
@@ -0,0 +1,106 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+#ifdef _WIN32
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+#endif //_WIN32
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,0,1,0
+ PRODUCTVERSION 0,0,1,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x21L
+#else
+ FILEFLAGS 0x20L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e3"
+ BEGIN
+ VALUE "CompanyName", "Tinelix\0"
+ VALUE "FileDescription", "Tinelix IRC Parser - DLL as Tinelix IRC App Extension\0"
+ VALUE "FileVersion", "0.0.1\0"
+ VALUE "InternalName", "Tinelix IRC Parser\0"
+ VALUE "LegalCopyright", "Copyright © 2023 Dmitry Tretyakov (aka. Tinelix). Licensed under GPLv3.\0"
+ VALUE "OriginalFilename", "ircpars.dll\0"
+ VALUE "ProductName", "Tinelix IRC Parser\0"
+ VALUE "ProductVersion", "0.0.1\0"
+ VALUE "SpecialBuild", "Source code: https://github.com/tinelix/irc-client-win32s\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1251
+ END
+END
+
+#endif // !_MAC
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Russian resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/windows/win32s/libs/IRCParser/Tinelix IRC Parser.mak b/windows/win32s/libs/IRCParser/Tinelix IRC Parser.mak
new file mode 100644
index 0000000..2b24988
--- /dev/null
+++ b/windows/win32s/libs/IRCParser/Tinelix IRC Parser.mak
@@ -0,0 +1,237 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+!IF "$(CFG)" == ""
+CFG=Tinelix IRC Parser - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to Tinelix IRC Parser - Win32\
+ Debug.
+!ENDIF
+
+!IF "$(CFG)" != "Tinelix IRC Parser - Win32 Release" && "$(CFG)" !=\
+ "Tinelix IRC Parser - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Tinelix IRC Parser.mak"\
+ CFG="Tinelix IRC Parser - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Tinelix IRC Parser - Win32 Release" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "Tinelix IRC Parser - Win32 Debug" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "Tinelix IRC Parser - Win32 Debug"
+MTL=mktyplib.exe
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "Tinelix IRC Parser - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(OUTDIR)\ircpars.dll"
+
+CLEAN :
+ -@erase ".\Release\ircpars.dll"
+ -@erase ".\Release\IRCParser.obj"
+ -@erase ".\Release\ircpars.lib"
+ -@erase ".\Release\ircpars.exp"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/Tinelix IRC Parser.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\Release/
+CPP_SBRS=
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/Tinelix IRC Parser.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/ircpars.dll"
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
+ /pdb:"$(OUTDIR)/ircpars.pdb" /machine:I386 /def:".\IRCParser.def"\
+ /out:"$(OUTDIR)/ircpars.dll" /implib:"$(OUTDIR)/ircpars.lib"
+DEF_FILE= \
+ ".\IRCParser.def"
+LINK32_OBJS= \
+ "$(INTDIR)/IRCParser.obj"
+
+"$(OUTDIR)\ircpars.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "Tinelix IRC Parser - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Tinelix_"
+# PROP BASE Intermediate_Dir "Tinelix_"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Tinelix_"
+# PROP Intermediate_Dir "Tinelix_"
+# PROP Target_Dir ""
+OUTDIR=.\Tinelix_
+INTDIR=.\Tinelix_
+
+ALL : "$(OUTDIR)\ircpars.dll"
+
+CLEAN :
+ -@erase ".\Tinelix_\vc40.pdb"
+ -@erase ".\Tinelix_\vc40.idb"
+ -@erase ".\Debug\ircpars.dll"
+ -@erase ".\Tinelix_\IRCParser.obj"
+ -@erase ".\Debug\ircpars.ilk"
+ -@erase ".\Tinelix_\ircpars.lib"
+ -@erase ".\Tinelix_\ircpars.exp"
+ -@erase ".\Tinelix_\ircpars.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/Tinelix IRC Parser.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\Tinelix_/
+CPP_SBRS=
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/Tinelix IRC Parser.bsc"
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Debug/ircpars.dll"
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:windows /dll /incremental:yes\
+ /pdb:"$(OUTDIR)/ircpars.pdb" /debug /machine:I386 /def:".\IRCParser.def"\
+ /out:"Debug/ircpars.dll" /implib:"$(OUTDIR)/ircpars.lib"
+DEF_FILE= \
+ ".\IRCParser.def"
+LINK32_OBJS= \
+ "$(INTDIR)/IRCParser.obj"
+
+"$(OUTDIR)\ircpars.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+################################################################################
+# Begin Target
+
+# Name "Tinelix IRC Parser - Win32 Release"
+# Name "Tinelix IRC Parser - Win32 Debug"
+
+!IF "$(CFG)" == "Tinelix IRC Parser - Win32 Release"
+
+!ELSEIF "$(CFG)" == "Tinelix IRC Parser - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\IRCParser.h
+
+!IF "$(CFG)" == "Tinelix IRC Parser - Win32 Release"
+
+!ELSEIF "$(CFG)" == "Tinelix IRC Parser - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\IRCParser.cpp
+DEP_CPP_IRCPA=\
+ ".\IRCParser.h"\
+
+
+"$(INTDIR)\IRCParser.obj" : $(SOURCE) $(DEP_CPP_IRCPA) "$(INTDIR)"
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\IRCParser.def
+
+!IF "$(CFG)" == "Tinelix IRC Parser - Win32 Release"
+
+!ELSEIF "$(CFG)" == "Tinelix IRC Parser - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/windows/win32s/libs/IRCParser/Tinelix IRC Parser.mdp b/windows/win32s/libs/IRCParser/Tinelix IRC Parser.mdp
new file mode 100644
index 0000000..6969602
Binary files /dev/null and b/windows/win32s/libs/IRCParser/Tinelix IRC Parser.mdp differ
diff --git a/windows/win32s/libs/IRCParser/Tinelix IRC Parser.ncb b/windows/win32s/libs/IRCParser/Tinelix IRC Parser.ncb
new file mode 100644
index 0000000..b7be383
Binary files /dev/null and b/windows/win32s/libs/IRCParser/Tinelix IRC Parser.ncb differ
diff --git a/windows/win32s/libs/IRCParser/resource.h b/windows/win32s/libs/IRCParser/resource.h
new file mode 100644
index 0000000..3e61b5e
--- /dev/null
+++ b/windows/win32s/libs/IRCParser/resource.h
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by IRCParser.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/windows/win32s/mfc_readme.txt b/windows/win32s/mfc_readme.txt
new file mode 100644
index 0000000..4e66285
--- /dev/null
+++ b/windows/win32s/mfc_readme.txt
@@ -0,0 +1,64 @@
+========================================================================
+ MICROSOFT FOUNDATION CLASS LIBRARY : Tinelix IRC
+========================================================================
+
+
+AppWizard has created this Tinelix IRC application for you. This application
+not only demonstrates the basics of using the Microsoft Foundation classes
+but is also a starting point for writing your application.
+
+This file contains a summary of what you will find in each of the files that
+make up your Tinelix IRC application.
+
+Tinelix IRC.h
+ This is the main header file for the application. It includes other
+ project specific headers (including Resource.h) and declares the
+ CIRCApplication application class.
+
+Tinelix IRC.cpp
+ This is the main application source file that contains the application
+ class CIRCApplication.
+
+Tinelix IRC.rc
+ This is a listing of all of the Microsoft Windows resources that the
+ program uses. It includes the icons, bitmaps, and cursors that are stored
+ in the RES subdirectory. This file can be directly edited in Microsoft
+ Developer Studio.
+
+res\Tinelix IRC.ico
+ This is an icon file, which is used as the application's icon. This
+ icon is included by the main resource file Tinelix IRC.rc.
+
+res\Tinelix IRC.rc2
+ This file contains resources that are not edited by Microsoft
+ Developer Studio. You should place all resources not
+ editable by the resource editor in this file.
+
+Tinelix IRC.clw
+ This file contains information used by ClassWizard to edit existing
+ classes or add new classes. ClassWizard also uses this file to store
+ information needed to create and edit message maps and dialog data
+ maps and to create prototype member functions.
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+AppWizard creates one dialog class:
+
+dialogs\MainDlg.h, dialogs\MainDlg.cpp - the dialog
+ These files contain your CMainDlg class. This class defines
+ the behavior of your application's main dialog. The dialog's
+ template is in Tinelix IRC.rc, which can be edited in Microsoft
+ Developer Studio.
+
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named Tinelix IRC.pch and a precompiled types file named StdAfx.obj.
+
+Resource.h
+ This is the standard header file, which defines new resource IDs.
+ Microsoft Developer Studio reads and updates this file.
diff --git a/windows/win32s/res/Tinelix IRC.ico b/windows/win32s/res/Tinelix IRC.ico
new file mode 100644
index 0000000..3d7b373
Binary files /dev/null and b/windows/win32s/res/Tinelix IRC.ico differ
diff --git a/windows/win32s/res/Tinelix IRC.rc2 b/windows/win32s/res/Tinelix IRC.rc2
new file mode 100644
index 0000000..0bb3b87
--- /dev/null
+++ b/windows/win32s/res/Tinelix IRC.rc2
@@ -0,0 +1,13 @@
+//
+// TINELIX IRC.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+ #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/windows/win32s/resource.h b/windows/win32s/resource.h
new file mode 100644
index 0000000..a1de20f
--- /dev/null
+++ b/windows/win32s/resource.h
@@ -0,0 +1,75 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Tinelix IRC.rc
+//
+#define IDM_ABOUTBOX 0x0010
+#define IDD_ABOUTBOX 100
+#define IDS_ABOUTBOX 101
+#define IDD_TINELIXIRC_DIALOG 102
+#define IDS_CONNECTION_FAILED_1 102
+#define IDS_TABS_THREAD 103
+#define IDS_APP_NAME 104
+#define IDR_MAINFRAME 128
+#define IDR_APPICON 128
+#define IDR_MAINMENU 129
+#define IDD_TABCHAT 131
+#define IDD_TABTHREAD 132
+#define IDD_MAINDIALOG 135
+#define IDD_CONNMANDIALOG 136
+#define IDD_TEXTDIALOG 137
+#define IDD_CONNECTION_PROGRESS 138
+#define IDD_STATSDIALOG 139
+#define IDC_CHAT_INPUT 1004
+#define IDC_CHAT_OUTPUT 1005
+#define IDC_CHAT_SEND_MSG 1006
+#define IDC_CHAT_MEMBERS 1007
+#define IDC_MAINDLG_TABS 1009
+#define IDC_CUSTOM1 1011
+#define IDC_PROFILE_LIST 1012
+#define IDC_CREATE_PROFILE 1013
+#define IDC_REMOVE_PROFILE 1014
+#define IDC_EDIT_PROFILE 1015
+#define IDC_PROFILES_GROUP 1016
+#define IDC_EDITTEXT 1017
+#define IDC_EDITTEXTAREA 1018
+#define IDC_PROGRESS 1019
+#define IDC_STATUS 1020
+#define IDC_PACKETS_GROUP 1023
+#define IDC_PACKETS_SENT_LABEL 1024
+#define IDC_PACKETS_SENT_VALUE 1025
+#define IDC_PACKETS_READ_LABEL 1026
+#define IDC_PACKETS_READ_VALUE 1027
+#define IDC_DATA_GROUP 1028
+#define IDC_TOTAL_PACKETS_LABEL 1029
+#define IDC_TOTAL_PACKETS_VALUE 1030
+#define IDC_CONNECTION_GROUP 1031
+#define IDC_BYTES_SENT_LABEL 1032
+#define IDC_BYTES_SENT_VALUE 1033
+#define IDC_READ_BYTES_LABEL 1034
+#define IDC_BYTES_READ_VALUE 1035
+#define IDC_TOTAL_BYTES_LABEL2 1036
+#define IDC_TOTAL_BYTES_VALUE 1037
+#define IDC_CONNQUALITY_LABEL 1038
+#define IDC_PING_STRENGTH 1039
+#define IDC_CONNQUALITY_VALUE 1040
+#define IDC_LICENSE 1043
+#define IDC_LICENSE2 1044
+#define IDC_SRC_CODE_ADDR 1045
+#define IDC_SRC_CODE 1046
+#define ID_FILE_CONNECT 32771
+#define ID_FILE_QUIT 32773
+#define ID_ABOUT 32774
+#define ID_CHANNEL_JOIN 32775
+#define ID_CHANNEL_LEAVE 32776
+#define ID_CONNECTION_STATISTICS 32777
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 140
+#define _APS_NEXT_COMMAND_VALUE 32778
+#define _APS_NEXT_CONTROL_VALUE 1047
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/windows/win32s/tabs/AppThreadTab.cpp b/windows/win32s/tabs/AppThreadTab.cpp
new file mode 100644
index 0000000..68b0dae
--- /dev/null
+++ b/windows/win32s/tabs/AppThreadTab.cpp
@@ -0,0 +1,111 @@
+// appthreadtab.cpp : implementation file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+#include "stdafx.h"
+#include "..\Tinelix IRC.h"
+#include "..\dialogs\MainDlg.h"
+#include "AppThreadTab.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+CWnd* parent;
+
+/////////////////////////////////////////////////////////////////////////////
+// CAppThreadTab dialog
+
+
+CAppThreadTab::CAppThreadTab(CWnd* pParent /*=NULL*/)
+ : CDialog(CAppThreadTab::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CAppThreadTab)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+}
+
+
+void CAppThreadTab::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CAppThreadTab)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CAppThreadTab, CDialog)
+ //{{AFX_MSG_MAP(CAppThreadTab)
+ ON_BN_CLICKED(IDC_CHAT_SEND_MSG, OnChatSendMsg)
+ ON_WM_SIZE()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CAppThreadTab message handlers
+
+void CAppThreadTab::SetParentWnd(CWnd* _parent) {
+ parent = _parent;
+}
+
+void CAppThreadTab::OnChatSendMsg()
+{
+ CMainDlg mainDlg = AfxGetMainWnd();
+ CEdit* chat_output = (CEdit*)GetDlgItem(IDC_CHAT_OUTPUT);
+ CString message;
+ chat_output->GetWindowText(message);
+ if(message.GetLength() > 0) {
+ mainDlg.SendIRCMessage(parent);
+ }
+
+}
+
+void CAppThreadTab::OnSize(UINT nType, int cx, int cy)
+{
+ CDialog::OnSize(nType, cx, cy);
+
+ CRect rect;
+
+ GetWindowRect(&rect);
+
+ CEdit* chat_input = (CEdit*)GetDlgItem(IDC_CHAT_INPUT);
+ CEdit* chat_output = (CEdit*)GetDlgItem(IDC_CHAT_OUTPUT);
+ CButton* chat_send_message = (CButton*)GetDlgItem(IDC_CHAT_SEND_MSG);
+ if(chat_input != NULL) {
+ chat_input->MoveWindow(6, 5, rect.Width() - 12, rect.Height() - 38);
+ chat_output->MoveWindow(6, rect.Height() - 28, rect.Width() - 78, 23);
+ chat_send_message->MoveWindow(rect.Width() - 68, rect.Height() - 29, 63, 24);
+ }
+
+}
+
+void CAppThreadTab::OnOK()
+{
+ OnChatSendMsg();
+
+ //CDialog::OnOK();
+}
+
+void CAppThreadTab::OnCancel()
+{
+
+ //CDialog::OnCancel();
+}
diff --git a/windows/win32s/tabs/AppThreadTab.h b/windows/win32s/tabs/AppThreadTab.h
new file mode 100644
index 0000000..3e2ede3
--- /dev/null
+++ b/windows/win32s/tabs/AppThreadTab.h
@@ -0,0 +1,55 @@
+// appthreadtab.h : header file
+//
+// Copyright © 2023 Dmitry Tretyakov (aka. Tinelix)
+//
+// This file is part of Tinelix IRC Client.
+//
+// Tinelix IRC Client is free software: you can 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.
+// Tinelix IRC Client is distributed in the hope that it will be useful, but WITHOUT 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 https://www.gnu.org/licenses/.
+//
+// Source code: https://github.com/tinelix/irc-client-win32s
+
+/////////////////////////////////////////////////////////////////////////////
+// CAppThreadTab dialog
+
+class CAppThreadTab : public CDialog
+{
+// Construction
+public:
+ CAppThreadTab(CWnd* pParent = NULL); // standard constructor
+ void SetParentWnd(CWnd*);
+
+// Dialog Data
+ //{{AFX_DATA(CAppThreadTab)
+ enum { IDD = IDD_TABTHREAD };
+ // NOTE: the ClassWizard will add data members here
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CAppThreadTab)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CAppThreadTab)
+ afx_msg void OnChatSendMsg();
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+ virtual void OnOK();
+ virtual void OnCancel();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};