pax_global_header00006660000000000000000000000064125775523250014527gustar00rootroot0000000000000052 comment=60acf6f05be8f121b0d06b65cea484fd30ac7925 profanity-0.4.7/000077500000000000000000000000001257755232500135525ustar00rootroot00000000000000profanity-0.4.7/.gitignore000066400000000000000000000020161257755232500155410ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ # IDE .codelite/ profanity.mk profanity.project profanity.workspace compile_commands.json .tern-port .tern-project # autotools .libs/ Makefile Makefile.in _configs.sed aclocal.m4 autom4te.cache/ build-aux/ config.log config.status configure libprofanity.la libtool m4/ **/.deps/ **.dirstamp src/config.h src/config.h.in src/config.h.in~ src/gitversion.h src/gitversion.h.in src/stamp-h1 # binaries profanity **/*.o # test output tests/functionaltests/functionaltests tests/functionaltests/functionaltests.log tests/functionaltests/functionaltests.trs tests/unittests/unittests tests/unittests/unittests.log tests/unittests/unittests.trs test-suite.log # local scripts clean-test.sh gen_docs.sh gitpushall.sh # website files main_fragment.html toc_fragment.html # valgrind files valgrind.out profanity-0.4.7/.travis.yml000066400000000000000000000020571257755232500156670ustar00rootroot00000000000000language: c install: - lsb_release -a - uname -a - sudo apt-get update - sudo apt-get -y install libssl-dev libexpat1-dev libncursesw5-dev libglib2.0-dev libnotify-dev libcurl3-dev libxss-dev libotr2-dev libgpgme11-dev uuid-dev expect-dev tcl-dev - git clone git://github.com/strophe/libstrophe.git - cd libstrophe - mkdir m4 - ./bootstrap.sh - ./configure --prefix=/usr - make - sudo make install - cd .. - rm -rf libstrophe - wget https://cmocka.org/files/1.0/cmocka-1.0.0.tar.xz - tar -xvf cmocka-1.0.0.tar.xz - cd cmocka-1.0.0 - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug .. - make - sudo make install - cd ../.. - rm -rf cmocka-1.0.0 - sudo apt-get install libmicrohttpd-dev - git clone git://github.com/boothj5/stabber.git - cd stabber - ./bootstrap.sh - ./configure --prefix=/usr - make - sudo make install - cd .. - rm -rf stabber - ./bootstrap.sh script: ./configure && make && make check profanity-0.4.7/CHANGELOG000066400000000000000000000023571257755232500147730ustar00rootroot000000000000000.4.7 ===== - GNU Readline - OpenPGP support - Message Carbons (xep-0280) - Message Delivery Receipts (xep-0184) - MUC Mediated Invitation support - Configurable time formatting - Option to show JIDs in roster - Option to hide empty groups in roster - Generate UUID for unnamed new MUC rooms - Themable UI preference to indicate OTR and PGP messages - Reformatted help - devel: Added functional tests using libexpect and libstabber 0.4.6 ===== - 16 colour support (/theme colours) - UI preferences included in themes - /wrap - Word wrapping - /time - Show/hide time in main window, and configure precision - /roster - Show/hide and customise roster panel - /roster and /occupants panel size settings (% of screen width) - /account default - Set default account for /connect - /account remove - /presence - Show/hide contact presence in titlebar - /resource - Override resource during chat, resource display settings - Improved chat session handling - Lower CPU usage with dynamic input blocking timeout - Keychain/keyring integration using account eval_password property - Disable term window title by default - Fixed remote code execution bug on OSX when desktop notifications configured to show message text profanity-0.4.7/COPYING000066400000000000000000001045131257755232500146110ustar00rootroot00000000000000 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 . profanity-0.4.7/LICENSE.txt000066400000000000000000000017561257755232500154060ustar00rootroot00000000000000Profanity Copyright (C) 2012 - 2015 James Booth Profanity 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. Profanity 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 Profanity. If not, see . There is an additional exception from the author permitting linking with OpenSSL: As copyright holder, I give permission for profanity to be linked to the OpenSSL libraries. This includes permission for profanity binaries to be distributed linked against the OpenSSL libraries. All other obligations under the GPL v3 remain intact. profanity-0.4.7/Makefile.am000066400000000000000000000174601257755232500156160ustar00rootroot00000000000000core_sources = \ src/contact.c src/contact.h src/log.c src/common.c \ src/log.h src/profanity.c src/common.h \ src/profanity.h src/chat_session.c \ src/chat_session.h src/muc.c src/muc.h src/jid.h src/jid.c \ src/chat_state.h src/chat_state.c \ src/resource.c src/resource.h \ src/roster_list.c src/roster_list.h \ src/xmpp/xmpp.h src/xmpp/capabilities.c src/xmpp/connection.c \ src/xmpp/iq.c src/xmpp/message.c src/xmpp/presence.c src/xmpp/stanza.c \ src/xmpp/stanza.h src/xmpp/message.h src/xmpp/iq.h src/xmpp/presence.h \ src/xmpp/capabilities.h src/xmpp/connection.h \ src/xmpp/roster.c src/xmpp/roster.h \ src/xmpp/bookmark.c src/xmpp/bookmark.h \ src/xmpp/form.c src/xmpp/form.h \ src/event/server_events.c src/event/server_events.h \ src/event/client_events.c src/event/client_events.h \ src/event/ui_events.c src/event/ui_events.h \ src/ui/ui.h src/ui/window.c src/ui/window.h src/ui/core.c \ src/ui/titlebar.c src/ui/statusbar.c src/ui/inputwin.c \ src/ui/titlebar.h src/ui/statusbar.h src/ui/inputwin.h \ src/ui/console.c src/ui/notifier.c \ src/ui/win_types.h \ src/window_list.c src/window_list.h \ src/ui/rosterwin.c src/ui/occupantswin.c \ src/ui/buffer.c src/ui/buffer.h \ src/command/command.h src/command/command.c \ src/command/commands.h src/command/commands.c \ src/tools/parser.c \ src/tools/parser.h \ src/tools/p_sha1.h src/tools/p_sha1.c \ src/tools/autocomplete.c src/tools/autocomplete.h \ src/tools/tinyurl.c src/tools/tinyurl.h \ src/config/accounts.c src/config/accounts.h \ src/config/account.c src/config/account.h \ src/config/preferences.c src/config/preferences.h \ src/config/theme.c src/config/theme.h unittest_sources = \ src/contact.c src/contact.h src/common.c \ src/log.h src/profanity.c src/common.h \ src/profanity.h src/chat_session.c \ src/chat_session.h src/muc.c src/muc.h src/jid.h src/jid.c \ src/resource.c src/resource.h \ src/chat_state.h src/chat_state.c \ src/roster_list.c src/roster_list.h \ src/xmpp/xmpp.h src/xmpp/form.c \ src/ui/ui.h \ src/otr/otr.h \ src/pgp/gpg.h \ src/command/command.h src/command/command.c \ src/command/commands.h src/command/commands.c \ src/tools/parser.c \ src/tools/parser.h \ src/tools/p_sha1.h src/tools/p_sha1.c \ src/tools/autocomplete.c src/tools/autocomplete.h \ src/tools/tinyurl.c src/tools/tinyurl.h \ src/config/accounts.h \ src/config/account.c src/config/account.h \ src/config/preferences.c src/config/preferences.h \ src/config/theme.c src/config/theme.h \ src/window_list.c src/window_list.h \ src/event/server_events.c src/event/server_events.h \ src/event/client_events.c src/event/client_events.h \ src/event/ui_events.c src/event/ui_events.h \ tests/unittests/xmpp/stub_xmpp.c \ tests/unittests/ui/stub_ui.c \ tests/unittests/log/stub_log.c \ tests/unittests/config/stub_accounts.c \ tests/unittests/helpers.c tests/unittests/helpers.h \ tests/unittests/test_form.c tests/unittests/test_form.h \ tests/unittests/test_common.c tests/unittests/test_common.h \ tests/unittests/test_autocomplete.c tests/unittests/test_autocomplete.h \ tests/unittests/test_jid.c tests/unittests/test_jid.h \ tests/unittests/test_parser.c tests/unittests/test_parser.h \ tests/unittests/test_roster_list.c tests/unittests/test_roster_list.h \ tests/unittests/test_chat_session.c tests/unittests/test_chat_session.h \ tests/unittests/test_contact.c tests/unittests/test_contact.h \ tests/unittests/test_preferences.c tests/unittests/test_preferences.h \ tests/unittests/test_server_events.c tests/unittests/test_server_events.h \ tests/unittests/test_muc.c tests/unittests/test_muc.h \ tests/unittests/test_cmd_statuses.c tests/unittests/test_cmd_statuses.h \ tests/unittests/test_cmd_alias.c tests/unittests/test_cmd_alias.h \ tests/unittests/test_cmd_connect.c tests/unittests/test_cmd_connect.h \ tests/unittests/test_cmd_rooms.c tests/unittests/test_cmd_rooms.h \ tests/unittests/test_cmd_account.c tests/unittests/test_cmd_account.h \ tests/unittests/test_cmd_sub.c tests/unittests/test_cmd_sub.h \ tests/unittests/test_cmd_bookmark.c tests/unittests/test_cmd_bookmark.h \ tests/unittests/test_cmd_otr.c tests/unittests/test_cmd_otr.h \ tests/unittests/test_cmd_pgp.c tests/unittests/test_cmd_pgp.h \ tests/unittests/test_cmd_join.c tests/unittests/test_cmd_join.h \ tests/unittests/test_cmd_roster.c tests/unittests/test_cmd_roster.h \ tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \ tests/unittests/unittests.c functionaltest_sources = \ tests/functionaltests/proftest.c tests/functionaltests/proftest.h \ tests/functionaltests/test_connect.c tests/functionaltests/test_connect.h \ tests/functionaltests/test_ping.c tests/functionaltests/test_ping.h \ tests/functionaltests/test_rooms.c tests/functionaltests/test_rooms.h \ tests/functionaltests/test_presence.c tests/functionaltests/test_presence.h \ tests/functionaltests/test_message.c tests/functionaltests/test_message.h \ tests/functionaltests/test_chat_session.c tests/functionaltests/test_chat_session.h \ tests/functionaltests/test_carbons.c tests/functionaltests/test_carbons.h \ tests/functionaltests/test_receipts.c tests/functionaltests/test_receipts.h \ tests/functionaltests/test_roster.c tests/functionaltests/test_roster.h \ tests/functionaltests/test_software.c tests/functionaltests/test_software.h \ tests/functionaltests/functionaltests.c main_source = src/main.c git_include = src/gitversion.h pgp_sources = \ src/pgp/gpg.h src/pgp/gpg.c pgp_unittest_sources = \ tests/unittests/pgp/stub_gpg.c otr3_sources = \ src/otr/otrlib.h src/otr/otrlibv3.c src/otr/otr.h src/otr/otr.c otr4_sources = \ src/otr/otrlib.h src/otr/otrlibv4.c src/otr/otr.h src/otr/otr.c otr_unittest_sources = \ tests/unittests/otr/stub_otr.c themes_sources = themes/* script_sources = bootstrap.sh configure-debug install-all.sh man_sources = docs/profanity.1 if BUILD_PGP core_sources += $(pgp_sources) unittest_sources += $(pgp_unittest_sources) endif if BUILD_OTR unittest_sources += $(otr_unittest_sources) if BUILD_OTR3 core_sources += $(otr3_sources) endif if BUILD_OTR4 core_sources += $(otr4_sources) endif endif bin_PROGRAMS = profanity profanity_SOURCES = $(core_sources) $(main_source) if THEMES_INSTALL profanity_themesdir = @THEMES_PATH@ profanity_themes_DATA = $(themes_sources) endif if INCLUDE_GIT_VERSION BUILT_SOURCES = $(git_include) endif TESTS = tests/unittests/unittests check_PROGRAMS = tests/unittests/unittests tests_unittests_unittests_SOURCES = $(unittest_sources) tests_unittests_unittests_CFLAGS = -w tests_unittests_unittests_LDADD = -lcmocka if HAVE_STABBER if HAVE_EXPECT TESTS += tests/functionaltests/functionaltests check_PROGRAMS += tests/functionaltests/functionaltests tests_functionaltests_functionaltests_SOURCES = $(functionaltest_sources) tests_functionaltests_functionaltests_CFLAGS = -I/usr/include/tcl8.6 -I/usr/include/tcl8.5 tests_functionaltests_functionaltests_LDADD = -lcmocka -lstabber -lexpect -ltcl endif endif man_MANS = $(man_sources) EXTRA_DIST = $(man_sources) $(themes_sources) $(script_sources) profrc.example LICENSE.txt if INCLUDE_GIT_VERSION EXTRA_DIST += .git/HEAD .git/index $(git_include).in: .git/HEAD .git/index rm -f $@ echo "#ifndef PROF_GIT_BRANCH" >> $@ echo "#define PROF_GIT_BRANCH \"$(shell git rev-parse --symbolic-full-name --abbrev-ref HEAD)\"" >> $@ echo "#endif" >> $@ echo "#ifndef PROF_GIT_REVISION" >> $@ echo "#define PROF_GIT_REVISION \"$(shell git log --pretty=format:'%h' -n 1)\"" >> $@ echo "#endif" >> $@ # # Create $(git_include) atomically to catch possible race. The race can occur # when $(git_include) is generated in parallel with building of src/profanity.c. # So this hack allows to find and fix the problem earlier. # $(git_include): $(git_include).in cp $< $@ clean-local: rm -f $(git_include) $(git_include).in endif check-unit: tests/unittests/unittests tests/unittests/unittests profanity-0.4.7/README.md000066400000000000000000000010071257755232500150270ustar00rootroot00000000000000Profanity [![Build Status](https://travis-ci.org/boothj5/profanity.png?branch=master)](https://travis-ci.org/boothj5/profanity) ========= Profanity is a console based XMPP client inspired by [Irssi](http://www.irssi.org/), ![alt tag](http://www.profanity.im/images/prof-1.png) See the [User Guide](http://www.profanity.im/userguide.html) for information on installing, upgrading and using Profanity. Links ----- Homepage: http://www.profanity.im Mailing List: https://groups.google.com/forum/#!forum/profanitydev profanity-0.4.7/bootstrap.sh000077500000000000000000000000401257755232500161200ustar00rootroot00000000000000#!/bin/sh autoreconf --install profanity-0.4.7/configure-debug000077500000000000000000000000761257755232500165500ustar00rootroot00000000000000#!/bin/sh ./configure CFLAGS='-g3 -O0' CXXFLAGS='-g3 -O0' $@ profanity-0.4.7/configure.ac000066400000000000000000000263431257755232500160500ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_INIT([profanity], [0.4.7], [boothj5web@gmail.com]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([foreign subdir-objects]) ### Checks for programs. AC_PROG_CC ## Check for LFS AC_SYS_LARGEFILE ### Get canonical host AC_CANONICAL_HOST PLATFORM="unknown" AS_CASE([$host_os], [freebsd*], [PLATFORM="freebsd"], [darwin*], [PLATFORM="osx"], [cygwin], [PLATFORM="cygwin"], [PLATFORM="nix"]) PACKAGE_STATUS="release" ### Get git branch and revision if in development if test "x$PACKAGE_STATUS" = xdevelopment; then AM_CONDITIONAL([INCLUDE_GIT_VERSION], [true]) AC_DEFINE([HAVE_GIT_VERSION], [1], [Include git info]) else AM_CONDITIONAL([INCLUDE_GIT_VERSION], [false]) fi AC_DEFINE_UNQUOTED([PACKAGE_STATUS], ["$PACKAGE_STATUS"], [Status of this build]) AS_IF([test "x$PLATFORM" = xcygwin], [AC_DEFINE([PLATFORM_CYGWIN], [1], [Cygwin])]) AS_IF([test "x$PLATFORM" = xosx], [AC_DEFINE([PLATFORM_OSX], [1], [OSx])]) ### Options AC_ARG_ENABLE([notifications], [AS_HELP_STRING([--enable-notifications], [enable desktop notifications])]) AC_ARG_ENABLE([otr], [AS_HELP_STRING([--enable-otr], [enable otr encryption])]) AC_ARG_ENABLE([pgp], [AS_HELP_STRING([--enable-pgp], [enable pgp])]) AC_ARG_WITH([libxml2], [AS_HELP_STRING([--with-libxml2], [link with libxml2 instead of expat])]) AC_ARG_WITH([xscreensaver], [AS_HELP_STRING([--with-xscreensaver], [use libXScrnSaver to determine idle time])]) AC_ARG_WITH([themes], [AS_HELP_STRING([--with-themes[[=PATH]]], [install themes (default yes)])]) # Use the CFLAGS and libs provided by libstrophe.pc if libstrophe has pkg-config support. PKG_CHECK_MODULES([libstrophe], [libstrophe], [LIBS="$libstrophe_LIBS $LIBS"], [ if test "x$PLATFORM" != xfreebsd; then AC_CHECK_LIB([resolv], [res_query], [], [AC_CHECK_LIB([resolv], [__res_query], [], [AC_MSG_ERROR([libresolv not found; libresolv required for profanity])])]) else AC_MSG_NOTICE([skipping libresolv checks for freebsd]) fi ### Check for libstrophe dependencies ### Select first existing xml library among expat and libxml2 PARSER="" PARSER_LIBS="" PARSER_CFLAGS="" AS_IF([test "x$with_libxml2" != xyes], [PKG_CHECK_MODULES([expat], [expat], [PARSER_CFLAGS="$expat_CFLAGS"; PARSER_LIBS="$expat_LIBS"; PARSER="expat"], [AC_CHECK_LIB([expat], [XML_ParserCreate], [PARSER_LIBS="-lexpat"; PARSER="expat"], AS_IF([test "x$with_libxml2" = xno], [AC_MSG_ERROR([expat is required but does not exist])]))]) ]) AS_IF([test "x$PARSER" = x -a "x$with_libxml2" != xno], [PKG_CHECK_MODULES([libxml2], [libxml-2.0], [PARSER_CFLAGS="$libxml2_CFLAGS"; PARSER_LIBS="$libxml2_LIBS"; PARSER="libxml2"], AS_IF([test "x$with_libxml2" = xyes], [AC_MSG_ERROR([libxml2 is required but does not exist])])) ]) AS_IF([test "x$PARSER" = x], [AC_MSG_ERROR([either expat or libxml2 is required for profanity])]) AM_CPPFLAGS="$AM_CPPFLAGS $PARSER_CFLAGS" LIBS="$PARSER_LIBS $LIBS" PKG_CHECK_MODULES([openssl], [openssl], [], [AC_CHECK_HEADER(openssl/ssl.h, [openssl_LIBS="-lssl -lcrypto"], [AC_MSG_ERROR([openssl not found; openssl required for profanity])])]) AM_CPPFLAGS="$AM_CPPFLAGS $openssl_CFLAGS" LIBS="$openssl_LIBS $LIBS" CFLAGS_RESTORE="$CFLAGS" CFLAGS="$CFLAGS $AM_CPPFLAGS" AC_CHECK_LIB([strophe], [xmpp_ctx_new], [LIBS="-lstrophe $LIBS"; listrophe_CFLAGS=""], [AC_MSG_ERROR([libstrophe linked with $PARSER is required for profanity])]) CFLAGS="$CFLAGS_RESTORE" ]) CFLAGS="$CFLAGS $libstrophe_CFLAGS" ### Check for ncurses library PKG_CHECK_MODULES([ncursesw], [ncursesw], [NCURSES_CFLAGS="$ncursesw_CFLAGS"; NCURSES_LIBS="$ncursesw_LIBS"; NCURSES="ncursesw"], [PKG_CHECK_MODULES([ncurses], [ncurses], [NCURSES_CFLAGS="$ncurses_CFLAGS"; NCURSES_LIBS="$ncurses_LIBS"; NCURSES="ncurses"], [AC_CHECK_LIB([ncursesw], [main], [], [AC_CHECK_LIB([ncurses], [main], [], [AC_MSG_ERROR([ncurses is required for profanity])])])])]) AM_CPPFLAGS="$AM_CPPFLAGS $NCURSES_CFLAGS" LIBS="$NCURSES_LIBS $LIBS" AS_IF([test "x$PLATFORM" = xosx], [LIBS="-lncurses $LIBS"]) ### Check wide characters support in ncurses library CFLAGS_RESTORE="$CFLAGS" CFLAGS="$CFLAGS $NCURSES_CFLAGS" AC_CACHE_CHECK([for wget_wch support in $NCURSES], ncurses_cv_wget_wch, [AC_LINK_IFELSE([AC_LANG_SOURCE([ void wget_wch(void); int main() { wget_wch(); return 0; } ])], [ncurses_cv_wget_wch=yes], [ncurses_cv_wget_wch=no]) ]) CFLAGS="$CFLAGS_RESTORE" AS_IF([test "x$ncurses_cv_wget_wch" != xyes], [AC_MSG_ERROR([ncurses does not support wide characters])]) ### Check for other profanity dependencies PKG_CHECK_MODULES([glib], [glib-2.0 >= 2.26], [], [AC_MSG_ERROR([glib 2.26 or higher is required for profanity])]) PKG_CHECK_MODULES([curl], [libcurl], [], [AC_MSG_ERROR([libcurl is required for profanity])]) AS_IF([test "x$PLATFORM" != xosx], [AC_CHECK_LIB([readline], [main], [], [AC_MSG_ERROR([libreadline is required for profanity])])], [AC_CHECK_FILE([/usr/local/opt/readline/lib], [LIBS="-lreadline $LIBS" AM_CPPFLAGS="-I/usr/local/opt/readline/include $AM_CPPFLAGS" AM_LDFLAGS="-L/usr/local/opt/readline/lib $AM_LDFLAGS" AC_SUBST(AM_LDFLAGS)], [AC_MSG_ERROR([libreadline is required for profanity])])]) AC_CHECK_LIB([uuid], [uuid_generate], [], [AC_MSG_ERROR([libuuid is required for profanity])]) AS_IF([test "x$PLATFORM" = xosx], [LIBS="-lcurl $LIBS"]) ### Check for desktop notification support ### Linux/FreeBSD require libnotify ### Windows uses native OS calls ### OSX requires terminal-notifier AS_IF([test "x$PLATFORM" = xosx], [AS_IF([test "x$enable_notifications" != xno], [NOTIFIER_PATH="no" AC_PATH_PROG(NOTIFIER_PATH, terminal-notifier, no) AS_IF([test "x$NOTIFIER_PATH" = xno], [AS_IF([test "x$enable_notifications" = xyes], [AC_MSG_ERROR([terminal-notifier not found, required for desktop notifications.])], [AC_MSG_NOTICE([Desktop notifications not supported.])])], [AC_DEFINE([HAVE_OSXNOTIFY], [1], [terminal notifier])])])], [test "x$PLATFORM" = xnix -o "x$PLATFORM" = xfreebsd], [AS_IF([test "x$enable_notifications" != xno], [PKG_CHECK_MODULES([libnotify], [libnotify], [AC_DEFINE([HAVE_LIBNOTIFY], [1], [libnotify module])], [AS_IF([test "x$enable_notifications" = xyes], [AC_MSG_ERROR([libnotify is required but does not exist])], [AC_MSG_NOTICE([libnotify support will be disabled])])])])]) # TODO: rewrite this if test "x$with_xscreensaver" = xyes; then AC_CHECK_LIB([Xss], [main], [], [AC_MSG_ERROR([libXss is required for x autoaway support])]) AC_CHECK_LIB([X11], [main], [], [AC_MSG_ERROR([libX11 is required for x autoaway support])]) elif test "x$with_xscreensaver" = x; then AC_CHECK_LIB([Xss], [main], [], [AC_MSG_NOTICE([libXss not found, falling back to profanity auto-away])]) AC_CHECK_LIB([X11], [main], [], [AC_MSG_NOTICE([libX11 not found, falling back to profanity auto-away])]) fi AM_CONDITIONAL([BUILD_PGP], [false]) if test "x$enable_pgp" != xno; then AC_CHECK_LIB([gpgme], [main], [AM_CONDITIONAL([BUILD_PGP], [true]) AC_DEFINE([HAVE_LIBGPGME], [1], [Have libgpgme]) AC_PATH_PROG([GPGME_CONFIG], [gpgme-config], ["failed"]) AS_IF([test "x$GPGME_CONFIG" = xfailed], [LIBS="-lgpgme $LIBS"], [LIBS="`$GPGME_CONFIG --libs` $LIBS" AM_CPPFLAGS="`$GPGME_CONFIG --cflags` $AM_CPPFLAGS"])], [AS_IF([test "x$enable_pgp" = xyes], [AC_MSG_ERROR([libgpgme is required for pgp support])], [AC_MSG_NOTICE([libgpgme not found, pgp support not enabled])])]) fi AM_CONDITIONAL([BUILD_OTR], [false]) AM_CONDITIONAL([BUILD_OTR3], [false]) AM_CONDITIONAL([BUILD_OTR4], [false]) if test "x$enable_otr" != xno; then AC_SEARCH_LIBS([otrl_init], [otr], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[ #include ]],[[ #if OTRL_VERSION_MAJOR == 4 // OK #else # assume version 3 #endif ]])], [AM_CONDITIONAL([BUILD_OTR], [true]) AM_CONDITIONAL([BUILD_OTR4], [true]) AC_DEFINE([HAVE_LIBOTR], [1], [Have libotr])], [AM_CONDITIONAL([BUILD_OTR], [true]) AM_CONDITIONAL([BUILD_OTR3], [true]) AC_DEFINE([HAVE_LIBOTR], [1], [Have libotr])])], [AS_IF([test "x$enable_otr" = xyes], [AC_MSG_ERROR([libotr is required for otr encryption support])], [AC_MSG_NOTICE([libotr not found, otr encryption support not enabled])])]) fi AS_IF([test "x$with_themes" = xno], [THEMES_INSTALL="false"], [THEMES_INSTALL="true"]) AS_IF([test "x$with_themes" = xno -o "x$with_themes" = xyes -o "x$with_themes" = x], [THEMES_PATH='${pkgdatadir}/themes'], [THEMES_PATH="$with_themes"]) AC_SUBST(THEMES_PATH) AM_CONDITIONAL([THEMES_INSTALL], "$THEMES_INSTALL") ### cmocka is required only for tests, profanity shouldn't be linked with it ### TODO: pass cmocka_CFLAGS and cmocka_LIBS to Makefile.am PKG_CHECK_MODULES([cmocka], [cmocka], [], [AC_MSG_NOTICE([cmocka is not found, will not be able to run tests])]) AM_CONDITIONAL([HAVE_STABBER], [false]) AC_CHECK_LIB([stabber], [stbbr_start], [AM_CONDITIONAL([HAVE_STABBER], [true])], [AC_MSG_NOTICE([libstabber not found, will not be able to run functional tests])]) AM_CONDITIONAL([HAVE_EXPECT], [false]) AC_CHECK_LIB([expect], [main], [AM_CONDITIONAL([HAVE_EXPECT], [true])], [AC_MSG_NOTICE([libexpect not found, will not be able to run functional tests])]) ### Check for ncursesw/ncurses.h first, Arch linux uses ncurses.h for ncursesw AC_CHECK_HEADERS([ncursesw/ncurses.h], [], []) AC_CHECK_HEADERS([ncurses.h], [], []) ### Default parameters AM_CFLAGS="-Wall -Wno-deprecated-declarations" AS_IF([test "x$PACKAGE_STATUS" = xdevelopment], [AM_CFLAGS="$AM_CFLAGS -Wunused -Werror"]) AM_CPPFLAGS="$AM_CPPFLAGS $glib_CFLAGS $curl_CFLAGS $libnotify_CFLAGS" AM_CPPFLAGS="$AM_CPPFLAGS -DTHEMES_PATH=\"\\\"$THEMES_PATH\\\"\"" LIBS="$glib_LIBS $curl_LIBS $libnotify_LIBS $LIBS" AC_SUBST(AM_CFLAGS) AC_SUBST(AM_CPPFLAGS) ### Checks for library functions. AC_CHECK_FUNCS([atexit memset strdup strstr]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT echo "" echo "PLATFORM : $host_os" echo "PACKAGE_STATUS : $PACKAGE_STATUS" echo "AM_CFLAGS : $AM_CFLAGS" echo "AM_CPPFLAGS : $AM_CPPFLAGS" echo "LIBS : $LIBS" echo "XML Parser : $PARSER" echo "Install themes : $THEMES_INSTALL" echo "Themes path : $THEMES_PATH" echo "" echo "Now you can run \`make' to build profanity" profanity-0.4.7/docs/000077500000000000000000000000001257755232500145025ustar00rootroot00000000000000profanity-0.4.7/docs/profanity.1000066400000000000000000000041461257755232500166040ustar00rootroot00000000000000.TH Profanity 1 "February 2015" "Profanity XMPP client" .SH NAME Profanity \- a simple console based XMPP chat client. .SH SYNOPSIS .B profanity [\-vhd] [\-l level] [\-a account] .SH DESCRIPTION .B Profanity is a simple lightweight console based XMPP chat client. Its emphasis is on having a simple and configurable command driven UI, see the homepage at: .br .PP .SH OPTIONS .TP .BI "\-v, \-\-version" Show version and build information. .TP .BI "\-h, \-\-help" Show help on command line arguments. .TP .BI "\-a, \-\-account "ACCOUNT Auto connect to an account on startup, .I ACCOUNT must be an existing account. .TP .BI "\-d, \-\-disable\-tls" Disable TLS for servers that either don't support it, or claim to but do not complete the handshake. .TP .BI "\-l, \-\-log "LEVEL Set the logging level, .I LEVEL may be set to DEBUG, INFO (the default), WARN or ERROR. .SH USING PROFANITY The user guide can be found at . .SH SEE ALSO .B Profanity itself has a lot of built\-in help. Check the /help command for more information. Type "/help help" for information on how to use help itself. .SH CONFIGURATION Configuration for .B Profanity is stored in .I $XDG_CONFIG_HOME/profanity/profrc , details on configuring Profanity can be found at . .PP .SH BUGS Bugs can either be reported by raising an issue at the Github issue tracker: .br .PP .br .PP or to the mailing list at: .br .PP .br .PP or by sending a mail directly to: .br .PP .br .PP .SH LICENSE Copyright (C) 2012 \- 2015 James Booth . License GPLv3+: GNU GPL version 3 or later This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. .SH AUTHORS/CREDITS .B Profanity was written by James Booth .B with many contributions from others, see the full list at: profanity-0.4.7/install-all.sh000077500000000000000000000122611257755232500163270ustar00rootroot00000000000000#!/bin/bash set -o errtrace STATUS=development error_handler() { ERR_CODE=$? echo "Error $ERR_CODE with command '$BASH_COMMAND' on line ${BASH_LINENO[0]}. Exiting." exit $ERR_CODE } trap error_handler ERR debian_prepare() { echo echo Profanity installer ... updating apt repositories echo sudo apt-get update echo echo Profanity installer... installing dependencies echo sudo apt-get -y install git automake autoconf libssl-dev libexpat1-dev libncursesw5-dev libglib2.0-dev libnotify-dev libcurl3-dev libxss-dev libotr5-dev libreadline-dev libtool libgpgme11-dev uuid-dev } fedora_prepare() { echo echo Profanity installer... installing dependencies echo sudo dnf -y install gcc git autoconf automake openssl-devel expat-devel ncurses-devel glib2-devel libnotify-devel libcurl-devel libXScrnSaver-devel libotr3-devel readline-devel libtool libuuid-devel gpgme-devel } opensuse_prepare() { echo echo Profanity installer...installing dependencies echo sudo zypper -n in gcc git automake make autoconf libopenssl-devel expat libexpat-devel ncurses-devel glib2-devel libnotify-devel libcurl-devel libXScrnSaver-devel libotr-devel readline-devel libtool libuuid-devel libgpgme-devel } centos_prepare() { echo echo Profanity installer...installing dependencies echo sudo yum -y install epel-release sudo yum -y install git sudo yum -y install gcc autoconf automake cmake sudo yum -y install openssl-devel expat-devel ncurses-devel glib2-devel libnotify-devel libcurl-devel libXScrnSaver-devel libotr-devel readline-devel libtool libuuid-devel gpgme-devel } cygwin_prepare() { echo echo Profanity installer... installing dependencies echo wget https://raw.githubusercontent.com/transcode-open/apt-cyg/master/apt-cyg #wget --no-check-certificate https://raw.github.com/boothj5/apt-cyg/master/apt-cyg #wget http://apt-cyg.googlecode.com/svn/trunk/apt-cyg chmod +x apt-cyg mv apt-cyg /usr/local/bin/ if [ -n "$CYG_MIRROR" ]; then apt-cyg -m $CYG_MIRROR install git make gcc-core m4 automake autoconf pkg-config openssl-devel libexpat-devel zlib-devel libncursesw-devel libglib2.0-devel libcurl-devel libidn-devel libssh2-devel libkrb5-devel openldap-devel libgcrypt-devel libreadline-devel libgpgme-devel libtool libuuid-devel else apt-cyg install git make gcc-core m4 automake autoconf pkg-config openssl-devel libexpat-devel zlib-devel libncursesw-devel libglib2.0-devel libcurl-devel libidn-devel libssh2-devel libkrb5-devel openldap-devel libgcrypt-devel libreadline-devel libgpgme-devel libtool libuuid-devel fi } install_lib_strophe() { echo echo Profanity installer... installing libstrophe echo git clone git://github.com/strophe/libstrophe.git cd libstrophe git checkout 0.8.8 ./bootstrap.sh ./configure --prefix=$1 make sudo make install cd .. } install_profanity() { echo echo Profanity installer... installing Profanity echo if [ "${STATUS}" = "development" ]; then ./bootstrap.sh fi ./configure make sudo make install } cyg_install_lib_strophe() { echo echo Profanity installer... installing libstrophe echo git clone git://github.com/strophe/libstrophe.git cd libstrophe git checkout 0.8.8 ./bootstrap.sh ./bootstrap.sh # second call seems to fix problem on cygwin ./configure --prefix=/usr make make install cd .. } cyg_install_profanity() { echo echo Profanity installer... installing Profanity echo if [ "${STATUS}" = "development" ]; then ./bootstrap.sh fi ./configure make make install } cleanup() { echo echo Profanity installer... cleaning up echo echo Removing libstrophe repository... rm -rf libstrophe echo echo Profanity installer... complete! echo echo Type \'profanity\' to run. echo } while getopts m: opt do case "$opt" in m) CYG_MIRROR=$OPTARG;; esac done OS=`uname -s` DIST=unknown if [ "${OS}" = "Linux" ]; then if [ -f /etc/fedora-release ]; then DIST=fedora elif [ -f /etc/debian_version ]; then DIST=debian elif [ -f /etc/centos-release ]; then DIST=centos elif [ -f /etc/os-release ]; then DIST=opensuse fi else echo $OS | grep -i cygwin if [ "$?" -eq 0 ]; then DIST=cygwin fi fi case "$DIST" in unknown) echo The install script will not work on this OS. echo Try a manual install instead. exit ;; fedora) fedora_prepare install_lib_strophe /usr install_profanity ;; debian) debian_prepare install_lib_strophe /usr install_profanity ;; opensuse) opensuse_prepare install_lib_strophe /usr/local sudo /sbin/ldconfig install_profanity ;; centos) centos_prepare install_lib_strophe /usr sudo ldconfig install_profanity ;; cygwin) cygwin_prepare cyg_install_lib_strophe cyg_install_profanity ;; esac cleanup profanity-0.4.7/prof.supp000066400000000000000000000005201257755232500154260ustar00rootroot00000000000000{ _dl_init Memcheck:Leak ... fun:_dl_init ... } # libotr { otrl_init Memcheck:Leak ... fun:_otr_init fun:_init fun:prof_run ... } { otrl_privkey_read Memcheck:Leak ... fun:otrl_privkey_read_FILEp fun:otrl_privkey_read ... } # glib { glib Memcheck:Leak ... fun:start_thread fun:clone } profanity-0.4.7/profanity.spec000066400000000000000000000015471257755232500164500ustar00rootroot00000000000000Name: profanity Version: 0.5.0 Release: 2%{?dist} Summary: A console based XMPP client Group: Application/System License: GPL URL: http://www.profanity.im/ Source0: %{name}-%{version}.tar.gz BuildRequires: libstrophe-devel BuildRequires: libcurl-devel BuildRequires: ncurses-devel BuildRequires: openssl-devel BuildRequires: glib2-devel BuildRequires: expat-devel BuildRequires: libotr-devel BuildRequires: gnutls-devel Requires: libstrophe Requires: libcurl Requires: ncurses-libs Requires: openssl Requires: glib2 Requires: expat Requires: libotr Requires: gnutls %description Profanity is a console based XMPP client written in C using ncurses and libstrophe, inspired by Irssi. %prep %setup -q %build %configure make %{?_smp_mflags} %install make install DESTDIR=%{buildroot} %files %{_bindir}/profanity %doc %{_datadir}/man/man1/profanity.1.gz %changelog profanity-0.4.7/profrc.example000066400000000000000000000013641257755232500164260ustar00rootroot00000000000000[ui] splash=true intype=true beep=false statuses.muc=all theme=boothj5 history=true titlebar=true mouse=false flash=false vercheck=false statuses.console=all statuses.chat=all [connection] autoping=60 reconnect=5 account=me@server.org [chatstates] enabled=true outtype=false gone=10 [notifications] remind=60 invite=true sub=true message=true room=mention message.current=true room.current=true typing=true typing.current=false message.text=true room.text=true [alias] friends=/who online friends bob=/msg bob@server.org hey wassup? [logging] chlog=true grlog=true maxsize=1048580 rotate=true shared=true [otr] warn=true log=redact policy=manual [presence] autoaway.mode=away autoaway.time=15 autoaway.message=Away from computer autoaway.check=true profanity-0.4.7/src/000077500000000000000000000000001257755232500143415ustar00rootroot00000000000000profanity-0.4.7/src/chat_session.c000066400000000000000000000110531257755232500171670ustar00rootroot00000000000000/* * chat_session.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include "chat_session.h" #include "config/preferences.h" #include "log.h" #include "xmpp/xmpp.h" static GHashTable *sessions; static void _chat_session_new(const char * const barejid, const char * const resource, gboolean resource_override, gboolean send_states) { assert(barejid != NULL); assert(resource != NULL); ChatSession *new_session = malloc(sizeof(struct chat_session_t)); new_session->barejid = strdup(barejid); new_session->resource = strdup(resource); new_session->resource_override = resource_override; new_session->send_states = send_states; g_hash_table_replace(sessions, strdup(barejid), new_session); } static void _chat_session_free(ChatSession *session) { if (session) { free(session->barejid); free(session->resource); free(session); } } void chat_sessions_init(void) { sessions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_chat_session_free); } void chat_sessions_clear(void) { if (sessions) g_hash_table_remove_all(sessions); } void chat_session_resource_override(const char * const barejid, const char * const resource) { _chat_session_new(barejid, resource, TRUE, TRUE); } ChatSession* chat_session_get(const char * const barejid) { return g_hash_table_lookup(sessions, barejid); } void chat_session_recipient_gone(const char * const barejid, const char * const resource) { assert(barejid != NULL); assert(resource != NULL); ChatSession *session = g_hash_table_lookup(sessions, barejid); if (session && g_strcmp0(session->resource, resource) == 0) { if (!session->resource_override) { chat_session_remove(barejid); } } } void chat_session_recipient_typing(const char * const barejid, const char * const resource) { chat_session_recipient_active(barejid, resource, TRUE); } void chat_session_recipient_paused(const char * const barejid, const char * const resource) { chat_session_recipient_active(barejid, resource, TRUE); } void chat_session_recipient_inactive(const char * const barejid, const char * const resource) { chat_session_recipient_active(barejid, resource, TRUE); } void chat_session_recipient_active(const char * const barejid, const char * const resource, gboolean send_states) { assert(barejid != NULL); assert(resource != NULL); ChatSession *session = g_hash_table_lookup(sessions, barejid); if (session) { // session exists with resource, update chat_states if (g_strcmp0(session->resource, resource) == 0) { session->send_states = send_states; // session exists with different resource and no override, replace } else if (!session->resource_override) { _chat_session_new(barejid, resource, FALSE, send_states); } // no session, create one } else { _chat_session_new(barejid, resource, FALSE, send_states); } } void chat_session_remove(const char * const barejid) { g_hash_table_remove(sessions, barejid); }profanity-0.4.7/src/chat_session.h000066400000000000000000000046721257755232500172050ustar00rootroot00000000000000/* * chat_session.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef CHAT_SESSION_H #define CHAT_SESSION_H #include typedef struct chat_session_t { char *barejid; char *resource; gboolean resource_override; gboolean send_states; } ChatSession; void chat_sessions_init(void); void chat_sessions_clear(void); void chat_session_resource_override(const char * const barejid, const char * const resource); ChatSession* chat_session_get(const char * const barejid); void chat_session_recipient_active(const char * const barejid, const char * const resource, gboolean send_states); void chat_session_recipient_typing(const char * const barejid, const char * const resource); void chat_session_recipient_paused(const char * const barejid, const char * const resource); void chat_session_recipient_gone(const char * const barejid, const char * const resource); void chat_session_recipient_inactive(const char * const barejid, const char * const resource); void chat_session_remove(const char * const barejid); #endif profanity-0.4.7/src/chat_state.c000066400000000000000000000123231257755232500166250ustar00rootroot00000000000000/* * chat_state.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include "chat_state.h" #include "chat_session.h" #include "xmpp/xmpp.h" #include "config/preferences.h" #define PAUSED_TIMEOUT 10.0 #define INACTIVE_TIMEOUT 30.0 static void _send_if_supported(const char * const barejid, void(*send_func)(const char * const)); ChatState* chat_state_new(void) { ChatState *new_state = malloc(sizeof(struct prof_chat_state_t)); new_state->type = CHAT_STATE_GONE; new_state->timer = g_timer_new(); return new_state; } void chat_state_free(ChatState *state) { if (state && state->timer!= NULL) { g_timer_destroy(state->timer); } free(state); } void chat_state_handle_idle(const char * const barejid, ChatState *state) { gdouble elapsed = g_timer_elapsed(state->timer, NULL); // TYPING -> PAUSED if (state->type == CHAT_STATE_COMPOSING && elapsed > PAUSED_TIMEOUT) { state->type = CHAT_STATE_PAUSED; g_timer_start(state->timer); if (prefs_get_boolean(PREF_STATES) && prefs_get_boolean(PREF_OUTTYPE)) { _send_if_supported(barejid, message_send_paused); } return; } // PAUSED|ACTIVE -> INACTIVE if ((state->type == CHAT_STATE_PAUSED || state->type == CHAT_STATE_ACTIVE) && elapsed > INACTIVE_TIMEOUT) { state->type = CHAT_STATE_INACTIVE; g_timer_start(state->timer); if (prefs_get_boolean(PREF_STATES)) { _send_if_supported(barejid, message_send_inactive); } return; } // INACTIVE -> GONE if (state->type == CHAT_STATE_INACTIVE) { if (prefs_get_gone() != 0 && (elapsed > (prefs_get_gone() * 60.0))) { ChatSession *session = chat_session_get(barejid); if (session) { // never move to GONE when resource override if (!session->resource_override) { if (prefs_get_boolean(PREF_STATES)) { _send_if_supported(barejid, message_send_gone); } chat_session_remove(barejid); state->type = CHAT_STATE_GONE; g_timer_start(state->timer); } } else { if (prefs_get_boolean(PREF_STATES)) { message_send_gone(barejid); } state->type = CHAT_STATE_GONE; g_timer_start(state->timer); } return; } } } void chat_state_handle_typing(const char * const barejid, ChatState *state) { // ACTIVE|INACTIVE|PAUSED|GONE -> COMPOSING if (state->type != CHAT_STATE_COMPOSING) { state->type = CHAT_STATE_COMPOSING; g_timer_start(state->timer); if (prefs_get_boolean(PREF_STATES) && prefs_get_boolean(PREF_OUTTYPE)) { _send_if_supported(barejid, message_send_composing); } } } void chat_state_active(ChatState *state) { state->type = CHAT_STATE_ACTIVE; g_timer_start(state->timer); } void chat_state_gone(const char * const barejid, ChatState *state) { if (state->type != CHAT_STATE_GONE) { if (prefs_get_boolean(PREF_STATES)) { _send_if_supported(barejid, message_send_gone); } state->type = CHAT_STATE_GONE; g_timer_start(state->timer); } } static void _send_if_supported(const char * const barejid, void(*send_func)(const char * const)) { gboolean send = TRUE; GString *jid = g_string_new(barejid); ChatSession *session = chat_session_get(barejid); if (session) { if (session->send_states) { g_string_append(jid, "/"); g_string_append(jid, session->resource); } else { send = FALSE; } } if (send) { send_func(jid->str); } g_string_free(jid, TRUE); }profanity-0.4.7/src/chat_state.h000066400000000000000000000041601257755232500166320ustar00rootroot00000000000000/* * chat_state.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef CHAT_STATE_H #define CHAT_STATE_H #include typedef enum { CHAT_STATE_ACTIVE, CHAT_STATE_COMPOSING, CHAT_STATE_PAUSED, CHAT_STATE_INACTIVE, CHAT_STATE_GONE } chat_state_type_t; typedef struct prof_chat_state_t { chat_state_type_t type; GTimer *timer; } ChatState; ChatState* chat_state_new(void); void chat_state_free(ChatState *state); void chat_state_handle_idle(const char * const barejid, ChatState *state); void chat_state_handle_typing(const char * const barejid, ChatState *state); void chat_state_active(ChatState *state); void chat_state_gone(const char * const barejid, ChatState *state); #endif profanity-0.4.7/src/command/000077500000000000000000000000001257755232500157575ustar00rootroot00000000000000profanity-0.4.7/src/command/command.c000066400000000000000000004020371257755232500175470ustar00rootroot00000000000000/* * command.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include #include #include #include "config.h" #include "chat_session.h" #include "command/command.h" #include "command/commands.h" #include "common.h" #include "config/accounts.h" #include "config/preferences.h" #include "config/theme.h" #include "contact.h" #include "roster_list.h" #include "jid.h" #include "xmpp/form.h" #include "log.h" #include "muc.h" #ifdef HAVE_LIBOTR #include "otr/otr.h" #endif #ifdef HAVE_LIBGPGME #include "pgp/gpg.h" #endif #include "profanity.h" #include "tools/autocomplete.h" #include "tools/parser.h" #include "tools/tinyurl.h" #include "xmpp/xmpp.h" #include "xmpp/bookmark.h" #include "ui/ui.h" #include "window_list.h" static gboolean _cmd_execute(ProfWin *window, const char * const command, const char * const inp); static char * _cmd_complete_parameters(ProfWin *window, const char * const input); static char * _sub_autocomplete(ProfWin *window, const char * const input); static char * _notify_autocomplete(ProfWin *window, const char * const input); static char * _theme_autocomplete(ProfWin *window, const char * const input); static char * _autoaway_autocomplete(ProfWin *window, const char * const input); static char * _autoconnect_autocomplete(ProfWin *window, const char * const input); static char * _account_autocomplete(ProfWin *window, const char * const input); static char * _who_autocomplete(ProfWin *window, const char * const input); static char * _roster_autocomplete(ProfWin *window, const char * const input); static char * _group_autocomplete(ProfWin *window, const char * const input); static char * _bookmark_autocomplete(ProfWin *window, const char * const input); static char * _otr_autocomplete(ProfWin *window, const char * const input); static char * _pgp_autocomplete(ProfWin *window, const char * const input); static char * _connect_autocomplete(ProfWin *window, const char * const input); static char * _statuses_autocomplete(ProfWin *window, const char * const input); static char * _alias_autocomplete(ProfWin *window, const char * const input); static char * _join_autocomplete(ProfWin *window, const char * const input); static char * _log_autocomplete(ProfWin *window, const char * const input); static char * _form_autocomplete(ProfWin *window, const char * const input); static char * _form_field_autocomplete(ProfWin *window, const char * const input); static char * _occupants_autocomplete(ProfWin *window, const char * const input); static char * _kick_autocomplete(ProfWin *window, const char * const input); static char * _ban_autocomplete(ProfWin *window, const char * const input); static char * _affiliation_autocomplete(ProfWin *window, const char * const input); static char * _role_autocomplete(ProfWin *window, const char * const input); static char * _resource_autocomplete(ProfWin *window, const char * const input); static char * _titlebar_autocomplete(ProfWin *window, const char * const input); static char * _inpblock_autocomplete(ProfWin *window, const char * const input); static char * _time_autocomplete(ProfWin *window, const char * const input); static char * _receipts_autocomplete(ProfWin *window, const char * const input); static char * _help_autocomplete(ProfWin *window, const char * const input); static char * _wins_autocomplete(ProfWin *window, const char * const input); GHashTable *commands = NULL; #define CMD_TAG_CHAT "chat" #define CMD_TAG_GROUPCHAT "groupchat" #define CMD_TAG_ROSTER "roster" #define CMD_TAG_PRESENCE "presence" #define CMD_TAG_CONNECTION "connection" #define CMD_TAG_DISCOVERY "discovery" #define CMD_TAG_UI "ui" #define CMD_NOTAGS { { NULL }, #define CMD_TAGS(...) { { __VA_ARGS__, NULL }, #define CMD_SYN(...) { __VA_ARGS__, NULL }, #define CMD_DESC(desc) desc, #define CMD_NOARGS { { NULL, NULL } }, #define CMD_ARGS(...) { __VA_ARGS__, { NULL, NULL } }, #define CMD_NOEXAMPLES { NULL } } #define CMD_EXAMPLES(...) { __VA_ARGS__, NULL } } /* * Command list */ static struct cmd_t command_defs[] = { { "/help", cmd_help, parse_args, 0, 2, NULL, CMD_NOTAGS CMD_SYN( "/help [|]") CMD_DESC( "Help on using Profanity. Passing no arguments list help areas. " "For command help, optional arguments are shown using square brackets e.g. [argument], " "arguments representing variables rather than a literal name are surrounded by angle brackets " "e.g. . " "Arguments that may be one of a number of values are separated by a pipe " "e.g. val1|val2|val3.") CMD_ARGS( { "", "Summary help for commands in a certain area of functionality." }, { "", "Full help for a specific command, for example '/help connect'." }) CMD_EXAMPLES( "/help commands", "/help presence", "/help who") }, { "/about", cmd_about, parse_args, 0, 0, NULL, CMD_NOTAGS CMD_SYN( "/about") CMD_DESC( "Show version and license information.") CMD_NOARGS CMD_NOEXAMPLES }, { "/connect", cmd_connect, parse_args, 0, 5, NULL, CMD_TAGS( CMD_TAG_CONNECTION) CMD_SYN( "/connect []", "/connect [server ] [port ]") CMD_DESC( "Login to a chat service. " "If no account is specified, the default is used if one is configured. " "A local account is created with the JID as it's name if it doesn't already exist.") CMD_ARGS( { "", "The local account you wish to connect with, or a JID if connecting for the first time." }, { "server ", "Supply a server if it is different to the domain part of your JID." }, { "port ", "The port to use if different to the default (5222, or 5223 for SSL)." }) CMD_EXAMPLES( "/connect", "/connect myuser@gmail.com", "/connect myuser@mycompany.com server talk.google.com", "/connect bob@someplace port 5678", "/connect me@chatty server chatty.com port 5443") }, { "/disconnect", cmd_disconnect, parse_args, 0, 0, NULL, CMD_TAGS( CMD_TAG_CONNECTION) CMD_SYN( "/disconnect") CMD_DESC( "Disconnect from the current chat service.") CMD_NOARGS CMD_NOEXAMPLES }, { "/msg", cmd_msg, parse_args_with_freetext, 1, 2, NULL, CMD_TAGS( CMD_TAG_CHAT) CMD_SYN( "/msg []", "/msg []") CMD_DESC( "Send a one to one chat message, or a private message to a chat room occupant. " "If the message is omitted, a new chat window will be opened without sending a message. " "Use quotes if the nickname includes spaces.") CMD_ARGS( { "", "Open chat window with contact, by JID or nickname." }, { " []", "Send message to contact, by JID or nickname." }, { "", "Open private chat window with chat room occupant." }, { " []", "Send a private message to a chat room occupant." }) CMD_EXAMPLES( "/msg myfriend@server.com Hey, here's a message!", "/msg otherfriend@server.com", "/msg Bob Here is a private message", "/msg \"My Friend\" Hi, how are you?") }, { "/roster", cmd_roster, parse_args_with_freetext, 0, 3, NULL, CMD_TAGS( CMD_TAG_ROSTER, CMD_TAG_UI) CMD_SYN( "/roster", "/roster online", "/roster show [offline|resource|empty]", "/roster hide [offline|resource|empty]", "/roster by group|presence|none", "/roster size ", "/roster add []", "/roster remove ", "/roster remove_all contacts", "/roster nick ", "/roster clearnick ") CMD_DESC( "Manage your roster, and roster display settings. " "Passing no arguments lists all contacts in your roster.") CMD_ARGS( { "online", "Show all online contacts in your roster." }, { "show", "Show the roster panel." }, { "show offline", "Show offline contacts in the roster panel." }, { "show resource", "Show contact's connected resources in the roster panel." }, { "show empty", "When grouping by presence, show empty presence groups." }, { "hide", "Hide the roster panel." }, { "hide offline", "Hide offline contacts in the roster panel." }, { "hide resource", "Hide contact's connected resources in the roster panel." }, { "hide empty", "When grouping by presence, hide empty presence groups." }, { "by group", "Group contacts in the roster panel by roster group." }, { "by presence", "Group contacts in the roster panel by presence." }, { "by none", "No grouping in the roster panel." }, { "size ", "Percentage of the screen taken up by the roster (1-99)." }, { "add []", "Add a new item to the roster." }, { "remove ", "Removes an item from the roster." }, { "remove_all contacts", "Remove all items from roster." }, { "nick ", "Change a contacts nickname." }, { "clearnick ", "Removes the current nickname." }) CMD_EXAMPLES( "/roster", "/roster add someone@contacts.org", "/roster add someone@contacts.org Buddy", "/roster remove someone@contacts.org", "/roster nick myfriend@chat.org My Friend", "/roster clearnick kai@server.com", "/roster size 15") }, { "/group", cmd_group, parse_args_with_freetext, 0, 3, NULL, CMD_TAGS( CMD_TAG_ROSTER, CMD_TAG_UI) CMD_SYN( "/group", "/group show ", "/group add " "/group remove ") CMD_DESC( "View, add to, and remove from roster groups. " "Passing no argument will list all roster groups.") CMD_ARGS( { "show ", "List all roster items a group." }, { "add ", "Add a contact to a group." }, { "remove ", "Remove a contact from a group." }) CMD_EXAMPLES( "/group", "/group show friends", "/group add friends newfriend@server.org", "/group add family Brother", "/group remove colleagues boss@work.com") }, { "/info", cmd_info, parse_args, 0, 1, NULL, CMD_TAGS( CMD_TAG_ROSTER, CMD_TAG_CHAT, CMD_TAG_GROUPCHAT) CMD_SYN( "/info", "/info |") CMD_DESC( "Show information about a contact, room, or room member. " "Passing no argument in a chat window will use the current recipient. " "Passing no argument in a chat room will display information about the room.") CMD_ARGS( { "", "The contact you wish to view information about." }, { "", "When in a chat room, the occupant you wish to view information about." }) CMD_EXAMPLES( "/info mybuddy@chat.server.org", "/info kai") }, { "/caps", cmd_caps, parse_args, 0, 1, NULL, CMD_TAGS( CMD_TAG_DISCOVERY, CMD_TAG_CHAT, CMD_TAG_GROUPCHAT) CMD_SYN( "/caps", "/caps |") CMD_DESC( "Find out a contacts, or room members client software capabilities. " "If in private chat initiated from a chat room, no parameter is required.") CMD_ARGS( { "", "If in the console or a chat window, the full JID for which you wish to see capabilities." }, { "", "If in a chat room, nickname for which you wish to see capabilities." }) CMD_EXAMPLES( "/caps mybuddy@chat.server.org/laptop", "/caps mybuddy@chat.server.org/phone", "/caps bruce") }, { "/software", cmd_software, parse_args, 0, 1, NULL, CMD_TAGS( CMD_TAG_DISCOVERY, CMD_TAG_CHAT, CMD_TAG_GROUPCHAT) CMD_SYN( "/software", "/software |") CMD_DESC( "Find out a contact, or room members software version information. " "If in private chat initiated from a chat room, no parameter is required. " "If the contact's software does not support software version requests, nothing will be displayed.") CMD_ARGS( { "", "If in the console or a chat window, the full JID for which you wish to see software information." }, { "", "If in a chat room, nickname for which you wish to see software information." }) CMD_EXAMPLES( "/software mybuddy@chat.server.org/laptop", "/software mybuddy@chat.server.org/phone", "/software bruce") }, { "/status", cmd_status, parse_args, 0, 1, NULL, CMD_TAGS( CMD_TAG_CHAT, CMD_TAG_GROUPCHAT) CMD_SYN( "/status", "/status |") CMD_DESC( "Find out a contact, or room members presence information. " "If in a chat window the parameter is not required, the current recipient will be used.") CMD_ARGS( { "", "The contact who's presence you which to see." }, { "", "If in a chat room, the occupant who's presence you wish to see." }) CMD_EXAMPLES( "/status buddy@server.com", "/status jon") }, { "/resource", cmd_resource, parse_args, 1, 2, &cons_resource_setting, CMD_TAGS( CMD_TAG_CHAT, CMD_TAG_UI) CMD_SYN( "/resource set ", "/resource off", "/resource title on|off", "/resource message on|off") CMD_DESC( "Override chat session resource, and manage resource display settings.") CMD_ARGS( { "set ", "Set the resource to which messages will be sent." }, { "off", "Let the server choose which resource to route messages to." }, { "title on|off", "Show or hide the current resource in the titlebar." }, { "message on|off", "Show or hide the resource when showing an incoming message." }) CMD_NOEXAMPLES }, { "/join", cmd_join, parse_args, 0, 5, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/join", "/join [nick ] [password ]") CMD_DESC( "Join a chat room at the conference server. " "If no room is supplied, a generated name will be used with the format private-chat-[UUID]. " "If the domain part is not included in the room name, the account preference 'muc.service' will be used. " "If no nickname is specified the account preference 'muc.nick' will be used which by default is the localpart of your JID. " "If the room doesn't exist, and the server allows it, a new one will be created.") CMD_ARGS( { "", "The chat room to join." }, { "nick ", "Nickname to use in the room." }, { "password ", "Password if the room requires one." }) CMD_EXAMPLES( "/join", "/join jdev@conference.jabber.org", "/join jdev@conference.jabber.org nick mynick", "/join private@conference.jabber.org nick mynick password mypassword", "/join jdev") }, { "/leave", cmd_leave, parse_args, 0, 0, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/leave") CMD_DESC( "Leave the current chat room.") CMD_NOARGS CMD_NOEXAMPLES }, { "/invite", cmd_invite, parse_args_with_freetext, 1, 2, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/invite []") CMD_DESC( "Send an invite to a contact for the current chat room.") CMD_ARGS( { "", "The contact you wish to invite." }, { "", "An optional message to send with the invite." }) CMD_NOEXAMPLES }, { "/invites", cmd_invites, parse_args_with_freetext, 0, 0, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/invites") CMD_DESC( "Show all rooms that you have been invited to, and not accepted or declined.") CMD_NOARGS CMD_NOEXAMPLES }, { "/decline", cmd_decline, parse_args_with_freetext, 1, 1, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/decline ") CMD_DESC( "Decline a chat room invitation.") CMD_ARGS( { "", "The room for the invite you wish to decline." }) CMD_NOEXAMPLES }, { "/room", cmd_room, parse_args, 1, 1, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/room accept|destroy|config") CMD_DESC( "Chat room configuration.") CMD_ARGS( { "accept", "Accept default room configuration." }, { "destroy", "Reject default room configuration, and destroy the room." }, { "config", "Edit room configuration." }) CMD_NOEXAMPLES }, { "/kick", cmd_kick, parse_args_with_freetext, 1, 2, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/kick []") CMD_DESC( "Kick occupant from chat room.") CMD_ARGS( { "", "Nickname of the occupant to kick from the room." }, { "", "Optional reason for kicking the occupant." }) CMD_NOEXAMPLES }, { "/ban", cmd_ban, parse_args_with_freetext, 1, 2, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/ban []") CMD_DESC( "Ban user from chat room.") CMD_ARGS( { "", "Bare JID of the user to ban from the room." }, { "", "Optional reason for banning the user." }) CMD_NOEXAMPLES }, { "/subject", cmd_subject, parse_args_with_freetext, 0, 2, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/subject set ", "/subject clear") CMD_DESC( "Set or clear room subject.") CMD_ARGS( { "set ", "Set the room subject." }, { "clear", "Clear the room subject." }) CMD_NOEXAMPLES }, { "/affiliation", cmd_affiliation, parse_args_with_freetext, 1, 4, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/affiliation set []", "/list []") CMD_DESC( "Manage room affiliations. " "Affiliation may be one of owner, admin, member, outcast or none.") CMD_ARGS( { "set []", "Set the affiliation of user with jid, with an optional reason." }, { "list []", "List all users with the specified affiliation, or all if none specified." }) CMD_NOEXAMPLES }, { "/role", cmd_role, parse_args_with_freetext, 1, 4, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/role set []", "/list []") CMD_DESC( "Manage room roles. " "Role may be one of moderator, participant, visitor or none.") CMD_ARGS( { "set []", "Set the role of occupant with nick, with an optional reason." }, { "list []", "List all occupants with the specified role, or all if none specified." }) CMD_NOEXAMPLES }, { "/occupants", cmd_occupants, parse_args, 1, 3, cons_occupants_setting, CMD_TAGS( CMD_TAG_GROUPCHAT, CMD_TAG_UI) CMD_SYN( "/occupants show|hide [jid]", "/occupants default show|hide [jid]", "/occupants size []") CMD_DESC( "Show or hide room occupants, and occupants panel display settings.") CMD_ARGS( { "show", "Show the occupants panel in current room." }, { "hide", "Hide the occupants panel in current room." }, { "show jid", "Show jid in the occupants panel in current room." }, { "hide jid", "Hide jid in the occupants panel in current room." }, { "default show|hide", "Whether occupants are shown by default in new rooms." }, { "default show|hide jid", "Whether occupants jids are shown by default in new rooms." }, { "size ", "Percentage of the screen taken by the occupants list in rooms (1-99)." }) CMD_NOEXAMPLES }, { "/form", cmd_form, parse_args, 1, 2, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/form show", "/form submit", "/form cancel", "/form help []") CMD_DESC( "Form configuration.") CMD_ARGS( { "show", "Show the current form." }, { "submit", "Submit the current form." }, { "cancel", "Cancel changes to the current form." }, { "help []", "Display help for form, or a specific field." }) CMD_NOEXAMPLES }, { "/rooms", cmd_rooms, parse_args, 0, 1, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/rooms []") CMD_DESC( "List the chat rooms available at the specified conference service. " "If no argument is supplied, the account preference 'muc.service' is used, 'conference.' by default.") CMD_ARGS( { "", "The conference service to query." }) CMD_EXAMPLES( "/rooms conference.jabber.org") }, { "/bookmark", cmd_bookmark, parse_args, 0, 8, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/bookmark", "/bookmark list", "/bookmark add [nick ] [password ] [autojoin on|off]", "/bookmark update [nick ] [password ] [autojoin on|off]", "/bookmark remove ", "/bookmark join ") CMD_DESC( "Manage bookmarks and join bookmarked rooms. " "In a chat room, no arguments will bookmark the current room, setting autojoin to \"on\".") CMD_ARGS( { "list", "List all bookmarks." }, { "add ", "Add a bookmark." }, { "remove ", "Remove a bookmark." }, { "update ", "Update the properties associated with a bookmark." }, { "nick ", "Nickname used in the chat room." }, { "password ", "Password if required, may be stored in plaintext on your server." }, { "autojoin on|off", "Whether to join the room automatically on login." }, { "join ", "Join room using the properties associated with the bookmark." }) CMD_NOEXAMPLES }, { "/disco", cmd_disco, parse_args, 1, 2, NULL, CMD_TAGS( CMD_TAG_DISCOVERY) CMD_SYN( "/disco info []", "/disco items []") CMD_DESC( "Find out information about an entities supported services. " "Calling with no arguments will query the server you are currently connected to.") CMD_ARGS( { "info []", "List protocols and features supported by an entity." }, { "items []", "List items associated with an entity." }) CMD_EXAMPLES( "/disco info", "/disco items myserver.org", "/disco items conference.jabber.org", "/disco info myfriend@server.com/laptop") }, { "/nick", cmd_nick, parse_args_with_freetext, 1, 1, NULL, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/nick ") CMD_DESC( "Change your nickname in the current chat room.") CMD_ARGS( { "", "Your new nickname." }) CMD_NOEXAMPLES }, { "/win", cmd_win, parse_args, 1, 1, NULL, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/win ") CMD_DESC( "Move to the specified window.") CMD_ARGS( { "", "Window number to display." }) CMD_NOEXAMPLES }, { "/wins", cmd_wins, parse_args, 0, 3, NULL, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/wins tidy", "/wins autotidy on|off", "/wins prune", "/wins swap ") CMD_DESC( "Manage windows. " "Passing no argument will list all currently active windows and information about their usage.") CMD_ARGS( { "tidy", "Move windows so there are no gaps." }, { "autotidy on|off", "Automatically remove gaps when closing windows." }, { "prune", "Close all windows with no unread messages, and then tidy so there are no gaps." }, { "swap ", "Swap windows, target may be an empty position." }) CMD_NOEXAMPLES }, { "/sub", cmd_sub, parse_args, 1, 2, NULL, CMD_TAGS( CMD_TAG_ROSTER) CMD_SYN( "/sub request []", "/sub allow []", "/sub deny []", "/sub show []", "/sub sent", "/sub received") CMD_DESC( "Manage subscriptions to contact presence. " "If jid is omitted, the contact of the current window is used.") CMD_ARGS( { "request []", "Send a subscription request to the user." }, { "allow []", "Approve a contact's subscription request." }, { "deny []", "Remove subscription for a contact, or deny a request." }, { "show []", "Show subscription status for a contact." }, { "sent", "Show all sent subscription requests pending a response." }, { "received", "Show all received subscription requests awaiting your response." }) CMD_EXAMPLES( "/sub request myfriend@jabber.org", "/sub allow myfriend@jabber.org", "/sub request", "/sub sent") }, { "/tiny", cmd_tiny, parse_args, 1, 1, NULL, CMD_TAGS( CMD_TAG_CHAT, CMD_TAG_GROUPCHAT) CMD_SYN( "/tiny ") CMD_DESC( "Send url as tinyurl in current chat.") CMD_ARGS( { "", "The url to make tiny." }) CMD_EXAMPLES( "Example: /tiny http://www.profanity.im") }, { "/who", cmd_who, parse_args, 0, 2, NULL, CMD_TAGS( CMD_TAG_CHAT, CMD_TAG_GROUPCHAT, CMD_TAG_ROSTER) CMD_SYN( "/who", "/who online|offline|away|dnd|xa|chat|available|unavailable|any []", "/who moderator|participant|visitor", "/who owner|admin|member") CMD_DESC( "Show contacts or room occupants with chosen status, role or affiliation") CMD_ARGS( { "offline|away|dnd|xa|chat", "Show contacts or room occupants with specified presence." }, { "online", "Contacts that are online, chat, away, xa, dnd." }, { "available", "Contacts that are available for chat - online, chat." }, { "unavailable", "Contacts that are not available for chat - offline, away, xa, dnd." }, { "any", "Contacts with any status (same as calling with no argument)." }, { "", "Filter the results by the specified roster group, not applicable in chat rooms." }, { "moderator|participant|visitor", "Room occupants with the specified role." }, { "owner|admin|member", "Room occupants with the specified affiliation." }) CMD_EXAMPLES( "/who", "/who xa", "/who online friends", "/who any family", "/who participant", "/who admin") }, { "/close", cmd_close, parse_args, 0, 1, NULL, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/close []", "/close all|read") CMD_DESC( "Close windows. " "Passing no argument closes the current window.") CMD_ARGS( { "", "Close the specified window." }, { "all", "Close all windows." }, { "read", "Close all windows that have no unread messages." }) CMD_NOEXAMPLES }, { "/clear", cmd_clear, parse_args, 0, 0, NULL, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/clear") CMD_DESC( "Clear the current window.") CMD_NOARGS CMD_NOEXAMPLES }, { "/quit", cmd_quit, parse_args, 0, 0, NULL, CMD_NOTAGS CMD_SYN( "/quit") CMD_DESC( "Logout of any current session, and quit Profanity.") CMD_NOARGS CMD_NOEXAMPLES }, { "/privileges", cmd_privileges, parse_args, 1, 1, &cons_privileges_setting, CMD_TAGS( CMD_TAG_GROUPCHAT, CMD_TAG_UI) CMD_SYN( "/privileges on|off") CMD_DESC( "Group occupants panel by role, and show role information in chat rooms.") CMD_ARGS( { "on|off", "Enable or disable privilege information." }) CMD_NOEXAMPLES }, { "/beep", cmd_beep, parse_args, 1, 1, &cons_beep_setting, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/beep on|off") CMD_DESC( "Switch the terminal bell on or off. " "The bell will sound when incoming messages are received. " "If the terminal does not support sounds, it may attempt to flash the screen instead.") CMD_ARGS( { "on|off", "Enable or disable terminal bell." }) CMD_NOEXAMPLES }, { "/encwarn", cmd_encwarn, parse_args, 1, 1, &cons_encwarn_setting, CMD_TAGS( CMD_TAG_CHAT, CMD_TAG_UI) CMD_SYN( "/encwarn on|off") CMD_DESC( "Titlebar encryption warning.") CMD_ARGS( { "on|off", "Enabled or disable the unencrypted warning message in the titlebar." }) CMD_NOEXAMPLES }, { "/presence", cmd_presence, parse_args, 1, 1, &cons_presence_setting, CMD_TAGS( CMD_TAG_UI, CMD_TAG_CHAT) CMD_SYN( "/presence on|off") CMD_DESC( "Show the contacts presence in the titlebar.") CMD_ARGS( { "on|off", "Switch display of the contacts presence in the titlebar on or off." }) CMD_NOEXAMPLES }, { "/wrap", cmd_wrap, parse_args, 1, 1, &cons_wrap_setting, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/wrap on|off") CMD_DESC( "Word wrapping.") CMD_ARGS( { "on|off", "Enable or disable word wrapping in the main window." }) CMD_NOEXAMPLES }, { "/time", cmd_time, parse_args, 1, 3, &cons_time_setting, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/time main set ", "/time main off", "/time statusbar set ", "/time statusbar off") CMD_DESC( "Configure time display preferences. " "Time formats are strings supported by g_date_time_format. " "See https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format for more details. " "Setting the format to an unsupported string, will display the string. " "If the format contains spaces, it must be surrounded with double quotes.") CMD_ARGS( { "main set ", "Change time format in main window." }, { "main off", "Do not show time in main window." }, { "statusbar set ", "Change time format in statusbar." }, { "statusbar off", "Change time format in status bar." }) CMD_EXAMPLES( "/time main set \"%d-%m-%y %H:%M\"", "/time main off", "/time statusbar set %H:%M") }, { "/inpblock", cmd_inpblock, parse_args, 2, 2, &cons_inpblock_setting, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/inpblock timeout ", "/inpblock dynamic on|off") CMD_DESC( "How long to wait for keyboard input before checking for new messages or checking for state changes such as 'idle'.") CMD_ARGS( { "timeout ", "Time to wait (1-1000) in milliseconds before reading input from the terminal buffer, default: 1000." }, { "dynamic on|off", "Start with 0 millis and dynamically increase up to timeout when no activity, default: on." }) CMD_NOEXAMPLES }, { "/notify", cmd_notify, parse_args, 2, 3, &cons_notify_setting, CMD_TAGS( CMD_TAG_UI, CMD_TAG_CHAT, CMD_TAG_GROUPCHAT) CMD_SYN( "/notify message on|off", "/notify message current on|off", "/notify message text on|off", "/notify room on|off|mention", "/notify room current on|off", "/notify room text on|off", "/notify remind ", "/notify typing on|off", "/notify typing current on|off", "/notify invite on|off", "/notify sub on|off") CMD_DESC( "Settings for various kinds of desktop notifications.") CMD_ARGS( { "message on|off", "Notifications for regular chat messages." }, { "message current on|off", "Whether messages in the current window trigger notifications." }, { "message text on|off", "Show message text in regular message notifications." }, { "room on|off|mention", "Notifications for chat room messages, mention triggers notifications only when your nick is mentioned." }, { "room current on|off", "Whether chat room messages in the current window trigger notifications." }, { "room text on|off", "Show message text in chat room message notifications." }, { "remind ", "Notification reminder period for unread messages, use 0 to disable." }, { "typing on|off", "Notifications when contacts are typing." }, { "typing current on|off", "Whether typing notifications are triggered for the current window." }, { "invite on|off", "Notifications for chat room invites." }, { "sub on|off", "Notifications for subscription requests." }) CMD_EXAMPLES( "/notify message on", "/notify message text on", "/notify room mention", "/notify room current off", "/notify room text off", "/notify remind 10", "/notify typing on", "/notify invite on") }, { "/flash", cmd_flash, parse_args, 1, 1, &cons_flash_setting, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/flash on|off") CMD_DESC( "Make the terminal flash when incoming messages are received in another window. " "If the terminal doesn't support flashing, it may attempt to beep.") CMD_ARGS( { "on|off", "Enable or disable terminal flash." }) CMD_NOEXAMPLES }, { "/intype", cmd_intype, parse_args, 1, 1, &cons_intype_setting, CMD_TAGS( CMD_TAG_UI, CMD_TAG_CHAT) CMD_SYN( "/intype on|off") CMD_DESC( "Show when a contact is typing in the console, and in active message window.") CMD_ARGS( { "on|off", "Enable or disable contact typing messages." }) CMD_NOEXAMPLES }, { "/splash", cmd_splash, parse_args, 1, 1, &cons_splash_setting, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/splash on|off") CMD_DESC( "Switch on or off the ascii logo on start up and when the /about command is called.") CMD_ARGS( { "on|off", "Enable or disable splash logo." }) CMD_NOEXAMPLES }, { "/autoconnect", cmd_autoconnect, parse_args, 1, 2, &cons_autoconnect_setting, CMD_TAGS( CMD_TAG_CONNECTION) CMD_SYN( "/autoconnect set ", "/autoconnect off") CMD_DESC( "Enable or disable autoconnect on start up. " "The setting can be overridden by the -a (--account) command line option.") CMD_ARGS( { "set ", "Connect with account on start up." }, { "off", "Disable autoconnect." }) CMD_EXAMPLES( "/autoconnect set jc@stuntteam.org", "/autoconnect off") }, { "/vercheck", cmd_vercheck, parse_args, 0, 1, NULL, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/vercheck on|off") CMD_DESC( "Check for new versions when Profanity starts, and when the /about command is run.") CMD_ARGS( { "on|off", "Enable or disable the version check." }) CMD_NOEXAMPLES }, { "/titlebar", cmd_titlebar, parse_args, 2, 2, &cons_titlebar_setting, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/titlebar show on|off", "/titlebar goodbye on|off") CMD_DESC( "Allow Profanity to modify the window title bar.") CMD_ARGS( { "show on|off", "Show current logged in user, and unread messages as the window title." }, { "goodbye on|off", "Show a message in the title when exiting profanity." }) CMD_NOEXAMPLES }, { "/alias", cmd_alias, parse_args_with_freetext, 1, 3, NULL, CMD_NOTAGS CMD_SYN( "/alias list", "/alias add ", "/alias remove ") CMD_DESC( "Add, remove or list command aliases.") CMD_ARGS( { "list", "List all aliases." }, { "add ", "Add a new command alias." }, { "remove ", "Remove a command alias." }) CMD_EXAMPLES( "/alias add friends /who online friends", "/alias add /q /quit", "/alias a /away \"I'm in a meeting.\"", "/alias remove q", "/alias list") }, { "/chlog", cmd_chlog, parse_args, 1, 1, &cons_chlog_setting, CMD_TAGS( CMD_TAG_CHAT) CMD_SYN( "/chlog on|off") CMD_DESC( "Switch chat logging on or off. " "This setting will be enabled if /history is set to on. " "When disabling this option, /history will also be disabled. " "See the /grlog setting for enabling logging of chat room (groupchat) messages.") CMD_ARGS( { "on|off", "Enable or disable chat logging." }) CMD_NOEXAMPLES }, { "/grlog", cmd_grlog, parse_args, 1, 1, &cons_grlog_setting, CMD_TAGS( CMD_TAG_GROUPCHAT) CMD_SYN( "/grlog on|off") CMD_DESC( "Switch chat room logging on or off. " "See the /chlog setting for enabling logging of one to one chat.") CMD_ARGS( { "on|off", "Enable or disable chat room logging." }) CMD_NOEXAMPLES }, { "/states", cmd_states, parse_args, 1, 1, &cons_states_setting, CMD_TAGS( CMD_TAG_CHAT) CMD_SYN( "/states on|off") CMD_DESC( "Send chat state notifications to recipient during chat sessions, such as typing, paused, active, gone.") CMD_ARGS( { "on|off", "Enable or disable sending of chat state notifications." }) CMD_NOEXAMPLES }, { "/pgp", cmd_pgp, parse_args, 1, 3, NULL, CMD_TAGS( CMD_TAG_CHAT, CMD_TAG_UI) CMD_SYN( "/pgp libver", "/pgp keys", "/pgp contacts", "/pgp setkey ", "/pgp start []", "/pgp end", "/pgp log on|off|redact", "/pgp char ") CMD_DESC( "Open PGP commands to manage keys, and perform PGP encryption during chat sessions. " "See the /account command to set your own PGP key.") CMD_ARGS( { "libver", "Show which version of the libgpgme library is being used." }, { "keys", "List all keys known to the system." }, { "contacts", "Show contacts with assigned public keys." }, { "setkey ", "Manually associate a contact with a public key." }, { "start []", "Start PGP encrypted chat, current contact will be used if not specified." }, { "end", "End PGP encrypted chat with the current recipient." }, { "log on|off", "Enable or disable plaintext logging of PGP encrypted messages." }, { "log redact", "Log PGP encrypted messages, but replace the contents with [redacted]. This is the default." }, { "char ", "Set the character to be displayed next to PGP encrypted messages." }) CMD_EXAMPLES( "/pgp log off", "/pgp setkey buddy@buddychat.org BA19CACE5A9592C5", "/pgp start buddy@buddychat.org", "/pgp end", "/pgp char P") }, { "/otr", cmd_otr, parse_args, 1, 3, NULL, CMD_TAGS( CMD_TAG_CHAT, CMD_TAG_UI) CMD_SYN( "/otr libver", "/otr gen", "/otr myfp|theirfp", "/otr start []", "/otr end", "/otr trust|untrust", "/otr secret ", "/otr question ", "/otr answer ", "/otr policy manual|opportunistic|always", "/otr log on|off|redact", "/otr char ") CMD_DESC( "Off The Record (OTR) commands to manage keys, and perform OTR encryption during chat sessions.") CMD_ARGS( { "libver", "Show which version of the libotr library is being used." }, { "gen", "Generate your private key." }, { "myfp", "Show your fingerprint." }, { "theirfp", "Show contacts fingerprint." }, { "start []", "Start an OTR session with contact, or current recipient if omitted." }, { "end", "End the current OTR session," }, { "trust|untrust", "Indicate whether or not you trust the contact's fingerprint." }, { "secret ", "Verify a contact's identity using a shared secret." }, { "question ", "Verify a contact's identity using a question and expected answer." }, { "answer ", "Respond to a question answer verification request with your answer." }, { "policy manual", "Set the global OTR policy to manual, OTR sessions must be started manually." }, { "policy opportunistic", "Set the global OTR policy to opportunistic, and OTR sessions will be attempted upon starting a conversation." }, { "policy always", "Set the global OTR policy to always, an error will be displayed if an OTR session cannot be initiated upon starting a conversation." }, { "log on|off", "Enable or disable plaintext logging of OTR encrypted messages." }, { "log redact", "Log OTR encrypted messages, but replace the contents with [redacted]. This is the default." }, { "char ", "Set the character to be displayed next to OTR encrypted messages." }) CMD_EXAMPLES( "/otr log off", "/otr policy manual", "/otr gen", "/otr start buddy@buddychat.org", "/otr myfp", "/otr theirfp", "/otr question \"What is the name of my rabbit?\" fiffi", "/otr end", "/otr char *") }, { "/outtype", cmd_outtype, parse_args, 1, 1, &cons_outtype_setting, CMD_TAGS( CMD_TAG_CHAT) CMD_SYN( "/outtype on|off") CMD_DESC( "Send typing notifications, chat states (/states) will be enabled if this setting is enabled.") CMD_ARGS( { "on|off", "Enable or disable sending typing notifications." }) CMD_NOEXAMPLES }, { "/gone", cmd_gone, parse_args, 1, 1, &cons_gone_setting, CMD_TAGS( CMD_TAG_CHAT) CMD_SYN( "/gone ") CMD_DESC( "Send a 'gone' state to the recipient after the specified number of minutes. " "Chat states (/states) will be enabled if this setting is set.") CMD_ARGS( { "", "Number of minutes of inactivity before sending the 'gone' state, a value of 0 will disable sending this state." }) CMD_NOEXAMPLES }, { "/history", cmd_history, parse_args, 1, 1, &cons_history_setting, CMD_TAGS( CMD_TAG_UI, CMD_TAG_CHAT) CMD_SYN( "/history on|off") CMD_DESC( "Switch chat history on or off, /chlog will automatically be enabled when this setting is on. " "When history is enabled, previous messages are shown in chat windows.") CMD_ARGS( { "on|off", "Enable or disable showing chat history." }) CMD_NOEXAMPLES }, { "/log", cmd_log, parse_args, 1, 2, &cons_log_setting, CMD_NOTAGS CMD_SYN( "/log where", "/log rotate on|off", "/log maxsize ", "/log shared on|off") CMD_DESC( "Manage profanity log settings.") CMD_ARGS( { "where", "Show the current log file location." }, { "rotate on|off", "Rotate log, default on." }, { "maxsize ", "With rotate enabled, specifies the max log size, defaults to 1048580 (1MB)." }, { "shared on|off", "Share logs between all instances, default: on. When off, the process id will be included in the log." }) CMD_NOEXAMPLES }, { "/carbons", cmd_carbons, parse_args, 1, 1, &cons_carbons_setting, CMD_TAGS( CMD_TAG_CHAT) CMD_SYN( "/carbons on|off") CMD_DESC( "Enable or disable message carbons. " "Message carbons ensure that both sides of all conversations are shared with all the user's clients that implement this protocol.") CMD_ARGS( { "on|off", "Enable or disable message carbons." }) CMD_NOEXAMPLES }, { "/receipts", cmd_receipts, parse_args, 2, 2, &cons_receipts_setting, CMD_TAGS( CMD_TAG_CHAT) CMD_SYN( "/receipts request on|off", "/receipts send on|off") CMD_DESC( "Enable or disable message delivery receipts. The interface will indicate when a message has been received.") CMD_ARGS( { "request on|off", "Whether or not to request a receipt upon sending a message." }, { "send on|off", "Whether or not to send a receipt if one has been requested with a received message." }) CMD_NOEXAMPLES }, { "/reconnect", cmd_reconnect, parse_args, 1, 1, &cons_reconnect_setting, CMD_TAGS( CMD_TAG_CONNECTION) CMD_SYN( "/reconnect ") CMD_DESC( "Set the reconnect attempt interval for when the connection is lost.") CMD_ARGS( { "", "Number of seconds before attempting to reconnect, a value of 0 disables reconnect." }) CMD_NOEXAMPLES }, { "/autoping", cmd_autoping, parse_args, 1, 1, &cons_autoping_setting, CMD_TAGS( CMD_TAG_CONNECTION) CMD_SYN( "/autoping ") CMD_DESC( "Set the interval between sending ping requests to the server to ensure the connection is kept alive.") CMD_ARGS( { "", "Number of seconds between sending pings, a value of 0 disables autoping." }) CMD_NOEXAMPLES }, { "/ping", cmd_ping, parse_args, 0, 1, NULL, CMD_TAGS( CMD_TAG_CONNECTION) CMD_SYN( "/ping []") CMD_DESC( "Sends an IQ ping stanza to the specified JID. " "If no JID is supplied, your chat server will be pinged.") CMD_ARGS( { "", "The Jabber ID to send the ping request to." }) CMD_NOEXAMPLES }, { "/autoaway", cmd_autoaway, parse_args_with_freetext, 2, 2, &cons_autoaway_setting, CMD_TAGS( CMD_TAG_PRESENCE) CMD_SYN( "/autoaway mode idle|away|off", "/autoaway time ", "/autoaway message |off", "/autoaway check on|off") CMD_DESC( "Manage autoway settings for idle time.") CMD_ARGS( { "mode idle", "Sends idle time, status remains online." }, { "mode away", "Sends an away presence." }, { "mode off", "Disabled (default)." }, { "time ", "Number of minutes before the presence change is sent, default: 15." }, { "message ", "Optional message to send with the presence change, default: off (disabled)." }, { "message off", "Send no message with autoaway presence." }, { "check on|off", "When enabled, checks for activity and sends online presence, default: on." }) CMD_EXAMPLES( "/autoaway mode idle", "/autoaway time 30", "/autoaway message I'm not really doing much", "/autoaway check off") }, { "/priority", cmd_priority, parse_args, 1, 1, &cons_priority_setting, CMD_TAGS( CMD_TAG_PRESENCE) CMD_SYN( "/priority ") CMD_DESC( "Set priority for the current account. " "See the /account command for specific priority settings per presence status.") CMD_ARGS( { "", "Number between -128 and 127, default: 0." }) CMD_NOEXAMPLES }, { "/account", cmd_account, parse_args, 0, 4, NULL, CMD_TAGS( CMD_TAG_CONNECTION CMD_TAG_PRESENCE, CMD_TAG_CHAT, CMD_TAG_GROUPCHAT) CMD_SYN( "/account", "/account list", "/account show ", "/account enable|disable ", "/account default set ", "/account default off", "/account add ", "/account remove ", "/account rename ", "/account set jid ", "/account set server ", "/account set port ", "/account set status ", "/account set status last", "/account set ", "/account set resource ", "/account set password ", "/account set eval_password ", "/account set muc ", "/account set nick ", "/account set otr ", "/account set pgpkeyid ", "/account clear password", "/account clear eval_password", "/account clear server", "/account clear port", "/account clear otr", "/account clear pgpkeyid") CMD_DESC( "Commands for creating and managing accounts. " "Calling with no arguments will display information for the current account.") CMD_ARGS( { "list", "List all accounts." }, { "enable ", "Enable the account, it will be used for autocompletion." }, { "show ", "Show details for the specified account." }, { "disable ", "Disable the account." }, { "default set ", "Set the default account, used when no argument passed to the /connect command." }, { "default off", "Clear the default account setting." }, { "add ", "Create a new account." }, { "remove ", "Remove an account." }, { "rename ", "Rename 'account' to 'newaccount'." }, { "set jid ", "Set the Jabber ID for the account, account name will be used if not set." }, { "set server ", "The chat server, if different to the domainpart of the JID." }, { "set port ", "The port used for connecting if not the default (5222, or 5223 for SSL)." }, { "set status ", "The presence status to use on login." }, { "set status last", "Use your last status before logging out, when logging in." }, { "set ", "Set the priority (-128..127) to use for the specified presence." }, { "set resource ", "The resource to be used for this account." }, { "set password ", "Password for the account, note this is currently stored in plaintext if set." }, { "set eval_password ", "Shell command evaluated to retrieve password for the account. Can be used to retrieve password from keyring." }, { "set muc ", "The default MUC chat service to use, defaults to 'conference.' where the domain part is from the account JID." }, { "set nick ", "The default nickname to use when joining chat rooms." }, { "set otr ", "Override global OTR policy for this account, see /otr." }, { "set pgpkeyid ", "Set the ID of the PGP key for this account, see /pgp." }, { "clear server", "Remove the server setting for this account." }, { "clear port", "Remove the port setting for this account." }, { "clear password", "Remove the password setting for this account." }, { "clear eval_password", "Remove the eval_password setting for this account." }, { "clear otr", "Remove the OTR policy setting for this account." }, { "clear pgpkeyid", "Remove pgpkeyid associated with this account." }) CMD_EXAMPLES( "/account add me", "/account set me jid me@chatty", "/account set me server talk.chat.com", "/account set me port 5111", "/account set me muc chatservice.mycompany.com", "/account set me nick dennis", "/account set me status dnd", "/account set me dnd -1", "/account rename me gtalk") }, { "/prefs", cmd_prefs, parse_args, 0, 1, NULL, CMD_NOTAGS CMD_SYN( "/prefs [ui|desktop|chat|log|conn|presence|otr|pgp]") CMD_DESC( "Show preferences for different areas of functionality. " "Passing no arguments shows all preferences.") CMD_ARGS( { "ui", "User interface preferences." }, { "desktop", "Desktop notification preferences." }, { "chat", "Chat state preferences." }, { "log", "Logging preferences." }, { "conn", "Connection handling preferences." }, { "presence", "Chat presence preferences." }, { "otr", "Off The Record preferences." }, { "pgp", "OpenPGP preferences." }) CMD_NOEXAMPLES }, { "/theme", cmd_theme, parse_args, 1, 2, &cons_theme_setting, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/theme list", "/theme load ", "/theme colours") CMD_DESC( "Load a theme, includes colours and UI options.") CMD_ARGS( { "list", "List all available themes." }, { "load ", "Load the specified theme. 'default' will reset to the default theme." }, { "colours", "Show the colour values as rendered by the terminal." }) CMD_EXAMPLES( "/theme list", "/theme load forest") }, { "/statuses", cmd_statuses, parse_args, 2, 2, &cons_statuses_setting, CMD_TAGS( CMD_TAG_UI, CMD_TAG_CHAT, CMD_TAG_GROUPCHAT) CMD_SYN( "/statuses console|chat|muc all|online|none") CMD_DESC( "Configure which presence changes are displayed in various windows. " "The default is 'all' for all windows.") CMD_ARGS( { "console", "Configure what is displayed in the console window." }, { "chat", "Configure what is displayed in chat windows." }, { "muc", "Configure what is displayed in chat room windows." }, { "all", "Show all presence changes." }, { "online", "Show only online/offline changes." }, { "none", "Don't show any presence changes." }) CMD_EXAMPLES( "/statuses console none", "/statuses chat online", "/statuses muc all") }, { "/xmlconsole", cmd_xmlconsole, parse_args, 0, 0, NULL, CMD_TAGS( CMD_TAG_UI) CMD_SYN( "/xmlconsole") CMD_DESC( "Open the XML console to view incoming and outgoing XMPP traffic.") CMD_NOARGS CMD_NOEXAMPLES }, { "/away", cmd_away, parse_args_with_freetext, 0, 1, NULL, CMD_TAGS( CMD_TAG_PRESENCE) CMD_SYN( "/away []") CMD_DESC( "Set your status to 'away'.") CMD_ARGS( { "", "Optional message to use with the status." }) CMD_EXAMPLES( "/away", "/away Gone for lunch") }, { "/chat", cmd_chat, parse_args_with_freetext, 0, 1, NULL, CMD_TAGS( CMD_TAG_PRESENCE) CMD_SYN( "/chat []") CMD_DESC( "Set your status to 'chat' (available for chat).") CMD_ARGS( { "", "Optional message to use with the status." }) CMD_EXAMPLES( "/chat", "/chat Please talk to me!") }, { "/dnd", cmd_dnd, parse_args_with_freetext, 0, 1, NULL, CMD_TAGS( CMD_TAG_PRESENCE) CMD_SYN( "/dnd []") CMD_DESC( "Set your status to 'dnd' (do not disturb).") CMD_ARGS( { "", "Optional message to use with the status." }) CMD_EXAMPLES( "/dnd", "/dnd I'm in the zone") }, { "/online", cmd_online, parse_args_with_freetext, 0, 1, NULL, CMD_TAGS( CMD_TAG_PRESENCE) CMD_SYN( "/online []") CMD_DESC( "Set your status to 'online'.") CMD_ARGS( { "", "Optional message to use with the status." }) CMD_EXAMPLES( "/online", "/online Up the Irons!") }, { "/xa", cmd_xa, parse_args_with_freetext, 0, 1, NULL, CMD_TAGS( CMD_TAG_PRESENCE) CMD_SYN( "/xa []") CMD_DESC( "Set your status to 'xa' (extended away).") CMD_ARGS( { "", "Optional message to use with the status." }) CMD_EXAMPLES( "/xa", "/xa This meeting is going to be a long one") }, }; static Autocomplete commands_ac; static Autocomplete who_room_ac; static Autocomplete who_roster_ac; static Autocomplete help_ac; static Autocomplete help_commands_ac; static Autocomplete notify_ac; static Autocomplete notify_room_ac; static Autocomplete notify_message_ac; static Autocomplete notify_typing_ac; static Autocomplete prefs_ac; static Autocomplete sub_ac; static Autocomplete log_ac; static Autocomplete autoaway_ac; static Autocomplete autoaway_mode_ac; static Autocomplete autoconnect_ac; static Autocomplete titlebar_ac; static Autocomplete theme_ac; static Autocomplete theme_load_ac; static Autocomplete account_ac; static Autocomplete account_set_ac; static Autocomplete account_clear_ac; static Autocomplete account_default_ac; static Autocomplete account_status_ac; static Autocomplete disco_ac; static Autocomplete close_ac; static Autocomplete wins_ac; static Autocomplete roster_ac; static Autocomplete roster_option_ac; static Autocomplete roster_by_ac; static Autocomplete roster_remove_all_ac; static Autocomplete group_ac; static Autocomplete bookmark_ac; static Autocomplete bookmark_property_ac; static Autocomplete otr_ac; static Autocomplete otr_log_ac; static Autocomplete otr_policy_ac; static Autocomplete connect_property_ac; static Autocomplete statuses_ac; static Autocomplete statuses_setting_ac; static Autocomplete alias_ac; static Autocomplete aliases_ac; static Autocomplete join_property_ac; static Autocomplete room_ac; static Autocomplete affiliation_ac; static Autocomplete role_ac; static Autocomplete privilege_cmd_ac; static Autocomplete subject_ac; static Autocomplete form_ac; static Autocomplete form_field_multi_ac; static Autocomplete occupants_ac; static Autocomplete occupants_default_ac; static Autocomplete occupants_show_ac; static Autocomplete time_ac; static Autocomplete time_format_ac; static Autocomplete resource_ac; static Autocomplete inpblock_ac; static Autocomplete receipts_ac; static Autocomplete pgp_ac; static Autocomplete pgp_log_ac; /* * Initialise command autocompleter and history */ void cmd_init(void) { log_info("Initialising commands"); commands_ac = autocomplete_new(); aliases_ac = autocomplete_new(); help_ac = autocomplete_new(); autocomplete_add(help_ac, "commands"); autocomplete_add(help_ac, "navigation"); // load command defs into hash table commands = g_hash_table_new(g_str_hash, g_str_equal); unsigned int i; for (i = 0; i < ARRAY_SIZE(command_defs); i++) { Command *pcmd = command_defs+i; // add to hash g_hash_table_insert(commands, pcmd->cmd, pcmd); // add to commands and help autocompleters autocomplete_add(commands_ac, pcmd->cmd); autocomplete_add(help_ac, pcmd->cmd+1); } // load aliases GList *aliases = prefs_get_aliases(); GList *curr = aliases; while (curr) { ProfAlias *alias = curr->data; GString *ac_alias = g_string_new("/"); g_string_append(ac_alias, alias->name); autocomplete_add(commands_ac, ac_alias->str); autocomplete_add(aliases_ac, alias->name); g_string_free(ac_alias, TRUE); curr = g_list_next(curr); } prefs_free_aliases(aliases); help_commands_ac = autocomplete_new(); autocomplete_add(help_commands_ac, "chat"); autocomplete_add(help_commands_ac, "groupchat"); autocomplete_add(help_commands_ac, "roster"); autocomplete_add(help_commands_ac, "presence"); autocomplete_add(help_commands_ac, "discovery"); autocomplete_add(help_commands_ac, "connection"); autocomplete_add(help_commands_ac, "ui"); prefs_ac = autocomplete_new(); autocomplete_add(prefs_ac, "ui"); autocomplete_add(prefs_ac, "desktop"); autocomplete_add(prefs_ac, "chat"); autocomplete_add(prefs_ac, "log"); autocomplete_add(prefs_ac, "conn"); autocomplete_add(prefs_ac, "presence"); autocomplete_add(prefs_ac, "otr"); autocomplete_add(prefs_ac, "pgp"); notify_ac = autocomplete_new(); autocomplete_add(notify_ac, "message"); autocomplete_add(notify_ac, "room"); autocomplete_add(notify_ac, "typing"); autocomplete_add(notify_ac, "remind"); autocomplete_add(notify_ac, "invite"); autocomplete_add(notify_ac, "sub"); notify_message_ac = autocomplete_new(); autocomplete_add(notify_message_ac, "on"); autocomplete_add(notify_message_ac, "off"); autocomplete_add(notify_message_ac, "current"); autocomplete_add(notify_message_ac, "text"); notify_room_ac = autocomplete_new(); autocomplete_add(notify_room_ac, "on"); autocomplete_add(notify_room_ac, "off"); autocomplete_add(notify_room_ac, "mention"); autocomplete_add(notify_room_ac, "current"); autocomplete_add(notify_room_ac, "text"); notify_typing_ac = autocomplete_new(); autocomplete_add(notify_typing_ac, "on"); autocomplete_add(notify_typing_ac, "off"); autocomplete_add(notify_typing_ac, "current"); sub_ac = autocomplete_new(); autocomplete_add(sub_ac, "request"); autocomplete_add(sub_ac, "allow"); autocomplete_add(sub_ac, "deny"); autocomplete_add(sub_ac, "show"); autocomplete_add(sub_ac, "sent"); autocomplete_add(sub_ac, "received"); titlebar_ac = autocomplete_new(); autocomplete_add(titlebar_ac, "show"); autocomplete_add(titlebar_ac, "goodbye"); log_ac = autocomplete_new(); autocomplete_add(log_ac, "maxsize"); autocomplete_add(log_ac, "rotate"); autocomplete_add(log_ac, "shared"); autocomplete_add(log_ac, "where"); autoaway_ac = autocomplete_new(); autocomplete_add(autoaway_ac, "mode"); autocomplete_add(autoaway_ac, "time"); autocomplete_add(autoaway_ac, "message"); autocomplete_add(autoaway_ac, "check"); autoaway_mode_ac = autocomplete_new(); autocomplete_add(autoaway_mode_ac, "away"); autocomplete_add(autoaway_mode_ac, "idle"); autocomplete_add(autoaway_mode_ac, "off"); autoconnect_ac = autocomplete_new(); autocomplete_add(autoconnect_ac, "set"); autocomplete_add(autoconnect_ac, "off"); theme_ac = autocomplete_new(); autocomplete_add(theme_ac, "load"); autocomplete_add(theme_ac, "list"); autocomplete_add(theme_ac, "colours"); disco_ac = autocomplete_new(); autocomplete_add(disco_ac, "info"); autocomplete_add(disco_ac, "items"); account_ac = autocomplete_new(); autocomplete_add(account_ac, "list"); autocomplete_add(account_ac, "show"); autocomplete_add(account_ac, "add"); autocomplete_add(account_ac, "remove"); autocomplete_add(account_ac, "enable"); autocomplete_add(account_ac, "disable"); autocomplete_add(account_ac, "default"); autocomplete_add(account_ac, "rename"); autocomplete_add(account_ac, "set"); autocomplete_add(account_ac, "clear"); account_set_ac = autocomplete_new(); autocomplete_add(account_set_ac, "jid"); autocomplete_add(account_set_ac, "server"); autocomplete_add(account_set_ac, "port"); autocomplete_add(account_set_ac, "status"); autocomplete_add(account_set_ac, "online"); autocomplete_add(account_set_ac, "chat"); autocomplete_add(account_set_ac, "away"); autocomplete_add(account_set_ac, "xa"); autocomplete_add(account_set_ac, "dnd"); autocomplete_add(account_set_ac, "resource"); autocomplete_add(account_set_ac, "password"); autocomplete_add(account_set_ac, "eval_password"); autocomplete_add(account_set_ac, "muc"); autocomplete_add(account_set_ac, "nick"); autocomplete_add(account_set_ac, "otr"); autocomplete_add(account_set_ac, "pgpkeyid"); account_clear_ac = autocomplete_new(); autocomplete_add(account_clear_ac, "password"); autocomplete_add(account_clear_ac, "eval_password"); autocomplete_add(account_clear_ac, "server"); autocomplete_add(account_clear_ac, "port"); autocomplete_add(account_clear_ac, "otr"); autocomplete_add(account_clear_ac, "pgpkeyid"); account_default_ac = autocomplete_new(); autocomplete_add(account_default_ac, "set"); autocomplete_add(account_default_ac, "off"); account_status_ac = autocomplete_new(); autocomplete_add(account_status_ac, "online"); autocomplete_add(account_status_ac, "chat"); autocomplete_add(account_status_ac, "away"); autocomplete_add(account_status_ac, "xa"); autocomplete_add(account_status_ac, "dnd"); autocomplete_add(account_status_ac, "last"); close_ac = autocomplete_new(); autocomplete_add(close_ac, "read"); autocomplete_add(close_ac, "all"); wins_ac = autocomplete_new(); autocomplete_add(wins_ac, "prune"); autocomplete_add(wins_ac, "tidy"); autocomplete_add(wins_ac, "autotidy"); autocomplete_add(wins_ac, "swap"); roster_ac = autocomplete_new(); autocomplete_add(roster_ac, "add"); autocomplete_add(roster_ac, "online"); autocomplete_add(roster_ac, "nick"); autocomplete_add(roster_ac, "clearnick"); autocomplete_add(roster_ac, "remove"); autocomplete_add(roster_ac, "remove_all"); autocomplete_add(roster_ac, "show"); autocomplete_add(roster_ac, "hide"); autocomplete_add(roster_ac, "by"); autocomplete_add(roster_ac, "size"); roster_option_ac = autocomplete_new(); autocomplete_add(roster_option_ac, "offline"); autocomplete_add(roster_option_ac, "resource"); autocomplete_add(roster_option_ac, "empty"); roster_by_ac = autocomplete_new(); autocomplete_add(roster_by_ac, "group"); autocomplete_add(roster_by_ac, "presence"); autocomplete_add(roster_by_ac, "none"); roster_remove_all_ac = autocomplete_new(); autocomplete_add(roster_remove_all_ac, "contacts"); group_ac = autocomplete_new(); autocomplete_add(group_ac, "show"); autocomplete_add(group_ac, "add"); autocomplete_add(group_ac, "remove"); theme_load_ac = NULL; who_roster_ac = autocomplete_new(); autocomplete_add(who_roster_ac, "chat"); autocomplete_add(who_roster_ac, "online"); autocomplete_add(who_roster_ac, "away"); autocomplete_add(who_roster_ac, "xa"); autocomplete_add(who_roster_ac, "dnd"); autocomplete_add(who_roster_ac, "offline"); autocomplete_add(who_roster_ac, "available"); autocomplete_add(who_roster_ac, "unavailable"); autocomplete_add(who_roster_ac, "any"); who_room_ac = autocomplete_new(); autocomplete_add(who_room_ac, "chat"); autocomplete_add(who_room_ac, "online"); autocomplete_add(who_room_ac, "away"); autocomplete_add(who_room_ac, "xa"); autocomplete_add(who_room_ac, "dnd"); autocomplete_add(who_room_ac, "available"); autocomplete_add(who_room_ac, "unavailable"); autocomplete_add(who_room_ac, "moderator"); autocomplete_add(who_room_ac, "participant"); autocomplete_add(who_room_ac, "visitor"); autocomplete_add(who_room_ac, "owner"); autocomplete_add(who_room_ac, "admin"); autocomplete_add(who_room_ac, "member"); bookmark_ac = autocomplete_new(); autocomplete_add(bookmark_ac, "list"); autocomplete_add(bookmark_ac, "add"); autocomplete_add(bookmark_ac, "update"); autocomplete_add(bookmark_ac, "remove"); autocomplete_add(bookmark_ac, "join"); bookmark_property_ac = autocomplete_new(); autocomplete_add(bookmark_property_ac, "nick"); autocomplete_add(bookmark_property_ac, "password"); autocomplete_add(bookmark_property_ac, "autojoin"); otr_ac = autocomplete_new(); autocomplete_add(otr_ac, "gen"); autocomplete_add(otr_ac, "start"); autocomplete_add(otr_ac, "end"); autocomplete_add(otr_ac, "myfp"); autocomplete_add(otr_ac, "theirfp"); autocomplete_add(otr_ac, "trust"); autocomplete_add(otr_ac, "untrust"); autocomplete_add(otr_ac, "secret"); autocomplete_add(otr_ac, "log"); autocomplete_add(otr_ac, "libver"); autocomplete_add(otr_ac, "policy"); autocomplete_add(otr_ac, "question"); autocomplete_add(otr_ac, "answer"); autocomplete_add(otr_ac, "char"); otr_log_ac = autocomplete_new(); autocomplete_add(otr_log_ac, "on"); autocomplete_add(otr_log_ac, "off"); autocomplete_add(otr_log_ac, "redact"); otr_policy_ac = autocomplete_new(); autocomplete_add(otr_policy_ac, "manual"); autocomplete_add(otr_policy_ac, "opportunistic"); autocomplete_add(otr_policy_ac, "always"); connect_property_ac = autocomplete_new(); autocomplete_add(connect_property_ac, "server"); autocomplete_add(connect_property_ac, "port"); join_property_ac = autocomplete_new(); autocomplete_add(join_property_ac, "nick"); autocomplete_add(join_property_ac, "password"); statuses_ac = autocomplete_new(); autocomplete_add(statuses_ac, "console"); autocomplete_add(statuses_ac, "chat"); autocomplete_add(statuses_ac, "muc"); statuses_setting_ac = autocomplete_new(); autocomplete_add(statuses_setting_ac, "all"); autocomplete_add(statuses_setting_ac, "online"); autocomplete_add(statuses_setting_ac, "none"); alias_ac = autocomplete_new(); autocomplete_add(alias_ac, "add"); autocomplete_add(alias_ac, "remove"); autocomplete_add(alias_ac, "list"); room_ac = autocomplete_new(); autocomplete_add(room_ac, "accept"); autocomplete_add(room_ac, "destroy"); autocomplete_add(room_ac, "config"); affiliation_ac = autocomplete_new(); autocomplete_add(affiliation_ac, "owner"); autocomplete_add(affiliation_ac, "admin"); autocomplete_add(affiliation_ac, "member"); autocomplete_add(affiliation_ac, "none"); autocomplete_add(affiliation_ac, "outcast"); role_ac = autocomplete_new(); autocomplete_add(role_ac, "moderator"); autocomplete_add(role_ac, "participant"); autocomplete_add(role_ac, "visitor"); autocomplete_add(role_ac, "none"); privilege_cmd_ac = autocomplete_new(); autocomplete_add(privilege_cmd_ac, "list"); autocomplete_add(privilege_cmd_ac, "set"); subject_ac = autocomplete_new(); autocomplete_add(subject_ac, "set"); autocomplete_add(subject_ac, "clear"); form_ac = autocomplete_new(); autocomplete_add(form_ac, "submit"); autocomplete_add(form_ac, "cancel"); autocomplete_add(form_ac, "show"); autocomplete_add(form_ac, "help"); form_field_multi_ac = autocomplete_new(); autocomplete_add(form_field_multi_ac, "add"); autocomplete_add(form_field_multi_ac, "remove"); occupants_ac = autocomplete_new(); autocomplete_add(occupants_ac, "show"); autocomplete_add(occupants_ac, "hide"); autocomplete_add(occupants_ac, "default"); autocomplete_add(occupants_ac, "size"); occupants_default_ac = autocomplete_new(); autocomplete_add(occupants_default_ac, "show"); autocomplete_add(occupants_default_ac, "hide"); occupants_show_ac = autocomplete_new(); autocomplete_add(occupants_show_ac, "jid"); time_ac = autocomplete_new(); autocomplete_add(time_ac, "main"); autocomplete_add(time_ac, "statusbar"); time_format_ac = autocomplete_new(); autocomplete_add(time_format_ac, "set"); autocomplete_add(time_format_ac, "off"); resource_ac = autocomplete_new(); autocomplete_add(resource_ac, "set"); autocomplete_add(resource_ac, "off"); autocomplete_add(resource_ac, "title"); autocomplete_add(resource_ac, "message"); inpblock_ac = autocomplete_new(); autocomplete_add(inpblock_ac, "timeout"); autocomplete_add(inpblock_ac, "dynamic"); receipts_ac = autocomplete_new(); autocomplete_add(receipts_ac, "send"); autocomplete_add(receipts_ac, "request"); pgp_ac = autocomplete_new(); autocomplete_add(pgp_ac, "keys"); autocomplete_add(pgp_ac, "contacts"); autocomplete_add(pgp_ac, "setkey"); autocomplete_add(pgp_ac, "libver"); autocomplete_add(pgp_ac, "start"); autocomplete_add(pgp_ac, "end"); autocomplete_add(pgp_ac, "log"); autocomplete_add(pgp_ac, "char"); pgp_log_ac = autocomplete_new(); autocomplete_add(pgp_log_ac, "on"); autocomplete_add(pgp_log_ac, "off"); autocomplete_add(pgp_log_ac, "redact"); } void cmd_uninit(void) { autocomplete_free(commands_ac); autocomplete_free(who_room_ac); autocomplete_free(who_roster_ac); autocomplete_free(help_ac); autocomplete_free(help_commands_ac); autocomplete_free(notify_ac); autocomplete_free(notify_message_ac); autocomplete_free(notify_room_ac); autocomplete_free(notify_typing_ac); autocomplete_free(sub_ac); autocomplete_free(titlebar_ac); autocomplete_free(log_ac); autocomplete_free(prefs_ac); autocomplete_free(autoaway_ac); autocomplete_free(autoaway_mode_ac); autocomplete_free(autoconnect_ac); autocomplete_free(theme_ac); autocomplete_free(theme_load_ac); autocomplete_free(account_ac); autocomplete_free(account_set_ac); autocomplete_free(account_clear_ac); autocomplete_free(account_default_ac); autocomplete_free(account_status_ac); autocomplete_free(disco_ac); autocomplete_free(close_ac); autocomplete_free(wins_ac); autocomplete_free(roster_ac); autocomplete_free(roster_option_ac); autocomplete_free(roster_by_ac); autocomplete_free(roster_remove_all_ac); autocomplete_free(group_ac); autocomplete_free(bookmark_ac); autocomplete_free(bookmark_property_ac); autocomplete_free(otr_ac); autocomplete_free(otr_log_ac); autocomplete_free(otr_policy_ac); autocomplete_free(connect_property_ac); autocomplete_free(statuses_ac); autocomplete_free(statuses_setting_ac); autocomplete_free(alias_ac); autocomplete_free(aliases_ac); autocomplete_free(join_property_ac); autocomplete_free(room_ac); autocomplete_free(affiliation_ac); autocomplete_free(role_ac); autocomplete_free(privilege_cmd_ac); autocomplete_free(subject_ac); autocomplete_free(form_ac); autocomplete_free(form_field_multi_ac); autocomplete_free(occupants_ac); autocomplete_free(occupants_default_ac); autocomplete_free(occupants_show_ac); autocomplete_free(time_ac); autocomplete_free(time_format_ac); autocomplete_free(resource_ac); autocomplete_free(inpblock_ac); autocomplete_free(receipts_ac); autocomplete_free(pgp_ac); autocomplete_free(pgp_log_ac); } gboolean cmd_exists(char *cmd) { if (commands_ac == NULL) { return FALSE; } else { return autocomplete_contains(commands_ac, cmd); } } void cmd_autocomplete_add(char *value) { if (commands_ac) { autocomplete_add(commands_ac, value); } } void cmd_autocomplete_add_form_fields(DataForm *form) { if (form == NULL) { return; } GSList *fields = autocomplete_create_list(form->tag_ac); GSList *curr_field = fields; while (curr_field) { GString *field_str = g_string_new("/"); g_string_append(field_str, curr_field->data); cmd_autocomplete_add(field_str->str); g_string_free(field_str, TRUE); curr_field = g_slist_next(curr_field); } g_slist_free_full(fields, free); } void cmd_autocomplete_remove_form_fields(DataForm *form) { if (form == NULL) { return; } GSList *fields = autocomplete_create_list(form->tag_ac); GSList *curr_field = fields; while (curr_field) { GString *field_str = g_string_new("/"); g_string_append(field_str, curr_field->data); cmd_autocomplete_remove(field_str->str); g_string_free(field_str, TRUE); curr_field = g_slist_next(curr_field); } g_slist_free_full(fields, free); } void cmd_autocomplete_remove(char *value) { if (commands_ac) { autocomplete_remove(commands_ac, value); } } void cmd_alias_add(char *value) { if (aliases_ac) { autocomplete_add(aliases_ac, value); } } void cmd_alias_remove(char *value) { if (aliases_ac) { autocomplete_remove(aliases_ac, value); } } // Command autocompletion functions char* cmd_autocomplete(ProfWin *window, const char * const input) { // autocomplete command if ((strncmp(input, "/", 1) == 0) && (!str_contains(input, strlen(input), ' '))) { char *found = NULL; found = autocomplete_complete(commands_ac, input, TRUE); if (found) { return found; } // autocomplete parameters } else { char *found = _cmd_complete_parameters(window, input); if (found) { return found; } } return NULL; } void cmd_reset_autocomplete(ProfWin *window) { roster_reset_search_attempts(); muc_invites_reset_ac(); accounts_reset_all_search(); accounts_reset_enabled_search(); prefs_reset_boolean_choice(); presence_reset_sub_request_search(); #ifdef HAVE_LIBGPGME p_gpg_autocomplete_key_reset(); #endif autocomplete_reset(help_ac); autocomplete_reset(help_commands_ac); autocomplete_reset(notify_ac); autocomplete_reset(notify_message_ac); autocomplete_reset(notify_room_ac); autocomplete_reset(notify_typing_ac); autocomplete_reset(sub_ac); autocomplete_reset(who_room_ac); autocomplete_reset(who_roster_ac); autocomplete_reset(prefs_ac); autocomplete_reset(log_ac); autocomplete_reset(commands_ac); autocomplete_reset(autoaway_ac); autocomplete_reset(autoaway_mode_ac); autocomplete_reset(autoconnect_ac); autocomplete_reset(theme_ac); if (theme_load_ac) { autocomplete_free(theme_load_ac); theme_load_ac = NULL; } autocomplete_reset(account_ac); autocomplete_reset(account_set_ac); autocomplete_reset(account_clear_ac); autocomplete_reset(account_default_ac); autocomplete_reset(account_status_ac); autocomplete_reset(disco_ac); autocomplete_reset(close_ac); autocomplete_reset(wins_ac); autocomplete_reset(roster_ac); autocomplete_reset(roster_option_ac); autocomplete_reset(roster_by_ac); autocomplete_reset(roster_remove_all_ac); autocomplete_reset(group_ac); autocomplete_reset(titlebar_ac); autocomplete_reset(bookmark_ac); autocomplete_reset(bookmark_property_ac); autocomplete_reset(otr_ac); autocomplete_reset(otr_log_ac); autocomplete_reset(otr_policy_ac); autocomplete_reset(connect_property_ac); autocomplete_reset(statuses_ac); autocomplete_reset(statuses_setting_ac); autocomplete_reset(alias_ac); autocomplete_reset(aliases_ac); autocomplete_reset(join_property_ac); autocomplete_reset(room_ac); autocomplete_reset(affiliation_ac); autocomplete_reset(role_ac); autocomplete_reset(privilege_cmd_ac); autocomplete_reset(subject_ac); autocomplete_reset(form_ac); autocomplete_reset(form_field_multi_ac); autocomplete_reset(occupants_ac); autocomplete_reset(occupants_default_ac); autocomplete_reset(occupants_show_ac); autocomplete_reset(time_ac); autocomplete_reset(time_format_ac); autocomplete_reset(resource_ac); autocomplete_reset(inpblock_ac); autocomplete_reset(receipts_ac); autocomplete_reset(pgp_ac); autocomplete_reset(pgp_log_ac); if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); PContact contact = roster_get_contact(chatwin->barejid); if (contact) { p_contact_resource_ac_reset(contact); } } if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); muc_autocomplete_reset(mucwin->roomjid); muc_jid_autocomplete_reset(mucwin->roomjid); } if (window->type == WIN_MUC_CONFIG) { ProfMucConfWin *confwin = (ProfMucConfWin*)window; assert(confwin->memcheck == PROFCONFWIN_MEMCHECK); if (confwin->form) { form_reset_autocompleters(confwin->form); } } bookmark_autocomplete_reset(); } gboolean cmd_valid_tag(const char * const str) { return ((g_strcmp0(str, CMD_TAG_CHAT) == 0) || (g_strcmp0(str, CMD_TAG_GROUPCHAT) == 0) || (g_strcmp0(str, CMD_TAG_PRESENCE) == 0) || (g_strcmp0(str, CMD_TAG_ROSTER) == 0) || (g_strcmp0(str, CMD_TAG_DISCOVERY) == 0) || (g_strcmp0(str, CMD_TAG_CONNECTION) == 0) || (g_strcmp0(str, CMD_TAG_UI) == 0)); } gboolean cmd_has_tag(Command *pcmd, const char * const tag) { int i = 0; for (i = 0; pcmd->help.tags[i] != NULL; i++) { if (g_strcmp0(tag, pcmd->help.tags[i]) == 0) { return TRUE; } } return FALSE; } /* * Take a line of input and process it, return TRUE if profanity is to * continue, FALSE otherwise */ gboolean cmd_process_input(ProfWin *window, char *inp) { log_debug("Input received: %s", inp); gboolean result = FALSE; g_strchomp(inp); // just carry on if no input if (strlen(inp) == 0) { result = TRUE; // handle command if input starts with a '/' } else if (inp[0] == '/') { char *inp_cpy = strdup(inp); char *command = strtok(inp_cpy, " "); result = _cmd_execute(window, command, inp); free(inp_cpy); // call a default handler if input didn't start with '/' } else { result = cmd_execute_default(window, inp); } return result; } // Command execution void cmd_execute_connect(ProfWin *window, const char * const account) { GString *command = g_string_new("/connect "); g_string_append(command, account); cmd_process_input(window, command->str); g_string_free(command, TRUE); } static gboolean _cmd_execute(ProfWin *window, const char * const command, const char * const inp) { if (g_str_has_prefix(command, "/field") && window->type == WIN_MUC_CONFIG) { gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 1, 2, &result); if (!result) { ui_current_print_formatted_line('!', 0, "Invalid command, see /form help"); result = TRUE; } else { gchar **tokens = g_strsplit(inp, " ", 2); char *field = tokens[0] + 1; result = cmd_form_field(window, field, args); g_strfreev(tokens); } g_strfreev(args); return result; } Command *cmd = g_hash_table_lookup(commands, command); gboolean result = FALSE; if (cmd) { gchar **args = cmd->parser(inp, cmd->min_args, cmd->max_args, &result); if (result == FALSE) { ui_invalid_command_usage(cmd->cmd, cmd->setting_func); return TRUE; } else { gboolean result = cmd->func(window, command, args); g_strfreev(args); return result; } } else { gboolean ran_alias = FALSE; gboolean alias_result = cmd_execute_alias(window, inp, &ran_alias); if (!ran_alias) { return cmd_execute_default(window, inp); } else { return alias_result; } } } static char * _cmd_complete_parameters(ProfWin *window, const char * const input) { int i; char *result = NULL; // autocomplete boolean settings gchar *boolean_choices[] = { "/beep", "/intype", "/states", "/outtype", "/flash", "/splash", "/chlog", "/grlog", "/history", "/vercheck", "/privileges", "/presence", "/wrap", "/winstidy", "/carbons", "/encwarn" }; for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) { result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice); if (result) { return result; } } // autocomplete nickname in chat rooms if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid); if (nick_ac) { gchar *nick_choices[] = { "/msg", "/info", "/caps", "/status", "/software" } ; // Remove quote character before and after names when doing autocomplete char *unquoted = strip_arg_quotes(input); for (i = 0; i < ARRAY_SIZE(nick_choices); i++) { result = autocomplete_param_with_ac(unquoted, nick_choices[i], nick_ac, TRUE); if (result) { free(unquoted); return result; } } free(unquoted); } // otherwise autocomplete using roster } else { gchar *contact_choices[] = { "/msg", "/info", "/status" }; // Remove quote character before and after names when doing autocomplete char *unquoted = strip_arg_quotes(input); for (i = 0; i < ARRAY_SIZE(contact_choices); i++) { result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_contact_autocomplete); if (result) { free(unquoted); return result; } } free(unquoted); gchar *resource_choices[] = { "/caps", "/software", "/ping" }; for (i = 0; i < ARRAY_SIZE(resource_choices); i++) { result = autocomplete_param_with_func(input, resource_choices[i], roster_fulljid_autocomplete); if (result) { return result; } } } result = autocomplete_param_with_func(input, "/invite", roster_contact_autocomplete); if (result) { return result; } gchar *invite_choices[] = { "/decline", "/join" }; for (i = 0; i < ARRAY_SIZE(invite_choices); i++) { result = autocomplete_param_with_func(input, invite_choices[i], muc_invites_find); if (result) { return result; } } gchar *cmds[] = { "/prefs", "/disco", "/close", "/subject", "/room" }; Autocomplete completers[] = { prefs_ac, disco_ac, close_ac, subject_ac, room_ac }; for (i = 0; i < ARRAY_SIZE(cmds); i++) { result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE); if (result) { return result; } } GHashTable *ac_funcs = g_hash_table_new(g_str_hash, g_str_equal); g_hash_table_insert(ac_funcs, "/help", _help_autocomplete); g_hash_table_insert(ac_funcs, "/who", _who_autocomplete); g_hash_table_insert(ac_funcs, "/sub", _sub_autocomplete); g_hash_table_insert(ac_funcs, "/notify", _notify_autocomplete); g_hash_table_insert(ac_funcs, "/autoaway", _autoaway_autocomplete); g_hash_table_insert(ac_funcs, "/theme", _theme_autocomplete); g_hash_table_insert(ac_funcs, "/log", _log_autocomplete); g_hash_table_insert(ac_funcs, "/account", _account_autocomplete); g_hash_table_insert(ac_funcs, "/roster", _roster_autocomplete); g_hash_table_insert(ac_funcs, "/group", _group_autocomplete); g_hash_table_insert(ac_funcs, "/bookmark", _bookmark_autocomplete); g_hash_table_insert(ac_funcs, "/autoconnect", _autoconnect_autocomplete); g_hash_table_insert(ac_funcs, "/otr", _otr_autocomplete); g_hash_table_insert(ac_funcs, "/pgp", _pgp_autocomplete); g_hash_table_insert(ac_funcs, "/connect", _connect_autocomplete); g_hash_table_insert(ac_funcs, "/statuses", _statuses_autocomplete); g_hash_table_insert(ac_funcs, "/alias", _alias_autocomplete); g_hash_table_insert(ac_funcs, "/join", _join_autocomplete); g_hash_table_insert(ac_funcs, "/form", _form_autocomplete); g_hash_table_insert(ac_funcs, "/occupants", _occupants_autocomplete); g_hash_table_insert(ac_funcs, "/kick", _kick_autocomplete); g_hash_table_insert(ac_funcs, "/ban", _ban_autocomplete); g_hash_table_insert(ac_funcs, "/affiliation", _affiliation_autocomplete); g_hash_table_insert(ac_funcs, "/role", _role_autocomplete); g_hash_table_insert(ac_funcs, "/resource", _resource_autocomplete); g_hash_table_insert(ac_funcs, "/titlebar", _titlebar_autocomplete); g_hash_table_insert(ac_funcs, "/inpblock", _inpblock_autocomplete); g_hash_table_insert(ac_funcs, "/time", _time_autocomplete); g_hash_table_insert(ac_funcs, "/receipts", _receipts_autocomplete); g_hash_table_insert(ac_funcs, "/wins", _wins_autocomplete); int len = strlen(input); char parsed[len+1]; i = 0; while (i < len) { if (input[i] == ' ') { break; } else { parsed[i] = input[i]; } i++; } parsed[i] = '\0'; char * (*ac_func)(ProfWin*, const char * const) = g_hash_table_lookup(ac_funcs, parsed); if (ac_func) { result = ac_func(window, input); if (result) { g_hash_table_destroy(ac_funcs); return result; } } g_hash_table_destroy(ac_funcs); if (g_str_has_prefix(input, "/field")) { result = _form_field_autocomplete(window, input); if (result) { return result; } } return NULL; } static char * _sub_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_func(input, "/sub allow", presence_sub_request_find); if (result) { return result; } result = autocomplete_param_with_func(input, "/sub deny", presence_sub_request_find); if (result) { return result; } result = autocomplete_param_with_ac(input, "/sub", sub_ac, TRUE); if (result) { return result; } return NULL; } static char * _who_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; if (window->type == WIN_MUC) { result = autocomplete_param_with_ac(input, "/who", who_room_ac, TRUE); if (result) { return result; } } else { int i = 0; gchar *group_commands[] = { "/who any", "/who online", "/who offline", "/who chat", "/who away", "/who xa", "/who dnd", "/who available", "/who unavailable" }; for (i = 0; i < ARRAY_SIZE(group_commands); i++) { result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete); if (result) { return result; } } result = autocomplete_param_with_ac(input, "/who", who_roster_ac, TRUE); if (result) { return result; } } return NULL; } static char * _roster_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_func(input, "/roster nick", roster_barejid_autocomplete); if (result) { return result; } result = autocomplete_param_with_func(input, "/roster clearnick", roster_barejid_autocomplete); if (result) { return result; } result = autocomplete_param_with_func(input, "/roster remove", roster_barejid_autocomplete); if (result) { return result; } result = autocomplete_param_with_ac(input, "/roster remove_all", roster_remove_all_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/roster show", roster_option_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/roster hide", roster_option_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/roster by", roster_by_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/roster", roster_ac, TRUE); if (result) { return result; } return NULL; } static char * _group_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_func(input, "/group show", roster_group_autocomplete); if (result) { return result; } result = autocomplete_param_no_with_func(input, "/group add", 4, roster_contact_autocomplete); if (result) { return result; } result = autocomplete_param_no_with_func(input, "/group remove", 4, roster_contact_autocomplete); if (result) { return result; } result = autocomplete_param_with_func(input, "/group add", roster_group_autocomplete); if (result) { return result; } result = autocomplete_param_with_func(input, "/group remove", roster_group_autocomplete); if (result) { return result; } result = autocomplete_param_with_ac(input, "/group", group_ac, TRUE); if (result) { return result; } return NULL; } static char * _bookmark_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; gboolean result; gchar **args = parse_args(input, 3, 8, &result); gboolean handle_options = result && (g_strv_length(args) > 2); if (handle_options && ((strcmp(args[0], "add") == 0) || (strcmp(args[0], "update") == 0)) ) { GString *beginning = g_string_new("/bookmark"); gboolean autojoin = FALSE; int num_args = g_strv_length(args); g_string_append(beginning, " "); g_string_append(beginning, args[0]); g_string_append(beginning, " "); g_string_append(beginning, args[1]); if (num_args == 4 && g_strcmp0(args[2], "autojoin") == 0) { g_string_append(beginning, " "); g_string_append(beginning, args[2]); autojoin = TRUE; } if (num_args > 4) { g_string_append(beginning, " "); g_string_append(beginning, args[2]); g_string_append(beginning, " "); g_string_append(beginning, args[3]); if (num_args == 6 && g_strcmp0(args[4], "autojoin") == 0) { g_string_append(beginning, " "); g_string_append(beginning, args[4]); autojoin = TRUE; } } if (num_args > 6) { g_string_append(beginning, " "); g_string_append(beginning, args[4]); g_string_append(beginning, " "); g_string_append(beginning, args[5]); if (num_args == 8 && g_strcmp0(args[6], "autojoin") == 0) { g_string_append(beginning, " "); g_string_append(beginning, args[6]); autojoin = TRUE; } } if (autojoin) { found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice); } else { found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE); } g_string_free(beginning, TRUE); if (found) { g_strfreev(args); return found; } } g_strfreev(args); found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find); if (found) { return found; } found = autocomplete_param_with_func(input, "/bookmark join", bookmark_find); if (found) { return found; } found = autocomplete_param_with_func(input, "/bookmark update", bookmark_find); if (found) { return found; } found = autocomplete_param_with_ac(input, "/bookmark", bookmark_ac, TRUE); return found; } static char * _notify_autocomplete(ProfWin *window, const char * const input) { int i = 0; char *result = NULL; result = autocomplete_param_with_func(input, "/notify room current", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_func(input, "/notify message current", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_func(input, "/notify typing current", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_func(input, "/notify room text", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_func(input, "/notify message text", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_ac(input, "/notify room", notify_room_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/notify message", notify_message_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/notify typing", notify_typing_ac, TRUE); if (result) { return result; } gchar *boolean_choices[] = { "/notify invite", "/notify sub" }; for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) { result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice); if (result) { return result; } } result = autocomplete_param_with_ac(input, "/notify", notify_ac, TRUE); if (result) { return result; } return NULL; } static char * _autoaway_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_ac(input, "/autoaway mode", autoaway_mode_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_func(input, "/autoaway check", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_ac(input, "/autoaway", autoaway_ac, TRUE); if (result) { return result; } return NULL; } static char * _log_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_func(input, "/log rotate", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_func(input, "/log shared", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_ac(input, "/log", log_ac, TRUE); if (result) { return result; } return NULL; } static char * _autoconnect_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_func(input, "/autoconnect set", accounts_find_enabled); if (result) { return result; } result = autocomplete_param_with_ac(input, "/autoconnect", autoconnect_ac, TRUE); if (result) { return result; } return NULL; } static char * _otr_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; found = autocomplete_param_with_func(input, "/otr start", roster_contact_autocomplete); if (found) { return found; } found = autocomplete_param_with_ac(input, "/otr log", otr_log_ac, TRUE); if (found) { return found; } // /otr policy always user@server.com gboolean result; gchar **args = parse_args(input, 3, 3, &result); if (result && (strcmp(args[0], "policy") == 0)) { GString *beginning = g_string_new("/otr "); g_string_append(beginning, args[0]); g_string_append(beginning, " "); g_string_append(beginning, args[1]); found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete); g_string_free(beginning, TRUE); if (found) { g_strfreev(args); return found; } } g_strfreev(args); found = autocomplete_param_with_ac(input, "/otr policy", otr_policy_ac, TRUE); if (found) { return found; } found = autocomplete_param_with_ac(input, "/otr", otr_ac, TRUE); if (found) { return found; } return NULL; } static char * _pgp_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; found = autocomplete_param_with_func(input, "/pgp start", roster_contact_autocomplete); if (found) { return found; } found = autocomplete_param_with_ac(input, "/pgp log", pgp_log_ac, TRUE); if (found) { return found; } #ifdef HAVE_LIBGPGME gboolean result; gchar **args = parse_args(input, 2, 3, &result); if ((strncmp(input, "/pgp", 4) == 0) && (result == TRUE)) { GString *beginning = g_string_new("/pgp "); g_string_append(beginning, args[0]); if (args[1]) { g_string_append(beginning, " "); g_string_append(beginning, args[1]); } found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key); g_string_free(beginning, TRUE); if (found) { g_strfreev(args); return found; } } g_strfreev(args); #endif found = autocomplete_param_with_func(input, "/pgp setkey", roster_barejid_autocomplete); if (found) { return found; } found = autocomplete_param_with_ac(input, "/pgp", pgp_ac, TRUE); if (found) { return found; } return NULL; } static char * _theme_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; if ((strncmp(input, "/theme load ", 12) == 0) && (strlen(input) > 12)) { if (theme_load_ac == NULL) { theme_load_ac = autocomplete_new(); GSList *themes = theme_list(); GSList *curr = themes; while (curr) { autocomplete_add(theme_load_ac, curr->data); curr = g_slist_next(curr); } g_slist_free_full(themes, g_free); autocomplete_add(theme_load_ac, "default"); } result = autocomplete_param_with_ac(input, "/theme load", theme_load_ac, TRUE); if (result) { return result; } } result = autocomplete_param_with_ac(input, "/theme", theme_ac, TRUE); if (result) { return result; } return NULL; } static char * _resource_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); PContact contact = roster_get_contact(chatwin->barejid); if (contact) { Autocomplete ac = p_contact_resource_ac(contact); found = autocomplete_param_with_ac(input, "/resource set", ac, FALSE); if (found) { return found; } } } found = autocomplete_param_with_func(input, "/resource title", prefs_autocomplete_boolean_choice); if (found) { return found; } found = autocomplete_param_with_func(input, "/resource message", prefs_autocomplete_boolean_choice); if (found) { return found; } found = autocomplete_param_with_ac(input, "/resource", resource_ac, FALSE); if (found) { return found; } return NULL; } static char * _titlebar_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; found = autocomplete_param_with_func(input, "/titlebar show", prefs_autocomplete_boolean_choice); if (found) { return found; } found = autocomplete_param_with_func(input, "/titlebar goodbye", prefs_autocomplete_boolean_choice); if (found) { return found; } found = autocomplete_param_with_ac(input, "/titlebar", titlebar_ac, FALSE); if (found) { return found; } return NULL; } static char * _inpblock_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; found = autocomplete_param_with_func(input, "/inpblock dynamic", prefs_autocomplete_boolean_choice); if (found) { return found; } found = autocomplete_param_with_ac(input, "/inpblock", inpblock_ac, FALSE); if (found) { return found; } return NULL; } static char * _form_autocomplete(ProfWin *window, const char * const input) { if (window->type != WIN_MUC_CONFIG) { return NULL; } char *found = NULL; ProfMucConfWin *confwin = (ProfMucConfWin*)window; DataForm *form = confwin->form; if (form) { found = autocomplete_param_with_ac(input, "/form help", form->tag_ac, TRUE); if (found) { return found; } } found = autocomplete_param_with_ac(input, "/form", form_ac, TRUE); if (found) { return found; } return NULL; } static char * _form_field_autocomplete(ProfWin *window, const char * const input) { if (window->type != WIN_MUC_CONFIG) { return NULL; } char *found = NULL; ProfMucConfWin *confwin = (ProfMucConfWin*)window; DataForm *form = confwin->form; if (form == NULL) { return NULL; } gchar **split = g_strsplit(input, " ", 0); if (g_strv_length(split) == 3) { char *field_tag = split[0]+1; if (form_tag_exists(form, field_tag)) { form_field_type_t field_type = form_get_field_type(form, field_tag); Autocomplete value_ac = form_get_value_ac(form, field_tag);; GString *beginning = g_string_new(split[0]); g_string_append(beginning, " "); g_string_append(beginning, split[1]); if (((g_strcmp0(split[1], "add") == 0) || (g_strcmp0(split[1], "remove") == 0)) && field_type == FIELD_LIST_MULTI) { found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE); } else if ((g_strcmp0(split[1], "remove") == 0) && field_type == FIELD_TEXT_MULTI) { found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE); } else if ((g_strcmp0(split[1], "remove") == 0) && field_type == FIELD_JID_MULTI) { found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE); } g_string_free(beginning, TRUE); } } else if (g_strv_length(split) == 2) { char *field_tag = split[0]+1; if (form_tag_exists(form, field_tag)) { form_field_type_t field_type = form_get_field_type(form, field_tag); Autocomplete value_ac = form_get_value_ac(form, field_tag);; switch (field_type) { case FIELD_BOOLEAN: found = autocomplete_param_with_func(input, split[0], prefs_autocomplete_boolean_choice); break; case FIELD_LIST_SINGLE: found = autocomplete_param_with_ac(input, split[0], value_ac, TRUE); break; case FIELD_LIST_MULTI: case FIELD_JID_MULTI: case FIELD_TEXT_MULTI: found = autocomplete_param_with_ac(input, split[0], form_field_multi_ac, TRUE); break; default: break; } } } g_strfreev(split); return found; } static char * _occupants_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; found = autocomplete_param_with_ac(input, "/occupants default show", occupants_show_ac, TRUE); if (found) { return found; } found = autocomplete_param_with_ac(input, "/occupants default hide", occupants_show_ac, TRUE); if (found) { return found; } found = autocomplete_param_with_ac(input, "/occupants default", occupants_default_ac, TRUE); if (found) { return found; } found = autocomplete_param_with_ac(input, "/occupants show", occupants_show_ac, TRUE); if (found) { return found; } found = autocomplete_param_with_ac(input, "/occupants hide", occupants_show_ac, TRUE); if (found) { return found; } found = autocomplete_param_with_ac(input, "/occupants", occupants_ac, TRUE); if (found) { return found; } return NULL; } static char * _time_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; found = autocomplete_param_with_ac(input, "/time statusbar", time_format_ac, TRUE); if (found) { return found; } found = autocomplete_param_with_ac(input, "/time main", time_format_ac, TRUE); if (found) { return found; } found = autocomplete_param_with_ac(input, "/time", time_ac, TRUE); if (found) { return found; } return NULL; } static char * _kick_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid); if (nick_ac) { result = autocomplete_param_with_ac(input, "/kick", nick_ac, TRUE); if (result) { return result; } } } return result; } static char * _ban_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid); if (jid_ac) { result = autocomplete_param_with_ac(input, "/ban", jid_ac, TRUE); if (result) { return result; } } } return result; } static char * _affiliation_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); gboolean parse_result; Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid); gchar **args = parse_args(input, 3, 3, &parse_result); if ((strncmp(input, "/affiliation", 12) == 0) && (parse_result == TRUE)) { GString *beginning = g_string_new("/affiliation "); g_string_append(beginning, args[0]); g_string_append(beginning, " "); g_string_append(beginning, args[1]); result = autocomplete_param_with_ac(input, beginning->str, jid_ac, TRUE); g_string_free(beginning, TRUE); if (result) { g_strfreev(args); return result; } } g_strfreev(args); } result = autocomplete_param_with_ac(input, "/affiliation set", affiliation_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/affiliation list", affiliation_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/affiliation", privilege_cmd_ac, TRUE); if (result) { return result; } return result; } static char * _role_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); gboolean parse_result; Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid); gchar **args = parse_args(input, 3, 3, &parse_result); if ((strncmp(input, "/role", 5) == 0) && (parse_result == TRUE)) { GString *beginning = g_string_new("/role "); g_string_append(beginning, args[0]); g_string_append(beginning, " "); g_string_append(beginning, args[1]); result = autocomplete_param_with_ac(input, beginning->str, nick_ac, TRUE); g_string_free(beginning, TRUE); if (result) { g_strfreev(args); return result; } } g_strfreev(args); } result = autocomplete_param_with_ac(input, "/role set", role_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/role list", role_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/role", privilege_cmd_ac, TRUE); if (result) { return result; } return result; } static char * _statuses_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_ac(input, "/statuses console", statuses_setting_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/statuses chat", statuses_setting_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/statuses muc", statuses_setting_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/statuses", statuses_ac, TRUE); if (result) { return result; } return NULL; } static char * _wins_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_func(input, "/wins autotidy", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_ac(input, "/wins", wins_ac, TRUE); if (result) { return result; } return NULL; } static char * _receipts_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_func(input, "/receipts send", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_func(input, "/receipts request", prefs_autocomplete_boolean_choice); if (result) { return result; } result = autocomplete_param_with_ac(input, "/receipts", receipts_ac, TRUE); if (result) { return result; } return NULL; } static char * _alias_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_ac(input, "/alias remove", aliases_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/alias", alias_ac, TRUE); if (result) { return result; } return NULL; } static char * _connect_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; gboolean result = FALSE; gchar **args = parse_args(input, 2, 4, &result); if ((strncmp(input, "/connect", 8) == 0) && (result == TRUE)) { GString *beginning = g_string_new("/connect "); g_string_append(beginning, args[0]); if (args[1] && args[2]) { g_string_append(beginning, " "); g_string_append(beginning, args[1]); g_string_append(beginning, " "); g_string_append(beginning, args[2]); } found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE); g_string_free(beginning, TRUE); if (found) { g_strfreev(args); return found; } } g_strfreev(args); found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled); if (found) { return found; } return NULL; } static char * _help_autocomplete(ProfWin *window, const char * const input) { char *result = NULL; result = autocomplete_param_with_ac(input, "/help commands", help_commands_ac, TRUE); if (result) { return result; } result = autocomplete_param_with_ac(input, "/help", help_ac, TRUE); if (result) { return result; } return NULL; } static char * _join_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; gboolean result = FALSE; found = autocomplete_param_with_func(input, "/join", bookmark_find); if (found) { return found; } gchar **args = parse_args(input, 2, 4, &result); if ((strncmp(input, "/join", 5) == 0) && (result == TRUE)) { GString *beginning = g_string_new("/join "); g_string_append(beginning, args[0]); if (args[1] && args[2]) { g_string_append(beginning, " "); g_string_append(beginning, args[1]); g_string_append(beginning, " "); g_string_append(beginning, args[2]); } found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE); g_string_free(beginning, TRUE); if (found) { g_strfreev(args); return found; } } g_strfreev(args); return NULL; } static char * _account_autocomplete(ProfWin *window, const char * const input) { char *found = NULL; gboolean result = FALSE; gchar **args = parse_args(input, 3, 4, &result); if ((strncmp(input, "/account set", 12) == 0) && (result == TRUE)) { GString *beginning = g_string_new("/account set "); g_string_append(beginning, args[1]); if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "otr")) == 0) { g_string_append(beginning, " "); g_string_append(beginning, args[2]); found = autocomplete_param_with_ac(input, beginning->str, otr_policy_ac, TRUE); g_string_free(beginning, TRUE); if (found) { g_strfreev(args); return found; } } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "status")) == 0) { g_string_append(beginning, " "); g_string_append(beginning, args[2]); found = autocomplete_param_with_ac(input, beginning->str, account_status_ac, TRUE); g_string_free(beginning, TRUE); if (found) { g_strfreev(args); return found; } #ifdef HAVE_LIBGPGME } else if ((g_strv_length(args) > 3) && (g_strcmp0(args[2], "pgpkeyid")) == 0) { g_string_append(beginning, " "); g_string_append(beginning, args[2]); found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key); g_string_free(beginning, TRUE); if (found) { g_strfreev(args); return found; } #endif } else { found = autocomplete_param_with_ac(input, beginning->str, account_set_ac, TRUE); g_string_free(beginning, TRUE); if (found) { g_strfreev(args); return found; } } } if ((strncmp(input, "/account clear", 14) == 0) && (result == TRUE)) { GString *beginning = g_string_new("/account clear "); g_string_append(beginning, args[1]); found = autocomplete_param_with_ac(input, beginning->str, account_clear_ac, TRUE); g_string_free(beginning, TRUE); if (found) { g_strfreev(args); return found; } } g_strfreev(args); found = autocomplete_param_with_ac(input, "/account default", account_default_ac, TRUE); if(found){ return found; } int i = 0; gchar *account_choice[] = { "/account set", "/account show", "/account enable", "/account disable", "/account rename", "/account clear", "/account remove", "/account default set" }; for (i = 0; i < ARRAY_SIZE(account_choice); i++) { found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all); if (found) { return found; } } found = autocomplete_param_with_ac(input, "/account", account_ac, TRUE); return found; } static int _cmp_command(Command *cmd1, Command *cmd2) { return g_strcmp0(cmd1->cmd, cmd2->cmd); } void command_docgen(void) { GList *cmds = NULL; unsigned int i; for (i = 0; i < ARRAY_SIZE(command_defs); i++) { Command *pcmd = command_defs+i; cmds = g_list_insert_sorted(cmds, pcmd, (GCompareFunc)_cmp_command); } FILE *toc_fragment = fopen("toc_fragment.html", "w"); FILE *main_fragment = fopen("main_fragment.html", "w"); fputs("
    • \n", toc_fragment); fputs("
      \n", main_fragment); GList *curr = cmds; while (curr) { Command *pcmd = curr->data; fprintf(toc_fragment, "%s,\n", &pcmd->cmd[1], pcmd->cmd); fprintf(main_fragment, "\n", &pcmd->cmd[1]); fprintf(main_fragment, "

      %s

      \n", pcmd->cmd); fputs("

      Synopsis

      \n", main_fragment); fputs("

      ", main_fragment);
              int i = 0;
              while (pcmd->help.synopsis[i]) {
                  char *str1 = str_replace(pcmd->help.synopsis[i], "<", "<");
                  char *str2 = str_replace(str1, ">", ">");
                  fprintf(main_fragment, "%s\n", str2);
                  i++;
              }
              fputs("

      \n", main_fragment); fputs("

      Description

      \n", main_fragment); fputs("

      ", main_fragment); fprintf(main_fragment, "%s\n", pcmd->help.desc); fputs("

      \n", main_fragment); if (pcmd->help.args[0][0] != NULL) { fputs("

      Arguments

      \n", main_fragment); fputs("", main_fragment); for (i = 0; pcmd->help.args[i][0] != NULL; i++) { fputs("", main_fragment); fputs("", main_fragment); fputs("", main_fragment); fputs("", main_fragment); } fputs("
      ", main_fragment); fputs("", main_fragment); char *str1 = str_replace(pcmd->help.args[i][0], "<", "<"); char *str2 = str_replace(str1, ">", ">"); fprintf(main_fragment, "%s", str2); fputs("", main_fragment); fputs("", main_fragment); fprintf(main_fragment, "%s", pcmd->help.args[i][1]); fputs("
      \n", main_fragment); } if (pcmd->help.examples[0] != NULL) { fputs("

      Examples

      \n", main_fragment); fputs("

      ", main_fragment);
                  int i = 0;
                  while (pcmd->help.examples[i]) {
                      fprintf(main_fragment, "%s\n", pcmd->help.examples[i]);
                      i++;
                  }
                  fputs("

      \n", main_fragment); } fputs("
      back to top


      \n", main_fragment); fputs("\n", main_fragment); curr = g_list_next(curr); } fputs("
\n", toc_fragment); fclose(toc_fragment); fclose(main_fragment); printf("\nProcessed %d commands.\n\n", g_list_length(cmds)); g_list_free(cmds); } profanity-0.4.7/src/command/command.h000066400000000000000000000050201257755232500175430ustar00rootroot00000000000000/* * command.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef COMMAND_H #define COMMAND_H #include #include "xmpp/form.h" #include "ui/ui.h" GHashTable *commands; void cmd_init(void); void cmd_uninit(void); char* cmd_autocomplete(ProfWin *window, const char * const input); void cmd_reset_autocomplete(ProfWin *window); void cmd_autocomplete_add(char *value); void cmd_autocomplete_remove(char *value); void cmd_autocomplete_add_form_fields(DataForm *form); void cmd_autocomplete_remove_form_fields(DataForm *form); void cmd_alias_add(char *value); void cmd_alias_remove(char *value); gboolean cmd_valid_tag(const char * const str); gboolean cmd_has_tag(Command *pcmd, const char * const tag); gboolean cmd_process_input(ProfWin *window, char *inp); void cmd_execute_connect(ProfWin *window, const char * const account); gboolean cmd_exists(char *cmd); GSList * cmd_get_basic_help(void); GSList * cmd_get_settings_help(void); GSList * cmd_get_presence_help(void); void cmd_history_append(char *inp); char *cmd_history_previous(char *inp); char *cmd_history_next(char *inp); void command_docgen(void); #endif profanity-0.4.7/src/command/commands.c000066400000000000000000004641171257755232500177410ustar00rootroot00000000000000/* * commands.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include #include #include #include #include "chat_session.h" #include "command/commands.h" #include "command/command.h" #include "common.h" #include "config/accounts.h" #include "config/account.h" #include "config/preferences.h" #include "config/theme.h" #include "contact.h" #include "roster_list.h" #include "jid.h" #include "log.h" #include "muc.h" #ifdef HAVE_LIBOTR #include "otr/otr.h" #endif #ifdef HAVE_LIBGPGME #include "pgp/gpg.h" #endif #include "profanity.h" #include "tools/autocomplete.h" #include "tools/parser.h" #include "tools/tinyurl.h" #include "xmpp/xmpp.h" #include "xmpp/bookmark.h" #include "ui/ui.h" #include "window_list.h" #include "event/client_events.h" #include "event/ui_events.h" static void _update_presence(const resource_presence_t presence, const char * const show, gchar **args); static gboolean _cmd_set_boolean_preference(gchar *arg, const char * const command, const char * const display, preference_t pref); //static void _cmd_show_filtered_help(char *heading, gchar *cmd_filter[], int filter_size); static void _who_room(ProfWin *window, const char * const command, gchar **args); static void _who_roster(ProfWin *window, const char * const command, gchar **args); extern GHashTable *commands; gboolean cmd_execute_default(ProfWin *window, const char * inp) { // handle escaped commands - treat as normal message if (g_str_has_prefix(inp, "//")) { inp++; // handle unknown commands } else if ((inp[0] == '/') && (!g_str_has_prefix(inp, "/me "))) { cons_show("Unknown command: %s", inp); cons_alert(); return TRUE; } // handle non commands in non chat windows if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) { cons_show("Unknown command: %s", inp); return TRUE; } jabber_conn_status_t status = jabber_get_connection_status(); if (status != JABBER_CONNECTED) { ui_current_print_line("You are not currently connected."); return TRUE; } switch (window->type) { case WIN_CHAT: { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); cl_ev_send_msg(chatwin, inp); break; } case WIN_PRIVATE: { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); cl_ev_send_priv_msg(privatewin, inp); break; } case WIN_MUC: { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); cl_ev_send_muc_msg(mucwin, inp); break; } default: break; } return TRUE; } gboolean cmd_execute_alias(ProfWin *window, const char * const inp, gboolean *ran) { if (inp[0] != '/') { ran = FALSE; return TRUE; } char *alias = strdup(inp+1); char *value = prefs_get_alias(alias); free(alias); if (value) { *ran = TRUE; return cmd_process_input(window, value); } *ran = FALSE; return TRUE; } gboolean cmd_connect(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if ((conn_status != JABBER_DISCONNECTED) && (conn_status != JABBER_STARTED)) { cons_show("You are either connected already, or a login is in process."); return TRUE; } gchar *opt_keys[] = { "server", "port", NULL }; gboolean parsed; GHashTable *options = parse_options(&args[args[0] ? 1 : 0], opt_keys, &parsed); if (!parsed) { cons_bad_cmd_usage(command); cons_show(""); return TRUE; } char *altdomain = g_hash_table_lookup(options, "server"); int port = 0; if (g_hash_table_contains(options, "port")) { char *port_str = g_hash_table_lookup(options, "port"); char *err_msg = NULL; gboolean res = strtoi_range(port_str, &port, 1, 65535, &err_msg); if (!res) { cons_show(err_msg); cons_show(""); free(err_msg); port = 0; return TRUE; } } char *user = args[0]; char *def = prefs_get_string(PREF_DEFAULT_ACCOUNT); if (!user) { if (def) { user = def; cons_show("Using default account %s.", user); } else { cons_show("No default account."); g_free(def); return TRUE; } } char *lower = g_utf8_strdown(user, -1); char *jid; g_free(def); // connect with account ProfAccount *account = accounts_get_account(lower); if (account) { // use password if set if (account->password) { conn_status = cl_ev_connect_account(account); // use eval_password if set } else if (account->eval_password) { gboolean res = account_eval_password(account); if (res) { conn_status = cl_ev_connect_account(account); free(account->password); account->password = NULL; } else { cons_show("Error evaluating password, see logs for details."); g_free(lower); account_free(account); return TRUE; } // no account password setting, prompt } else { account->password = ui_ask_password(); conn_status = cl_ev_connect_account(account); free(account->password); account->password = NULL; } jid = account_create_full_jid(account); account_free(account); // connect with JID } else { jid = strdup(lower); char *passwd = ui_ask_password(); conn_status = cl_ev_connect_jid(jid, passwd, altdomain, port); free(passwd); } if (conn_status == JABBER_DISCONNECTED) { cons_show_error("Connection attempt for %s failed.", jid); log_info("Connection attempt for %s failed", jid); } options_destroy(options); g_free(lower); free(jid); return TRUE; } gboolean cmd_account(ProfWin *window, const char * const command, gchar **args) { char *subcmd = args[0]; if (subcmd == NULL) { if (jabber_get_connection_status() != JABBER_CONNECTED) { cons_bad_cmd_usage(command); } else { ProfAccount *account = accounts_get_account(jabber_get_account_name()); cons_show_account(account); account_free(account); } } else if (strcmp(subcmd, "list") == 0) { gchar **accounts = accounts_get_list(); cons_show_account_list(accounts); g_strfreev(accounts); } else if (strcmp(subcmd, "show") == 0) { char *account_name = args[1]; if (account_name == NULL) { cons_bad_cmd_usage(command); } else { ProfAccount *account = accounts_get_account(account_name); if (account == NULL) { cons_show("No such account."); cons_show(""); } else { cons_show_account(account); account_free(account); } } } else if (strcmp(subcmd, "add") == 0) { char *account_name = args[1]; if (account_name == NULL) { cons_bad_cmd_usage(command); } else { accounts_add(account_name, NULL, 0); cons_show("Account created."); cons_show(""); } } else if (strcmp(subcmd, "remove") == 0) { char *account_name = args[1]; if(!account_name) { cons_bad_cmd_usage(command); } else { char *def = prefs_get_string(PREF_DEFAULT_ACCOUNT); if(accounts_remove(account_name)){ cons_show("Account %s removed.", account_name); if(def && strcmp(def, account_name) == 0){ prefs_set_string(PREF_DEFAULT_ACCOUNT, NULL); cons_show("Default account removed because the corresponding account was removed."); } } else { cons_show("Failed to remove account %s.", account_name); cons_show("Either the account does not exist, or an unknown error occurred."); } cons_show(""); g_free(def); } } else if (strcmp(subcmd, "enable") == 0) { char *account_name = args[1]; if (account_name == NULL) { cons_bad_cmd_usage(command); } else { if (accounts_enable(account_name)) { cons_show("Account enabled."); cons_show(""); } else { cons_show("No such account: %s", account_name); cons_show(""); } } } else if (strcmp(subcmd, "disable") == 0) { char *account_name = args[1]; if (account_name == NULL) { cons_bad_cmd_usage(command); } else { if (accounts_disable(account_name)) { cons_show("Account disabled."); cons_show(""); } else { cons_show("No such account: %s", account_name); cons_show(""); } } } else if (strcmp(subcmd, "rename") == 0) { if (g_strv_length(args) != 3) { cons_bad_cmd_usage(command); } else { char *account_name = args[1]; char *new_name = args[2]; if (accounts_rename(account_name, new_name)) { cons_show("Account renamed."); cons_show(""); } else { cons_show("Either account %s doesn't exist, or account %s already exists.", account_name, new_name); cons_show(""); } } } else if (strcmp(subcmd, "default") == 0) { if(g_strv_length(args) == 1){ char *def = prefs_get_string(PREF_DEFAULT_ACCOUNT); if(def){ cons_show("The default account is %s.", def); free(def); } else { cons_show("No default account."); } } else if(g_strv_length(args) == 2){ if(strcmp(args[1], "off") == 0){ prefs_set_string(PREF_DEFAULT_ACCOUNT, NULL); cons_show("Removed default account."); } else { cons_bad_cmd_usage(command); } } else if(g_strv_length(args) == 3) { if(strcmp(args[1], "set") == 0){ if(accounts_get_account(args[2])){ prefs_set_string(PREF_DEFAULT_ACCOUNT, args[2]); cons_show("Default account set to %s.", args[2]); } else { cons_show("Account %s does not exist.", args[2]); } } else { cons_bad_cmd_usage(command); } } else { cons_bad_cmd_usage(command); } } else if (strcmp(subcmd, "set") == 0) { if (g_strv_length(args) != 4) { cons_bad_cmd_usage(command); } else { char *account_name = args[1]; char *property = args[2]; char *value = args[3]; if (!accounts_account_exists(account_name)) { cons_show("Account %s doesn't exist", account_name); cons_show(""); } else { if (strcmp(property, "jid") == 0) { Jid *jid = jid_create(args[3]); if (jid == NULL) { cons_show("Malformed jid: %s", value); } else { accounts_set_jid(account_name, jid->barejid); cons_show("Updated jid for account %s: %s", account_name, jid->barejid); if (jid->resourcepart) { accounts_set_resource(account_name, jid->resourcepart); cons_show("Updated resource for account %s: %s", account_name, jid->resourcepart); } cons_show(""); } jid_destroy(jid); } else if (strcmp(property, "server") == 0) { accounts_set_server(account_name, value); cons_show("Updated server for account %s: %s", account_name, value); cons_show(""); } else if (strcmp(property, "port") == 0) { int port; char *err_msg = NULL; gboolean res = strtoi_range(value, &port, 1, 65535, &err_msg); if (!res) { cons_show(err_msg); cons_show(""); free(err_msg); return TRUE; } else { accounts_set_port(account_name, port); cons_show("Updated port for account %s: %s", account_name, value); cons_show(""); } } else if (strcmp(property, "resource") == 0) { accounts_set_resource(account_name, value); if (jabber_get_connection_status() == JABBER_CONNECTED) { cons_show("Updated resource for account %s: %s, you will need to reconnect to pick up the change.", account_name, value); } else { cons_show("Updated resource for account %s: %s", account_name, value); } cons_show(""); } else if (strcmp(property, "password") == 0) { if(accounts_get_account(account_name)->eval_password) { cons_show("Cannot set password when eval_password is set."); } else { accounts_set_password(account_name, value); cons_show("Updated password for account %s", account_name); cons_show(""); } } else if (strcmp(property, "eval_password") == 0) { if(accounts_get_account(account_name)->password) { cons_show("Cannot set eval_password when password is set."); } else { accounts_set_eval_password(account_name, value); cons_show("Updated eval_password for account %s", account_name); cons_show(""); } } else if (strcmp(property, "muc") == 0) { accounts_set_muc_service(account_name, value); cons_show("Updated muc service for account %s: %s", account_name, value); cons_show(""); } else if (strcmp(property, "nick") == 0) { accounts_set_muc_nick(account_name, value); cons_show("Updated muc nick for account %s: %s", account_name, value); cons_show(""); } else if (strcmp(property, "otr") == 0) { if ((g_strcmp0(value, "manual") != 0) && (g_strcmp0(value, "opportunistic") != 0) && (g_strcmp0(value, "always") != 0)) { cons_show("OTR policy must be one of: manual, opportunistic or always."); } else { accounts_set_otr_policy(account_name, value); cons_show("Updated OTR policy for account %s: %s", account_name, value); cons_show(""); } } else if (strcmp(property, "status") == 0) { if (!valid_resource_presence_string(value) && (strcmp(value, "last") != 0)) { cons_show("Invalid status: %s", value); } else { accounts_set_login_presence(account_name, value); cons_show("Updated login status for account %s: %s", account_name, value); } cons_show(""); } else if (strcmp(property, "pgpkeyid") == 0) { #ifdef HAVE_LIBGPGME if (!p_gpg_valid_key(value)) { cons_show("Invalid PGP key ID specified, see /pgp keys"); } else { accounts_set_pgp_keyid(account_name, value); cons_show("Updated PGP key ID for account %s: %s", account_name, value); } #else cons_show("PGP support is not included in this build."); #endif cons_show(""); } else if (valid_resource_presence_string(property)) { int intval; char *err_msg = NULL; gboolean res = strtoi_range(value, &intval, -128, 127, &err_msg); if (res) { resource_presence_t presence_type = resource_presence_from_string(property); switch (presence_type) { case (RESOURCE_ONLINE): accounts_set_priority_online(account_name, intval); break; case (RESOURCE_CHAT): accounts_set_priority_chat(account_name, intval); break; case (RESOURCE_AWAY): accounts_set_priority_away(account_name, intval); break; case (RESOURCE_XA): accounts_set_priority_xa(account_name, intval); break; case (RESOURCE_DND): accounts_set_priority_dnd(account_name, intval); break; } jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status == JABBER_CONNECTED) { char *connected_account = jabber_get_account_name(); resource_presence_t last_presence = accounts_get_last_presence(connected_account); if (presence_type == last_presence) { char *message = jabber_get_presence_message(); cl_ev_presence_send(last_presence, message, 0); } } cons_show("Updated %s priority for account %s: %s", property, account_name, value); cons_show(""); } else { cons_show(err_msg); free(err_msg); } } else { cons_show("Invalid property: %s", property); cons_show(""); } } } } else if (strcmp(subcmd, "clear") == 0) { if (g_strv_length(args) != 3) { cons_bad_cmd_usage(command); } else { char *account_name = args[1]; char *property = args[2]; if (!accounts_account_exists(account_name)) { cons_show("Account %s doesn't exist", account_name); cons_show(""); } else { if (strcmp(property, "password") == 0) { accounts_clear_password(account_name); cons_show("Removed password for account %s", account_name); cons_show(""); } else if (strcmp(property, "eval_password") == 0) { accounts_clear_eval_password(account_name); cons_show("Removed eval password for account %s", account_name); cons_show(""); } else if (strcmp(property, "server") == 0) { accounts_clear_server(account_name); cons_show("Removed server for account %s", account_name); cons_show(""); } else if (strcmp(property, "port") == 0) { accounts_clear_port(account_name); cons_show("Removed port for account %s", account_name); cons_show(""); } else if (strcmp(property, "otr") == 0) { accounts_clear_otr(account_name); cons_show("OTR policy removed for account %s", account_name); cons_show(""); } else if (strcmp(property, "pgpkeyid") == 0) { accounts_clear_pgp_keyid(account_name); cons_show("Removed PGP key ID for account %s", account_name); cons_show(""); } else { cons_show("Invalid property: %s", property); cons_show(""); } } } } else { cons_bad_cmd_usage(command); cons_show(""); } return TRUE; } gboolean cmd_sub(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are currently not connected."); return TRUE; } char *subcmd, *jid; subcmd = args[0]; jid = args[1]; if (subcmd == NULL) { cons_bad_cmd_usage(command); return TRUE; } if (strcmp(subcmd, "sent") == 0) { cons_show_sent_subs(); return TRUE; } if (strcmp(subcmd, "received") == 0) { cons_show_received_subs(); return TRUE; } if ((window->type != WIN_CHAT) && (jid == NULL)) { cons_show("You must specify a contact."); return TRUE; } if (jid == NULL) { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); jid = chatwin->barejid; } Jid *jidp = jid_create(jid); if (strcmp(subcmd, "allow") == 0) { presence_subscription(jidp->barejid, PRESENCE_SUBSCRIBED); cons_show("Accepted subscription for %s", jidp->barejid); log_info("Accepted subscription for %s", jidp->barejid); } else if (strcmp(subcmd, "deny") == 0) { presence_subscription(jidp->barejid, PRESENCE_UNSUBSCRIBED); cons_show("Deleted/denied subscription for %s", jidp->barejid); log_info("Deleted/denied subscription for %s", jidp->barejid); } else if (strcmp(subcmd, "request") == 0) { presence_subscription(jidp->barejid, PRESENCE_SUBSCRIBE); cons_show("Sent subscription request to %s.", jidp->barejid); log_info("Sent subscription request to %s.", jidp->barejid); } else if (strcmp(subcmd, "show") == 0) { PContact contact = roster_get_contact(jidp->barejid); if ((contact == NULL) || (p_contact_subscription(contact) == NULL)) { if (window->type == WIN_CHAT) { ui_current_print_line("No subscription information for %s.", jidp->barejid); } else { cons_show("No subscription information for %s.", jidp->barejid); } } else { if (window->type == WIN_CHAT) { if (p_contact_pending_out(contact)) { ui_current_print_line("%s subscription status: %s, request pending.", jidp->barejid, p_contact_subscription(contact)); } else { ui_current_print_line("%s subscription status: %s.", jidp->barejid, p_contact_subscription(contact)); } } else { if (p_contact_pending_out(contact)) { cons_show("%s subscription status: %s, request pending.", jidp->barejid, p_contact_subscription(contact)); } else { cons_show("%s subscription status: %s.", jidp->barejid, p_contact_subscription(contact)); } } } } else { cons_bad_cmd_usage(command); } jid_destroy(jidp); return TRUE; } gboolean cmd_disconnect(ProfWin *window, const char * const command, gchar **args) { if (jabber_get_connection_status() == JABBER_CONNECTED) { char *jid = strdup(jabber_get_fulljid()); cons_show("%s logged out successfully.", jid); jabber_disconnect(); roster_clear(); muc_invites_clear(); chat_sessions_clear(); ui_disconnected(); #ifdef HAVE_LIBGPGME p_gpg_on_disconnect(); #endif free(jid); } else { cons_show("You are not currently connected."); } return TRUE; } gboolean cmd_quit(ProfWin *window, const char * const command, gchar **args) { log_info("Profanity is shutting down..."); exit(0); return FALSE; } gboolean cmd_wins(ProfWin *window, const char * const command, gchar **args) { if (args[0] == NULL) { cons_show_wins(); } else if (strcmp(args[0], "tidy") == 0) { if (ui_tidy_wins()) { cons_show("Windows tidied."); } else { cons_show("No tidy needed."); } } else if (strcmp(args[0], "prune") == 0) { ui_prune_wins(); } else if (strcmp(args[0], "swap") == 0) { if ((args[1] == NULL) || (args[2] == NULL)) { cons_bad_cmd_usage(command); } else { int source_win = atoi(args[1]); int target_win = atoi(args[2]); if ((source_win == 1) || (target_win == 1)) { cons_show("Cannot move console window."); } else if (source_win == 10 || target_win == 10) { cons_show("Window 10 does not exist"); } else if (source_win != target_win) { gboolean swapped = ui_swap_wins(source_win, target_win); if (swapped) { cons_show("Swapped windows %d <-> %d", source_win, target_win); } else { cons_show("Window %d does not exist", source_win); } } else { cons_show("Same source and target window supplied."); } } } else if (strcmp(args[0], "autotidy") == 0) { if (g_strcmp0(args[1], "on") == 0) { cons_show("Window autotidy enabled"); prefs_set_boolean(PREF_WINS_AUTO_TIDY, TRUE); ui_tidy_wins(); } else if (g_strcmp0(args[1], "off") == 0) { cons_show("Window autotidy disabled"); prefs_set_boolean(PREF_WINS_AUTO_TIDY, FALSE); } else { cons_bad_cmd_usage(command); } } else { cons_bad_cmd_usage(command); } return TRUE; } gboolean cmd_win(ProfWin *window, const char * const command, gchar **args) { int num = atoi(args[0]); ProfWin *focuswin = wins_get_by_num(num); if (!focuswin) { cons_show("Window %d does not exist.", num); } else { ui_ev_focus_win(focuswin); } return TRUE; } static void _cmd_help_cmd_list(const char * const tag) { cons_show(""); ProfWin *console = wins_get_console(); if (tag) { win_vprint(console, '-', 0, NULL, 0, THEME_WHITE_BOLD, "", "%s commands", tag); } else { win_print(console, '-', 0, NULL, 0, THEME_WHITE_BOLD, "", "All commands"); } GList *ordered_commands = NULL; GHashTableIter iter; gpointer key; gpointer value; g_hash_table_iter_init(&iter, commands); while (g_hash_table_iter_next(&iter, &key, &value)) { Command *pcmd = (Command *)value; if (tag) { if (cmd_has_tag(pcmd, tag)) { ordered_commands = g_list_insert_sorted(ordered_commands, pcmd->cmd, (GCompareFunc)g_strcmp0); } } else { ordered_commands = g_list_insert_sorted(ordered_commands, pcmd->cmd, (GCompareFunc)g_strcmp0); } } int maxlen = 0; GList *curr = ordered_commands; while (curr) { gchar *cmd = curr->data; int len = strlen(cmd); if (len > maxlen) maxlen = len; curr = g_list_next(curr); } GString *cmds = g_string_new(""); curr = ordered_commands; int count = 0; while (curr) { gchar *cmd = curr->data; if (count == 5) { cons_show(cmds->str); g_string_free(cmds, TRUE); cmds = g_string_new(""); count = 0; } g_string_append_printf(cmds, "%-*s", maxlen + 1, cmd); curr = g_list_next(curr); count++; } cons_show(cmds->str); g_string_free(cmds, TRUE); g_list_free(ordered_commands); g_list_free(curr); cons_show(""); cons_show("Use /help [command] without the leading slash, for help on a specific command"); cons_show(""); } gboolean cmd_help(ProfWin *window, const char * const command, gchar **args) { int num_args = g_strv_length(args); if (num_args == 0) { cons_help(); } else if (strcmp(args[0], "commands") == 0) { if (args[1]) { if (!cmd_valid_tag(args[1])) { cons_bad_cmd_usage(command); } else { _cmd_help_cmd_list(args[1]); } } else { _cmd_help_cmd_list(NULL); } } else if (strcmp(args[0], "navigation") == 0) { cons_navigation_help(); } else { char *cmd = args[0]; char cmd_with_slash[1 + strlen(cmd) + 1]; sprintf(cmd_with_slash, "/%s", cmd); Command *command = g_hash_table_lookup(commands, cmd_with_slash); if (command) { cons_show_help(command); } else { cons_show("No such command."); } cons_show(""); } return TRUE; } gboolean cmd_about(ProfWin *window, const char * const command, gchar **args) { ui_about(); return TRUE; } gboolean cmd_prefs(ProfWin *window, const char * const command, gchar **args) { if (args[0] == NULL) { cons_prefs(); cons_show("Use the /account command for preferences for individual accounts."); } else if (strcmp(args[0], "ui") == 0) { cons_show(""); cons_show_ui_prefs(); cons_show(""); } else if (strcmp(args[0], "desktop") == 0) { cons_show(""); cons_show_desktop_prefs(); cons_show(""); } else if (strcmp(args[0], "chat") == 0) { cons_show(""); cons_show_chat_prefs(); cons_show(""); } else if (strcmp(args[0], "log") == 0) { cons_show(""); cons_show_log_prefs(); cons_show(""); } else if (strcmp(args[0], "conn") == 0) { cons_show(""); cons_show_connection_prefs(); cons_show(""); } else if (strcmp(args[0], "presence") == 0) { cons_show(""); cons_show_presence_prefs(); cons_show(""); } else if (strcmp(args[0], "otr") == 0) { cons_show(""); cons_show_otr_prefs(); cons_show(""); } else if (strcmp(args[0], "pgp") == 0) { cons_show(""); cons_show_pgp_prefs(); cons_show(""); } else { cons_bad_cmd_usage(command); } return TRUE; } gboolean cmd_theme(ProfWin *window, const char * const command, gchar **args) { // list themes if (g_strcmp0(args[0], "list") == 0) { GSList *themes = theme_list(); cons_show_themes(themes); g_slist_free_full(themes, g_free); // load a theme } else if (g_strcmp0(args[0], "load") == 0) { if (args[1] == NULL) { cons_bad_cmd_usage(command); } else if (theme_load(args[1])) { ui_load_colours(); prefs_set_string(PREF_THEME, args[1]); if (prefs_get_boolean(PREF_ROSTER)) { ui_show_roster(); } else { ui_hide_roster(); } if (prefs_get_boolean(PREF_OCCUPANTS)) { ui_show_all_room_rosters(); } else { ui_hide_all_room_rosters(); } ui_redraw(); cons_show("Loaded theme: %s", args[1]); } else { cons_show("Couldn't find theme: %s", args[1]); } // show colours } else if (g_strcmp0(args[0], "colours") == 0) { cons_theme_colours(); } else { cons_bad_cmd_usage(command); } return TRUE; } static void _who_room(ProfWin *window, const char * const command, gchar **args) { if ((g_strv_length(args) == 2) && args[1]) { cons_show("Argument group is not applicable to chat rooms."); return; } // bad arg if (args[0] && (g_strcmp0(args[0], "online") != 0) && (g_strcmp0(args[0], "available") != 0) && (g_strcmp0(args[0], "unavailable") != 0) && (g_strcmp0(args[0], "away") != 0) && (g_strcmp0(args[0], "chat") != 0) && (g_strcmp0(args[0], "xa") != 0) && (g_strcmp0(args[0], "dnd") != 0) && (g_strcmp0(args[0], "any") != 0) && (g_strcmp0(args[0], "moderator") != 0) && (g_strcmp0(args[0], "participant") != 0) && (g_strcmp0(args[0], "visitor") != 0) && (g_strcmp0(args[0], "owner") != 0) && (g_strcmp0(args[0], "admin") != 0) && (g_strcmp0(args[0], "member") != 0) && (g_strcmp0(args[0], "outcast") != 0)) { cons_bad_cmd_usage(command); return; } ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); // presence filter if (args[0] == NULL || (g_strcmp0(args[0], "online") == 0) || (g_strcmp0(args[0], "available") == 0) || (g_strcmp0(args[0], "unavailable") == 0) || (g_strcmp0(args[0], "away") == 0) || (g_strcmp0(args[0], "chat") == 0) || (g_strcmp0(args[0], "xa") == 0) || (g_strcmp0(args[0], "dnd") == 0) || (g_strcmp0(args[0], "any") == 0)) { char *presence = args[0]; GList *occupants = muc_roster(mucwin->roomjid); // no arg, show all contacts if ((presence == NULL) || (g_strcmp0(presence, "any") == 0)) { ui_room_roster(mucwin->roomjid, occupants, NULL); // available } else if (strcmp("available", presence) == 0) { GList *filtered = NULL; while (occupants) { Occupant *occupant = occupants->data; if (muc_occupant_available(occupant)) { filtered = g_list_append(filtered, occupant); } occupants = g_list_next(occupants); } ui_room_roster(mucwin->roomjid, filtered, "available"); // unavailable } else if (strcmp("unavailable", presence) == 0) { GList *filtered = NULL; while (occupants) { Occupant *occupant = occupants->data; if (!muc_occupant_available(occupant)) { filtered = g_list_append(filtered, occupant); } occupants = g_list_next(occupants); } ui_room_roster(mucwin->roomjid, filtered, "unavailable"); // show specific status } else { GList *filtered = NULL; while (occupants) { Occupant *occupant = occupants->data; const char *presence_str = string_from_resource_presence(occupant->presence); if (strcmp(presence_str, presence) == 0) { filtered = g_list_append(filtered, occupant); } occupants = g_list_next(occupants); } ui_room_roster(mucwin->roomjid, filtered, presence); } g_list_free(occupants); // role or affiliation filter } else { if (g_strcmp0(args[0], "moderator") == 0) { ui_show_room_role_list(mucwin, MUC_ROLE_MODERATOR); return; } if (g_strcmp0(args[0], "participant") == 0) { ui_show_room_role_list(mucwin, MUC_ROLE_PARTICIPANT); return; } if (g_strcmp0(args[0], "visitor") == 0) { ui_show_room_role_list(mucwin, MUC_ROLE_VISITOR); return; } if (g_strcmp0(args[0], "owner") == 0) { ui_show_room_affiliation_list(mucwin, MUC_AFFILIATION_OWNER); return; } if (g_strcmp0(args[0], "admin") == 0) { ui_show_room_affiliation_list(mucwin, MUC_AFFILIATION_ADMIN); return; } if (g_strcmp0(args[0], "member") == 0) { ui_show_room_affiliation_list(mucwin, MUC_AFFILIATION_MEMBER); return; } if (g_strcmp0(args[0], "outcast") == 0) { ui_show_room_affiliation_list(mucwin, MUC_AFFILIATION_OUTCAST); return; } } } static void _who_roster(ProfWin *window, const char * const command, gchar **args) { char *presence = args[0]; // bad arg if (presence && (strcmp(presence, "online") != 0) && (strcmp(presence, "available") != 0) && (strcmp(presence, "unavailable") != 0) && (strcmp(presence, "offline") != 0) && (strcmp(presence, "away") != 0) && (strcmp(presence, "chat") != 0) && (strcmp(presence, "xa") != 0) && (strcmp(presence, "dnd") != 0) && (strcmp(presence, "any") != 0)) { cons_bad_cmd_usage(command); return; } char *group = NULL; if ((g_strv_length(args) == 2) && args[1]) { group = args[1]; } cons_show(""); GSList *list = NULL; if (group) { list = roster_get_group(group); if (list == NULL) { cons_show("No such group: %s.", group); return; } } else { list = roster_get_contacts(); if (list == NULL) { cons_show("No contacts in roster."); return; } } // no arg, show all contacts if ((presence == NULL) || (g_strcmp0(presence, "any") == 0)) { if (group) { if (list == NULL) { cons_show("No contacts in group %s.", group); } else { cons_show("%s:", group); cons_show_contacts(list); } } else { if (list == NULL) { cons_show("You have no contacts."); } else { cons_show("All contacts:"); cons_show_contacts(list); } } // available } else if (strcmp("available", presence) == 0) { GSList *filtered = NULL; GSList *curr = list; while (curr) { PContact contact = curr->data; if (p_contact_is_available(contact)) { filtered = g_slist_append(filtered, contact); } curr = g_slist_next(curr); } if (group) { if (filtered == NULL) { cons_show("No contacts in group %s are %s.", group, presence); } else { cons_show("%s (%s):", group, presence); cons_show_contacts(filtered); } } else { if (filtered == NULL) { cons_show("No contacts are %s.", presence); } else { cons_show("Contacts (%s):", presence); cons_show_contacts(filtered); } } g_slist_free(filtered); // unavailable } else if (strcmp("unavailable", presence) == 0) { GSList *filtered = NULL; GSList *curr = list; while (curr) { PContact contact = curr->data; if (!p_contact_is_available(contact)) { filtered = g_slist_append(filtered, contact); } curr = g_slist_next(curr); } if (group) { if (filtered == NULL) { cons_show("No contacts in group %s are %s.", group, presence); } else { cons_show("%s (%s):", group, presence); cons_show_contacts(filtered); } } else { if (filtered == NULL) { cons_show("No contacts are %s.", presence); } else { cons_show("Contacts (%s):", presence); cons_show_contacts(filtered); } } g_slist_free(filtered); // online, available resources } else if (strcmp("online", presence) == 0) { GSList *filtered = NULL; GSList *curr = list; while (curr) { PContact contact = curr->data; if (p_contact_has_available_resource(contact)) { filtered = g_slist_append(filtered, contact); } curr = g_slist_next(curr); } if (group) { if (filtered == NULL) { cons_show("No contacts in group %s are %s.", group, presence); } else { cons_show("%s (%s):", group, presence); cons_show_contacts(filtered); } } else { if (filtered == NULL) { cons_show("No contacts are %s.", presence); } else { cons_show("Contacts (%s):", presence); cons_show_contacts(filtered); } } g_slist_free(filtered); // offline, no available resources } else if (strcmp("offline", presence) == 0) { GSList *filtered = NULL; GSList *curr = list; while (curr) { PContact contact = curr->data; if (!p_contact_has_available_resource(contact)) { filtered = g_slist_append(filtered, contact); } curr = g_slist_next(curr); } if (group) { if (filtered == NULL) { cons_show("No contacts in group %s are %s.", group, presence); } else { cons_show("%s (%s):", group, presence); cons_show_contacts(filtered); } } else { if (filtered == NULL) { cons_show("No contacts are %s.", presence); } else { cons_show("Contacts (%s):", presence); cons_show_contacts(filtered); } } g_slist_free(filtered); // show specific status } else { GSList *filtered = NULL; GSList *curr = list; while (curr) { PContact contact = curr->data; if (strcmp(p_contact_presence(contact), presence) == 0) { filtered = g_slist_append(filtered, contact); } curr = g_slist_next(curr); } if (group) { if (filtered == NULL) { cons_show("No contacts in group %s are %s.", group, presence); } else { cons_show("%s (%s):", group, presence); cons_show_contacts(filtered); } } else { if (filtered == NULL) { cons_show("No contacts are %s.", presence); } else { cons_show("Contacts (%s):", presence); cons_show_contacts(filtered); } } g_slist_free(filtered); } g_slist_free(list); } gboolean cmd_who(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); } else if (window->type == WIN_MUC) { _who_room(window, command, args); } else { _who_roster(window, command, args); } if (window->type != WIN_CONSOLE && window->type != WIN_MUC) { ui_statusbar_new(1); } return TRUE; } gboolean cmd_msg(ProfWin *window, const char * const command, gchar **args) { char *usr = args[0]; char *msg = args[1]; jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } // send private message when in MUC room if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); if (muc_roster_contains_nick(mucwin->roomjid, usr)) { GString *full_jid = g_string_new(mucwin->roomjid); g_string_append(full_jid, "/"); g_string_append(full_jid, usr); ProfPrivateWin *privwin = wins_get_private(full_jid->str); if (!privwin) { privwin = ui_ev_new_private_win(full_jid->str); } ui_ev_focus_win((ProfWin*)privwin); if (msg) { cl_ev_send_priv_msg(privwin, msg); } g_string_free(full_jid, TRUE); } else { ui_current_print_line("No such participant \"%s\" in room.", usr); } return TRUE; // send chat message } else { char *barejid = roster_barejid_from_name(usr); if (barejid == NULL) { barejid = usr; } ProfChatWin *chatwin = wins_get_chat(barejid); if (!chatwin) { chatwin = ui_ev_new_chat_win(barejid); } ui_ev_focus_win((ProfWin*)chatwin); if (msg) { cl_ev_send_msg(chatwin, msg); } else { #ifdef HAVE_LIBOTR if (otr_is_secure(barejid)) { ui_gone_secure(barejid, otr_is_trusted(barejid)); } #endif } return TRUE; } } gboolean cmd_group(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } // list all groups if (args[0] == NULL) { GSList *groups = roster_get_groups(); GSList *curr = groups; if (curr) { cons_show("Groups:"); while (curr) { cons_show(" %s", curr->data); curr = g_slist_next(curr); } g_slist_free_full(groups, g_free); } else { cons_show("No groups."); } return TRUE; } // show contacts in group if (strcmp(args[0], "show") == 0) { char *group = args[1]; if (group == NULL) { cons_bad_cmd_usage(command); return TRUE; } GSList *list = roster_get_group(group); cons_show_roster_group(group, list); return TRUE; } // add contact to group if (strcmp(args[0], "add") == 0) { char *group = args[1]; char *contact = args[2]; if ((group == NULL) || (contact == NULL)) { cons_bad_cmd_usage(command); return TRUE; } char *barejid = roster_barejid_from_name(contact); if (barejid == NULL) { barejid = contact; } PContact pcontact = roster_get_contact(barejid); if (pcontact == NULL) { cons_show("Contact not found in roster: %s", barejid); return TRUE; } if (p_contact_in_group(pcontact, group)) { const char *display_name = p_contact_name_or_jid(pcontact); ui_contact_already_in_group(display_name, group); } else { roster_send_add_to_group(group, pcontact); } return TRUE; } // remove contact from group if (strcmp(args[0], "remove") == 0) { char *group = args[1]; char *contact = args[2]; if ((group == NULL) || (contact == NULL)) { cons_bad_cmd_usage(command); return TRUE; } char *barejid = roster_barejid_from_name(contact); if (barejid == NULL) { barejid = contact; } PContact pcontact = roster_get_contact(barejid); if (pcontact == NULL) { cons_show("Contact not found in roster: %s", barejid); return TRUE; } if (!p_contact_in_group(pcontact, group)) { const char *display_name = p_contact_name_or_jid(pcontact); ui_contact_not_in_group(display_name, group); } else { roster_send_remove_from_group(group, pcontact); } return TRUE; } cons_bad_cmd_usage(command); return TRUE; } gboolean cmd_roster(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); // show roster if (args[0] == NULL) { if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } GSList *list = roster_get_contacts(); cons_show_roster(list); g_slist_free(list); return TRUE; // show roster, only online contacts } else if(g_strcmp0(args[0], "online") == 0){ if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } GSList *list = roster_get_contacts_online(); cons_show_roster(list); g_slist_free(list); return TRUE; // set roster size } else if (g_strcmp0(args[0], "size") == 0) { if (!args[1]) { cons_bad_cmd_usage(command); return TRUE; } int intval = 0; char *err_msg = NULL; gboolean res = strtoi_range(args[1], &intval, 1, 99, &err_msg); if (res) { prefs_set_roster_size(intval); cons_show("Roster screen size set to: %d%%", intval); if (conn_status == JABBER_CONNECTED && prefs_get_boolean(PREF_ROSTER)) { wins_resize_all(); } return TRUE; } else { cons_show(err_msg); free(err_msg); return TRUE; } // show/hide roster } else if (g_strcmp0(args[0], "show") == 0) { if (args[1] == NULL) { cons_show("Roster enabled."); prefs_set_boolean(PREF_ROSTER, TRUE); if (conn_status == JABBER_CONNECTED) { ui_show_roster(); } return TRUE; } else if (g_strcmp0(args[1], "offline") == 0) { cons_show("Roster offline enabled"); prefs_set_boolean(PREF_ROSTER_OFFLINE, TRUE); if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } return TRUE; } else if (g_strcmp0(args[1], "resource") == 0) { cons_show("Roster resource enabled"); prefs_set_boolean(PREF_ROSTER_RESOURCE, TRUE); if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } return TRUE; } else if (g_strcmp0(args[1], "empty") == 0) { cons_show("Roster empty enabled"); prefs_set_boolean(PREF_ROSTER_EMPTY, TRUE); if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; } } else if (g_strcmp0(args[0], "hide") == 0) { if (args[1] == NULL) { cons_show("Roster disabled."); prefs_set_boolean(PREF_ROSTER, FALSE); if (conn_status == JABBER_CONNECTED) { ui_hide_roster(); } return TRUE; } else if (g_strcmp0(args[1], "offline") == 0) { cons_show("Roster offline disabled"); prefs_set_boolean(PREF_ROSTER_OFFLINE, FALSE); if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } return TRUE; } else if (g_strcmp0(args[1], "resource") == 0) { cons_show("Roster resource disabled"); prefs_set_boolean(PREF_ROSTER_RESOURCE, FALSE); if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } return TRUE; } else if (g_strcmp0(args[1], "empty") == 0) { cons_show("Roster empty disabled"); prefs_set_boolean(PREF_ROSTER_EMPTY, FALSE); if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; } // roster grouping } else if (g_strcmp0(args[0], "by") == 0) { if (g_strcmp0(args[1], "group") == 0) { cons_show("Grouping roster by roster group"); prefs_set_string(PREF_ROSTER_BY, "group"); if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } return TRUE; } else if (g_strcmp0(args[1], "presence") == 0) { cons_show("Grouping roster by presence"); prefs_set_string(PREF_ROSTER_BY, "presence"); if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } return TRUE; } else if (g_strcmp0(args[1], "none") == 0) { cons_show("Roster grouping disabled"); prefs_set_string(PREF_ROSTER_BY, "none"); if (conn_status == JABBER_CONNECTED) { rosterwin_roster(); } return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; } // add contact } else if (strcmp(args[0], "add") == 0) { if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } char *jid = args[1]; if (jid == NULL) { cons_bad_cmd_usage(command); } else { char *name = args[2]; roster_send_add_new(jid, name); } return TRUE; // remove contact } else if (strcmp(args[0], "remove") == 0) { if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } char *jid = args[1]; if (jid == NULL) { cons_bad_cmd_usage(command); } else { roster_send_remove(jid); } return TRUE; } else if (strcmp(args[0], "remove_all") == 0) { if (g_strcmp0(args[1], "contacts") != 0) { cons_bad_cmd_usage(command); return TRUE; } if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } GSList *all = roster_get_contacts(); GSList *curr = all; while (curr) { PContact contact = curr->data; roster_send_remove(p_contact_barejid(contact)); curr = g_slist_next(curr); } g_slist_free(all); return TRUE; // change nickname } else if (strcmp(args[0], "nick") == 0) { if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } char *jid = args[1]; if (jid == NULL) { cons_bad_cmd_usage(command); return TRUE; } char *name = args[2]; if (name == NULL) { cons_bad_cmd_usage(command); return TRUE; } // contact does not exist PContact contact = roster_get_contact(jid); if (contact == NULL) { cons_show("Contact not found in roster: %s", jid); return TRUE; } const char *barejid = p_contact_barejid(contact); roster_change_name(contact, name); GSList *groups = p_contact_groups(contact); roster_send_name_change(barejid, name, groups); cons_show("Nickname for %s set to: %s.", jid, name); return TRUE; // remove nickname } else if (strcmp(args[0], "clearnick") == 0) { if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } char *jid = args[1]; if (jid == NULL) { cons_bad_cmd_usage(command); return TRUE; } // contact does not exist PContact contact = roster_get_contact(jid); if (contact == NULL) { cons_show("Contact not found in roster: %s", jid); return TRUE; } const char *barejid = p_contact_barejid(contact); roster_change_name(contact, NULL); GSList *groups = p_contact_groups(contact); roster_send_name_change(barejid, NULL, groups); cons_show("Nickname for %s removed.", jid); return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; } } gboolean cmd_resource(ProfWin *window, const char * const command, gchar **args) { char *cmd = args[0]; char *setting = NULL; if (g_strcmp0(cmd, "message") == 0) { setting = args[1]; if (!setting) { cons_bad_cmd_usage(command); return TRUE; } else { return _cmd_set_boolean_preference(setting, command, "Message resource", PREF_RESOURCE_MESSAGE); } } else if (g_strcmp0(cmd, "title") == 0) { setting = args[1]; if (!setting) { cons_bad_cmd_usage(command); return TRUE; } else { return _cmd_set_boolean_preference(setting, command, "Title resource", PREF_RESOURCE_TITLE); } } if (window->type != WIN_CHAT) { cons_show("Resource can only be changed in chat windows."); return TRUE; } ProfChatWin *chatwin = (ProfChatWin*)window; if (g_strcmp0(cmd, "set") == 0) { char *resource = args[1]; if (!resource) { cons_bad_cmd_usage(command); return TRUE; } #ifdef HAVE_LIBOTR if (otr_is_secure(chatwin->barejid)) { cons_show("Cannot choose resource during an OTR session."); return TRUE; } #endif PContact contact = roster_get_contact(chatwin->barejid); if (!contact) { cons_show("Cannot choose resource for contact not in roster."); return TRUE; } if (!p_contact_get_resource(contact, resource)) { cons_show("No such resource %s.", resource); return TRUE; } chatwin->resource_override = strdup(resource); chat_state_free(chatwin->state); chatwin->state = chat_state_new(); chat_session_resource_override(chatwin->barejid, resource); return TRUE; } else if (g_strcmp0(cmd, "off") == 0) { FREE_SET_NULL(chatwin->resource_override); chat_state_free(chatwin->state); chatwin->state = chat_state_new(); chat_session_remove(chatwin->barejid); return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; } } gboolean cmd_status(ProfWin *window, const char * const command, gchar **args) { char *usr = args[0]; jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } switch (window->type) { case WIN_MUC: if (usr) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); Occupant *occupant = muc_roster_item(mucwin->roomjid, usr); if (occupant) { win_show_occupant(window, occupant); } else { win_vprint(window, '-', 0, NULL, 0, 0, "", "No such participant \"%s\" in room.", usr); } } else { ui_current_print_line("You must specify a nickname."); } break; case WIN_CHAT: if (usr) { ui_current_print_line("No parameter required when in chat."); } else { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); PContact pcontact = roster_get_contact(chatwin->barejid); if (pcontact) { win_show_contact(window, pcontact); } else { win_println(window, 0, "Error getting contact info."); } } break; case WIN_PRIVATE: if (usr) { ui_current_print_line("No parameter required when in chat."); } else { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); Jid *jid = jid_create(privatewin->fulljid); Occupant *occupant = muc_roster_item(jid->barejid, jid->resourcepart); if (occupant) { win_show_occupant(window, occupant); } else { win_println(window, 0, "Error getting contact info."); } jid_destroy(jid); } break; case WIN_CONSOLE: if (usr) { char *usr_jid = roster_barejid_from_name(usr); if (usr_jid == NULL) { usr_jid = usr; } cons_show_status(usr_jid); } else { cons_bad_cmd_usage(command); } break; default: break; } return TRUE; } gboolean cmd_info(ProfWin *window, const char * const command, gchar **args) { char *usr = args[0]; jabber_conn_status_t conn_status = jabber_get_connection_status(); PContact pcontact = NULL; if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } switch (window->type) { case WIN_MUC: if (usr) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); Occupant *occupant = muc_roster_item(mucwin->roomjid, usr); if (occupant) { win_show_occupant_info(window, mucwin->roomjid, occupant); } else { ui_current_print_line("No such occupant \"%s\" in room.", usr); } } else { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); iq_room_info_request(mucwin->roomjid, TRUE); ui_show_room_info(mucwin); return TRUE; } break; case WIN_CHAT: if (usr) { ui_current_print_line("No parameter required when in chat."); } else { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); PContact pcontact = roster_get_contact(chatwin->barejid); if (pcontact) { win_show_info(window, pcontact); } else { win_println(window, 0, "Error getting contact info."); } } break; case WIN_PRIVATE: if (usr) { ui_current_print_line("No parameter required when in chat."); } else { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); Jid *jid = jid_create(privatewin->fulljid); Occupant *occupant = muc_roster_item(jid->barejid, jid->resourcepart); if (occupant) { win_show_occupant_info(window, jid->barejid, occupant); } else { win_println(window, 0, "Error getting contact info."); } jid_destroy(jid); } break; case WIN_CONSOLE: if (usr) { char *usr_jid = roster_barejid_from_name(usr); if (usr_jid == NULL) { usr_jid = usr; } pcontact = roster_get_contact(usr_jid); if (pcontact) { cons_show_info(pcontact); } else { cons_show("No such contact \"%s\" in roster.", usr); } } else { cons_bad_cmd_usage(command); } break; default: break; } return TRUE; } gboolean cmd_caps(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); PContact pcontact = NULL; Occupant *occupant = NULL; if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } switch (window->type) { case WIN_MUC: if (args[0]) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); occupant = muc_roster_item(mucwin->roomjid, args[0]); if (occupant) { Jid *jidp = jid_create_from_bare_and_resource(mucwin->roomjid, args[0]); cons_show_caps(jidp->fulljid, occupant->presence); jid_destroy(jidp); } else { cons_show("No such participant \"%s\" in room.", args[0]); } } else { cons_show("No nickname supplied to /caps in chat room."); } break; case WIN_CHAT: case WIN_CONSOLE: if (args[0]) { Jid *jid = jid_create(args[0]); if (jid->fulljid == NULL) { cons_show("You must provide a full jid to the /caps command."); } else { pcontact = roster_get_contact(jid->barejid); if (pcontact == NULL) { cons_show("Contact not found in roster: %s", jid->barejid); } else { Resource *resource = p_contact_get_resource(pcontact, jid->resourcepart); if (resource == NULL) { cons_show("Could not find resource %s, for contact %s", jid->barejid, jid->resourcepart); } else { cons_show_caps(jid->fulljid, resource->presence); } } } jid_destroy(jid); } else { cons_show("You must provide a jid to the /caps command."); } break; case WIN_PRIVATE: if (args[0]) { cons_show("No parameter needed to /caps when in private chat."); } else { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); Jid *jid = jid_create(privatewin->fulljid); if (jid) { occupant = muc_roster_item(jid->barejid, jid->resourcepart); cons_show_caps(jid->resourcepart, occupant->presence); jid_destroy(jid); } } break; default: break; } return TRUE; } gboolean cmd_software(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); Occupant *occupant = NULL; if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } switch (window->type) { case WIN_MUC: if (args[0]) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); occupant = muc_roster_item(mucwin->roomjid, args[0]); if (occupant) { Jid *jid = jid_create_from_bare_and_resource(mucwin->roomjid, args[0]); iq_send_software_version(jid->fulljid); jid_destroy(jid); } else { cons_show("No such participant \"%s\" in room.", args[0]); } } else { cons_show("No nickname supplied to /software in chat room."); } break; case WIN_CHAT: if (args[0]) { cons_show("No parameter needed to /software when in chat."); } else { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); char *resource = NULL; ChatSession *session = chat_session_get(chatwin->barejid); if (chatwin->resource_override) { resource = chatwin->resource_override; } else if (session && session->resource) { resource = session->resource; } if (resource) { GString *fulljid = g_string_new(chatwin->barejid); g_string_append_printf(fulljid, "/%s", resource); iq_send_software_version(fulljid->str); g_string_free(fulljid, TRUE); } else { win_println(window, 0, "Unknown resource for /software command."); } } break; case WIN_CONSOLE: if (args[0]) { Jid *myJid = jid_create(jabber_get_fulljid()); Jid *jid = jid_create(args[0]); if (jid == NULL || jid->fulljid == NULL) { cons_show("You must provide a full jid to the /software command."); } else if (g_strcmp0(jid->barejid, myJid->barejid) == 0) { cons_show("Cannot request software version for yourself."); } else { iq_send_software_version(jid->fulljid); } jid_destroy(myJid); jid_destroy(jid); } else { cons_show("You must provide a jid to the /software command."); } break; case WIN_PRIVATE: if (args[0]) { cons_show("No parameter needed to /software when in private chat."); } else { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); iq_send_software_version(privatewin->fulljid); } break; default: break; } return TRUE; } gboolean cmd_join(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (args[0] == NULL) { uuid_t uuid; uuid_generate(uuid); char *uuid_str = malloc(sizeof(char) * 37); uuid_unparse_lower(uuid, uuid_str); char *account_name = jabber_get_account_name(); ProfAccount *account = accounts_get_account(account_name); GString *room_str = g_string_new(""); g_string_append_printf(room_str, "private-chat-%s@%s", uuid_str, account->muc_service); presence_join_room(room_str->str, account->muc_nick, NULL); muc_join(room_str->str, account->muc_nick, NULL, FALSE); g_string_free(room_str, TRUE); free(uuid_str); account_free(account); return TRUE; } Jid *room_arg = jid_create(args[0]); if (room_arg == NULL) { cons_show_error("Specified room has incorrect format."); cons_show(""); return TRUE; } char *room = NULL; char *nick = NULL; char *passwd = NULL; GString *room_str = g_string_new(""); char *account_name = jabber_get_account_name(); ProfAccount *account = accounts_get_account(account_name); // full room jid supplied (room@server) if (room_arg->localpart) { room = args[0]; // server not supplied (room), use account preference } else { g_string_append(room_str, args[0]); g_string_append(room_str, "@"); g_string_append(room_str, account->muc_service); room = room_str->str; } // Additional args supplied gchar *opt_keys[] = { "nick", "password", NULL }; gboolean parsed; GHashTable *options = parse_options(&args[1], opt_keys, &parsed); if (!parsed) { cons_bad_cmd_usage(command); cons_show(""); jid_destroy(room_arg); return TRUE; } nick = g_hash_table_lookup(options, "nick"); passwd = g_hash_table_lookup(options, "password"); options_destroy(options); // In the case that a nick wasn't provided by the optional args... if (!nick) { nick = account->muc_nick; } // When no password, check for invite with password if (!passwd) { passwd = muc_invite_password(room); } if (!muc_active(room)) { presence_join_room(room, nick, passwd); muc_join(room, nick, passwd, FALSE); } else if (muc_roster_complete(room)) { ui_switch_to_room(room); } jid_destroy(room_arg); g_string_free(room_str, TRUE); account_free(account); return TRUE; } gboolean cmd_invite(ProfWin *window, const char * const command, gchar **args) { char *contact = args[0]; char *reason = args[1]; jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (window->type != WIN_MUC) { cons_show("You must be in a chat room to send an invite."); return TRUE; } char *usr_jid = roster_barejid_from_name(contact); if (usr_jid == NULL) { usr_jid = contact; } ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); message_send_invite(mucwin->roomjid, usr_jid, reason); if (reason) { cons_show("Room invite sent, contact: %s, room: %s, reason: \"%s\".", contact, mucwin->roomjid, reason); } else { cons_show("Room invite sent, contact: %s, room: %s.", contact, mucwin->roomjid); } return TRUE; } gboolean cmd_invites(ProfWin *window, const char * const command, gchar **args) { GSList *invites = muc_invites(); cons_show_room_invites(invites); g_slist_free_full(invites, g_free); return TRUE; } gboolean cmd_decline(ProfWin *window, const char * const command, gchar **args) { if (!muc_invites_contain(args[0])) { cons_show("No such invite exists."); } else { muc_invites_remove(args[0]); cons_show("Declined invite to %s.", args[0]); } return TRUE; } gboolean cmd_form_field(ProfWin *window, char *tag, gchar **args) { if (window->type != WIN_MUC_CONFIG) { return TRUE; } ProfMucConfWin *confwin = (ProfMucConfWin*)window; DataForm *form = confwin->form; if (form) { if (!form_tag_exists(form, tag)) { ui_current_print_line("Form does not contain a field with tag %s", tag); return TRUE; } form_field_type_t field_type = form_get_field_type(form, tag); char *cmd = NULL; char *value = NULL; gboolean valid = FALSE; gboolean added = FALSE; gboolean removed = FALSE; switch (field_type) { case FIELD_BOOLEAN: value = args[0]; if (g_strcmp0(value, "on") == 0) { form_set_value(form, tag, "1"); ui_current_print_line("Field updated..."); ui_show_form_field(window, form, tag); } else if (g_strcmp0(value, "off") == 0) { form_set_value(form, tag, "0"); ui_current_print_line("Field updated..."); ui_show_form_field(window, form, tag); } else { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); } break; case FIELD_TEXT_PRIVATE: case FIELD_TEXT_SINGLE: case FIELD_JID_SINGLE: value = args[0]; if (value == NULL) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); } else { form_set_value(form, tag, value); ui_current_print_line("Field updated..."); ui_show_form_field(window, form, tag); } break; case FIELD_LIST_SINGLE: value = args[0]; if ((value == NULL) || !form_field_contains_option(form, tag, value)) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); } else { form_set_value(form, tag, value); ui_current_print_line("Field updated..."); ui_show_form_field(window, form, tag); } break; case FIELD_TEXT_MULTI: cmd = args[0]; if (cmd) { value = args[1]; } if ((g_strcmp0(cmd, "add") != 0) && (g_strcmp0(cmd, "remove"))) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); break; } if (value == NULL) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); break; } if (g_strcmp0(cmd, "add") == 0) { form_add_value(form, tag, value); ui_current_print_line("Field updated..."); ui_show_form_field(window, form, tag); break; } if (g_strcmp0(args[0], "remove") == 0) { if (!g_str_has_prefix(value, "val")) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); break; } if (strlen(value) < 4) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); break; } int index = strtol(&value[3], NULL, 10); if ((index < 1) || (index > form_get_value_count(form, tag))) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); break; } removed = form_remove_text_multi_value(form, tag, index); if (removed) { ui_current_print_line("Field updated..."); ui_show_form_field(window, form, tag); } else { ui_current_print_line("Could not remove %s from %s", value, tag); } } break; case FIELD_LIST_MULTI: cmd = args[0]; if (cmd) { value = args[1]; } if ((g_strcmp0(cmd, "add") != 0) && (g_strcmp0(cmd, "remove"))) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); break; } if (value == NULL) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); break; } if (g_strcmp0(args[0], "add") == 0) { valid = form_field_contains_option(form, tag, value); if (valid) { added = form_add_unique_value(form, tag, value); if (added) { ui_current_print_line("Field updated..."); ui_show_form_field(window, form, tag); } else { ui_current_print_line("Value %s already selected for %s", value, tag); } } else { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); } break; } if (g_strcmp0(args[0], "remove") == 0) { valid = form_field_contains_option(form, tag, value); if (valid == TRUE) { removed = form_remove_value(form, tag, value); if (removed) { ui_current_print_line("Field updated..."); ui_show_form_field(window, form, tag); } else { ui_current_print_line("Value %s is not currently set for %s", value, tag); } } else { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); } } break; case FIELD_JID_MULTI: cmd = args[0]; if (cmd) { value = args[1]; } if ((g_strcmp0(cmd, "add") != 0) && (g_strcmp0(cmd, "remove"))) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); break; } if (value == NULL) { ui_current_print_line("Invalid command, usage:"); ui_show_form_field_help(confwin, tag); ui_current_print_line(""); break; } if (g_strcmp0(args[0], "add") == 0) { added = form_add_unique_value(form, tag, value); if (added) { ui_current_print_line("Field updated..."); ui_show_form_field(window, form, tag); } else { ui_current_print_line("JID %s already exists in %s", value, tag); } break; } if (g_strcmp0(args[0], "remove") == 0) { removed = form_remove_value(form, tag, value); if (removed) { ui_current_print_line("Field updated..."); ui_show_form_field(window, form, tag); } else { ui_current_print_line("Field %s does not contain %s", tag, value); } } break; default: break; } } return TRUE; } gboolean cmd_form(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (window->type != WIN_MUC_CONFIG) { cons_show("Command '/form' does not apply to this window."); return TRUE; } if ((g_strcmp0(args[0], "submit") != 0) && (g_strcmp0(args[0], "cancel") != 0) && (g_strcmp0(args[0], "show") != 0) && (g_strcmp0(args[0], "help") != 0)) { cons_bad_cmd_usage(command); return TRUE; } ProfMucConfWin *confwin = (ProfMucConfWin*)window; assert(confwin->memcheck == PROFCONFWIN_MEMCHECK); if (g_strcmp0(args[0], "show") == 0) { ui_show_form(confwin); return TRUE; } if (g_strcmp0(args[0], "help") == 0) { char *tag = args[1]; if (tag) { ui_show_form_field_help(confwin, tag); } else { ui_show_form_help(confwin); const gchar **help_text = NULL; Command *command = g_hash_table_lookup(commands, "/form"); if (command) { help_text = command->help.synopsis; } ui_show_lines((ProfWin*) confwin, help_text); } ui_current_print_line(""); return TRUE; } if (g_strcmp0(args[0], "submit") == 0) { iq_submit_room_config(confwin->roomjid, confwin->form); } if (g_strcmp0(args[0], "cancel") == 0) { iq_room_config_cancel(confwin->roomjid); } if ((g_strcmp0(args[0], "submit") == 0) || (g_strcmp0(args[0], "cancel") == 0)) { if (confwin->form) { cmd_autocomplete_remove_form_fields(confwin->form); } wins_close_current(); ProfWin *new_current = (ProfWin*)wins_get_muc(confwin->roomjid); if (!new_current) { new_current = wins_get_console(); } ui_ev_focus_win(new_current); } return TRUE; } gboolean cmd_kick(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (window->type != WIN_MUC) { cons_show("Command '/kick' only applies in chat rooms."); return TRUE; } ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); char *nick = args[0]; if (nick) { if (muc_roster_contains_nick(mucwin->roomjid, nick)) { char *reason = args[1]; iq_room_kick_occupant(mucwin->roomjid, nick, reason); } else { win_vprint((ProfWin*) mucwin, '!', 0, NULL, 0, 0, "", "Occupant does not exist: %s", nick); } } else { cons_bad_cmd_usage(command); } return TRUE; } gboolean cmd_ban(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (window->type != WIN_MUC) { cons_show("Command '/ban' only applies in chat rooms."); return TRUE; } ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); char *jid = args[0]; if (jid) { char *reason = args[1]; iq_room_affiliation_set(mucwin->roomjid, jid, "outcast", reason); } else { cons_bad_cmd_usage(command); } return TRUE; } gboolean cmd_subject(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (window->type != WIN_MUC) { cons_show("Command '/room' does not apply to this window."); return TRUE; } ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); if (args[0] == NULL) { char *subject = muc_subject(mucwin->roomjid); if (subject) { win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "Room subject: "); win_vprint(window, '!', 0, NULL, NO_DATE, 0, "", "%s", subject); } else { win_print(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "Room has no subject"); } return TRUE; } if (g_strcmp0(args[0], "set") == 0) { if (args[1]) { message_send_groupchat_subject(mucwin->roomjid, args[1]); } else { cons_bad_cmd_usage(command); } return TRUE; } if (g_strcmp0(args[0], "clear") == 0) { message_send_groupchat_subject(mucwin->roomjid, NULL); return TRUE; } cons_bad_cmd_usage(command); return TRUE; } gboolean cmd_affiliation(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (window->type != WIN_MUC) { cons_show("Command '/affiliation' does not apply to this window."); return TRUE; } char *cmd = args[0]; if (cmd == NULL) { cons_bad_cmd_usage(command); return TRUE; } char *affiliation = args[1]; if (affiliation && (g_strcmp0(affiliation, "owner") != 0) && (g_strcmp0(affiliation, "admin") != 0) && (g_strcmp0(affiliation, "member") != 0) && (g_strcmp0(affiliation, "none") != 0) && (g_strcmp0(affiliation, "outcast") != 0)) { cons_bad_cmd_usage(command); return TRUE; } ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); if (g_strcmp0(cmd, "list") == 0) { if (!affiliation) { iq_room_affiliation_list(mucwin->roomjid, "owner"); iq_room_affiliation_list(mucwin->roomjid, "admin"); iq_room_affiliation_list(mucwin->roomjid, "member"); iq_room_affiliation_list(mucwin->roomjid, "outcast"); } else if (g_strcmp0(affiliation, "none") == 0) { win_print((ProfWin*) mucwin, '!', 0, NULL, 0, 0, "", "Cannot list users with no affiliation."); } else { iq_room_affiliation_list(mucwin->roomjid, affiliation); } return TRUE; } if (g_strcmp0(cmd, "set") == 0) { if (!affiliation) { cons_bad_cmd_usage(command); return TRUE; } char *jid = args[2]; if (jid == NULL) { cons_bad_cmd_usage(command); return TRUE; } else { char *reason = args[3]; iq_room_affiliation_set(mucwin->roomjid, jid, affiliation, reason); return TRUE; } } cons_bad_cmd_usage(command); return TRUE; } gboolean cmd_role(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (window->type != WIN_MUC) { cons_show("Command '/role' does not apply to this window."); return TRUE; } char *cmd = args[0]; if (cmd == NULL) { cons_bad_cmd_usage(command); return TRUE; } char *role = args[1]; if (role && (g_strcmp0(role, "visitor") != 0) && (g_strcmp0(role, "participant") != 0) && (g_strcmp0(role, "moderator") != 0) && (g_strcmp0(role, "none") != 0)) { cons_bad_cmd_usage(command); return TRUE; } ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); if (g_strcmp0(cmd, "list") == 0) { if (!role) { iq_room_role_list(mucwin->roomjid, "moderator"); iq_room_role_list(mucwin->roomjid, "participant"); iq_room_role_list(mucwin->roomjid, "visitor"); } else if (g_strcmp0(role, "none") == 0) { win_print((ProfWin*) mucwin, '!', 0, NULL, 0, 0, "", "Cannot list users with no role."); } else { iq_room_role_list(mucwin->roomjid, role); } return TRUE; } if (g_strcmp0(cmd, "set") == 0) { if (!role) { cons_bad_cmd_usage(command); return TRUE; } char *nick = args[2]; if (nick == NULL) { cons_bad_cmd_usage(command); return TRUE; } else { char *reason = args[3]; iq_room_role_set(mucwin->roomjid, nick, role, reason); return TRUE; } } cons_bad_cmd_usage(command); return TRUE; } gboolean cmd_room(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (window->type != WIN_MUC) { cons_show("Command '/room' does not apply to this window."); return TRUE; } if ((g_strcmp0(args[0], "accept") != 0) && (g_strcmp0(args[0], "destroy") != 0) && (g_strcmp0(args[0], "config") != 0)) { cons_bad_cmd_usage(command); return TRUE; } ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); int num = wins_get_num(window); int ui_index = num; if (ui_index == 10) { ui_index = 0; } if (g_strcmp0(args[0], "accept") == 0) { gboolean requires_config = muc_requires_config(mucwin->roomjid); if (!requires_config) { win_print(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "Current room does not require configuration."); return TRUE; } else { iq_confirm_instant_room(mucwin->roomjid); muc_set_requires_config(mucwin->roomjid, FALSE); win_print(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "Room unlocked."); return TRUE; } } if (g_strcmp0(args[0], "destroy") == 0) { iq_destroy_room(mucwin->roomjid); return TRUE; } if (g_strcmp0(args[0], "config") == 0) { ProfMucConfWin *confwin = wins_get_muc_conf(mucwin->roomjid); if (confwin) { ui_ev_focus_win((ProfWin*)confwin); } else { iq_request_room_config_form(mucwin->roomjid); } return TRUE; } return TRUE; } gboolean cmd_occupants(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (g_strcmp0(args[0], "size") == 0) { if (!args[1]) { cons_bad_cmd_usage(command); return TRUE; } else { int intval = 0; char *err_msg = NULL; gboolean res = strtoi_range(args[1], &intval, 1, 99, &err_msg); if (res) { prefs_set_occupants_size(intval); cons_show("Occupants screen size set to: %d%%", intval); wins_resize_all(); return TRUE; } else { cons_show(err_msg); free(err_msg); return TRUE; } } } if (g_strcmp0(args[0], "default") == 0) { if (g_strcmp0(args[1], "show") == 0) { if (g_strcmp0(args[2], "jid") == 0) { cons_show("Occupant jids enabled."); prefs_set_boolean(PREF_OCCUPANTS_JID, TRUE); } else { cons_show("Occupant list enabled."); prefs_set_boolean(PREF_OCCUPANTS, TRUE); } return TRUE; } else if (g_strcmp0(args[1], "hide") == 0) { if (g_strcmp0(args[2], "jid") == 0) { cons_show("Occupant jids disabled."); prefs_set_boolean(PREF_OCCUPANTS_JID, FALSE); } else { cons_show("Occupant list disabled."); prefs_set_boolean(PREF_OCCUPANTS, FALSE); } return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; } } if (window->type != WIN_MUC) { cons_show("Cannot apply setting when not in chat room."); return TRUE; } ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); if (g_strcmp0(args[0], "show") == 0) { if (g_strcmp0(args[1], "jid") == 0) { mucwin->showjid = TRUE; ui_room_update_occupants(mucwin->roomjid); } else { ui_room_show_occupants(mucwin->roomjid); } } else if (g_strcmp0(args[0], "hide") == 0) { if (g_strcmp0(args[1], "jid") == 0) { mucwin->showjid = FALSE; ui_room_update_occupants(mucwin->roomjid); } else { ui_room_hide_occupants(mucwin->roomjid); } } else { cons_bad_cmd_usage(command); } return TRUE; } gboolean cmd_rooms(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (args[0] == NULL) { ProfAccount *account = accounts_get_account(jabber_get_account_name()); iq_room_list_request(account->muc_service); account_free(account); } else { iq_room_list_request(args[0]); } return TRUE; } gboolean cmd_bookmark(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } gchar *cmd = args[0]; if (window->type == WIN_MUC && cmd == NULL) { // default to current nickname, password, and autojoin "on" ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); char *nick = muc_nick(mucwin->roomjid); char *password = muc_password(mucwin->roomjid); gboolean added = bookmark_add(mucwin->roomjid, nick, password, "on"); if (added) { ui_current_print_formatted_line('!', 0, "Bookmark added for %s.", mucwin->roomjid); } else { ui_current_print_formatted_line('!', 0, "Bookmark already exists for %s.", mucwin->roomjid); } return TRUE; } else { if (cmd == NULL) { cons_bad_cmd_usage(command); return TRUE; } if (strcmp(cmd, "list") == 0) { const GList *bookmarks = bookmark_get_list(); cons_show_bookmarks(bookmarks); } else { char *jid = args[1]; if (jid == NULL) { cons_bad_cmd_usage(command); cons_show(""); return TRUE; } if (strcmp(cmd, "remove") == 0) { gboolean removed = bookmark_remove(jid); if (removed) { cons_show("Bookmark removed for %s.", jid); } else { cons_show("No bookmark exists for %s.", jid); } return TRUE; } if (strcmp(cmd, "join") == 0) { gboolean joined = bookmark_join(jid); if (!joined) { cons_show("No bookmark exists for %s.", jid); } return TRUE; } gchar *opt_keys[] = { "autojoin", "nick", "password", NULL }; gboolean parsed; GHashTable *options = parse_options(&args[2], opt_keys, &parsed); if (!parsed) { cons_bad_cmd_usage(command); cons_show(""); return TRUE; } char *nick = g_hash_table_lookup(options, "nick"); char *password = g_hash_table_lookup(options, "password"); char *autojoin = g_hash_table_lookup(options, "autojoin"); if (autojoin) { if ((strcmp(autojoin, "on") != 0) && (strcmp(autojoin, "off") != 0)) { cons_bad_cmd_usage(command); cons_show(""); return TRUE; } } if (strcmp(cmd, "add") == 0) { if (strchr(jid, '@')==NULL) { cons_show("Can't add bookmark with JID '%s'; should be '%s@domain.tld'", jid, jid); } else { gboolean added = bookmark_add(jid, nick, password, autojoin); if (added) { cons_show("Bookmark added for %s.", jid); } else { cons_show("Bookmark already exists, use /bookmark update to edit."); } } } else if (strcmp(cmd, "update") == 0) { gboolean updated = bookmark_update(jid, nick, password, autojoin); if (updated) { cons_show("Bookmark updated."); } else { cons_show("No bookmark exists for %s.", jid); } } else { cons_bad_cmd_usage(command); } options_destroy(options); } } return TRUE; } gboolean cmd_disco(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currenlty connected."); return TRUE; } GString *jid = g_string_new(""); if (args[1]) { jid = g_string_append(jid, args[1]); } else { Jid *jidp = jid_create(jabber_get_fulljid()); jid = g_string_append(jid, jidp->domainpart); jid_destroy(jidp); } if (g_strcmp0(args[0], "info") == 0) { iq_disco_info_request(jid->str); } else { iq_disco_items_request(jid->str); } g_string_free(jid, TRUE); return TRUE; } gboolean cmd_nick(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (window->type != WIN_MUC) { cons_show("You can only change your nickname in a chat room window."); return TRUE; } ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); char *nick = args[0]; presence_change_room_nick(mucwin->roomjid, nick); return TRUE; } gboolean cmd_alias(ProfWin *window, const char * const command, gchar **args) { char *subcmd = args[0]; if (strcmp(subcmd, "add") == 0) { char *alias = args[1]; if (alias == NULL) { cons_bad_cmd_usage(command); return TRUE; } else { char *alias_p = alias; GString *ac_value = g_string_new(""); if (alias[0] == '/') { g_string_append(ac_value, alias); alias_p = &alias[1]; } else { g_string_append(ac_value, "/"); g_string_append(ac_value, alias); } char *value = args[2]; if (value == NULL) { cons_bad_cmd_usage(command); g_string_free(ac_value, TRUE); return TRUE; } else if (cmd_exists(ac_value->str)) { cons_show("Command or alias '%s' already exists.", ac_value->str); g_string_free(ac_value, TRUE); return TRUE; } else { prefs_add_alias(alias_p, value); cmd_autocomplete_add(ac_value->str); cmd_alias_add(alias_p); cons_show("Command alias added %s -> %s", ac_value->str, value); g_string_free(ac_value, TRUE); return TRUE; } } } else if (strcmp(subcmd, "remove") == 0) { char *alias = args[1]; if (alias == NULL) { cons_bad_cmd_usage(command); return TRUE; } else { if (alias[0] == '/') { alias = &alias[1]; } gboolean removed = prefs_remove_alias(alias); if (!removed) { cons_show("No such command alias /%s", alias); } else { GString *ac_value = g_string_new("/"); g_string_append(ac_value, alias); cmd_autocomplete_remove(ac_value->str); cmd_alias_remove(alias); g_string_free(ac_value, TRUE); cons_show("Command alias removed -> /%s", alias); } return TRUE; } } else if (strcmp(subcmd, "list") == 0) { GList *aliases = prefs_get_aliases(); cons_show_aliases(aliases); prefs_free_aliases(aliases); return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; } } gboolean cmd_tiny(ProfWin *window, const char * const command, gchar **args) { char *url = args[0]; if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) { cons_show("/tiny can only be used in chat windows"); return TRUE; } if (!tinyurl_valid(url)) { win_vprint(window, '-', 0, NULL, 0, THEME_ERROR, "", "/tiny, badly formed URL: %s", url); return TRUE; } char *tiny = tinyurl_get(url); if (!tiny) { win_print(window, '-', 0, NULL, 0, THEME_ERROR, "", "Couldn't create tinyurl."); return TRUE; } switch (window->type){ case WIN_CHAT: { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); cl_ev_send_msg(chatwin, tiny); break; } case WIN_PRIVATE: { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); cl_ev_send_priv_msg(privatewin, tiny); break; } case WIN_MUC: { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); cl_ev_send_muc_msg(mucwin, tiny); break; } default: break; } free(tiny); return TRUE; } gboolean cmd_clear(ProfWin *window, const char * const command, gchar **args) { ui_clear_win(window); return TRUE; } gboolean cmd_close(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); int index = 0; int count = 0; if (args[0] == NULL) { index = wins_get_current_num(); } else if (strcmp(args[0], "all") == 0) { count = ui_close_all_wins(); if (count == 0) { cons_show("No windows to close."); } else if (count == 1) { cons_show("Closed 1 window."); } else { cons_show("Closed %d windows.", count); } return TRUE; } else if (strcmp(args[0], "read") == 0) { count = ui_close_read_wins(); if (count == 0) { cons_show("No windows to close."); } else if (count == 1) { cons_show("Closed 1 window."); } else { cons_show("Closed %d windows.", count); } return TRUE; } else { index = atoi(args[0]); } if (index < 0 || index == 10) { cons_show("No such window exists."); return TRUE; } if (index == 1) { cons_show("Cannot close console window."); return TRUE; } ProfWin *toclose = wins_get_by_num(index); if (!toclose) { cons_show("Window is not open."); return TRUE; } // check for unsaved form if (ui_win_has_unsaved_form(index)) { ui_current_print_line("You have unsaved changes, use /form submit or /form cancel"); return TRUE; } // handle leaving rooms, or chat if (conn_status == JABBER_CONNECTED) { ui_close_connected_win(index); } // close the window ui_close_win(index); cons_show("Closed window %d", index); // Tidy up the window list. if (prefs_get_boolean(PREF_WINS_AUTO_TIDY)) { ui_tidy_wins(); } return TRUE; } gboolean cmd_leave(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); int index = wins_get_current_num(); if (window->type != WIN_MUC) { cons_show("You can only use the /leave command in a chat room."); cons_alert(); return TRUE; } // handle leaving rooms, or chat if (conn_status == JABBER_CONNECTED) { ui_close_connected_win(index); } // close the window ui_close_win(index); return TRUE; } gboolean cmd_privileges(ProfWin *window, const char * const command, gchar **args) { gboolean result = _cmd_set_boolean_preference(args[0], command, "MUC privileges", PREF_MUC_PRIVILEGES); ui_redraw_all_room_rosters(); return result; } gboolean cmd_beep(ProfWin *window, const char * const command, gchar **args) { return _cmd_set_boolean_preference(args[0], command, "Sound", PREF_BEEP); } gboolean cmd_presence(ProfWin *window, const char * const command, gchar **args) { return _cmd_set_boolean_preference(args[0], command, "Contact presence", PREF_PRESENCE); } gboolean cmd_wrap(ProfWin *window, const char * const command, gchar **args) { gboolean result = _cmd_set_boolean_preference(args[0], command, "Word wrap", PREF_WRAP); wins_resize_all(); return result; } gboolean cmd_time(ProfWin *window, const char * const command, gchar **args) { if (g_strcmp0(args[0], "statusbar") == 0) { if (args[1] == NULL) { cons_show("Current status bar time format is '%s'.", prefs_get_string(PREF_TIME_STATUSBAR)); return TRUE; } else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) { prefs_set_string(PREF_TIME_STATUSBAR, args[2]); cons_show("Status bar time format set to '%s'.", args[2]); ui_redraw(); return TRUE; } else if (g_strcmp0(args[1], "off") == 0) { prefs_set_string(PREF_TIME_STATUSBAR, ""); cons_show("Status bar time display disabled."); ui_redraw(); return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; } } else if (g_strcmp0(args[0], "main") == 0) { if (args[1] == NULL) { cons_show("Current time format is '%s'.", prefs_get_string(PREF_TIME)); return TRUE; } else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) { prefs_set_string(PREF_TIME, args[2]); cons_show("Time format set to '%s'.", args[2]); wins_resize_all(); return TRUE; } else if (g_strcmp0(args[1], "off") == 0) { prefs_set_string(PREF_TIME, ""); cons_show("Time display disabled."); wins_resize_all(); return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; } } else { cons_bad_cmd_usage(command); return TRUE; } } gboolean cmd_states(ProfWin *window, const char * const command, gchar **args) { gboolean result = _cmd_set_boolean_preference(args[0], command, "Sending chat states", PREF_STATES); // if disabled, disable outtype and gone if (result == TRUE && (strcmp(args[0], "off") == 0)) { prefs_set_boolean(PREF_OUTTYPE, FALSE); prefs_set_gone(0); } return result; } gboolean cmd_titlebar(ProfWin *window, const char * const command, gchar **args) { if (g_strcmp0(args[0], "show") != 0 && g_strcmp0(args[0], "goodbye") != 0) { cons_bad_cmd_usage(command); return TRUE; } if (g_strcmp0(args[0], "show") == 0 && g_strcmp0(args[1], "off") == 0) { ui_clear_win_title(); } if (g_strcmp0(args[0], "show") == 0) { return _cmd_set_boolean_preference(args[1], command, "Titlebar show", PREF_TITLEBAR_SHOW); } else { return _cmd_set_boolean_preference(args[1], command, "Titlebar goodbye", PREF_TITLEBAR_GOODBYE); } } gboolean cmd_outtype(ProfWin *window, const char * const command, gchar **args) { gboolean result = _cmd_set_boolean_preference(args[0], command, "Sending typing notifications", PREF_OUTTYPE); // if enabled, enable states if (result == TRUE && (strcmp(args[0], "on") == 0)) { prefs_set_boolean(PREF_STATES, TRUE); } return result; } gboolean cmd_gone(ProfWin *window, const char * const command, gchar **args) { char *value = args[0]; gint period = atoi(value); prefs_set_gone(period); if (period == 0) { cons_show("Automatic leaving conversations after period disabled."); } else if (period == 1) { cons_show("Leaving conversations after 1 minute of inactivity."); } else { cons_show("Leaving conversations after %d minutes of inactivity.", period); } // if enabled, enable states if (period > 0) { prefs_set_boolean(PREF_STATES, TRUE); } return TRUE; } gboolean cmd_notify(ProfWin *window, const char * const command, gchar **args) { char *kind = args[0]; // bad kind if ((strcmp(kind, "message") != 0) && (strcmp(kind, "typing") != 0) && (strcmp(kind, "remind") != 0) && (strcmp(kind, "invite") != 0) && (strcmp(kind, "sub") != 0) && (strcmp(kind, "room") != 0)) { cons_bad_cmd_usage(command); // set message setting } else if (strcmp(kind, "message") == 0) { if (strcmp(args[1], "on") == 0) { cons_show("Message notifications enabled."); prefs_set_boolean(PREF_NOTIFY_MESSAGE, TRUE); } else if (strcmp(args[1], "off") == 0) { cons_show("Message notifications disabled."); prefs_set_boolean(PREF_NOTIFY_MESSAGE, FALSE); } else if (strcmp(args[1], "current") == 0) { if (g_strcmp0(args[2], "on") == 0) { cons_show("Current window message notifications enabled."); prefs_set_boolean(PREF_NOTIFY_MESSAGE_CURRENT, TRUE); } else if (g_strcmp0(args[2], "off") == 0) { cons_show("Current window message notifications disabled."); prefs_set_boolean(PREF_NOTIFY_MESSAGE_CURRENT, FALSE); } else { cons_show("Usage: /notify message current on|off"); } } else if (strcmp(args[1], "text") == 0) { if (g_strcmp0(args[2], "on") == 0) { cons_show("Showing text in message notifications enabled."); prefs_set_boolean(PREF_NOTIFY_MESSAGE_TEXT, TRUE); } else if (g_strcmp0(args[2], "off") == 0) { cons_show("Showing text in message notifications disabled."); prefs_set_boolean(PREF_NOTIFY_MESSAGE_TEXT, FALSE); } else { cons_show("Usage: /notify message text on|off"); } } else { cons_show("Usage: /notify message on|off"); } // set room setting } else if (strcmp(kind, "room") == 0) { if (strcmp(args[1], "on") == 0) { cons_show("Chat room notifications enabled."); prefs_set_string(PREF_NOTIFY_ROOM, "on"); } else if (strcmp(args[1], "off") == 0) { cons_show("Chat room notifications disabled."); prefs_set_string(PREF_NOTIFY_ROOM, "off"); } else if (strcmp(args[1], "mention") == 0) { cons_show("Chat room notifications enabled on mention."); prefs_set_string(PREF_NOTIFY_ROOM, "mention"); } else if (strcmp(args[1], "current") == 0) { if (g_strcmp0(args[2], "on") == 0) { cons_show("Current window chat room message notifications enabled."); prefs_set_boolean(PREF_NOTIFY_ROOM_CURRENT, TRUE); } else if (g_strcmp0(args[2], "off") == 0) { cons_show("Current window chat room message notifications disabled."); prefs_set_boolean(PREF_NOTIFY_ROOM_CURRENT, FALSE); } else { cons_show("Usage: /notify room current on|off"); } } else if (strcmp(args[1], "text") == 0) { if (g_strcmp0(args[2], "on") == 0) { cons_show("Showing text in chat room message notifications enabled."); prefs_set_boolean(PREF_NOTIFY_ROOM_TEXT, TRUE); } else if (g_strcmp0(args[2], "off") == 0) { cons_show("Showing text in chat room message notifications disabled."); prefs_set_boolean(PREF_NOTIFY_ROOM_TEXT, FALSE); } else { cons_show("Usage: /notify room text on|off"); } } else { cons_show("Usage: /notify room on|off|mention"); } // set typing setting } else if (strcmp(kind, "typing") == 0) { if (strcmp(args[1], "on") == 0) { cons_show("Typing notifications enabled."); prefs_set_boolean(PREF_NOTIFY_TYPING, TRUE); } else if (strcmp(args[1], "off") == 0) { cons_show("Typing notifications disabled."); prefs_set_boolean(PREF_NOTIFY_TYPING, FALSE); } else if (strcmp(args[1], "current") == 0) { if (g_strcmp0(args[2], "on") == 0) { cons_show("Current window typing notifications enabled."); prefs_set_boolean(PREF_NOTIFY_TYPING_CURRENT, TRUE); } else if (g_strcmp0(args[2], "off") == 0) { cons_show("Current window typing notifications disabled."); prefs_set_boolean(PREF_NOTIFY_TYPING_CURRENT, FALSE); } else { cons_show("Usage: /notify typing current on|off"); } } else { cons_show("Usage: /notify typing on|off"); } // set invite setting } else if (strcmp(kind, "invite") == 0) { if (strcmp(args[1], "on") == 0) { cons_show("Chat room invite notifications enabled."); prefs_set_boolean(PREF_NOTIFY_INVITE, TRUE); } else if (strcmp(args[1], "off") == 0) { cons_show("Chat room invite notifications disabled."); prefs_set_boolean(PREF_NOTIFY_INVITE, FALSE); } else { cons_show("Usage: /notify invite on|off"); } // set subscription setting } else if (strcmp(kind, "sub") == 0) { if (strcmp(args[1], "on") == 0) { cons_show("Subscription notifications enabled."); prefs_set_boolean(PREF_NOTIFY_SUB, TRUE); } else if (strcmp(args[1], "off") == 0) { cons_show("Subscription notifications disabled."); prefs_set_boolean(PREF_NOTIFY_SUB, FALSE); } else { cons_show("Usage: /notify sub on|off"); } // set remind setting } else if (strcmp(kind, "remind") == 0) { gint period = atoi(args[1]); prefs_set_notify_remind(period); if (period == 0) { cons_show("Message reminders disabled."); } else if (period == 1) { cons_show("Message reminder period set to 1 second."); } else { cons_show("Message reminder period set to %d seconds.", period); } } else { cons_show("Unknown command: %s.", kind); } return TRUE; } gboolean cmd_inpblock(ProfWin *window, const char * const command, gchar **args) { char *subcmd = args[0]; char *value = args[1]; if (g_strcmp0(subcmd, "timeout") == 0) { if (value == NULL) { cons_bad_cmd_usage(command); return TRUE; } int intval = 0; char *err_msg = NULL; gboolean res = strtoi_range(value, &intval, 1, 1000, &err_msg); if (res) { cons_show("Input blocking set to %d milliseconds.", intval); prefs_set_inpblock(intval); ui_input_nonblocking(FALSE); } else { cons_show(err_msg); free(err_msg); } return TRUE; } if (g_strcmp0(subcmd, "dynamic") == 0) { if (value == NULL) { cons_bad_cmd_usage(command); return TRUE; } if (g_strcmp0(value, "on") != 0 && g_strcmp0(value, "off") != 0) { cons_show("Dynamic must be one of 'on' or 'off'"); return TRUE; } return _cmd_set_boolean_preference(value, command, "Dynamic input blocking", PREF_INPBLOCK_DYNAMIC); } cons_bad_cmd_usage(command); return TRUE; } gboolean cmd_log(ProfWin *window, const char * const command, gchar **args) { char *subcmd = args[0]; char *value = args[1]; if (strcmp(subcmd, "maxsize") == 0) { if (value == NULL) { cons_bad_cmd_usage(command); return TRUE; } int intval = 0; char *err_msg = NULL; gboolean res = strtoi_range(value, &intval, PREFS_MIN_LOG_SIZE, INT_MAX, &err_msg); if (res) { prefs_set_max_log_size(intval); cons_show("Log maxinum size set to %d bytes", intval); } else { cons_show(err_msg); free(err_msg); } return TRUE; } if (strcmp(subcmd, "rotate") == 0) { if (value == NULL) { cons_bad_cmd_usage(command); return TRUE; } return _cmd_set_boolean_preference(value, command, "Log rotate", PREF_LOG_ROTATE); } if (strcmp(subcmd, "shared") == 0) { if (value == NULL) { cons_bad_cmd_usage(command); return TRUE; } gboolean result = _cmd_set_boolean_preference(value, command, "Shared log", PREF_LOG_SHARED); log_reinit(); return result; } if (strcmp(subcmd, "where") == 0) { char *logfile = get_log_file_location(); cons_show("Log file: %s", logfile); return TRUE; } cons_bad_cmd_usage(command); /* TODO: make 'level' subcommand for debug level */ return TRUE; } gboolean cmd_reconnect(ProfWin *window, const char * const command, gchar **args) { char *value = args[0]; int intval = 0; char *err_msg = NULL; gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg); if (res) { prefs_set_reconnect(intval); if (intval == 0) { cons_show("Reconnect disabled.", intval); } else { cons_show("Reconnect interval set to %d seconds.", intval); } } else { cons_show(err_msg); cons_bad_cmd_usage(command); free(err_msg); } return TRUE; } gboolean cmd_autoping(ProfWin *window, const char * const command, gchar **args) { char *value = args[0]; int intval = 0; char *err_msg = NULL; gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg); if (res) { prefs_set_autoping(intval); iq_set_autoping(intval); if (intval == 0) { cons_show("Autoping disabled.", intval); } else { cons_show("Autoping interval set to %d seconds.", intval); } } else { cons_show(err_msg); cons_bad_cmd_usage(command); free(err_msg); } return TRUE; } gboolean cmd_ping(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currenlty connected."); return TRUE; } iq_send_ping(args[0]); if (args[0] == NULL) { cons_show("Pinged server..."); } else { cons_show("Pinged %s...", args[0]); } return TRUE; } gboolean cmd_autoaway(ProfWin *window, const char * const command, gchar **args) { char *setting = args[0]; char *value = args[1]; if ((strcmp(setting, "mode") != 0) && (strcmp(setting, "time") != 0) && (strcmp(setting, "message") != 0) && (strcmp(setting, "check") != 0)) { cons_show("Setting must be one of 'mode', 'time', 'message' or 'check'"); return TRUE; } if (strcmp(setting, "mode") == 0) { if ((strcmp(value, "idle") != 0) && (strcmp(value, "away") != 0) && (strcmp(value, "off") != 0)) { cons_show("Mode must be one of 'idle', 'away' or 'off'"); } else { prefs_set_string(PREF_AUTOAWAY_MODE, value); cons_show("Auto away mode set to: %s.", value); } return TRUE; } if (strcmp(setting, "time") == 0) { int minutesval = 0; char *err_msg = NULL; gboolean res = strtoi_range(value, &minutesval, 1, INT_MAX, &err_msg); if (res) { prefs_set_autoaway_time(minutesval); cons_show("Auto away time set to: %d minutes.", minutesval); } else { cons_show(err_msg); free(err_msg); } return TRUE; } if (strcmp(setting, "message") == 0) { if (strcmp(value, "off") == 0) { prefs_set_string(PREF_AUTOAWAY_MESSAGE, NULL); cons_show("Auto away message cleared."); } else { prefs_set_string(PREF_AUTOAWAY_MESSAGE, value); cons_show("Auto away message set to: \"%s\".", value); } return TRUE; } if (strcmp(setting, "check") == 0) { return _cmd_set_boolean_preference(value, command, "Online check", PREF_AUTOAWAY_CHECK); } return TRUE; } gboolean cmd_priority(ProfWin *window, const char * const command, gchar **args) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } char *value = args[0]; int intval = 0; char *err_msg = NULL; gboolean res = strtoi_range(value, &intval, -128, 127, &err_msg); if (res) { accounts_set_priority_all(jabber_get_account_name(), intval); resource_presence_t last_presence = accounts_get_last_presence(jabber_get_account_name()); cl_ev_presence_send(last_presence, jabber_get_presence_message(), 0); cons_show("Priority set to %d.", intval); } else { cons_show(err_msg); free(err_msg); } return TRUE; } gboolean cmd_statuses(ProfWin *window, const char * const command, gchar **args) { if (strcmp(args[0], "console") != 0 && strcmp(args[0], "chat") != 0 && strcmp(args[0], "muc") != 0) { cons_bad_cmd_usage(command); return TRUE; } if (strcmp(args[1], "all") != 0 && strcmp(args[1], "online") != 0 && strcmp(args[1], "none") != 0) { cons_bad_cmd_usage(command); return TRUE; } if (strcmp(args[0], "console") == 0) { prefs_set_string(PREF_STATUSES_CONSOLE, args[1]); if (strcmp(args[1], "all") == 0) { cons_show("All presence updates will appear in the console."); } else if (strcmp(args[1], "online") == 0) { cons_show("Only online/offline presence updates will appear in the console."); } else { cons_show("Presence updates will not appear in the console."); } } if (strcmp(args[0], "chat") == 0) { prefs_set_string(PREF_STATUSES_CHAT, args[1]); if (strcmp(args[1], "all") == 0) { cons_show("All presence updates will appear in chat windows."); } else if (strcmp(args[1], "online") == 0) { cons_show("Only online/offline presence updates will appear in chat windows."); } else { cons_show("Presence updates will not appear in chat windows."); } } if (strcmp(args[0], "muc") == 0) { prefs_set_string(PREF_STATUSES_MUC, args[1]); if (strcmp(args[1], "all") == 0) { cons_show("All presence updates will appear in chat room windows."); } else if (strcmp(args[1], "online") == 0) { cons_show("Only join/leave presence updates will appear in chat room windows."); } else { cons_show("Presence updates will not appear in chat room windows."); } } return TRUE; } gboolean cmd_vercheck(ProfWin *window, const char * const command, gchar **args) { int num_args = g_strv_length(args); if (num_args == 0) { cons_check_version(TRUE); return TRUE; } else { return _cmd_set_boolean_preference(args[0], command, "Version checking", PREF_VERCHECK); } } gboolean cmd_xmlconsole(ProfWin *window, const char * const command, gchar **args) { if (!ui_xmlconsole_exists()) { ui_create_xmlconsole_win(); } else { ui_open_xmlconsole_win(); } return TRUE; } gboolean cmd_flash(ProfWin *window, const char * const command, gchar **args) { return _cmd_set_boolean_preference(args[0], command, "Screen flash", PREF_FLASH); } gboolean cmd_intype(ProfWin *window, const char * const command, gchar **args) { return _cmd_set_boolean_preference(args[0], command, "Show contact typing", PREF_INTYPE); } gboolean cmd_splash(ProfWin *window, const char * const command, gchar **args) { return _cmd_set_boolean_preference(args[0], command, "Splash screen", PREF_SPLASH); } gboolean cmd_autoconnect(ProfWin *window, const char * const command, gchar **args) { if (strcmp(args[0], "off") == 0) { prefs_set_string(PREF_CONNECT_ACCOUNT, NULL); cons_show("Autoconnect account disabled."); } else if (strcmp(args[0], "set") == 0) { prefs_set_string(PREF_CONNECT_ACCOUNT, args[1]); cons_show("Autoconnect account set to: %s.", args[1]); } else { cons_bad_cmd_usage(command); } return true; } gboolean cmd_chlog(ProfWin *window, const char * const command, gchar **args) { gboolean result = _cmd_set_boolean_preference(args[0], command, "Chat logging", PREF_CHLOG); // if set to off, disable history if (result == TRUE && (strcmp(args[0], "off") == 0)) { prefs_set_boolean(PREF_HISTORY, FALSE); } return result; } gboolean cmd_grlog(ProfWin *window, const char * const command, gchar **args) { gboolean result = _cmd_set_boolean_preference(args[0], command, "Groupchat logging", PREF_GRLOG); return result; } gboolean cmd_history(ProfWin *window, const char * const command, gchar **args) { gboolean result = _cmd_set_boolean_preference(args[0], command, "Chat history", PREF_HISTORY); // if set to on, set chlog if (result == TRUE && (strcmp(args[0], "on") == 0)) { prefs_set_boolean(PREF_CHLOG, TRUE); } return result; } gboolean cmd_carbons(ProfWin *window, const char * const command, gchar **args) { gboolean result = _cmd_set_boolean_preference(args[0], command, "Message carbons preference", PREF_CARBONS); jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status == JABBER_CONNECTED) { // enable carbons if (strcmp(args[0], "on") == 0) { iq_enable_carbons(); } else if (strcmp(args[0], "off") == 0){ iq_disable_carbons(); } } return result; } gboolean cmd_receipts(ProfWin *window, const char * const command, gchar **args) { if (g_strcmp0(args[0], "send") == 0) { return _cmd_set_boolean_preference(args[1], command, "Send delivery receipts", PREF_RECEIPTS_SEND); } else if (g_strcmp0(args[0], "request") == 0) { return _cmd_set_boolean_preference(args[1], command, "Request delivery receipts", PREF_RECEIPTS_REQUEST); } else { cons_bad_cmd_usage(command); return TRUE; } } gboolean cmd_away(ProfWin *window, const char * const command, gchar **args) { _update_presence(RESOURCE_AWAY, "away", args); return TRUE; } gboolean cmd_online(ProfWin *window, const char * const command, gchar **args) { _update_presence(RESOURCE_ONLINE, "online", args); return TRUE; } gboolean cmd_dnd(ProfWin *window, const char * const command, gchar **args) { _update_presence(RESOURCE_DND, "dnd", args); return TRUE; } gboolean cmd_chat(ProfWin *window, const char * const command, gchar **args) { _update_presence(RESOURCE_CHAT, "chat", args); return TRUE; } gboolean cmd_xa(ProfWin *window, const char * const command, gchar **args) { _update_presence(RESOURCE_XA, "xa", args); return TRUE; } gboolean cmd_pgp(ProfWin *window, const char * const command, gchar **args) { #ifdef HAVE_LIBGPGME if (args[0] == NULL) { cons_bad_cmd_usage(command); return TRUE; } if (strcmp(args[0], "char") == 0) { if (args[1] == NULL) { cons_bad_cmd_usage(command); } else if (strlen(args[1]) != 1) { cons_bad_cmd_usage(command); } else { prefs_set_pgp_char(args[1][0]); cons_show("PGP char set to %c.", args[1][0]); } return TRUE; } else if (g_strcmp0(args[0], "log") == 0) { char *choice = args[1]; if (g_strcmp0(choice, "on") == 0) { prefs_set_string(PREF_PGP_LOG, "on"); cons_show("PGP messages will be logged as plaintext."); if (!prefs_get_boolean(PREF_CHLOG)) { cons_show("Chat logging is currently disabled, use '/chlog on' to enable."); } } else if (g_strcmp0(choice, "off") == 0) { prefs_set_string(PREF_PGP_LOG, "off"); cons_show("PGP message logging disabled."); } else if (g_strcmp0(choice, "redact") == 0) { prefs_set_string(PREF_PGP_LOG, "redact"); cons_show("PGP messages will be logged as '[redacted]'."); if (!prefs_get_boolean(PREF_CHLOG)) { cons_show("Chat logging is currently disabled, use '/chlog on' to enable."); } } else { cons_bad_cmd_usage(command); } return TRUE; } if (g_strcmp0(args[0], "keys") == 0) { GHashTable *keys = p_gpg_list_keys(); if (!keys || g_hash_table_size(keys) == 0) { cons_show("No keys found"); return TRUE; } cons_show("PGP keys:"); GList *keylist = g_hash_table_get_keys(keys); GList *curr = keylist; while (curr) { ProfPGPKey *key = g_hash_table_lookup(keys, curr->data); cons_show(" %s", key->name); cons_show(" ID : %s", key->id); char *format_fp = p_gpg_format_fp_str(key->fp); cons_show(" Fingerprint : %s", format_fp); free(format_fp); if (key->secret) { cons_show(" Type : PUBLIC, PRIVATE"); } else { cons_show(" Type : PUBLIC"); } curr = g_list_next(curr); } g_list_free(keylist); p_gpg_free_keys(keys); return TRUE; } if (g_strcmp0(args[0], "setkey") == 0) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } char *jid = args[1]; if (!args[1]) { cons_bad_cmd_usage(command); return TRUE; } char *keyid = args[2]; if (!args[2]) { cons_bad_cmd_usage(command); return TRUE; } gboolean res = p_gpg_addkey(jid, keyid); if (!res) { cons_show("Key ID not found."); } else { cons_show("Key %s set for %s.", keyid, jid); } return TRUE; } if (g_strcmp0(args[0], "contacts") == 0) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } GHashTable *pubkeys = p_gpg_pubkeys(); GList *jids = g_hash_table_get_keys(pubkeys); if (!jids) { cons_show("No contacts found with PGP public keys assigned."); return TRUE; } cons_show("Assigned PGP public keys:"); GList *curr = jids; while (curr) { char *jid = curr->data; ProfPGPPubKeyId *pubkeyid = g_hash_table_lookup(pubkeys, jid); if (pubkeyid->received) { cons_show(" %s: %s (received)", jid, pubkeyid->id); } else { cons_show(" %s: %s (stored)", jid, pubkeyid->id); } curr = g_list_next(curr); } g_list_free(jids); return TRUE; } if (g_strcmp0(args[0], "libver") == 0) { const char *libver = p_gpg_libver(); if (!libver) { cons_show("Could not get libgpgme version"); return TRUE; } GString *fullstr = g_string_new("Using libgpgme version "); g_string_append(fullstr, libver); cons_show("%s", fullstr->str); g_string_free(fullstr, TRUE); return TRUE; } if (g_strcmp0(args[0], "start") == 0) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You must be connected to start PGP encrpytion."); return TRUE; } if (window->type != WIN_CHAT && args[1] == NULL) { cons_show("You must be in a regular chat window to start PGP encrpytion."); return TRUE; } ProfChatWin *chatwin = NULL; if (args[1]) { char *contact = args[1]; char *barejid = roster_barejid_from_name(contact); if (barejid == NULL) { barejid = contact; } chatwin = wins_get_chat(barejid); if (!chatwin) { chatwin = ui_ev_new_chat_win(barejid); } ui_ev_focus_win((ProfWin*)chatwin); } else { chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); } if (chatwin->is_otr) { ui_current_print_formatted_line('!', 0, "You must end the OTR session to start PGP encryption."); return TRUE; } if (chatwin->pgp_send) { ui_current_print_formatted_line('!', 0, "You have already started PGP encryption."); return TRUE; } ProfAccount *account = accounts_get_account(jabber_get_account_name()); if (!p_gpg_valid_key(account->pgp_keyid)) { ui_current_print_formatted_line('!', 0, "You must specify a valid PGP key ID for this account to start PGP encryption."); account_free(account); return TRUE; } account_free(account); if (!p_gpg_available(chatwin->barejid)) { ui_current_print_formatted_line('!', 0, "No PGP key found for %s.", chatwin->barejid); return TRUE; } chatwin->pgp_send = TRUE; ui_current_print_formatted_line('!', 0, "PGP encyption enabled."); return TRUE; } if (g_strcmp0(args[0], "end") == 0) { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); return TRUE; } if (window->type != WIN_CHAT) { cons_show("You must be in a regular chat window to end PGP encrpytion."); return TRUE; } ProfChatWin *chatwin = (ProfChatWin*)window; if (chatwin->pgp_send == FALSE) { ui_current_print_formatted_line('!', 0, "PGP encryption is not currently enabled."); return TRUE; } chatwin->pgp_send = FALSE; ui_current_print_formatted_line('!', 0, "PGP encyption disabled."); return TRUE; } cons_bad_cmd_usage(command); return TRUE; #else cons_show("This version of Profanity has not been built with PGP support enabled"); return TRUE; #endif } gboolean cmd_otr(ProfWin *window, const char * const command, gchar **args) { #ifdef HAVE_LIBOTR if (args[0] == NULL) { cons_bad_cmd_usage(command); return TRUE; } if (strcmp(args[0], "char") == 0) { if (args[1] == NULL) { cons_bad_cmd_usage(command); } else if (strlen(args[1]) != 1) { cons_bad_cmd_usage(command); } else { prefs_set_otr_char(args[1][0]); cons_show("OTR char set to %c.", args[1][0]); } return TRUE; } else if (strcmp(args[0], "log") == 0) { char *choice = args[1]; if (g_strcmp0(choice, "on") == 0) { prefs_set_string(PREF_OTR_LOG, "on"); cons_show("OTR messages will be logged as plaintext."); if (!prefs_get_boolean(PREF_CHLOG)) { cons_show("Chat logging is currently disabled, use '/chlog on' to enable."); } } else if (g_strcmp0(choice, "off") == 0) { prefs_set_string(PREF_OTR_LOG, "off"); cons_show("OTR message logging disabled."); } else if (g_strcmp0(choice, "redact") == 0) { prefs_set_string(PREF_OTR_LOG, "redact"); cons_show("OTR messages will be logged as '[redacted]'."); if (!prefs_get_boolean(PREF_CHLOG)) { cons_show("Chat logging is currently disabled, use '/chlog on' to enable."); } } else { cons_bad_cmd_usage(command); } return TRUE; } else if (strcmp(args[0], "libver") == 0) { char *version = otr_libotr_version(); cons_show("Using libotr version %s", version); return TRUE; } else if (strcmp(args[0], "policy") == 0) { if (args[1] == NULL) { char *policy = prefs_get_string(PREF_OTR_POLICY); cons_show("OTR policy is now set to: %s", policy); prefs_free_string(policy); return TRUE; } char *choice = args[1]; if ((g_strcmp0(choice, "manual") != 0) && (g_strcmp0(choice, "opportunistic") != 0) && (g_strcmp0(choice, "always") != 0)) { cons_show("OTR policy can be set to: manual, opportunistic or always."); return TRUE; } char *contact = args[2]; if (contact == NULL) { prefs_set_string(PREF_OTR_POLICY, choice); cons_show("OTR policy is now set to: %s", choice); return TRUE; } else { if (jabber_get_connection_status() != JABBER_CONNECTED) { cons_show("You must be connected to set the OTR policy for a contact."); return TRUE; } char *contact_jid = roster_barejid_from_name(contact); if (contact_jid == NULL) { contact_jid = contact; } accounts_add_otr_policy(jabber_get_account_name(), contact_jid, choice); cons_show("OTR policy for %s set to: %s", contact_jid, choice); return TRUE; } } if (jabber_get_connection_status() != JABBER_CONNECTED) { cons_show("You must be connected with an account to load OTR information."); return TRUE; } if (strcmp(args[0], "gen") == 0) { ProfAccount *account = accounts_get_account(jabber_get_account_name()); otr_keygen(account); account_free(account); return TRUE; } else if (strcmp(args[0], "myfp") == 0) { if (!otr_key_loaded()) { ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'"); return TRUE; } char *fingerprint = otr_get_my_fingerprint(); ui_current_print_formatted_line('!', 0, "Your OTR fingerprint: %s", fingerprint); free(fingerprint); return TRUE; } else if (strcmp(args[0], "theirfp") == 0) { if (window->type != WIN_CHAT) { ui_current_print_line("You must be in a regular chat window to view a recipient's fingerprint."); return TRUE; } ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); if (chatwin->is_otr == FALSE) { ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session."); return TRUE; } char *fingerprint = otr_get_their_fingerprint(chatwin->barejid); ui_current_print_formatted_line('!', 0, "%s's OTR fingerprint: %s", chatwin->barejid, fingerprint); free(fingerprint); return TRUE; } else if (strcmp(args[0], "start") == 0) { // recipient supplied if (args[1]) { char *contact = args[1]; char *barejid = roster_barejid_from_name(contact); if (barejid == NULL) { barejid = contact; } ProfChatWin *chatwin = wins_get_chat(barejid); if (!chatwin) { chatwin = ui_ev_new_chat_win(barejid); } ui_ev_focus_win((ProfWin*)chatwin); if (chatwin->pgp_send) { ui_current_print_formatted_line('!', 0, "You must disable PGP encryption before starting an OTR session."); return TRUE; } if (chatwin->is_otr) { ui_current_print_formatted_line('!', 0, "You are already in an OTR session."); return TRUE; } if (!otr_key_loaded()) { ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'"); return TRUE; } if (!otr_is_secure(barejid)) { char *otr_query_message = otr_start_query(); char *id = message_send_chat_otr(barejid, otr_query_message); free(id); return TRUE; } ui_gone_secure(barejid, otr_is_trusted(barejid)); return TRUE; // no recipient, use current chat } else { if (window->type != WIN_CHAT) { ui_current_print_line("You must be in a regular chat window to start an OTR session."); return TRUE; } ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); if (chatwin->pgp_send) { ui_current_print_formatted_line('!', 0, "You must disable PGP encryption before starting an OTR session."); return TRUE; } if (chatwin->is_otr) { ui_current_print_formatted_line('!', 0, "You are already in an OTR session."); return TRUE; } if (!otr_key_loaded()) { ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'"); return TRUE; } char *otr_query_message = otr_start_query(); char *id = message_send_chat_otr(chatwin->barejid, otr_query_message); free(id); return TRUE; } } else if (strcmp(args[0], "end") == 0) { if (window->type != WIN_CHAT) { ui_current_print_line("You must be in a regular chat window to use OTR."); return TRUE; } ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); if (chatwin->is_otr == FALSE) { ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session."); return TRUE; } ui_gone_insecure(chatwin->barejid); otr_end_session(chatwin->barejid); return TRUE; } else if (strcmp(args[0], "trust") == 0) { if (window->type != WIN_CHAT) { ui_current_print_line("You must be in an OTR session to trust a recipient."); return TRUE; } ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); if (chatwin->is_otr == FALSE) { ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session."); return TRUE; } ui_trust(chatwin->barejid); otr_trust(chatwin->barejid); return TRUE; } else if (strcmp(args[0], "untrust") == 0) { if (window->type != WIN_CHAT) { ui_current_print_line("You must be in an OTR session to untrust a recipient."); return TRUE; } ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); if (chatwin->is_otr == FALSE) { ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session."); return TRUE; } ui_untrust(chatwin->barejid); otr_untrust(chatwin->barejid); return TRUE; } else if (strcmp(args[0], "secret") == 0) { if (window->type != WIN_CHAT) { ui_current_print_line("You must be in an OTR session to trust a recipient."); return TRUE; } ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); if (chatwin->is_otr == FALSE) { ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session."); return TRUE; } char *secret = args[1]; if (secret == NULL) { cons_bad_cmd_usage(command); return TRUE; } otr_smp_secret(chatwin->barejid, secret); return TRUE; } else if (strcmp(args[0], "question") == 0) { char *question = args[1]; char *answer = args[2]; if (question == NULL || answer == NULL) { cons_bad_cmd_usage(command); return TRUE; } if (window->type != WIN_CHAT) { ui_current_print_line("You must be in an OTR session to trust a recipient."); return TRUE; } ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); if (chatwin->is_otr == FALSE) { ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session."); return TRUE; } otr_smp_question(chatwin->barejid, question, answer); return TRUE; } else if (strcmp(args[0], "answer") == 0) { if (window->type != WIN_CHAT) { ui_current_print_line("You must be in an OTR session to trust a recipient."); return TRUE; } ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); if (chatwin->is_otr == FALSE) { ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session."); return TRUE; } char *answer = args[1]; if (answer == NULL) { cons_bad_cmd_usage(command); return TRUE; } otr_smp_answer(chatwin->barejid, answer); return TRUE; } else { cons_bad_cmd_usage(command); return TRUE; } #else cons_show("This version of Profanity has not been built with OTR support enabled"); return TRUE; #endif } gboolean cmd_encwarn(ProfWin *window, const char * const command, gchar **args) { return _cmd_set_boolean_preference(args[0], command, "Encryption warning message", PREF_ENC_WARN); } // helper function for status change commands static void _update_presence(const resource_presence_t resource_presence, const char * const show, gchar **args) { char *msg = NULL; int num_args = g_strv_length(args); if (num_args == 1) { msg = args[0]; } jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); } else { cl_ev_presence_send(resource_presence, msg, 0); ui_update_presence(resource_presence, msg, show); } } // helper function for boolean preference commands static gboolean _cmd_set_boolean_preference(gchar *arg, const char * const command, const char * const display, preference_t pref) { GString *enabled = g_string_new(display); g_string_append(enabled, " enabled."); GString *disabled = g_string_new(display); g_string_append(disabled, " disabled."); if (arg == NULL) { cons_bad_cmd_usage(command); } else if (strcmp(arg, "on") == 0) { cons_show(enabled->str); prefs_set_boolean(pref, TRUE); } else if (strcmp(arg, "off") == 0) { cons_show(disabled->str); prefs_set_boolean(pref, FALSE); } else { cons_bad_cmd_usage(command); } g_string_free(enabled, TRUE); g_string_free(disabled, TRUE); return TRUE; } //static void //_cmd_show_filtered_help(char *heading, gchar *cmd_filter[], int filter_size) //{ // ProfWin *console = wins_get_console(); // cons_show(""); // win_print(console, '-', NULL, 0, THEME_WHITE_BOLD, "", heading); // // GList *ordered_commands = NULL; // int i; // for (i = 0; i < filter_size; i++) { // Command *pcmd = g_hash_table_lookup(commands, cmd_filter[i]); // ordered_commands = g_list_insert_sorted(ordered_commands, pcmd->cmd, (GCompareFunc)g_strcmp0); // } // // int maxlen = 0; // GList *curr = ordered_commands; // while (curr) { // gchar *cmd = curr->data; // int len = strlen(cmd); // if (len > maxlen) maxlen = len; // curr = g_list_next(curr); // } // // GString *cmds = g_string_new(""); // curr = ordered_commands; // int count = 0; // while (curr) { // gchar *cmd = curr->data; // if (count == 5) { // cons_show(cmds->str); // g_string_free(cmds, TRUE); // cmds = g_string_new(""); // count = 0; // } // g_string_append_printf(cmds, "%-*s", maxlen + 1, cmd); // curr = g_list_next(curr); // count++; // } // cons_show(cmds->str); // g_string_free(cmds, TRUE); // g_list_free(ordered_commands); // g_list_free(curr); // // cons_show(""); // cons_show("Use /help [command] without the leading slash, for help on a specific command"); // cons_show(""); //} profanity-0.4.7/src/command/commands.h000066400000000000000000000212121257755232500177270ustar00rootroot00000000000000/* * commands.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef COMMANDS_H #define COMMANDS_H #include "ui/win_types.h" // Command help strings typedef struct cmd_help_t { const gchar *tags[20]; const gchar *synopsis[50]; const gchar *desc; const gchar *args[50][2]; const gchar *examples[10]; } CommandHelp; /* * Command structure * * cmd - The command string including leading '/' * func - The function to execute for the command * parser - The function used to parse arguments * min_args - Minimum number of arguments * max_args - Maximum number of arguments * help - A help struct containing usage info etc */ typedef struct cmd_t { gchar *cmd; gboolean (*func)(ProfWin *window, const char * const command, gchar **args); gchar** (*parser)(const char * const inp, int min, int max, gboolean *result); int min_args; int max_args; void (*setting_func)(void); CommandHelp help; } Command; gboolean cmd_execute_alias(ProfWin *window, const char * const inp, gboolean *ran); gboolean cmd_execute_default(ProfWin *window, const char * inp); gboolean cmd_about(ProfWin *window, const char * const command, gchar **args); gboolean cmd_account(ProfWin *window, const char * const command, gchar **args); gboolean cmd_autoaway(ProfWin *window, const char * const command, gchar **args); gboolean cmd_autoconnect(ProfWin *window, const char * const command, gchar **args); gboolean cmd_autoping(ProfWin *window, const char * const command, gchar **args); gboolean cmd_away(ProfWin *window, const char * const command, gchar **args); gboolean cmd_beep(ProfWin *window, const char * const command, gchar **args); gboolean cmd_caps(ProfWin *window, const char * const command, gchar **args); gboolean cmd_chat(ProfWin *window, const char * const command, gchar **args); gboolean cmd_chlog(ProfWin *window, const char * const command, gchar **args); gboolean cmd_clear(ProfWin *window, const char * const command, gchar **args); gboolean cmd_close(ProfWin *window, const char * const command, gchar **args); gboolean cmd_connect(ProfWin *window, const char * const command, gchar **args); gboolean cmd_decline(ProfWin *window, const char * const command, gchar **args); gboolean cmd_disco(ProfWin *window, const char * const command, gchar **args); gboolean cmd_disconnect(ProfWin *window, const char * const command, gchar **args); gboolean cmd_dnd(ProfWin *window, const char * const command, gchar **args); gboolean cmd_flash(ProfWin *window, const char * const command, gchar **args); gboolean cmd_gone(ProfWin *window, const char * const command, gchar **args); gboolean cmd_grlog(ProfWin *window, const char * const command, gchar **args); gboolean cmd_group(ProfWin *window, const char * const command, gchar **args); gboolean cmd_help(ProfWin *window, const char * const command, gchar **args); gboolean cmd_history(ProfWin *window, const char * const command, gchar **args); gboolean cmd_carbons(ProfWin *window, const char * const command, gchar **args); gboolean cmd_receipts(ProfWin *window, const char * const command, gchar **args); gboolean cmd_info(ProfWin *window, const char * const command, gchar **args); gboolean cmd_intype(ProfWin *window, const char * const command, gchar **args); gboolean cmd_invite(ProfWin *window, const char * const command, gchar **args); gboolean cmd_invites(ProfWin *window, const char * const command, gchar **args); gboolean cmd_join(ProfWin *window, const char * const command, gchar **args); gboolean cmd_leave(ProfWin *window, const char * const command, gchar **args); gboolean cmd_log(ProfWin *window, const char * const command, gchar **args); gboolean cmd_msg(ProfWin *window, const char * const command, gchar **args); gboolean cmd_nick(ProfWin *window, const char * const command, gchar **args); gboolean cmd_notify(ProfWin *window, const char * const command, gchar **args); gboolean cmd_online(ProfWin *window, const char * const command, gchar **args); gboolean cmd_otr(ProfWin *window, const char * const command, gchar **args); gboolean cmd_pgp(ProfWin *window, const char * const command, gchar **args); gboolean cmd_outtype(ProfWin *window, const char * const command, gchar **args); gboolean cmd_prefs(ProfWin *window, const char * const command, gchar **args); gboolean cmd_priority(ProfWin *window, const char * const command, gchar **args); gboolean cmd_quit(ProfWin *window, const char * const command, gchar **args); gboolean cmd_reconnect(ProfWin *window, const char * const command, gchar **args); gboolean cmd_room(ProfWin *window, const char * const command, gchar **args); gboolean cmd_rooms(ProfWin *window, const char * const command, gchar **args); gboolean cmd_bookmark(ProfWin *window, const char * const command, gchar **args); gboolean cmd_roster(ProfWin *window, const char * const command, gchar **args); gboolean cmd_software(ProfWin *window, const char * const command, gchar **args); gboolean cmd_splash(ProfWin *window, const char * const command, gchar **args); gboolean cmd_states(ProfWin *window, const char * const command, gchar **args); gboolean cmd_status(ProfWin *window, const char * const command, gchar **args); gboolean cmd_statuses(ProfWin *window, const char * const command, gchar **args); gboolean cmd_sub(ProfWin *window, const char * const command, gchar **args); gboolean cmd_theme(ProfWin *window, const char * const command, gchar **args); gboolean cmd_tiny(ProfWin *window, const char * const command, gchar **args); gboolean cmd_titlebar(ProfWin *window, const char * const command, gchar **args); gboolean cmd_vercheck(ProfWin *window, const char * const command, gchar **args); gboolean cmd_who(ProfWin *window, const char * const command, gchar **args); gboolean cmd_win(ProfWin *window, const char * const command, gchar **args); gboolean cmd_wins(ProfWin *window, const char * const command, gchar **args); gboolean cmd_xa(ProfWin *window, const char * const command, gchar **args); gboolean cmd_alias(ProfWin *window, const char * const command, gchar **args); gboolean cmd_xmlconsole(ProfWin *window, const char * const command, gchar **args); gboolean cmd_ping(ProfWin *window, const char * const command, gchar **args); gboolean cmd_form(ProfWin *window, const char * const command, gchar **args); gboolean cmd_occupants(ProfWin *window, const char * const command, gchar **args); gboolean cmd_kick(ProfWin *window, const char * const command, gchar **args); gboolean cmd_ban(ProfWin *window, const char * const command, gchar **args); gboolean cmd_subject(ProfWin *window, const char * const command, gchar **args); gboolean cmd_affiliation(ProfWin *window, const char * const command, gchar **args); gboolean cmd_role(ProfWin *window, const char * const command, gchar **args); gboolean cmd_privileges(ProfWin *window, const char * const command, gchar **args); gboolean cmd_presence(ProfWin *window, const char * const command, gchar **args); gboolean cmd_wrap(ProfWin *window, const char * const command, gchar **args); gboolean cmd_time(ProfWin *window, const char * const command, gchar **args); gboolean cmd_resource(ProfWin *window, const char * const command, gchar **args); gboolean cmd_inpblock(ProfWin *window, const char * const command, gchar **args); gboolean cmd_encwarn(ProfWin *window, const char * const command, gchar **args); gboolean cmd_form_field(ProfWin *window, char *tag, gchar **args); #endif profanity-0.4.7/src/common.c000066400000000000000000000370131257755232500160010ustar00rootroot00000000000000/* * common.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "tools/p_sha1.h" #include "log.h" #include "common.h" struct curl_data_t { char *buffer; size_t size; }; static unsigned long unique_id = 0; static size_t _data_callback(void *ptr, size_t size, size_t nmemb, void *data); // taken from glib 2.30.3 gchar * p_utf8_substring(const gchar *str, glong start_pos, glong end_pos) { gchar *start, *end, *out; start = g_utf8_offset_to_pointer (str, start_pos); end = g_utf8_offset_to_pointer (start, end_pos - start_pos); out = g_malloc (end - start + 1); memcpy (out, start, end - start); out[end - start] = 0; return out; } void p_slist_free_full(GSList *items, GDestroyNotify free_func) { g_slist_foreach (items, (GFunc) free_func, NULL); g_slist_free (items); } void p_list_free_full(GList *items, GDestroyNotify free_func) { g_list_foreach (items, (GFunc) free_func, NULL); g_list_free (items); } gboolean p_hash_table_add(GHashTable *hash_table, gpointer key) { // doesn't handle when key exists, but value == NULL gpointer found = g_hash_table_lookup(hash_table, key); g_hash_table_replace(hash_table, key, key); return (found == NULL); } gboolean p_hash_table_contains(GHashTable *hash_table, gconstpointer key) { // doesn't handle when key exists, but value == NULL gpointer found = g_hash_table_lookup(hash_table, key); return (found != NULL); } gboolean create_dir(char *name) { struct stat sb; if (stat(name, &sb) != 0) { if (errno != ENOENT || mkdir(name, S_IRWXU) != 0) { return FALSE; } } else { if ((sb.st_mode & S_IFDIR) != S_IFDIR) { log_debug("create_dir: %s exists and is not a directory!", name); return FALSE; } } return TRUE; } gboolean mkdir_recursive(const char *dir) { int i; gboolean result = TRUE; for (i = 1; i <= strlen(dir); i++) { if (dir[i] == '/' || dir[i] == '\0') { gchar *next_dir = g_strndup(dir, i); result = create_dir(next_dir); g_free(next_dir); if (!result) { break; } } } return result; } char * str_replace(const char *string, const char *substr, const char *replacement) { char *tok = NULL; char *newstr = NULL; char *head = NULL; if (string == NULL) return NULL; if ( substr == NULL || replacement == NULL || (strcmp(substr, "") == 0)) return strdup (string); newstr = strdup (string); head = newstr; while ( (tok = strstr ( head, substr ))) { char *oldstr = newstr; newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) + 1 ); if ( newstr == NULL ) { free (oldstr); return NULL; } memcpy ( newstr, oldstr, tok - oldstr ); memcpy ( newstr + (tok - oldstr), replacement, strlen ( replacement ) ); memcpy ( newstr + (tok - oldstr) + strlen( replacement ), tok + strlen ( substr ), strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) ); memset ( newstr + strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) , 0, 1 ); head = newstr + (tok - oldstr) + strlen( replacement ); free (oldstr); } return newstr; } gboolean str_contains_str(const char * const searchstr, const char * const substr) { if (!searchstr) { return FALSE; } if (!substr) { return FALSE; } return g_strrstr(searchstr, substr) != NULL; } int str_contains(const char str[], int size, char ch) { int i; for (i = 0; i < size; i++) { if (str[i] == ch) return 1; } return 0; } gboolean strtoi_range(char *str, int *saveptr, int min, int max, char **err_msg) { char *ptr; int val; errno = 0; val = (int)strtol(str, &ptr, 0); if (errno != 0 || *str == '\0' || *ptr != '\0') { GString *err_str = g_string_new(""); g_string_printf(err_str, "Could not convert \"%s\" to a number.", str); *err_msg = err_str->str; g_string_free(err_str, FALSE); return FALSE; } else if (val < min || val > max) { GString *err_str = g_string_new(""); g_string_printf(err_str, "Value %s out of range. Must be in %d..%d.", str, min, max); *err_msg = err_str->str; g_string_free(err_str, FALSE); return FALSE; } *saveptr = val; return TRUE; } int utf8_display_len(const char * const str) { if (!str) { return 0; } int len = 0; gchar *curr = g_utf8_offset_to_pointer(str, 0); while (*curr != '\0') { gunichar curru = g_utf8_get_char(curr); if (g_unichar_iswide(curru)) { len += 2; } else { len ++; } curr = g_utf8_next_char(curr); } return len; } char * prof_getline(FILE *stream) { char *buf; char *result; char *s = NULL; size_t s_size = 1; int need_exit = 0; buf = (char *)malloc(READ_BUF_SIZE); while (TRUE) { result = fgets(buf, READ_BUF_SIZE, stream); if (result == NULL) break; size_t buf_size = strlen(buf); if (buf[buf_size - 1] == '\n') { buf_size--; buf[buf_size] = '\0'; need_exit = 1; } result = (char *)realloc(s, s_size + buf_size); if (result == NULL) { if (s) { free(s); s = NULL; } break; } s = result; memcpy(s + s_size - 1, buf, buf_size); s_size += buf_size; s[s_size - 1] = '\0'; if (need_exit != 0 || feof(stream) != 0) break; } free(buf); return s; } char * release_get_latest() { char *url = "http://www.profanity.im/profanity_version.txt"; CURL *handle = curl_easy_init(); struct curl_data_t output; output.buffer = NULL; output.size = 0; curl_easy_setopt(handle, CURLOPT_URL, url); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, _data_callback); curl_easy_setopt(handle, CURLOPT_TIMEOUT, 2); curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&output); curl_easy_perform(handle); curl_easy_cleanup(handle); if (output.buffer) { output.buffer[output.size++] = '\0'; return output.buffer; } else { return NULL; } } gboolean release_is_new(char *found_version) { int curr_maj, curr_min, curr_patch, found_maj, found_min, found_patch; int parse_curr = sscanf(PACKAGE_VERSION, "%d.%d.%d", &curr_maj, &curr_min, &curr_patch); int parse_found = sscanf(found_version, "%d.%d.%d", &found_maj, &found_min, &found_patch); if (parse_found == 3 && parse_curr == 3) { if (found_maj > curr_maj) { return TRUE; } else if (found_maj == curr_maj && found_min > curr_min) { return TRUE; } else if (found_maj == curr_maj && found_min == curr_min && found_patch > curr_patch) { return TRUE; } else { return FALSE; } } else { return FALSE; } } gboolean valid_resource_presence_string(const char * const str) { assert(str != NULL); if ((strcmp(str, "online") == 0) || (strcmp(str, "chat") == 0) || (strcmp(str, "away") == 0) || (strcmp(str, "xa") == 0) || (strcmp(str, "dnd") == 0)) { return TRUE; } else { return FALSE; } } const char * string_from_resource_presence(resource_presence_t presence) { switch(presence) { case RESOURCE_CHAT: return "chat"; case RESOURCE_AWAY: return "away"; case RESOURCE_XA: return "xa"; case RESOURCE_DND: return "dnd"; default: return "online"; } } resource_presence_t resource_presence_from_string(const char * const str) { if (str == NULL) { return RESOURCE_ONLINE; } else if (strcmp(str, "online") == 0) { return RESOURCE_ONLINE; } else if (strcmp(str, "chat") == 0) { return RESOURCE_CHAT; } else if (strcmp(str, "away") == 0) { return RESOURCE_AWAY; } else if (strcmp(str, "xa") == 0) { return RESOURCE_XA; } else if (strcmp(str, "dnd") == 0) { return RESOURCE_DND; } else { return RESOURCE_ONLINE; } } contact_presence_t contact_presence_from_resource_presence(resource_presence_t resource_presence) { switch(resource_presence) { case RESOURCE_CHAT: return CONTACT_CHAT; case RESOURCE_AWAY: return CONTACT_AWAY; case RESOURCE_XA: return CONTACT_XA; case RESOURCE_DND: return CONTACT_DND; default: return CONTACT_ONLINE; } } gchar * xdg_get_config_home(void) { gchar *xdg_config_home = getenv("XDG_CONFIG_HOME"); if (xdg_config_home) g_strstrip(xdg_config_home); if (xdg_config_home && (strcmp(xdg_config_home, "") != 0)) { return strdup(xdg_config_home); } else { GString *default_path = g_string_new(getenv("HOME")); g_string_append(default_path, "/.config"); gchar *result = strdup(default_path->str); g_string_free(default_path, TRUE); return result; } } gchar * xdg_get_data_home(void) { gchar *xdg_data_home = getenv("XDG_DATA_HOME"); if (xdg_data_home) g_strstrip(xdg_data_home); if (xdg_data_home && (strcmp(xdg_data_home, "") != 0)) { return strdup(xdg_data_home); } else { GString *default_path = g_string_new(getenv("HOME")); g_string_append(default_path, "/.local/share"); gchar *result = strdup(default_path->str); g_string_free(default_path, TRUE); return result; } } char * create_unique_id(char *prefix) { char *result = NULL; GString *result_str = g_string_new(""); unique_id++; if (prefix) { g_string_printf(result_str, "prof_%s_%lu", prefix, unique_id); } else { g_string_printf(result_str, "prof_%lu", unique_id); } result = result_str->str; g_string_free(result_str, FALSE); return result; } void reset_unique_id(void) { unique_id = 0; } char * p_sha1_hash(char *str) { P_SHA1_CTX ctx; uint8_t digest[20]; uint8_t *input = (uint8_t*)malloc(strlen(str) + 1); memcpy(input, str, strlen(str) + 1); P_SHA1_Init(&ctx); P_SHA1_Update(&ctx, input, strlen(str)); P_SHA1_Final(&ctx, digest); free(input); return g_base64_encode(digest, sizeof(digest)); } int cmp_win_num(gconstpointer a, gconstpointer b) { int real_a = GPOINTER_TO_INT(a); int real_b = GPOINTER_TO_INT(b); if (real_a == 0) { real_a = 10; } if (real_b == 0) { real_b = 10; } if (real_a < real_b) { return -1; } else if (real_a == real_b) { return 0; } else { return 1; } } int get_next_available_win_num(GList *used) { // only console used if (g_list_length(used) == 1) { return 2; } else { GList *sorted = NULL; GList *curr = used; while (curr) { sorted = g_list_insert_sorted(sorted, curr->data, cmp_win_num); curr = g_list_next(curr); } int result = 0; int last_num = 1; curr = sorted; // skip console curr = g_list_next(curr); while (curr) { int curr_num = GPOINTER_TO_INT(curr->data); if (((last_num != 9) && ((last_num + 1) != curr_num)) || ((last_num == 9) && (curr_num != 0))) { result = last_num + 1; if (result == 10) { result = 0; } g_list_free(sorted); return (result); } else { last_num = curr_num; if (last_num == 0) { last_num = 10; } } curr = g_list_next(curr); } result = last_num + 1; if (result == 10) { result = 0; } g_list_free(sorted); return result; } } static size_t _data_callback(void *ptr, size_t size, size_t nmemb, void *data) { size_t realsize = size * nmemb; struct curl_data_t *mem = (struct curl_data_t *) data; mem->buffer = realloc(mem->buffer, mem->size + realsize + 1); if ( mem->buffer ) { memcpy( &( mem->buffer[ mem->size ] ), ptr, realsize ); mem->size += realsize; mem->buffer[ mem->size ] = 0; } return realsize; } char* get_file_or_linked(char *loc, char *basedir) { char *true_loc = NULL; // check for symlink if (g_file_test(loc, G_FILE_TEST_IS_SYMLINK)) { true_loc = g_file_read_link(loc, NULL); // if relative, add basedir if (!g_str_has_prefix(true_loc, "/") && !g_str_has_prefix(true_loc, "~")) { GString *base_str = g_string_new(basedir); g_string_append(base_str, true_loc); free(true_loc); true_loc = base_str->str; g_string_free(base_str, FALSE); } // use given location } else { true_loc = strdup(loc); } return true_loc; } char * strip_arg_quotes(const char * const input) { char *unquoted = strdup(input); // Remove starting quote if it exists if(strchr(unquoted, '"')) { if(strchr(unquoted, ' ') + 1 == strchr(unquoted, '"')) { memmove(strchr(unquoted, '"'), strchr(unquoted, '"')+1, strchr(unquoted, '\0') - strchr(unquoted, '"')); } } // Remove ending quote if it exists if(strchr(unquoted, '"')) { if(strchr(unquoted, '\0') - 1 == strchr(unquoted, '"')) { memmove(strchr(unquoted, '"'), strchr(unquoted, '"')+1, strchr(unquoted, '\0') - strchr(unquoted, '"')); } } return unquoted; } profanity-0.4.7/src/common.h000066400000000000000000000106751257755232500160130ustar00rootroot00000000000000/* * common.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef COMMON_H #define COMMON_H #include #include #include #if !GLIB_CHECK_VERSION(2,28,0) #define g_slist_free_full(items, free_func) p_slist_free_full(items, free_func) #define g_list_free_full(items, free_func) p_list_free_full(items, free_func) #endif #if !GLIB_CHECK_VERSION(2,30,0) #define g_utf8_substring(str, start_pos, end_pos) p_utf8_substring(str, start_pos, end_pos) #endif #if !GLIB_CHECK_VERSION(2,32,0) #define g_hash_table_add(hash_table, key) p_hash_table_add(hash_table, key) #define g_hash_table_contains(hash_table, key) p_hash_table_contains(hash_table, key) #endif #ifndef NOTIFY_CHECK_VERSION #define notify_notification_new(summary, body, icon) notify_notification_new(summary, body, icon, NULL) #endif #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) // assume malloc stores at most 8 bytes for size of allocated memory // and page size is at least 4KB #define READ_BUF_SIZE 4088 #define FREE_SET_NULL(resource) \ do { \ free(resource); \ resource = NULL; \ } while (0) #define GFREE_SET_NULL(resource) \ do { \ g_free(resource); \ resource = NULL; \ } while (0) typedef enum { CONTACT_OFFLINE, CONTACT_ONLINE, CONTACT_AWAY, CONTACT_DND, CONTACT_CHAT, CONTACT_XA } contact_presence_t; typedef enum { RESOURCE_ONLINE, RESOURCE_AWAY, RESOURCE_DND, RESOURCE_CHAT, RESOURCE_XA } resource_presence_t; gchar* p_utf8_substring(const gchar *str, glong start_pos, glong end_pos); void p_slist_free_full(GSList *items, GDestroyNotify free_func); void p_list_free_full(GList *items, GDestroyNotify free_func); gboolean p_hash_table_add(GHashTable *hash_table, gpointer key); gboolean p_hash_table_contains(GHashTable *hash_table, gconstpointer key); gboolean create_dir(char *name); gboolean mkdir_recursive(const char *dir); char * str_replace(const char *string, const char *substr, const char *replacement); gboolean str_contains_str(const char * const searchstr, const char * const substr); int str_contains(const char str[], int size, char ch); gboolean strtoi_range(char *str, int *saveptr, int min, int max, char **err_msg); int utf8_display_len(const char * const str); char * prof_getline(FILE *stream); char* release_get_latest(void); gboolean release_is_new(char *found_version); gchar * xdg_get_config_home(void); gchar * xdg_get_data_home(void); gboolean valid_resource_presence_string(const char * const str); const char * string_from_resource_presence(resource_presence_t presence); resource_presence_t resource_presence_from_string(const char * const str); contact_presence_t contact_presence_from_resource_presence(resource_presence_t resource_presence); char * p_sha1_hash(char *str); char * create_unique_id(char *prefix); void reset_unique_id(void); int cmp_win_num(gconstpointer a, gconstpointer b); int get_next_available_win_num(GList *used); char* get_file_or_linked(char *loc, char *basedir); char * strip_arg_quotes(const char * const input); #endif profanity-0.4.7/src/config/000077500000000000000000000000001257755232500156065ustar00rootroot00000000000000profanity-0.4.7/src/config/account.c000066400000000000000000000157231257755232500174160ustar00rootroot00000000000000/* * account.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include "jid.h" #include "config/account.h" #include "common.h" #include "log.h" ProfAccount* account_new(const gchar * const name, const gchar * const jid, const gchar * const password, const gchar * eval_password, gboolean enabled, const gchar * const server, int port, const gchar * const resource, const gchar * const last_presence, const gchar * const login_presence, int priority_online, int priority_chat, int priority_away, int priority_xa, int priority_dnd, const gchar * const muc_service, const gchar * const muc_nick, const gchar * const otr_policy, GList *otr_manual, GList *otr_opportunistic, GList *otr_always, const gchar * const pgp_keyid) { ProfAccount *new_account = malloc(sizeof(ProfAccount)); new_account->name = strdup(name); if (jid) { new_account->jid = strdup(jid); } else { new_account->jid = strdup(name); } if (password) { new_account->password = strdup(password); } else { new_account->password = NULL; } if (eval_password) { new_account->eval_password = strdup(eval_password); } else { new_account->eval_password = NULL; } new_account->enabled = enabled; if (server) { new_account->server = strdup(server); } else { new_account->server = NULL; } if (resource) { new_account->resource = strdup(resource); } else { new_account->resource = NULL; } new_account->port = port; if (last_presence == NULL || !valid_resource_presence_string(last_presence)) { new_account->last_presence = strdup("online"); } else { new_account->last_presence = strdup(last_presence); } if (login_presence == NULL) { new_account->login_presence = strdup("online"); } else if (strcmp(login_presence, "last") == 0) { new_account->login_presence = strdup(login_presence); } else if (!valid_resource_presence_string(login_presence)) { new_account->login_presence = strdup("online"); } else { new_account->login_presence = strdup(login_presence); } new_account->priority_online = priority_online; new_account->priority_chat = priority_chat; new_account->priority_away = priority_away; new_account->priority_xa = priority_xa; new_account->priority_dnd = priority_dnd; if (muc_service == NULL) { GString *g_muc_service = g_string_new("conference."); Jid *jidp = jid_create(new_account->jid); g_string_append(g_muc_service, jidp->domainpart); new_account->muc_service = g_muc_service->str; g_string_free(g_muc_service, FALSE); jid_destroy(jidp); } else { new_account->muc_service = strdup(muc_service); } if (muc_nick == NULL) { Jid *jidp = jid_create(new_account->jid); new_account->muc_nick = strdup(jidp->domainpart); jid_destroy(jidp); } else { new_account->muc_nick = strdup(muc_nick); } if (otr_policy) { new_account->otr_policy = strdup(otr_policy); } else { new_account->otr_policy = NULL; } new_account->otr_manual = otr_manual; new_account->otr_opportunistic = otr_opportunistic; new_account->otr_always = otr_always; if (pgp_keyid != NULL) { new_account->pgp_keyid = strdup(pgp_keyid); } else { new_account->pgp_keyid = NULL; } return new_account; } char * account_create_full_jid(ProfAccount *account) { if (account->resource) { return create_fulljid(account->jid, account->resource); } else { return strdup(account->jid); } } gboolean account_eval_password(ProfAccount *account) { assert(account != NULL); assert(account->eval_password != NULL); // Evaluate as shell command to retrieve password GString *cmd = g_string_new(""); g_string_append_printf(cmd, "%s 2>/dev/null", account->eval_password); FILE *stream = popen(cmd->str, "r"); g_string_free(cmd, TRUE); if (stream) { // Limit to READ_BUF_SIZE bytes to prevent overflows in the case of a poorly chosen command account->password = g_malloc(READ_BUF_SIZE); if (!account->password) { log_error("Failed to allocate enough memory to read eval_password output"); return FALSE; } account->password = fgets(account->password, READ_BUF_SIZE, stream); pclose(stream); if (!account->password) { log_error("No result from eval_password."); return FALSE; } // strip trailing newline if (g_str_has_suffix(account->password, "\n")) { account->password[strlen(account->password)-1] = '\0'; } } else { log_error("popen failed when running eval_password."); return FALSE; } return TRUE; } void account_free(ProfAccount *account) { if (account) { free(account->name); free(account->jid); free(account->password); free(account->eval_password); free(account->resource); free(account->server); free(account->last_presence); free(account->login_presence); free(account->muc_service); free(account->muc_nick); free(account->otr_policy); free(account->pgp_keyid); g_list_free_full(account->otr_manual, g_free); g_list_free_full(account->otr_opportunistic, g_free); g_list_free_full(account->otr_always, g_free); free(account); } } profanity-0.4.7/src/config/account.h000066400000000000000000000054551257755232500174240ustar00rootroot00000000000000/* * account.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef ACCOUNT_H #define ACCOUNT_H #include "common.h" typedef struct prof_account_t { gchar *name; gchar *jid; gchar *password; gchar *eval_password; gchar *resource; gchar *server; int port; gchar *last_presence; gchar *login_presence; gint priority_online; gint priority_chat; gint priority_away; gint priority_xa; gint priority_dnd; gchar *muc_service; gchar *muc_nick; gboolean enabled; gchar *otr_policy; GList *otr_manual; GList *otr_opportunistic; GList *otr_always; gchar *pgp_keyid; } ProfAccount; ProfAccount* account_new(const gchar * const name, const gchar * const jid, const gchar * const passord, const gchar * eval_password, gboolean enabled, const gchar * const server, int port, const gchar * const resource, const gchar * const last_presence, const gchar * const login_presence, int priority_online, int priority_chat, int priority_away, int priority_xa, int priority_dnd, const gchar * const muc_service, const gchar * const muc_nick, const gchar * const otr_policy, GList *otr_manual, GList *otr_opportunistic, GList *otr_always, const gchar * const pgp_keyid); char* account_create_full_jid(ProfAccount *account); gboolean account_eval_password(ProfAccount *account); void account_free(ProfAccount *account); #endif profanity-0.4.7/src/config/accounts.c000066400000000000000000000706761257755232500176110ustar00rootroot00000000000000/* * accounts.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include "accounts.h" #include "common.h" #include "config/account.h" #include "jid.h" #include "log.h" #include "tools/autocomplete.h" #include "xmpp/xmpp.h" static gchar *accounts_loc; static GKeyFile *accounts; static Autocomplete all_ac; static Autocomplete enabled_ac; // used to rename account (copies properties to new account) static gchar *string_keys[] = { "jid", "server", "port", "resource", "password", "eval_password", "presence.last", "presence.login", "muc.service", "muc.nick", "otr.policy" }; static void _fix_legacy_accounts(const char * const account_name); static void _save_accounts(void); static gchar * _get_accounts_file(void); static void _remove_from_list(GKeyFile *accounts, const char * const account_name, const char * const key, const char * const contact_jid); void accounts_load(void) { log_info("Loading accounts"); all_ac = autocomplete_new(); enabled_ac = autocomplete_new(); accounts_loc = _get_accounts_file(); if (g_file_test(accounts_loc, G_FILE_TEST_EXISTS)) { g_chmod(accounts_loc, S_IRUSR | S_IWUSR); } accounts = g_key_file_new(); g_key_file_load_from_file(accounts, accounts_loc, G_KEY_FILE_KEEP_COMMENTS, NULL); // create the logins searchable list for autocompletion gsize naccounts; gchar **account_names = g_key_file_get_groups(accounts, &naccounts); gsize i; for (i = 0; i < naccounts; i++) { autocomplete_add(all_ac, account_names[i]); if (g_key_file_get_boolean(accounts, account_names[i], "enabled", NULL)) { autocomplete_add(enabled_ac, account_names[i]); } _fix_legacy_accounts(account_names[i]); } g_strfreev(account_names); } void accounts_close(void) { autocomplete_free(all_ac); autocomplete_free(enabled_ac); g_key_file_free(accounts); } char * accounts_find_enabled(const char * const prefix) { return autocomplete_complete(enabled_ac, prefix, TRUE); } char * accounts_find_all(const char * const prefix) { return autocomplete_complete(all_ac, prefix, TRUE); } void accounts_reset_all_search(void) { autocomplete_reset(all_ac); } void accounts_reset_enabled_search(void) { autocomplete_reset(enabled_ac); } void accounts_add(const char *account_name, const char *altdomain, const int port) { // set account name and resource const char *barejid = account_name; const char *resource = "profanity"; Jid *jid = jid_create(account_name); if (jid) { barejid = jid->barejid; if (jid->resourcepart) { resource = jid->resourcepart; } } // doesn't yet exist if (!g_key_file_has_group(accounts, account_name)) { g_key_file_set_boolean(accounts, account_name, "enabled", TRUE); g_key_file_set_string(accounts, account_name, "jid", barejid); g_key_file_set_string(accounts, account_name, "resource", resource); if (altdomain) { g_key_file_set_string(accounts, account_name, "server", altdomain); } if (port != 0) { g_key_file_set_integer(accounts, account_name, "port", port); } Jid *jidp = jid_create(barejid); GString *muc_service = g_string_new("conference."); g_string_append(muc_service, jidp->domainpart); g_key_file_set_string(accounts, account_name, "muc.service", muc_service->str); g_string_free(muc_service, TRUE); if (jidp->localpart == NULL) { g_key_file_set_string(accounts, account_name, "muc.nick", jidp->domainpart); } else { g_key_file_set_string(accounts, account_name, "muc.nick", jidp->localpart); } jid_destroy(jidp); g_key_file_set_string(accounts, account_name, "presence.last", "online"); g_key_file_set_string(accounts, account_name, "presence.login", "online"); g_key_file_set_integer(accounts, account_name, "priority.online", 0); g_key_file_set_integer(accounts, account_name, "priority.chat", 0); g_key_file_set_integer(accounts, account_name, "priority.away", 0); g_key_file_set_integer(accounts, account_name, "priority.xa", 0); g_key_file_set_integer(accounts, account_name, "priority.dnd", 0); _save_accounts(); autocomplete_add(all_ac, account_name); autocomplete_add(enabled_ac, account_name); } jid_destroy(jid); } int accounts_remove(const char *account_name) { int r = g_key_file_remove_group(accounts, account_name, NULL); _save_accounts(); autocomplete_remove(all_ac, account_name); autocomplete_remove(enabled_ac, account_name); return r; } gchar** accounts_get_list(void) { return g_key_file_get_groups(accounts, NULL); } ProfAccount* accounts_get_account(const char * const name) { if (!g_key_file_has_group(accounts, name)) { return NULL; } else { gchar *jid = g_key_file_get_string(accounts, name, "jid", NULL); // fix accounts that have no jid property by setting to name if (jid == NULL) { g_key_file_set_string(accounts, name, "jid", name); _save_accounts(); } gchar *password = g_key_file_get_string(accounts, name, "password", NULL); gchar *eval_password = g_key_file_get_string(accounts, name, "eval_password", NULL); gboolean enabled = g_key_file_get_boolean(accounts, name, "enabled", NULL); gchar *server = g_key_file_get_string(accounts, name, "server", NULL); gchar *resource = g_key_file_get_string(accounts, name, "resource", NULL); int port = g_key_file_get_integer(accounts, name, "port", NULL); gchar *last_presence = g_key_file_get_string(accounts, name, "presence.last", NULL); gchar *login_presence = g_key_file_get_string(accounts, name, "presence.login", NULL); int priority_online = g_key_file_get_integer(accounts, name, "priority.online", NULL); int priority_chat = g_key_file_get_integer(accounts, name, "priority.chat", NULL); int priority_away = g_key_file_get_integer(accounts, name, "priority.away", NULL); int priority_xa = g_key_file_get_integer(accounts, name, "priority.xa", NULL); int priority_dnd = g_key_file_get_integer(accounts, name, "priority.dnd", NULL); gchar *muc_service = g_key_file_get_string(accounts, name, "muc.service", NULL); gchar *muc_nick = g_key_file_get_string(accounts, name, "muc.nick", NULL); gchar *otr_policy = NULL; if (g_key_file_has_key(accounts, name, "otr.policy", NULL)) { otr_policy = g_key_file_get_string(accounts, name, "otr.policy", NULL); } gsize length; GList *otr_manual = NULL; gchar **manual = g_key_file_get_string_list(accounts, name, "otr.manual", &length, NULL); if (manual) { int i = 0; for (i = 0; i < length; i++) { otr_manual = g_list_append(otr_manual, strdup(manual[i])); } g_strfreev(manual); } GList *otr_opportunistic = NULL; gchar **opportunistic = g_key_file_get_string_list(accounts, name, "otr.opportunistic", &length, NULL); if (opportunistic) { int i = 0; for (i = 0; i < length; i++) { otr_opportunistic = g_list_append(otr_opportunistic, strdup(opportunistic[i])); } g_strfreev(opportunistic); } GList *otr_always = NULL; gchar **always = g_key_file_get_string_list(accounts, name, "otr.always", &length, NULL); if (always) { int i = 0; for (i = 0; i < length; i++) { otr_always = g_list_append(otr_always, strdup(always[i])); } g_strfreev(always); } gchar *pgp_keyid = NULL; if (g_key_file_has_key(accounts, name, "pgp.keyid", NULL)) { pgp_keyid = g_key_file_get_string(accounts, name, "pgp.keyid", NULL); } ProfAccount *new_account = account_new(name, jid, password, eval_password, enabled, server, port, resource, last_presence, login_presence, priority_online, priority_chat, priority_away, priority_xa, priority_dnd, muc_service, muc_nick, otr_policy, otr_manual, otr_opportunistic, otr_always, pgp_keyid); g_free(jid); g_free(password); g_free(eval_password); g_free(server); g_free(resource); g_free(last_presence); g_free(login_presence); g_free(muc_service); g_free(muc_nick); g_free(otr_policy); g_free(pgp_keyid); return new_account; } } gboolean accounts_enable(const char * const name) { if (g_key_file_has_group(accounts, name)) { g_key_file_set_boolean(accounts, name, "enabled", TRUE); _save_accounts(); autocomplete_add(enabled_ac, name); return TRUE; } else { return FALSE; } } gboolean accounts_disable(const char * const name) { if (g_key_file_has_group(accounts, name)) { g_key_file_set_boolean(accounts, name, "enabled", FALSE); _save_accounts(); autocomplete_remove(enabled_ac, name); return TRUE; } else { return FALSE; } } gboolean accounts_rename(const char * const account_name, const char * const new_name) { if (g_key_file_has_group(accounts, new_name)) { return FALSE; } if (!g_key_file_has_group(accounts, account_name)) { return FALSE; } g_key_file_set_boolean(accounts, new_name, "enabled", g_key_file_get_boolean(accounts, account_name, "enabled", NULL)); g_key_file_set_integer(accounts, new_name, "priority.online", g_key_file_get_integer(accounts, account_name, "priority.online", NULL)); g_key_file_set_integer(accounts, new_name, "priority.chat", g_key_file_get_integer(accounts, account_name, "priority.chat", NULL)); g_key_file_set_integer(accounts, new_name, "priority.away", g_key_file_get_integer(accounts, account_name, "priority.away", NULL)); g_key_file_set_integer(accounts, new_name, "priority.xa", g_key_file_get_integer(accounts, account_name, "priority.xa", NULL)); g_key_file_set_integer(accounts, new_name, "priority.dnd", g_key_file_get_integer(accounts, account_name, "priority.dnd", NULL)); // copy other string properties int i; for (i = 0; i < ARRAY_SIZE(string_keys); i++) { char *value = g_key_file_get_string(accounts, account_name, string_keys[i], NULL); if (value) { g_key_file_set_string(accounts, new_name, string_keys[i], value); g_free(value); } } g_key_file_remove_group(accounts, account_name, NULL); _save_accounts(); autocomplete_remove(all_ac, account_name); autocomplete_add(all_ac, new_name); if (g_key_file_get_boolean(accounts, new_name, "enabled", NULL)) { autocomplete_remove(enabled_ac, account_name); autocomplete_add(enabled_ac, new_name); } return TRUE; } gboolean accounts_account_exists(const char * const account_name) { return g_key_file_has_group(accounts, account_name); } void accounts_set_jid(const char * const account_name, const char * const value) { Jid *jid = jid_create(value); if (jid) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "jid", jid->barejid); if (jid->resourcepart) { g_key_file_set_string(accounts, account_name, "resource", jid->resourcepart); } GString *muc_service = g_string_new("conference."); g_string_append(muc_service, jid->domainpart); g_key_file_set_string(accounts, account_name, "muc.service", muc_service->str); g_string_free(muc_service, TRUE); if (jid->localpart == NULL) { g_key_file_set_string(accounts, account_name, "muc.nick", jid->domainpart); } else { g_key_file_set_string(accounts, account_name, "muc.nick", jid->localpart); } _save_accounts(); } jid_destroy(jid); } } void accounts_set_server(const char * const account_name, const char * const value) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "server", value); _save_accounts(); } } void accounts_set_port(const char * const account_name, const int value) { if (value != 0) { g_key_file_set_integer(accounts, account_name, "port", value); _save_accounts(); } } void accounts_set_resource(const char * const account_name, const char * const value) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "resource", value); _save_accounts(); } } void accounts_set_password(const char * const account_name, const char * const value) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "password", value); _save_accounts(); } } void accounts_set_eval_password(const char * const account_name, const char * const value) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "eval_password", value); _save_accounts(); } } void accounts_set_pgp_keyid(const char * const account_name, const char * const value) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "pgp.keyid", value); _save_accounts(); } } void accounts_clear_password(const char * const account_name) { if (accounts_account_exists(account_name)) { g_key_file_remove_key(accounts, account_name, "password", NULL); _save_accounts(); } } void accounts_clear_eval_password(const char * const account_name) { if (accounts_account_exists(account_name)) { g_key_file_remove_key(accounts, account_name, "eval_password", NULL); _save_accounts(); } } void accounts_clear_server(const char * const account_name) { if (accounts_account_exists(account_name)) { g_key_file_remove_key(accounts, account_name, "server", NULL); _save_accounts(); } } void accounts_clear_port(const char * const account_name) { if (accounts_account_exists(account_name)) { g_key_file_remove_key(accounts, account_name, "port", NULL); _save_accounts(); } } void accounts_clear_pgp_keyid(const char * const account_name) { if (accounts_account_exists(account_name)) { g_key_file_remove_key(accounts, account_name, "pgp.keyid", NULL); _save_accounts(); } } void accounts_clear_otr(const char * const account_name) { if (accounts_account_exists(account_name)) { g_key_file_remove_key(accounts, account_name, "otr.policy", NULL); _save_accounts(); } } void accounts_add_otr_policy(const char * const account_name, const char * const contact_jid, const char * const policy) { if (accounts_account_exists(account_name)) { GString *key = g_string_new("otr."); g_string_append(key, policy); gsize length; gchar **list = g_key_file_get_string_list(accounts, account_name, key->str, &length, NULL); GList *glist = NULL; // list found if (list) { int i = 0; for (i = 0; i < length; i++) { // item already in list, exit function if (strcmp(list[i], contact_jid) == 0) { g_list_free_full(glist, g_free); g_strfreev(list); return; } // add item to our g_list glist = g_list_append(glist, strdup(list[i])); } // item not found, add to our g_list glist = g_list_append(glist, strdup(contact_jid)); // create the new list entry const gchar* new_list[g_list_length(glist)+1]; GList *curr = glist; i = 0; while (curr) { new_list[i++] = strdup(curr->data); curr = g_list_next(curr); } new_list[i] = NULL; g_key_file_set_string_list(accounts, account_name, key->str, new_list, g_list_length(glist)); // list not found } else { const gchar* new_list[2]; new_list[0] = strdup(contact_jid); new_list[1] = NULL; g_key_file_set_string_list(accounts, account_name, key->str, new_list, 1); } g_strfreev(list); g_list_free_full(glist, g_free); g_string_free(key, TRUE); // check for and remove from other lists if (strcmp(policy, "manual") == 0) { _remove_from_list(accounts, account_name, "otr.opportunistic", contact_jid); _remove_from_list(accounts, account_name, "otr.always", contact_jid); } if (strcmp(policy, "opportunistic") == 0) { _remove_from_list(accounts, account_name, "otr.manual", contact_jid); _remove_from_list(accounts, account_name, "otr.always", contact_jid); } if (strcmp(policy, "always") == 0) { _remove_from_list(accounts, account_name, "otr.opportunistic", contact_jid); _remove_from_list(accounts, account_name, "otr.manual", contact_jid); } _save_accounts(); } } static void _remove_from_list(GKeyFile *accounts, const char * const account_name, const char * const key, const char * const contact_jid) { gsize length; gchar **list = g_key_file_get_string_list(accounts, account_name, key, &length, NULL); if (list) { int i = 0; GList *glist = NULL; gboolean deleted = FALSE; for (i = 0; i < length; i++) { // item found, mark as deleted if (strcmp(list[i], contact_jid) == 0) { deleted = TRUE; } else { // add item to our g_list glist = g_list_append(glist, strdup(list[i])); } } if (deleted) { if (g_list_length(glist) == 0) { g_key_file_remove_key(accounts, account_name, key, NULL); } else { // create the new list entry const gchar* new_list[g_list_length(glist)+1]; GList *curr = glist; i = 0; while (curr) { new_list[i++] = strdup(curr->data); curr = g_list_next(curr); } new_list[i] = NULL; g_key_file_set_string_list(accounts, account_name, key, new_list, g_list_length(glist)); } } g_list_free_full(glist, g_free); } g_strfreev(list); } void accounts_set_muc_service(const char * const account_name, const char * const value) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "muc.service", value); _save_accounts(); } } void accounts_set_muc_nick(const char * const account_name, const char * const value) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "muc.nick", value); _save_accounts(); } } void accounts_set_otr_policy(const char * const account_name, const char * const value) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "otr.policy", value); _save_accounts(); } } void accounts_set_priority_online(const char * const account_name, const gint value) { if (accounts_account_exists(account_name)) { g_key_file_set_integer(accounts, account_name, "priority.online", value); _save_accounts(); } } void accounts_set_priority_chat(const char * const account_name, const gint value) { if (accounts_account_exists(account_name)) { g_key_file_set_integer(accounts, account_name, "priority.chat", value); _save_accounts(); } } void accounts_set_priority_away(const char * const account_name, const gint value) { if (accounts_account_exists(account_name)) { g_key_file_set_integer(accounts, account_name, "priority.away", value); _save_accounts(); } } void accounts_set_priority_xa(const char * const account_name, const gint value) { if (accounts_account_exists(account_name)) { g_key_file_set_integer(accounts, account_name, "priority.xa", value); _save_accounts(); } } void accounts_set_priority_dnd(const char * const account_name, const gint value) { if (accounts_account_exists(account_name)) { g_key_file_set_integer(accounts, account_name, "priority.dnd", value); _save_accounts(); } } void accounts_set_priority_all(const char * const account_name, const gint value) { if (accounts_account_exists(account_name)) { accounts_set_priority_online(account_name, value); accounts_set_priority_chat(account_name, value); accounts_set_priority_away(account_name, value); accounts_set_priority_xa(account_name, value); accounts_set_priority_dnd(account_name, value); _save_accounts(); } } gint accounts_get_priority_for_presence_type(const char * const account_name, resource_presence_t presence_type) { gint result; switch (presence_type) { case (RESOURCE_ONLINE): result = g_key_file_get_integer(accounts, account_name, "priority.online", NULL); break; case (RESOURCE_CHAT): result = g_key_file_get_integer(accounts, account_name, "priority.chat", NULL); break; case (RESOURCE_AWAY): result = g_key_file_get_integer(accounts, account_name, "priority.away", NULL); break; case (RESOURCE_XA): result = g_key_file_get_integer(accounts, account_name, "priority.xa", NULL); break; default: result = g_key_file_get_integer(accounts, account_name, "priority.dnd", NULL); break; } if (result < JABBER_PRIORITY_MIN || result > JABBER_PRIORITY_MAX) result = 0; return result; } void accounts_set_last_presence(const char * const account_name, const char * const value) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "presence.last", value); _save_accounts(); } } void accounts_set_login_presence(const char * const account_name, const char * const value) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "presence.login", value); _save_accounts(); } } resource_presence_t accounts_get_last_presence(const char * const account_name) { resource_presence_t result; gchar *setting = g_key_file_get_string(accounts, account_name, "presence.last", NULL); if (setting == NULL || (strcmp(setting, "online") == 0)) { result = RESOURCE_ONLINE; } else if (strcmp(setting, "chat") == 0) { result = RESOURCE_CHAT; } else if (strcmp(setting, "away") == 0) { result = RESOURCE_AWAY; } else if (strcmp(setting, "xa") == 0) { result = RESOURCE_XA; } else if (strcmp(setting, "dnd") == 0) { result = RESOURCE_DND; } else { log_warning("Error reading presence.last for account: '%s', value: '%s', defaulting to 'online'", account_name, setting); result = RESOURCE_ONLINE; } if (setting) { g_free(setting); } return result; } resource_presence_t accounts_get_login_presence(const char * const account_name) { resource_presence_t result; gchar *setting = g_key_file_get_string(accounts, account_name, "presence.login", NULL); if (setting == NULL || (strcmp(setting, "online") == 0)) { result = RESOURCE_ONLINE; } else if (strcmp(setting, "chat") == 0) { result = RESOURCE_CHAT; } else if (strcmp(setting, "away") == 0) { result = RESOURCE_AWAY; } else if (strcmp(setting, "xa") == 0) { result = RESOURCE_XA; } else if (strcmp(setting, "dnd") == 0) { result = RESOURCE_DND; } else if (strcmp(setting, "last") == 0) { result = accounts_get_last_presence(account_name); } else { log_warning("Error reading presence.login for account: '%s', value: '%s', defaulting to 'online'", account_name, setting); result = RESOURCE_ONLINE; } if (setting) { g_free(setting); } return result; } static void _fix_legacy_accounts(const char * const account_name) { // set barejid and resource const char *barejid = account_name; const char *resource = "profanity"; Jid *jid = jid_create(account_name); if (jid) { barejid = jid->barejid; if (jid->resourcepart) { resource = jid->resourcepart; } } // accounts with no jid property if (!g_key_file_has_key(accounts, account_name, "jid", NULL)) { g_key_file_set_string(accounts, account_name, "jid", barejid); _save_accounts(); } // accounts with no resource, property if (!g_key_file_has_key(accounts, account_name, "resource", NULL)) { g_key_file_set_string(accounts, account_name, "resource", resource); _save_accounts(); } // accounts with no muc service or nick if (!g_key_file_has_key(accounts, account_name, "muc.service", NULL)) { gchar *account_jid = g_key_file_get_string(accounts, account_name, "jid", NULL); Jid *jidp = jid_create(account_jid); GString *muc_service = g_string_new("conference."); g_string_append(muc_service, jidp->domainpart); g_key_file_set_string(accounts, account_name, "muc.service", muc_service->str); g_string_free(muc_service, TRUE); jid_destroy(jidp); } if (!g_key_file_has_key(accounts, account_name, "muc.nick", NULL)) { gchar *account_jid = g_key_file_get_string(accounts, account_name, "jid", NULL); Jid *jidp = jid_create(account_jid); if (jidp->localpart == NULL) { g_key_file_set_string(accounts, account_name, "muc.nick", jidp->domainpart); } else { g_key_file_set_string(accounts, account_name, "muc.nick", jidp->localpart); } jid_destroy(jidp); } jid_destroy(jid); } static void _save_accounts(void) { gsize g_data_size; gchar *g_accounts_data = g_key_file_to_data(accounts, &g_data_size, NULL); gchar *xdg_data = xdg_get_data_home(); GString *base_str = g_string_new(xdg_data); g_string_append(base_str, "/profanity/"); gchar *true_loc = get_file_or_linked(accounts_loc, base_str->str); g_file_set_contents(true_loc, g_accounts_data, g_data_size, NULL); g_chmod(accounts_loc, S_IRUSR | S_IWUSR); g_free(xdg_data); free(true_loc); g_free(g_accounts_data); g_string_free(base_str, TRUE); } static gchar * _get_accounts_file(void) { gchar *xdg_data = xdg_get_data_home(); GString *logfile = g_string_new(xdg_data); g_string_append(logfile, "/profanity/accounts"); gchar *result = strdup(logfile->str); g_free(xdg_data); g_string_free(logfile, TRUE); return result; } profanity-0.4.7/src/config/accounts.h000066400000000000000000000110711257755232500175760ustar00rootroot00000000000000/* * accounts.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef ACCOUNTS_H #define ACCOUNTS_H #define MAX_PASSWORD_SIZE 64 #include "common.h" #include "config/account.h" void accounts_load(void); void accounts_close(void); char * accounts_find_all(const char * const prefix); char * accounts_find_enabled(const char * const prefix); void accounts_reset_all_search(void); void accounts_reset_enabled_search(void); void accounts_add(const char *jid, const char *altdomain, const int port); int accounts_remove(const char *jid); gchar** accounts_get_list(void); ProfAccount* accounts_get_account(const char * const name); gboolean accounts_enable(const char * const name); gboolean accounts_disable(const char * const name); gboolean accounts_rename(const char * const account_name, const char * const new_name); gboolean accounts_account_exists(const char * const account_name); void accounts_set_jid(const char * const account_name, const char * const value); void accounts_set_server(const char * const account_name, const char * const value); void accounts_set_port(const char * const account_name, const int value); void accounts_set_resource(const char * const account_name, const char * const value); void accounts_set_password(const char * const account_name, const char * const value); void accounts_set_eval_password(const char * const account_name, const char * const value); void accounts_set_muc_service(const char * const account_name, const char * const value); void accounts_set_muc_nick(const char * const account_name, const char * const value); void accounts_set_otr_policy(const char * const account_name, const char * const value); void accounts_set_last_presence(const char * const account_name, const char * const value); void accounts_set_login_presence(const char * const account_name, const char * const value); resource_presence_t accounts_get_login_presence(const char * const account_name); resource_presence_t accounts_get_last_presence(const char * const account_name); void accounts_set_priority_online(const char * const account_name, const gint value); void accounts_set_priority_chat(const char * const account_name, const gint value); void accounts_set_priority_away(const char * const account_name, const gint value); void accounts_set_priority_xa(const char * const account_name, const gint value); void accounts_set_priority_dnd(const char * const account_name, const gint value); void accounts_set_priority_all(const char * const account_name, const gint value); gint accounts_get_priority_for_presence_type(const char * const account_name, resource_presence_t presence_type); void accounts_set_pgp_keyid(const char * const account_name, const char * const value); void accounts_clear_password(const char * const account_name); void accounts_clear_eval_password(const char * const account_name); void accounts_clear_server(const char * const account_name); void accounts_clear_port(const char * const account_name); void accounts_clear_otr(const char * const account_name); void accounts_clear_pgp_keyid(const char * const account_name); void accounts_add_otr_policy(const char * const account_name, const char * const contact_jid, const char * const policy); #endif profanity-0.4.7/src/config/preferences.c000066400000000000000000000517641257755232500202700ustar00rootroot00000000000000/* * preferences.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include #include #include #include "common.h" #include "log.h" #include "preferences.h" #include "tools/autocomplete.h" // preference groups refer to the sections in .profrc, for example [ui] #define PREF_GROUP_LOGGING "logging" #define PREF_GROUP_CHATSTATES "chatstates" #define PREF_GROUP_UI "ui" #define PREF_GROUP_NOTIFICATIONS "notifications" #define PREF_GROUP_PRESENCE "presence" #define PREF_GROUP_CONNECTION "connection" #define PREF_GROUP_ALIAS "alias" #define PREF_GROUP_OTR "otr" #define PREF_GROUP_PGP "pgp" #define INPBLOCK_DEFAULT 1000 static gchar *prefs_loc; static GKeyFile *prefs; gint log_maxsize = 0; static Autocomplete boolean_choice_ac; static void _save_prefs(void); static gchar * _get_preferences_file(void); static const char * _get_group(preference_t pref); static const char * _get_key(preference_t pref); static gboolean _get_default_boolean(preference_t pref); static char * _get_default_string(preference_t pref); void prefs_load(void) { GError *err; prefs_loc = _get_preferences_file(); if (g_file_test(prefs_loc, G_FILE_TEST_EXISTS)) { g_chmod(prefs_loc, S_IRUSR | S_IWUSR); } prefs = g_key_file_new(); g_key_file_load_from_file(prefs, prefs_loc, G_KEY_FILE_KEEP_COMMENTS, NULL); err = NULL; log_maxsize = g_key_file_get_integer(prefs, PREF_GROUP_LOGGING, "maxsize", &err); if (err) { log_maxsize = 0; g_error_free(err); } // move pre 0.4.7 otr.warn to enc.warn err = NULL; gboolean otr_warn = g_key_file_get_boolean(prefs, PREF_GROUP_UI, "otr.warn", &err); if (err == NULL) { g_key_file_set_boolean(prefs, PREF_GROUP_UI, _get_key(PREF_ENC_WARN), otr_warn); g_key_file_remove_key(prefs, PREF_GROUP_UI, "otr.warn", NULL); } else { g_error_free(err); } // migrate pre 0.4.7 time settings format if (g_key_file_has_key(prefs, PREF_GROUP_UI, "time", NULL)) { char *time = g_key_file_get_string(prefs, PREF_GROUP_UI, "time", NULL); if (g_strcmp0(time, "minutes") == 0) { g_key_file_set_string(prefs, PREF_GROUP_UI, "time", "%H:%M"); } else if (g_strcmp0(time, "seconds") == 0) { g_key_file_set_string(prefs, PREF_GROUP_UI, "time", "%H:%M:%S"); } else if (g_strcmp0(time, "off") == 0) { g_key_file_set_string(prefs, PREF_GROUP_UI, "time", ""); } prefs_free_string(time); } if (g_key_file_has_key(prefs, PREF_GROUP_UI, "time.statusbar", NULL)) { char *time = g_key_file_get_string(prefs, PREF_GROUP_UI, "time.statusbar", NULL); if (g_strcmp0(time, "minutes") == 0) { g_key_file_set_string(prefs, PREF_GROUP_UI, "time.statusbar", "%H:%M"); } else if (g_strcmp0(time, "seconds") == 0) { g_key_file_set_string(prefs, PREF_GROUP_UI, "time.statusbar", "%H:%M:%S"); } else if (g_strcmp0(time, "off") == 0) { g_key_file_set_string(prefs, PREF_GROUP_UI, "time.statusbar", ""); } prefs_free_string(time); } _save_prefs(); boolean_choice_ac = autocomplete_new(); autocomplete_add(boolean_choice_ac, "on"); autocomplete_add(boolean_choice_ac, "off"); } void prefs_close(void) { autocomplete_free(boolean_choice_ac); g_key_file_free(prefs); prefs = NULL; } char * prefs_autocomplete_boolean_choice(const char * const prefix) { return autocomplete_complete(boolean_choice_ac, prefix, TRUE); } void prefs_reset_boolean_choice(void) { autocomplete_reset(boolean_choice_ac); } gboolean prefs_get_boolean(preference_t pref) { const char *group = _get_group(pref); const char *key = _get_key(pref); gboolean def = _get_default_boolean(pref); if (!g_key_file_has_key(prefs, group, key, NULL)) { return def; } return g_key_file_get_boolean(prefs, group, key, NULL); } void prefs_set_boolean(preference_t pref, gboolean value) { const char *group = _get_group(pref); const char *key = _get_key(pref); g_key_file_set_boolean(prefs, group, key, value); _save_prefs(); } char * prefs_get_string(preference_t pref) { const char *group = _get_group(pref); const char *key = _get_key(pref); char *def = _get_default_string(pref); char *result = g_key_file_get_string(prefs, group, key, NULL); if (result == NULL) { if (def) { return g_strdup(def); } else { return NULL; } } else { return result; } } void prefs_free_string(char *pref) { if (pref) { g_free(pref); } pref = NULL; } void prefs_set_string(preference_t pref, char *value) { const char *group = _get_group(pref); const char *key = _get_key(pref); if (value == NULL) { g_key_file_remove_key(prefs, group, key, NULL); } else { g_key_file_set_string(prefs, group, key, value); } _save_prefs(); } gint prefs_get_gone(void) { return g_key_file_get_integer(prefs, PREF_GROUP_CHATSTATES, "gone", NULL); } void prefs_set_gone(gint value) { g_key_file_set_integer(prefs, PREF_GROUP_CHATSTATES, "gone", value); _save_prefs(); } gint prefs_get_notify_remind(void) { return g_key_file_get_integer(prefs, PREF_GROUP_NOTIFICATIONS, "remind", NULL); } void prefs_set_notify_remind(gint value) { g_key_file_set_integer(prefs, PREF_GROUP_NOTIFICATIONS, "remind", value); _save_prefs(); } gint prefs_get_max_log_size(void) { if (log_maxsize < PREFS_MIN_LOG_SIZE) return PREFS_MAX_LOG_SIZE; else return log_maxsize; } void prefs_set_max_log_size(gint value) { log_maxsize = value; g_key_file_set_integer(prefs, PREF_GROUP_LOGGING, "maxsize", value); _save_prefs(); } gint prefs_get_inpblock(void) { int val = g_key_file_get_integer(prefs, PREF_GROUP_UI, "inpblock", NULL); if (val == 0) { return INPBLOCK_DEFAULT; } else { return val; } } void prefs_set_inpblock(gint value) { g_key_file_set_integer(prefs, PREF_GROUP_UI, "inpblock", value); _save_prefs(); } gint prefs_get_priority(void) { return g_key_file_get_integer(prefs, PREF_GROUP_PRESENCE, "priority", NULL); } gint prefs_get_reconnect(void) { if (!g_key_file_has_key(prefs, PREF_GROUP_CONNECTION, "reconnect", NULL)) { return 30; } else { return g_key_file_get_integer(prefs, PREF_GROUP_CONNECTION, "reconnect", NULL); } } void prefs_set_reconnect(gint value) { g_key_file_set_integer(prefs, PREF_GROUP_CONNECTION, "reconnect", value); _save_prefs(); } gint prefs_get_autoping(void) { if (!g_key_file_has_key(prefs, PREF_GROUP_CONNECTION, "autoping", NULL)) { return 60; } else { return g_key_file_get_integer(prefs, PREF_GROUP_CONNECTION, "autoping", NULL); } } void prefs_set_autoping(gint value) { g_key_file_set_integer(prefs, PREF_GROUP_CONNECTION, "autoping", value); _save_prefs(); } gint prefs_get_autoaway_time(void) { gint result = g_key_file_get_integer(prefs, PREF_GROUP_PRESENCE, "autoaway.time", NULL); if (result == 0) { return 15; } else { return result; } } void prefs_set_autoaway_time(gint value) { g_key_file_set_integer(prefs, PREF_GROUP_PRESENCE, "autoaway.time", value); _save_prefs(); } void prefs_set_occupants_size(gint value) { g_key_file_set_integer(prefs, PREF_GROUP_UI, "occupants.size", value); _save_prefs(); } gint prefs_get_occupants_size(void) { gint result = g_key_file_get_integer(prefs, PREF_GROUP_UI, "occupants.size", NULL); if (result > 99 || result < 1) { return 15; } else { return result; } } void prefs_set_roster_size(gint value) { g_key_file_set_integer(prefs, PREF_GROUP_UI, "roster.size", value); _save_prefs(); } gint prefs_get_roster_size(void) { gint result = g_key_file_get_integer(prefs, PREF_GROUP_UI, "roster.size", NULL); if (result > 99 || result < 1) { return 25; } else { return result; } } char prefs_get_otr_char(void) { char result = '~'; char *resultstr = g_key_file_get_string(prefs, PREF_GROUP_OTR, "otr.char", NULL); if (!resultstr) { result = '~'; } else { result = resultstr[0]; } free(resultstr); return result; } void prefs_set_otr_char(char ch) { char str[2]; str[0] = ch; str[1] = '\0'; g_key_file_set_string(prefs, PREF_GROUP_OTR, "otr.char", str); _save_prefs(); } char prefs_get_pgp_char(void) { char result = '~'; char *resultstr = g_key_file_get_string(prefs, PREF_GROUP_PGP, "pgp.char", NULL); if (!resultstr) { result = '~'; } else { result = resultstr[0]; } free(resultstr); return result; } void prefs_set_pgp_char(char ch) { char str[2]; str[0] = ch; str[1] = '\0'; g_key_file_set_string(prefs, PREF_GROUP_PGP, "pgp.char", str); _save_prefs(); } gboolean prefs_add_alias(const char * const name, const char * const value) { if (g_key_file_has_key(prefs, PREF_GROUP_ALIAS, name, NULL)) { return FALSE; } else { g_key_file_set_string(prefs, PREF_GROUP_ALIAS, name, value); _save_prefs(); return TRUE; } } char * prefs_get_alias(const char * const name) { return g_key_file_get_string(prefs, PREF_GROUP_ALIAS, name, NULL); } gboolean prefs_remove_alias(const char * const name) { if (!g_key_file_has_key(prefs, PREF_GROUP_ALIAS, name, NULL)) { return FALSE; } else { g_key_file_remove_key(prefs, PREF_GROUP_ALIAS, name, NULL); _save_prefs(); return TRUE; } } static gint _alias_cmp(gconstpointer *p1, gconstpointer *p2) { ProfAlias *alias1 = (ProfAlias*)p1; ProfAlias *alias2 = (ProfAlias*)p2; return strcmp(alias1->name, alias2->name); } GList * prefs_get_aliases(void) { if (!g_key_file_has_group(prefs, PREF_GROUP_ALIAS)) { return NULL; } else { GList *result = NULL; gsize len; gchar **keys = g_key_file_get_keys(prefs, PREF_GROUP_ALIAS, &len, NULL); int i; for (i = 0; i < len; i++) { char *name = keys[i]; char *value = g_key_file_get_string(prefs, PREF_GROUP_ALIAS, name, NULL); if (value) { ProfAlias *alias = malloc(sizeof(struct prof_alias_t)); alias->name = strdup(name); alias->value = strdup(value); free(value); result = g_list_insert_sorted(result, alias, (GCompareFunc)_alias_cmp); } } g_strfreev(keys); return result; } } void _free_alias(ProfAlias *alias) { FREE_SET_NULL(alias->name); FREE_SET_NULL(alias->value); FREE_SET_NULL(alias); } void prefs_free_aliases(GList *aliases) { g_list_free_full(aliases, (GDestroyNotify)_free_alias); } static void _save_prefs(void) { gsize g_data_size; gchar *g_prefs_data = g_key_file_to_data(prefs, &g_data_size, NULL); gchar *xdg_config = xdg_get_config_home(); GString *base_str = g_string_new(xdg_config); g_string_append(base_str, "/profanity/"); gchar *true_loc = get_file_or_linked(prefs_loc, base_str->str); g_file_set_contents(true_loc, g_prefs_data, g_data_size, NULL); g_chmod(prefs_loc, S_IRUSR | S_IWUSR); g_free(xdg_config); free(true_loc); g_free(g_prefs_data); g_string_free(base_str, TRUE); } static gchar * _get_preferences_file(void) { gchar *xdg_config = xdg_get_config_home(); GString *prefs_file = g_string_new(xdg_config); g_string_append(prefs_file, "/profanity/profrc"); gchar *result = strdup(prefs_file->str); g_free(xdg_config); g_string_free(prefs_file, TRUE); return result; } // get the preference group for a specific preference // for example the PREF_BEEP setting ("beep" in .profrc, see _get_key) belongs // to the [ui] section. static const char * _get_group(preference_t pref) { switch (pref) { case PREF_SPLASH: case PREF_BEEP: case PREF_THEME: case PREF_VERCHECK: case PREF_TITLEBAR_SHOW: case PREF_TITLEBAR_GOODBYE: case PREF_FLASH: case PREF_INTYPE: case PREF_HISTORY: case PREF_OCCUPANTS: case PREF_OCCUPANTS_JID: case PREF_STATUSES: case PREF_STATUSES_CONSOLE: case PREF_STATUSES_CHAT: case PREF_STATUSES_MUC: case PREF_MUC_PRIVILEGES: case PREF_PRESENCE: case PREF_WRAP: case PREF_WINS_AUTO_TIDY: case PREF_TIME: case PREF_TIME_STATUSBAR: case PREF_ROSTER: case PREF_ROSTER_OFFLINE: case PREF_ROSTER_RESOURCE: case PREF_ROSTER_EMPTY: case PREF_ROSTER_BY: case PREF_RESOURCE_TITLE: case PREF_RESOURCE_MESSAGE: case PREF_ENC_WARN: case PREF_INPBLOCK_DYNAMIC: return PREF_GROUP_UI; case PREF_STATES: case PREF_OUTTYPE: return PREF_GROUP_CHATSTATES; case PREF_NOTIFY_TYPING: case PREF_NOTIFY_TYPING_CURRENT: case PREF_NOTIFY_MESSAGE: case PREF_NOTIFY_MESSAGE_CURRENT: case PREF_NOTIFY_MESSAGE_TEXT: case PREF_NOTIFY_ROOM: case PREF_NOTIFY_ROOM_CURRENT: case PREF_NOTIFY_ROOM_TEXT: case PREF_NOTIFY_INVITE: case PREF_NOTIFY_SUB: return PREF_GROUP_NOTIFICATIONS; case PREF_CHLOG: case PREF_GRLOG: case PREF_LOG_ROTATE: case PREF_LOG_SHARED: return PREF_GROUP_LOGGING; case PREF_AUTOAWAY_CHECK: case PREF_AUTOAWAY_MODE: case PREF_AUTOAWAY_MESSAGE: return PREF_GROUP_PRESENCE; case PREF_CONNECT_ACCOUNT: case PREF_DEFAULT_ACCOUNT: case PREF_CARBONS: case PREF_RECEIPTS_SEND: case PREF_RECEIPTS_REQUEST: return PREF_GROUP_CONNECTION; case PREF_OTR_LOG: case PREF_OTR_POLICY: return PREF_GROUP_OTR; case PREF_PGP_LOG: return PREF_GROUP_PGP; default: return NULL; } } // get the key used in .profrc for the preference // for example the PREF_AUTOAWAY_MODE maps to "autoaway.mode" in .profrc static const char * _get_key(preference_t pref) { switch (pref) { case PREF_SPLASH: return "splash"; case PREF_BEEP: return "beep"; case PREF_THEME: return "theme"; case PREF_VERCHECK: return "vercheck"; case PREF_TITLEBAR_SHOW: return "titlebar.show"; case PREF_TITLEBAR_GOODBYE: return "titlebar.goodbye"; case PREF_FLASH: return "flash"; case PREF_INTYPE: return "intype"; case PREF_HISTORY: return "history"; case PREF_CARBONS: return "carbons"; case PREF_RECEIPTS_SEND: return "receipts.send"; case PREF_RECEIPTS_REQUEST: return "receipts.request"; case PREF_OCCUPANTS: return "occupants"; case PREF_OCCUPANTS_JID: return "occupants.jid"; case PREF_MUC_PRIVILEGES: return "privileges"; case PREF_STATUSES: return "statuses"; case PREF_STATUSES_CONSOLE: return "statuses.console"; case PREF_STATUSES_CHAT: return "statuses.chat"; case PREF_STATUSES_MUC: return "statuses.muc"; case PREF_STATES: return "enabled"; case PREF_OUTTYPE: return "outtype"; case PREF_NOTIFY_TYPING: return "typing"; case PREF_NOTIFY_TYPING_CURRENT: return "typing.current"; case PREF_NOTIFY_MESSAGE: return "message"; case PREF_NOTIFY_MESSAGE_CURRENT: return "message.current"; case PREF_NOTIFY_MESSAGE_TEXT: return "message.text"; case PREF_NOTIFY_ROOM: return "room"; case PREF_NOTIFY_ROOM_CURRENT: return "room.current"; case PREF_NOTIFY_ROOM_TEXT: return "room.text"; case PREF_NOTIFY_INVITE: return "invite"; case PREF_NOTIFY_SUB: return "sub"; case PREF_CHLOG: return "chlog"; case PREF_GRLOG: return "grlog"; case PREF_AUTOAWAY_CHECK: return "autoaway.check"; case PREF_AUTOAWAY_MODE: return "autoaway.mode"; case PREF_AUTOAWAY_MESSAGE: return "autoaway.message"; case PREF_CONNECT_ACCOUNT: return "account"; case PREF_DEFAULT_ACCOUNT: return "defaccount"; case PREF_OTR_LOG: return "log"; case PREF_OTR_POLICY: return "policy"; case PREF_LOG_ROTATE: return "rotate"; case PREF_LOG_SHARED: return "shared"; case PREF_PRESENCE: return "presence"; case PREF_WRAP: return "wrap"; case PREF_WINS_AUTO_TIDY: return "wins.autotidy"; case PREF_TIME: return "time"; case PREF_TIME_STATUSBAR: return "time.statusbar"; case PREF_ROSTER: return "roster"; case PREF_ROSTER_OFFLINE: return "roster.offline"; case PREF_ROSTER_RESOURCE: return "roster.resource"; case PREF_ROSTER_EMPTY: return "roster.empty"; case PREF_ROSTER_BY: return "roster.by"; case PREF_RESOURCE_TITLE: return "resource.title"; case PREF_RESOURCE_MESSAGE: return "resource.message"; case PREF_INPBLOCK_DYNAMIC: return "inpblock.dynamic"; case PREF_ENC_WARN: return "enc.warn"; case PREF_PGP_LOG: return "log"; default: return NULL; } } // the default setting for a boolean type preference // if it is not specified in .profrc static gboolean _get_default_boolean(preference_t pref) { switch (pref) { case PREF_ENC_WARN: case PREF_AUTOAWAY_CHECK: case PREF_LOG_ROTATE: case PREF_LOG_SHARED: case PREF_NOTIFY_MESSAGE: case PREF_NOTIFY_MESSAGE_CURRENT: case PREF_NOTIFY_ROOM_CURRENT: case PREF_NOTIFY_TYPING: case PREF_NOTIFY_TYPING_CURRENT: case PREF_NOTIFY_SUB: case PREF_NOTIFY_INVITE: case PREF_SPLASH: case PREF_OCCUPANTS: case PREF_MUC_PRIVILEGES: case PREF_PRESENCE: case PREF_WRAP: case PREF_WINS_AUTO_TIDY: case PREF_INPBLOCK_DYNAMIC: case PREF_RESOURCE_TITLE: case PREF_RESOURCE_MESSAGE: case PREF_ROSTER: case PREF_ROSTER_OFFLINE: case PREF_ROSTER_RESOURCE: case PREF_ROSTER_EMPTY: return TRUE; default: return FALSE; } } // the default setting for a string type preference // if it is not specified in .profrc static char * _get_default_string(preference_t pref) { switch (pref) { case PREF_AUTOAWAY_MODE: return "off"; case PREF_NOTIFY_ROOM: return "on"; case PREF_OTR_LOG: return "redact"; case PREF_OTR_POLICY: return "manual"; case PREF_STATUSES_CONSOLE: case PREF_STATUSES_CHAT: case PREF_STATUSES_MUC: return "all"; case PREF_ROSTER_BY: return "presence"; case PREF_TIME: return "%H:%M:%S"; case PREF_TIME_STATUSBAR: return "%H:%M"; case PREF_PGP_LOG: return "redact"; default: return NULL; } } profanity-0.4.7/src/config/preferences.h000066400000000000000000000112731257755232500202640ustar00rootroot00000000000000/* * preferences.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef PREFERENCES_H #define PREFERENCES_H #include "config.h" #include #define PREFS_MIN_LOG_SIZE 64 #define PREFS_MAX_LOG_SIZE 1048580 // represents all settings in .profrc // each enum value is mapped to a group and key in .profrc (see preferences.c) typedef enum { PREF_SPLASH, PREF_BEEP, PREF_VERCHECK, PREF_THEME, PREF_TITLEBAR_SHOW, PREF_TITLEBAR_GOODBYE, PREF_FLASH, PREF_INTYPE, PREF_HISTORY, PREF_CARBONS, PREF_RECEIPTS_SEND, PREF_RECEIPTS_REQUEST, PREF_OCCUPANTS, PREF_OCCUPANTS_SIZE, PREF_OCCUPANTS_JID, PREF_ROSTER, PREF_ROSTER_SIZE, PREF_ROSTER_OFFLINE, PREF_ROSTER_RESOURCE, PREF_ROSTER_EMPTY, PREF_ROSTER_BY, PREF_MUC_PRIVILEGES, PREF_PRESENCE, PREF_WRAP, PREF_WINS_AUTO_TIDY, PREF_TIME, PREF_TIME_STATUSBAR, PREF_STATUSES, PREF_STATUSES_CONSOLE, PREF_STATUSES_CHAT, PREF_STATUSES_MUC, PREF_STATES, PREF_OUTTYPE, PREF_NOTIFY_TYPING, PREF_NOTIFY_TYPING_CURRENT, PREF_NOTIFY_MESSAGE, PREF_NOTIFY_MESSAGE_CURRENT, PREF_NOTIFY_MESSAGE_TEXT, PREF_NOTIFY_ROOM, PREF_NOTIFY_ROOM_CURRENT, PREF_NOTIFY_ROOM_TEXT, PREF_NOTIFY_INVITE, PREF_NOTIFY_SUB, PREF_CHLOG, PREF_GRLOG, PREF_AUTOAWAY_CHECK, PREF_AUTOAWAY_MODE, PREF_AUTOAWAY_MESSAGE, PREF_CONNECT_ACCOUNT, PREF_DEFAULT_ACCOUNT, PREF_LOG_ROTATE, PREF_LOG_SHARED, PREF_OTR_LOG, PREF_OTR_POLICY, PREF_RESOURCE_TITLE, PREF_RESOURCE_MESSAGE, PREF_INPBLOCK_DYNAMIC, PREF_ENC_WARN, PREF_PGP_LOG } preference_t; typedef struct prof_alias_t { gchar *name; gchar *value; } ProfAlias; void prefs_load(void); void prefs_close(void); char * prefs_find_login(char *prefix); void prefs_reset_login_search(void); char * prefs_autocomplete_boolean_choice(const char * const prefix); void prefs_reset_boolean_choice(void); gint prefs_get_gone(void); void prefs_set_gone(gint value); void prefs_set_notify_remind(gint period); gint prefs_get_notify_remind(void); void prefs_set_max_log_size(gint value); gint prefs_get_max_log_size(void); gint prefs_get_priority(void); void prefs_set_reconnect(gint value); gint prefs_get_reconnect(void); void prefs_set_autoping(gint value); gint prefs_get_autoping(void); gint prefs_get_inpblock(void); void prefs_set_inpblock(gint value); void prefs_set_occupants_size(gint value); gint prefs_get_occupants_size(void); void prefs_set_roster_size(gint value); gint prefs_get_roster_size(void); gint prefs_get_autoaway_time(void); void prefs_set_autoaway_time(gint value); char prefs_get_otr_char(void); void prefs_set_otr_char(char ch); char prefs_get_pgp_char(void); void prefs_set_pgp_char(char ch); void prefs_add_login(const char *jid); gboolean prefs_add_alias(const char * const name, const char * const value); gboolean prefs_remove_alias(const char * const name); char* prefs_get_alias(const char * const name); GList* prefs_get_aliases(void); void prefs_free_aliases(GList *aliases); gboolean prefs_get_boolean(preference_t pref); void prefs_set_boolean(preference_t pref, gboolean value); char * prefs_get_string(preference_t pref); void prefs_free_string(char *pref); void prefs_set_string(preference_t pref, char *value); #endif profanity-0.4.7/src/config/theme.c000066400000000000000000000651621257755232500170660ustar00rootroot00000000000000/* * theme.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include #ifdef HAVE_NCURSESW_NCURSES_H #include #elif HAVE_NCURSES_H #include #endif #include "common.h" #include "log.h" #include "theme.h" #include "preferences.h" static GString *theme_loc; static GKeyFile *theme; static GHashTable *bold_items; struct colour_string_t { char *str; NCURSES_COLOR_T colour; }; static int num_colours = 9; static struct colour_string_t colours[] = { { "default", -1 }, { "white", COLOR_WHITE }, { "green", COLOR_GREEN }, { "red", COLOR_RED }, { "yellow", COLOR_YELLOW }, { "blue", COLOR_BLUE }, { "cyan", COLOR_CYAN }, { "black", COLOR_BLACK }, { "magenta", COLOR_MAGENTA }, }; // colour preferences static struct colours_t { NCURSES_COLOR_T bkgnd; NCURSES_COLOR_T titlebar; NCURSES_COLOR_T statusbar; NCURSES_COLOR_T titlebartext; NCURSES_COLOR_T titlebarbrackets; NCURSES_COLOR_T titlebarunencrypted; NCURSES_COLOR_T titlebarencrypted; NCURSES_COLOR_T titlebaruntrusted; NCURSES_COLOR_T titlebartrusted; NCURSES_COLOR_T titlebaronline; NCURSES_COLOR_T titlebaroffline; NCURSES_COLOR_T titlebaraway; NCURSES_COLOR_T titlebarxa; NCURSES_COLOR_T titlebardnd; NCURSES_COLOR_T titlebarchat; NCURSES_COLOR_T statusbartext; NCURSES_COLOR_T statusbarbrackets; NCURSES_COLOR_T statusbaractive; NCURSES_COLOR_T statusbarnew; NCURSES_COLOR_T maintext; NCURSES_COLOR_T maintextme; NCURSES_COLOR_T maintextthem; NCURSES_COLOR_T inputtext; NCURSES_COLOR_T timetext; NCURSES_COLOR_T splashtext; NCURSES_COLOR_T subscribed; NCURSES_COLOR_T unsubscribed; NCURSES_COLOR_T online; NCURSES_COLOR_T away; NCURSES_COLOR_T xa; NCURSES_COLOR_T dnd; NCURSES_COLOR_T chat; NCURSES_COLOR_T offline; NCURSES_COLOR_T typing; NCURSES_COLOR_T gone; NCURSES_COLOR_T error; NCURSES_COLOR_T incoming; NCURSES_COLOR_T roominfo; NCURSES_COLOR_T roommention; NCURSES_COLOR_T me; NCURSES_COLOR_T them; NCURSES_COLOR_T otrstartedtrusted; NCURSES_COLOR_T otrstarteduntrusted; NCURSES_COLOR_T otrended; NCURSES_COLOR_T otrtrusted; NCURSES_COLOR_T otruntrusted; NCURSES_COLOR_T rosterheader; NCURSES_COLOR_T occupantsheader; NCURSES_COLOR_T receiptsent; } colour_prefs; static NCURSES_COLOR_T _lookup_colour(const char * const colour); static void _set_colour(gchar *val, NCURSES_COLOR_T *pref, NCURSES_COLOR_T def, theme_item_t theme_item); static void _load_colours(void); static void _load_preferences(void); static gchar * _get_themes_dir(void); void _theme_list_dir(const gchar * const dir, GSList **result); static GString * _theme_find(const char * const theme_name); static gboolean _theme_load_file(const char * const theme_name); void theme_init(const char * const theme_name) { if (!_theme_load_file(theme_name) && !_theme_load_file("default")) { log_error("Theme initialisation failed"); } else { _load_colours(); } } gboolean theme_load(const char * const theme_name) { if (_theme_load_file(theme_name)) { _load_colours(); _load_preferences(); return TRUE; } else { return FALSE; } } static gboolean _theme_load_file(const char * const theme_name) { // use default theme if (theme_name == NULL || strcmp(theme_name, "default") == 0) { if (theme) { g_key_file_free(theme); } theme = g_key_file_new(); // load theme from file } else { GString *new_theme_file = _theme_find(theme_name); if (new_theme_file == NULL) { log_info("Theme does not exist \"%s\"", theme_name); return FALSE; } if (theme_loc) { g_string_free(theme_loc, TRUE); } theme_loc = new_theme_file; log_info("Loading theme \"%s\"", theme_name); if (theme) { g_key_file_free(theme); } theme = g_key_file_new(); g_key_file_load_from_file(theme, theme_loc->str, G_KEY_FILE_KEEP_COMMENTS, NULL); } return TRUE; } GSList * theme_list(void) { GSList *result = NULL; char *themes_dir = _get_themes_dir(); _theme_list_dir(themes_dir, &result); free(themes_dir); #ifdef THEMES_PATH _theme_list_dir(THEMES_PATH, &result); #endif return result; } void theme_close(void) { if (theme) { g_key_file_free(theme); theme = NULL; } if (theme_loc) { g_string_free(theme_loc, TRUE); theme_loc = NULL; } if (bold_items) { g_hash_table_destroy(bold_items); bold_items = NULL; } } void theme_init_colours(void) { // main text init_pair(1, colour_prefs.maintext, colour_prefs.bkgnd); init_pair(2, colour_prefs.maintextme, colour_prefs.bkgnd); init_pair(3, colour_prefs.maintextthem, colour_prefs.bkgnd); init_pair(4, colour_prefs.splashtext, colour_prefs.bkgnd); init_pair(5, colour_prefs.error, colour_prefs.bkgnd); init_pair(6, colour_prefs.incoming, colour_prefs.bkgnd); init_pair(7, colour_prefs.inputtext, colour_prefs.bkgnd); init_pair(8, colour_prefs.timetext, colour_prefs.bkgnd); // title bar init_pair(9, colour_prefs.titlebartext, colour_prefs.titlebar); init_pair(10, colour_prefs.titlebarbrackets, colour_prefs.titlebar); init_pair(11, colour_prefs.titlebarunencrypted, colour_prefs.titlebar); init_pair(12, colour_prefs.titlebarencrypted, colour_prefs.titlebar); init_pair(13, colour_prefs.titlebaruntrusted, colour_prefs.titlebar); init_pair(14, colour_prefs.titlebartrusted, colour_prefs.titlebar); init_pair(15, colour_prefs.titlebaronline, colour_prefs.titlebar); init_pair(16, colour_prefs.titlebaroffline, colour_prefs.titlebar); init_pair(17, colour_prefs.titlebaraway, colour_prefs.titlebar); init_pair(18, colour_prefs.titlebarchat, colour_prefs.titlebar); init_pair(19, colour_prefs.titlebardnd, colour_prefs.titlebar); init_pair(20, colour_prefs.titlebarxa, colour_prefs.titlebar); // status bar init_pair(21, colour_prefs.statusbartext, colour_prefs.statusbar); init_pair(22, colour_prefs.statusbarbrackets, colour_prefs.statusbar); init_pair(23, colour_prefs.statusbaractive, colour_prefs.statusbar); init_pair(24, colour_prefs.statusbarnew, colour_prefs.statusbar); // chat init_pair(25, colour_prefs.me, colour_prefs.bkgnd); init_pair(26, colour_prefs.them, colour_prefs.bkgnd); init_pair(27, colour_prefs.receiptsent, colour_prefs.bkgnd); // room chat init_pair(28, colour_prefs.roominfo, colour_prefs.bkgnd); init_pair(29, colour_prefs.roommention, colour_prefs.bkgnd); // statuses init_pair(30, colour_prefs.online, colour_prefs.bkgnd); init_pair(31, colour_prefs.offline, colour_prefs.bkgnd); init_pair(32, colour_prefs.away, colour_prefs.bkgnd); init_pair(33, colour_prefs.chat, colour_prefs.bkgnd); init_pair(34, colour_prefs.dnd, colour_prefs.bkgnd); init_pair(35, colour_prefs.xa, colour_prefs.bkgnd); // states init_pair(36, colour_prefs.typing, colour_prefs.bkgnd); init_pair(37, colour_prefs.gone, colour_prefs.bkgnd); // subscription status init_pair(38, colour_prefs.subscribed, colour_prefs.bkgnd); init_pair(39, colour_prefs.unsubscribed, colour_prefs.bkgnd); // otr messages init_pair(40, colour_prefs.otrstartedtrusted, colour_prefs.bkgnd); init_pair(41, colour_prefs.otrstarteduntrusted, colour_prefs.bkgnd); init_pair(42, colour_prefs.otrended, colour_prefs.bkgnd); init_pair(43, colour_prefs.otrtrusted, colour_prefs.bkgnd); init_pair(44, colour_prefs.otruntrusted, colour_prefs.bkgnd); // subwin headers init_pair(45, colour_prefs.rosterheader, colour_prefs.bkgnd); init_pair(46, colour_prefs.occupantsheader, colour_prefs.bkgnd); // raw init_pair(47, COLOR_WHITE, colour_prefs.bkgnd); init_pair(48, COLOR_GREEN, colour_prefs.bkgnd); init_pair(49, COLOR_RED, colour_prefs.bkgnd); init_pair(50, COLOR_YELLOW, colour_prefs.bkgnd); init_pair(51, COLOR_BLUE, colour_prefs.bkgnd); init_pair(52, COLOR_CYAN, colour_prefs.bkgnd); init_pair(53, COLOR_BLACK, colour_prefs.bkgnd); init_pair(54, COLOR_MAGENTA, colour_prefs.bkgnd); } static NCURSES_COLOR_T _lookup_colour(const char * const colour) { int i; for (i = 0; i < num_colours; i++) { if (strcmp(colours[i].str, colour) == 0) { return colours[i].colour; } } return -99; } static void _set_colour(char *setting, NCURSES_COLOR_T *pref, NCURSES_COLOR_T def, theme_item_t theme_item) { gchar *val = g_key_file_get_string(theme, "colours", setting, NULL); if(!val) { *pref = def; } else { gchar *true_val = val; if (g_str_has_prefix(val, "bold_")) { true_val = &val[5]; if (theme_item != THEME_NONE) { g_hash_table_insert(bold_items, GINT_TO_POINTER(theme_item), GINT_TO_POINTER(theme_item)); } } NCURSES_COLOR_T col = _lookup_colour(true_val); if (col == -99) { *pref = def; } else { *pref = col; } } g_free(val); } static void _load_colours(void) { if (bold_items) { g_hash_table_destroy(bold_items); } bold_items = g_hash_table_new(g_direct_hash, g_direct_equal); g_hash_table_insert(bold_items, GINT_TO_POINTER(THEME_WHITE_BOLD), GINT_TO_POINTER(THEME_WHITE_BOLD)); g_hash_table_insert(bold_items, GINT_TO_POINTER(THEME_GREEN_BOLD), GINT_TO_POINTER(THEME_GREEN_BOLD)); g_hash_table_insert(bold_items, GINT_TO_POINTER(THEME_RED_BOLD), GINT_TO_POINTER(THEME_RED_BOLD)); g_hash_table_insert(bold_items, GINT_TO_POINTER(THEME_YELLOW_BOLD), GINT_TO_POINTER(THEME_YELLOW_BOLD)); g_hash_table_insert(bold_items, GINT_TO_POINTER(THEME_BLUE_BOLD), GINT_TO_POINTER(THEME_BLUE_BOLD)); g_hash_table_insert(bold_items, GINT_TO_POINTER(THEME_CYAN_BOLD), GINT_TO_POINTER(THEME_CYAN_BOLD)); g_hash_table_insert(bold_items, GINT_TO_POINTER(THEME_BLACK_BOLD), GINT_TO_POINTER(THEME_BLACK_BOLD)); g_hash_table_insert(bold_items, GINT_TO_POINTER(THEME_MAGENTA_BOLD), GINT_TO_POINTER(THEME_MAGENTA_BOLD)); _set_colour("bkgnd", &colour_prefs.bkgnd, -1, THEME_NONE); _set_colour("titlebar", &colour_prefs.titlebar, COLOR_BLUE, THEME_NONE); _set_colour("statusbar", &colour_prefs.statusbar, COLOR_BLUE, THEME_NONE); _set_colour("titlebar.text", &colour_prefs.titlebartext, COLOR_WHITE, THEME_TITLE_TEXT); _set_colour("titlebar.brackets", &colour_prefs.titlebarbrackets, COLOR_CYAN, THEME_TITLE_BRACKET); _set_colour("titlebar.unencrypted", &colour_prefs.titlebarunencrypted, COLOR_RED, THEME_TITLE_UNENCRYPTED); _set_colour("titlebar.encrypted", &colour_prefs.titlebarencrypted, COLOR_WHITE, THEME_TITLE_ENCRYPTED); _set_colour("titlebar.untrusted", &colour_prefs.titlebaruntrusted, COLOR_YELLOW, THEME_TITLE_UNTRUSTED); _set_colour("titlebar.trusted", &colour_prefs.titlebartrusted, COLOR_WHITE, THEME_TITLE_TRUSTED); _set_colour("titlebar.online", &colour_prefs.titlebaronline, COLOR_WHITE, THEME_TITLE_ONLINE); _set_colour("titlebar.offline", &colour_prefs.titlebaroffline, COLOR_WHITE, THEME_TITLE_OFFLINE); _set_colour("titlebar.away", &colour_prefs.titlebaraway, COLOR_WHITE, THEME_TITLE_AWAY); _set_colour("titlebar.chat", &colour_prefs.titlebarchat, COLOR_WHITE, THEME_TITLE_CHAT); _set_colour("titlebar.dnd", &colour_prefs.titlebardnd, COLOR_WHITE, THEME_TITLE_DND); _set_colour("titlebar.xa", &colour_prefs.titlebarxa, COLOR_WHITE, THEME_TITLE_XA); _set_colour("statusbar.text", &colour_prefs.statusbartext, COLOR_WHITE, THEME_STATUS_TEXT); _set_colour("statusbar.brackets", &colour_prefs.statusbarbrackets, COLOR_CYAN, THEME_STATUS_BRACKET); _set_colour("statusbar.active", &colour_prefs.statusbaractive, COLOR_CYAN, THEME_STATUS_ACTIVE); _set_colour("statusbar.new", &colour_prefs.statusbarnew, COLOR_WHITE, THEME_STATUS_NEW); _set_colour("main.text", &colour_prefs.maintext, COLOR_WHITE, THEME_TEXT); _set_colour("main.text.me", &colour_prefs.maintextme, COLOR_WHITE, THEME_TEXT_ME); _set_colour("main.text.them", &colour_prefs.maintextthem, COLOR_WHITE, THEME_TEXT_THEM); _set_colour("main.splash", &colour_prefs.splashtext, COLOR_CYAN, THEME_SPLASH); _set_colour("input.text", &colour_prefs.inputtext, COLOR_WHITE, THEME_INPUT_TEXT); _set_colour("main.time", &colour_prefs.timetext, COLOR_WHITE, THEME_TIME); _set_colour("subscribed", &colour_prefs.subscribed, COLOR_GREEN, THEME_SUBSCRIBED); _set_colour("unsubscribed", &colour_prefs.unsubscribed, COLOR_RED, THEME_UNSUBSCRIBED); _set_colour("otr.started.trusted", &colour_prefs.otrstartedtrusted, COLOR_GREEN, THEME_OTR_STARTED_TRUSTED); _set_colour("otr.started.untrusted", &colour_prefs.otrstarteduntrusted, COLOR_YELLOW, THEME_OTR_STARTED_UNTRUSTED); _set_colour("otr.ended", &colour_prefs.otrended, COLOR_RED, THEME_OTR_ENDED); _set_colour("otr.trusted", &colour_prefs.otrtrusted, COLOR_GREEN, THEME_OTR_TRUSTED); _set_colour("otr.untrusted", &colour_prefs.otruntrusted, COLOR_YELLOW, THEME_OTR_UNTRUSTED); _set_colour("online", &colour_prefs.online, COLOR_GREEN, THEME_ONLINE); _set_colour("away", &colour_prefs.away, COLOR_CYAN, THEME_AWAY); _set_colour("chat", &colour_prefs.chat, COLOR_GREEN, THEME_CHAT); _set_colour("dnd", &colour_prefs.dnd, COLOR_RED, THEME_DND); _set_colour("xa", &colour_prefs.xa, COLOR_CYAN, THEME_XA); _set_colour("offline", &colour_prefs.offline, COLOR_RED, THEME_OFFLINE); _set_colour("typing", &colour_prefs.typing, COLOR_YELLOW, THEME_TYPING); _set_colour("gone", &colour_prefs.gone, COLOR_RED, THEME_GONE); _set_colour("error", &colour_prefs.error, COLOR_RED, THEME_ERROR); _set_colour("incoming", &colour_prefs.incoming, COLOR_YELLOW, THEME_INCOMING); _set_colour("roominfo", &colour_prefs.roominfo, COLOR_YELLOW, THEME_ROOMINFO); _set_colour("roommention", &colour_prefs.roommention, COLOR_YELLOW, THEME_ROOMMENTION); _set_colour("me", &colour_prefs.me, COLOR_YELLOW, THEME_ME); _set_colour("them", &colour_prefs.them, COLOR_GREEN, THEME_THEM); _set_colour("roster.header", &colour_prefs.rosterheader, COLOR_YELLOW, THEME_ROSTER_HEADER); _set_colour("occupants.header", &colour_prefs.occupantsheader, COLOR_YELLOW, THEME_OCCUPANTS_HEADER); _set_colour("receipt.sent", &colour_prefs.receiptsent, COLOR_RED, THEME_RECEIPT_SENT); } static void _set_string_preference(char *prefstr, preference_t pref) { if (g_key_file_has_key(theme, "ui", prefstr, NULL)) { gchar *val = g_key_file_get_string(theme, "ui", prefstr, NULL); prefs_set_string(pref, val); g_free(val); } } static void _set_boolean_preference(char *prefstr, preference_t pref) { if (g_key_file_has_key(theme, "ui", prefstr, NULL)) { gboolean val = g_key_file_get_boolean(theme, "ui", prefstr, NULL); prefs_set_boolean(pref, val); } } static void _load_preferences(void) { _set_boolean_preference("beep", PREF_BEEP); _set_boolean_preference("flash", PREF_FLASH); _set_boolean_preference("splash", PREF_SPLASH); _set_boolean_preference("wrap", PREF_WRAP); _set_boolean_preference("wins.autotidy", PREF_WINS_AUTO_TIDY); _set_string_preference("time", PREF_TIME); _set_string_preference("time.statusbar", PREF_TIME_STATUSBAR); _set_boolean_preference("resource.title", PREF_RESOURCE_TITLE); _set_boolean_preference("resource.message", PREF_RESOURCE_MESSAGE); _set_string_preference("statuses.console", PREF_STATUSES_CONSOLE); _set_string_preference("statuses.chat", PREF_STATUSES_CHAT); _set_string_preference("statuses.muc", PREF_STATUSES_MUC); _set_boolean_preference("occupants", PREF_OCCUPANTS); _set_boolean_preference("occupants.jid", PREF_OCCUPANTS_JID); if (g_key_file_has_key(theme, "ui", "occupants.size", NULL)) { gint occupants_size = g_key_file_get_integer(theme, "ui", "occupants.size", NULL); prefs_set_occupants_size(occupants_size); } _set_boolean_preference("roster", PREF_ROSTER); _set_boolean_preference("roster.offline", PREF_ROSTER_OFFLINE); _set_boolean_preference("roster.resource", PREF_ROSTER_RESOURCE); _set_boolean_preference("roster.empty", PREF_ROSTER_EMPTY); _set_string_preference("roster.by", PREF_ROSTER_BY); if (g_key_file_has_key(theme, "ui", "roster.size", NULL)) { gint roster_size = g_key_file_get_integer(theme, "ui", "roster.size", NULL); prefs_set_roster_size(roster_size); } _set_boolean_preference("privileges", PREF_MUC_PRIVILEGES); _set_boolean_preference("presence", PREF_PRESENCE); _set_boolean_preference("intype", PREF_INTYPE); _set_boolean_preference("enc.warn", PREF_ENC_WARN); if (g_key_file_has_key(theme, "ui", "otr.char", NULL)) { gchar *ch = g_key_file_get_string(theme, "ui", "otr.char", NULL); if (ch && strlen(ch) > 0) { prefs_set_otr_char(ch[0]); g_free(ch); } } if (g_key_file_has_key(theme, "ui", "pgp.char", NULL)) { gchar *ch = g_key_file_get_string(theme, "ui", "pgp.char", NULL); if (ch && strlen(ch) > 0) { prefs_set_pgp_char(ch[0]); g_free(ch); } } } static gchar * _get_themes_dir(void) { gchar *xdg_config = xdg_get_config_home(); GString *themes_dir = g_string_new(xdg_config); g_free(xdg_config); g_string_append(themes_dir, "/profanity/themes"); return g_string_free(themes_dir, FALSE); } void _theme_list_dir(const gchar * const dir, GSList **result) { GDir *themes = g_dir_open(dir, 0, NULL); if (themes) { const gchar *theme = g_dir_read_name(themes); while (theme) { *result = g_slist_append(*result, strdup(theme)); theme = g_dir_read_name(themes); } g_dir_close(themes); } } static GString * _theme_find(const char * const theme_name) { GString *path = NULL; gchar *themes_dir = _get_themes_dir(); if (themes_dir) { path = g_string_new(themes_dir); g_free(themes_dir); g_string_append(path, "/"); g_string_append(path, theme_name); if (!g_file_test(path->str, G_FILE_TEST_EXISTS)) { g_string_free(path, true); path = NULL; } } #ifdef THEMES_PATH if (path == NULL) { path = g_string_new(THEMES_PATH); g_string_append(path, "/"); g_string_append(path, theme_name); if (!g_file_test(path->str, G_FILE_TEST_EXISTS)) { g_string_free(path, true); path = NULL; } } #endif /* THEMES_PATH */ return path; } theme_item_t theme_main_presence_attrs(const char * const presence) { if (g_strcmp0(presence, "online") == 0) { return THEME_ONLINE; } else if (g_strcmp0(presence, "away") == 0) { return THEME_AWAY; } else if (g_strcmp0(presence, "chat") == 0) { return THEME_CHAT; } else if (g_strcmp0(presence, "dnd") == 0) { return THEME_DND; } else if (g_strcmp0(presence, "xa") == 0) { return THEME_XA; } else { return THEME_OFFLINE; } } int theme_attrs(theme_item_t attrs) { int result = 0; switch (attrs) { case THEME_TEXT: result = COLOR_PAIR(1); break; case THEME_TEXT_ME: result = COLOR_PAIR(2); break; case THEME_TEXT_THEM: result = COLOR_PAIR(3); break; case THEME_SPLASH: result = COLOR_PAIR(4); break; case THEME_ERROR: result = COLOR_PAIR(5); break; case THEME_INCOMING: result = COLOR_PAIR(6); break; case THEME_INPUT_TEXT: result = COLOR_PAIR(7); break; case THEME_TIME: result = COLOR_PAIR(8); break; case THEME_TITLE_TEXT: result = COLOR_PAIR(9); break; case THEME_TITLE_BRACKET: result = COLOR_PAIR(10); break; case THEME_TITLE_UNENCRYPTED: result = COLOR_PAIR(11); break; case THEME_TITLE_ENCRYPTED: result = COLOR_PAIR(12); break; case THEME_TITLE_UNTRUSTED: result = COLOR_PAIR(13); break; case THEME_TITLE_TRUSTED: result = COLOR_PAIR(14); break; case THEME_TITLE_ONLINE: result = COLOR_PAIR(15); break; case THEME_TITLE_OFFLINE: result = COLOR_PAIR(16); break; case THEME_TITLE_AWAY: result = COLOR_PAIR(17); break; case THEME_TITLE_CHAT: result = COLOR_PAIR(18); break; case THEME_TITLE_DND: result = COLOR_PAIR(19); break; case THEME_TITLE_XA: result = COLOR_PAIR(20); break; case THEME_STATUS_TEXT: result = COLOR_PAIR(21); break; case THEME_STATUS_BRACKET: result = COLOR_PAIR(22); break; case THEME_STATUS_ACTIVE: result = COLOR_PAIR(23); break; case THEME_STATUS_NEW: result = COLOR_PAIR(24); break; case THEME_ME: result = COLOR_PAIR(25); break; case THEME_THEM: result = COLOR_PAIR(26); break; case THEME_RECEIPT_SENT: result = COLOR_PAIR(27); break; case THEME_ROOMINFO: result = COLOR_PAIR(28); break; case THEME_ROOMMENTION: result = COLOR_PAIR(29); break; case THEME_ONLINE: result = COLOR_PAIR(30); break; case THEME_OFFLINE: result = COLOR_PAIR(31); break; case THEME_AWAY: result = COLOR_PAIR(32); break; case THEME_CHAT: result = COLOR_PAIR(33); break; case THEME_DND: result = COLOR_PAIR(34); break; case THEME_XA: result = COLOR_PAIR(35); break; case THEME_TYPING: result = COLOR_PAIR(36); break; case THEME_GONE: result = COLOR_PAIR(37); break; case THEME_SUBSCRIBED: result = COLOR_PAIR(38); break; case THEME_UNSUBSCRIBED: result = COLOR_PAIR(39); break; case THEME_OTR_STARTED_TRUSTED: result = COLOR_PAIR(40); break; case THEME_OTR_STARTED_UNTRUSTED: result = COLOR_PAIR(41); break; case THEME_OTR_ENDED: result = COLOR_PAIR(42); break; case THEME_OTR_TRUSTED: result = COLOR_PAIR(43); break; case THEME_OTR_UNTRUSTED: result = COLOR_PAIR(44); break; case THEME_ROSTER_HEADER: result = COLOR_PAIR(45); break; case THEME_OCCUPANTS_HEADER: result = COLOR_PAIR(46); break; case THEME_WHITE: result = COLOR_PAIR(47); break; case THEME_WHITE_BOLD: result = COLOR_PAIR(47); break; case THEME_GREEN: result = COLOR_PAIR(48); break; case THEME_GREEN_BOLD: result = COLOR_PAIR(48); break; case THEME_RED: result = COLOR_PAIR(49); break; case THEME_RED_BOLD: result = COLOR_PAIR(49); break; case THEME_YELLOW: result = COLOR_PAIR(50); break; case THEME_YELLOW_BOLD: result = COLOR_PAIR(50); break; case THEME_BLUE: result = COLOR_PAIR(51); break; case THEME_BLUE_BOLD: result = COLOR_PAIR(51); break; case THEME_CYAN: result = COLOR_PAIR(52); break; case THEME_CYAN_BOLD: result = COLOR_PAIR(52); break; case THEME_BLACK: result = COLOR_PAIR(53); break; case THEME_BLACK_BOLD: result = COLOR_PAIR(53); break; case THEME_MAGENTA: result = COLOR_PAIR(54); break; case THEME_MAGENTA_BOLD: result = COLOR_PAIR(54); break; default: break; } if (g_hash_table_lookup(bold_items, GINT_TO_POINTER(attrs))) { return result | A_BOLD; } else { return result; } } profanity-0.4.7/src/config/theme.h000066400000000000000000000062231257755232500170640ustar00rootroot00000000000000/* * theme.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef THEME_H #define THEME_H #include "config.h" #include typedef enum { THEME_TEXT, THEME_TEXT_ME, THEME_TEXT_THEM, THEME_SPLASH, THEME_ERROR, THEME_INCOMING, THEME_INPUT_TEXT, THEME_TIME, THEME_TITLE_TEXT, THEME_TITLE_BRACKET, THEME_TITLE_UNENCRYPTED, THEME_TITLE_ENCRYPTED, THEME_TITLE_UNTRUSTED, THEME_TITLE_TRUSTED, THEME_TITLE_ONLINE, THEME_TITLE_OFFLINE, THEME_TITLE_AWAY, THEME_TITLE_CHAT, THEME_TITLE_DND, THEME_TITLE_XA, THEME_STATUS_TEXT, THEME_STATUS_BRACKET, THEME_STATUS_ACTIVE, THEME_STATUS_NEW, THEME_ME, THEME_THEM, THEME_ROOMINFO, THEME_ROOMMENTION, THEME_ONLINE, THEME_OFFLINE, THEME_AWAY, THEME_CHAT, THEME_DND, THEME_XA, THEME_TYPING, THEME_GONE, THEME_SUBSCRIBED, THEME_UNSUBSCRIBED, THEME_OTR_STARTED_TRUSTED, THEME_OTR_STARTED_UNTRUSTED, THEME_OTR_ENDED, THEME_OTR_TRUSTED, THEME_OTR_UNTRUSTED, THEME_OCCUPANTS_HEADER, THEME_ROSTER_HEADER, THEME_RECEIPT_SENT, THEME_NONE, THEME_WHITE, THEME_WHITE_BOLD, THEME_GREEN, THEME_GREEN_BOLD, THEME_RED, THEME_RED_BOLD, THEME_YELLOW, THEME_YELLOW_BOLD, THEME_BLUE, THEME_BLUE_BOLD, THEME_CYAN, THEME_CYAN_BOLD, THEME_BLACK, THEME_BLACK_BOLD, THEME_MAGENTA, THEME_MAGENTA_BOLD } theme_item_t; void theme_init(const char * const theme_name); void theme_init_colours(void); gboolean theme_load(const char * const theme_name); GSList* theme_list(void); void theme_close(void); int theme_attrs(theme_item_t attrs); theme_item_t theme_main_presence_attrs(const char * const presence); #endif profanity-0.4.7/src/contact.c000066400000000000000000000263651257755232500161540ustar00rootroot00000000000000/* * contact.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include "contact.h" #include "common.h" #include "resource.h" #include "tools/autocomplete.h" struct p_contact_t { char *barejid; gchar *barejid_collate_key; char *name; gchar *name_collate_key; GSList *groups; char *subscription; char *offline_message; gboolean pending_out; GDateTime *last_activity; GHashTable *available_resources; Autocomplete resource_ac; }; PContact p_contact_new(const char * const barejid, const char * const name, GSList *groups, const char * const subscription, const char * const offline_message, gboolean pending_out) { PContact contact = malloc(sizeof(struct p_contact_t)); contact->barejid = strdup(barejid); contact->barejid_collate_key = g_utf8_collate_key(contact->barejid, -1); if (name) { contact->name = strdup(name); contact->name_collate_key = g_utf8_collate_key(contact->name, -1); } else { contact->name = NULL; contact->name_collate_key = NULL; } contact->groups = groups; if (subscription) contact->subscription = strdup(subscription); else contact->subscription = strdup("none"); if (offline_message) contact->offline_message = strdup(offline_message); else contact->offline_message = NULL; contact->pending_out = pending_out; contact->last_activity = NULL; contact->available_resources = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)resource_destroy); contact->resource_ac = autocomplete_new(); return contact; } void p_contact_set_name(const PContact contact, const char * const name) { FREE_SET_NULL(contact->name); FREE_SET_NULL(contact->name_collate_key); if (name) { contact->name = strdup(name); contact->name_collate_key = g_utf8_collate_key(contact->name, -1); } } void p_contact_set_groups(const PContact contact, GSList *groups) { if (contact->groups) { g_slist_free_full(contact->groups, g_free); contact->groups = NULL; } contact->groups = groups; } gboolean p_contact_in_group(const PContact contact, const char * const group) { GSList *groups = contact->groups; while (groups) { if (strcmp(groups->data, group) == 0) { return TRUE; } groups = g_slist_next(groups); } return FALSE; } GSList * p_contact_groups(const PContact contact) { return contact->groups; } gboolean p_contact_remove_resource(PContact contact, const char * const resource) { gboolean result = g_hash_table_remove(contact->available_resources, resource); autocomplete_remove(contact->resource_ac, resource); return result; } void p_contact_free(PContact contact) { if (contact) { free(contact->barejid); free(contact->barejid_collate_key); free(contact->name); free(contact->name_collate_key); free(contact->subscription); free(contact->offline_message); if (contact->groups) { g_slist_free_full(contact->groups, g_free); } if (contact->last_activity) { g_date_time_unref(contact->last_activity); } g_hash_table_destroy(contact->available_resources); autocomplete_free(contact->resource_ac); free(contact); } } const char * p_contact_barejid(const PContact contact) { return contact->barejid; } const char * p_contact_barejid_collate_key(const PContact contact) { return contact->barejid_collate_key; } const char * p_contact_name(const PContact contact) { return contact->name; } const char * p_contact_name_collate_key(const PContact contact) { return contact->name_collate_key; } const char * p_contact_name_or_jid(const PContact contact) { if (contact->name) { return contact->name; } else { return contact->barejid; } } char * p_contact_create_display_string(const PContact contact, const char * const resource) { GString *result_str = g_string_new(""); // use nickname if exists const char *display_name = p_contact_name_or_jid(contact); g_string_append(result_str, display_name); // add resource if not default provided by profanity if (strcmp(resource, "__prof_default") != 0) { g_string_append(result_str, " ("); g_string_append(result_str, resource); g_string_append(result_str, ")"); } char *result = result_str->str; g_string_free(result_str, FALSE); return result; } static Resource * _highest_presence(Resource *first, Resource *second) { if (first->presence == RESOURCE_CHAT) { return first; } else if (second->presence == RESOURCE_CHAT) { return second; } else if (first->presence == RESOURCE_ONLINE) { return first; } else if (second->presence == RESOURCE_ONLINE) { return second; } else if (first->presence == RESOURCE_AWAY) { return first; } else if (second->presence == RESOURCE_AWAY) { return second; } else if (first->presence == RESOURCE_XA) { return first; } else if (second->presence == RESOURCE_XA) { return second; } else { return first; } } Resource * _get_most_available_resource(PContact contact) { // find resource with highest priority, if more than one, // use highest availability, in the following order: // chat // online // away // xa // dnd GList *resources = g_hash_table_get_values(contact->available_resources); GList *curr = resources; Resource *current = curr->data; Resource *highest = current; curr = g_list_next(curr); while (curr) { current = curr->data; // priority is same as current highest, choose presence if (current->priority == highest->priority) { highest = _highest_presence(highest, current); // priority higher than current highest, set new presence } else if (current->priority > highest->priority) { highest = current; } curr = g_list_next(curr); } g_list_free(resources); return highest; } const char * p_contact_presence(const PContact contact) { assert(contact != NULL); // no available resources, offline if (g_hash_table_size(contact->available_resources) == 0) { return "offline"; } Resource *resource = _get_most_available_resource(contact); return string_from_resource_presence(resource->presence); } const char * p_contact_status(const PContact contact) { assert(contact != NULL); // no available resources, use offline message if (g_hash_table_size(contact->available_resources) == 0) { return contact->offline_message; } Resource *resource = _get_most_available_resource(contact); return resource->status; } const char * p_contact_subscription(const PContact contact) { return contact->subscription; } gboolean p_contact_subscribed(const PContact contact) { if (contact->subscription == NULL) { return FALSE; } else if (strcmp(contact->subscription, "to") == 0) { return TRUE; } else if (strcmp(contact->subscription, "both") == 0) { return TRUE; } else { return FALSE; } } Resource * p_contact_get_resource(const PContact contact, const char * const resource) { return g_hash_table_lookup(contact->available_resources, resource); } gboolean p_contact_pending_out(const PContact contact) { return contact->pending_out; } GDateTime * p_contact_last_activity(const PContact contact) { return contact->last_activity; } GList * p_contact_get_available_resources(const PContact contact) { assert(contact != NULL); GList *resources = g_hash_table_get_values(contact->available_resources); GList *ordered = NULL; GList *curr_resource = resources; while (curr_resource) { Resource *resource = curr_resource->data; ordered = g_list_insert_sorted(ordered, resource, (GCompareFunc)resource_compare_availability); curr_resource = g_list_next(curr_resource); } g_list_free(resources); return ordered; } gboolean p_contact_is_available(const PContact contact) { // no available resources, unavailable if (g_hash_table_size(contact->available_resources) == 0) { return FALSE; } // if most available resource is CHAT or ONLINE, available Resource *most_available = _get_most_available_resource(contact); if ((most_available->presence == RESOURCE_ONLINE) || (most_available->presence == RESOURCE_CHAT)) { return TRUE; } else { return FALSE; } } gboolean p_contact_has_available_resource(const PContact contact) { return (g_hash_table_size(contact->available_resources) > 0); } void p_contact_set_presence(const PContact contact, Resource *resource) { g_hash_table_replace(contact->available_resources, strdup(resource->name), resource); autocomplete_add(contact->resource_ac, resource->name); } void p_contact_set_subscription(const PContact contact, const char * const subscription) { FREE_SET_NULL(contact->subscription); if (subscription) { contact->subscription = strdup(subscription); } } void p_contact_set_pending_out(const PContact contact, gboolean pending_out) { contact->pending_out = pending_out; } void p_contact_set_last_activity(const PContact contact, GDateTime *last_activity) { if (contact->last_activity) { g_date_time_unref(contact->last_activity); contact->last_activity = NULL; } if (last_activity) { contact->last_activity = g_date_time_ref(last_activity); } } Autocomplete p_contact_resource_ac(const PContact contact) { return contact->resource_ac; } void p_contact_resource_ac_reset(const PContact contact) { autocomplete_reset(contact->resource_ac); }profanity-0.4.7/src/contact.h000066400000000000000000000073131257755232500161510ustar00rootroot00000000000000/* * contact.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef CONTACT_H #define CONTACT_H #include "resource.h" #include "tools/autocomplete.h" typedef struct p_contact_t *PContact; PContact p_contact_new(const char * const barejid, const char * const name, GSList *groups, const char * const subscription, const char * const offline_message, gboolean pending_out); void p_contact_add_resource(PContact contact, Resource *resource); gboolean p_contact_remove_resource(PContact contact, const char * const resource); void p_contact_free(PContact contact); const char* p_contact_barejid(PContact contact); const char* p_contact_barejid_collate_key(PContact contact); const char* p_contact_name(PContact contact); const char* p_contact_name_collate_key(PContact contact); const char* p_contact_name_or_jid(const PContact contact); const char* p_contact_presence(PContact contact); const char* p_contact_status(PContact contact); const char* p_contact_subscription(const PContact contact); GList * p_contact_get_available_resources(const PContact contact); GDateTime* p_contact_last_activity(const PContact contact); gboolean p_contact_pending_out(const PContact contact); void p_contact_set_presence(const PContact contact, Resource *resource); void p_contact_set_status(const PContact contact, const char * const status); void p_contact_set_name(const PContact contact, const char * const name); void p_contact_set_subscription(const PContact contact, const char * const subscription); void p_contact_set_pending_out(const PContact contact, gboolean pending_out); void p_contact_set_last_activity(const PContact contact, GDateTime *last_activity); gboolean p_contact_is_available(const PContact contact); gboolean p_contact_has_available_resource(const PContact contact); Resource * p_contact_get_resource(const PContact contact, const char * const resource); void p_contact_set_groups(const PContact contact, GSList *groups); GSList * p_contact_groups(const PContact contact); gboolean p_contact_in_group(const PContact contact, const char * const group); gboolean p_contact_subscribed(const PContact contact); char * p_contact_create_display_string(const PContact contact, const char * const resource); Autocomplete p_contact_resource_ac(const PContact contact); void p_contact_resource_ac_reset(const PContact contact); #endif profanity-0.4.7/src/event/000077500000000000000000000000001257755232500154625ustar00rootroot00000000000000profanity-0.4.7/src/event/client_events.c000066400000000000000000000116121257755232500204710ustar00rootroot00000000000000/* * client_events.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include "config.h" #include "log.h" #include "ui/ui.h" #include "window_list.h" #include "xmpp/xmpp.h" #ifdef HAVE_LIBOTR #include "otr/otr.h" #endif #ifdef HAVE_LIBGPGME #include "pgp/gpg.h" #endif jabber_conn_status_t cl_ev_connect_jid(const char * const jid, const char * const passwd, const char * const altdomain, const int port) { cons_show("Connecting as %s", jid); return jabber_connect_with_details(jid, passwd, altdomain, port); } jabber_conn_status_t cl_ev_connect_account(ProfAccount *account) { char *jid = account_create_full_jid(account); cons_show("Connecting with account %s as %s", account->name, jid); free(jid); return jabber_connect_with_account(account); } void cl_ev_presence_send(const resource_presence_t presence_type, const char * const msg, const int idle) { char *signed_status = NULL; #ifdef HAVE_LIBGPGME char *account_name = jabber_get_account_name(); ProfAccount *account = accounts_get_account(account_name); if (account->pgp_keyid) { signed_status = p_gpg_sign(msg, account->pgp_keyid); } account_free(account); #endif presence_send(presence_type, msg, idle, signed_status); free(signed_status); } void cl_ev_send_msg(ProfChatWin *chatwin, const char * const msg) { chat_state_active(chatwin->state); // OTR suported, PGP supported #ifdef HAVE_LIBOTR #ifdef HAVE_LIBGPGME if (chatwin->pgp_send) { char *id = message_send_chat_pgp(chatwin->barejid, msg); chat_log_pgp_msg_out(chatwin->barejid, msg); ui_outgoing_chat_msg(chatwin, msg, id, PROF_MSG_PGP); free(id); } else { gboolean handled = otr_on_message_send(chatwin, msg); if (!handled) { char *id = message_send_chat(chatwin->barejid, msg); chat_log_msg_out(chatwin->barejid, msg); ui_outgoing_chat_msg(chatwin, msg, id, PROF_MSG_PLAIN); free(id); } } return; #endif #endif // OTR supported, PGP unsupported #ifdef HAVE_LIBOTR #ifndef HAVE_LIBGPGME gboolean handled = otr_on_message_send(chatwin, msg); if (!handled) { char *id = message_send_chat(chatwin->barejid, msg); chat_log_msg_out(chatwin->barejid, msg); ui_outgoing_chat_msg(chatwin, msg, id, PROF_MSG_PLAIN); free(id); } return; #endif #endif // OTR unsupported, PGP supported #ifndef HAVE_LIBOTR #ifdef HAVE_LIBGPGME if (chatwin->pgp_send) { char *id = message_send_chat_pgp(chatwin->barejid, msg); chat_log_pgp_msg_out(chatwin->barejid, msg); ui_outgoing_chat_msg(chatwin, msg, id, PROF_MSG_PGP); free(id); } else { char *id = message_send_chat(chatwin->barejid, msg); chat_log_msg_out(chatwin->barejid, msg); ui_outgoing_chat_msg(chatwin, msg, id, PROF_MSG_PLAIN); free(id); } return; #endif #endif // OTR unsupported, PGP unsupported #ifndef HAVE_LIBOTR #ifndef HAVE_LIBGPGME char *id = message_send_chat(chatwin->barejid, msg); chat_log_msg_out(chatwin->barejid, msg); ui_outgoing_chat_msg(chatwin, msg, id, PROF_MSG_PLAIN); free(id); return; #endif #endif } void cl_ev_send_muc_msg(ProfMucWin *mucwin, const char * const msg) { message_send_groupchat(mucwin->roomjid, msg); } void cl_ev_send_priv_msg(ProfPrivateWin *privwin, const char * const msg) { message_send_private(privwin->fulljid, msg); ui_outgoing_private_msg(privwin, msg); } profanity-0.4.7/src/event/client_events.h000066400000000000000000000040461257755232500205010ustar00rootroot00000000000000/* * client_events.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef CLIENT_EVENTS_H #define CLIENT_EVENTS_H jabber_conn_status_t cl_ev_connect_jid(const char * const jid, const char * const passwd, const char * const altdomain, const int port); jabber_conn_status_t cl_ev_connect_account(ProfAccount *account); void cl_ev_presence_send(const resource_presence_t presence_type, const char * const msg, const int idle); void cl_ev_send_msg(ProfChatWin *chatwin, const char * const msg); void cl_ev_send_muc_msg(ProfMucWin *mucwin, const char * const msg); void cl_ev_send_priv_msg(ProfPrivateWin *privwin, const char * const msg); #endifprofanity-0.4.7/src/event/server_events.c000066400000000000000000000441531257755232500205270ustar00rootroot00000000000000/* * server_events.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include "config.h" #include "chat_session.h" #include "log.h" #include "muc.h" #include "config/preferences.h" #include "config/account.h" #include "roster_list.h" #include "window_list.h" #ifdef HAVE_LIBOTR #include "otr/otr.h" #endif #ifdef HAVE_LIBGPGME #include "pgp/gpg.h" #endif #include "ui/ui.h" void sv_ev_login_account_success(char *account_name) { ProfAccount *account = accounts_get_account(account_name); #ifdef HAVE_LIBOTR otr_on_connect(account); #endif #ifdef HAVE_LIBGPGME p_gpg_on_connect(account->jid); #endif ui_handle_login_account_success(account); // attempt to rejoin rooms with passwords GList *curr = muc_rooms(); while (curr) { char *password = muc_password(curr->data); if (password) { char *nick = muc_nick(curr->data); presence_join_room(curr->data, nick, password); } curr = g_list_next(curr); } g_list_free(curr); log_info("%s logged in successfully", account->jid); account_free(account); } void sv_ev_roster_received(void) { if (prefs_get_boolean(PREF_ROSTER)) { ui_show_roster(); } } void sv_ev_lost_connection(void) { cons_show_error("Lost connection."); roster_clear(); muc_invites_clear(); chat_sessions_clear(); ui_disconnected(); #ifdef HAVE_LIBGPGME p_gpg_on_disconnect(); #endif } void sv_ev_failed_login(void) { cons_show_error("Login failed."); log_info("Login failed"); } void sv_ev_room_invite(jabber_invite_t invite_type, const char * const invitor, const char * const room, const char * const reason, const char * const password) { if (!muc_active(room) && !muc_invites_contain(room)) { cons_show_room_invite(invitor, room, reason); muc_invites_add(room, password); } } void sv_ev_room_broadcast(const char *const room_jid, const char * const message) { if (muc_roster_complete(room_jid)) { ui_room_broadcast(room_jid, message); } else { muc_pending_broadcasts_add(room_jid, message); } } void sv_ev_room_subject(const char * const room, const char * const nick, const char * const subject) { muc_set_subject(room, subject); if (muc_roster_complete(room)) { ui_room_subject(room, nick, subject); } } void sv_ev_room_history(const char * const room_jid, const char * const nick, GDateTime *timestamp, const char * const message) { ui_room_history(room_jid, nick, timestamp, message); } void sv_ev_room_message(const char * const room_jid, const char * const nick, const char * const message) { ui_room_message(room_jid, nick, message); if (prefs_get_boolean(PREF_GRLOG)) { Jid *jid = jid_create(jabber_get_fulljid()); groupchat_log_chat(jid->barejid, room_jid, nick, message); jid_destroy(jid); } } void sv_ev_incoming_private_message(const char * const fulljid, char *message) { ui_incoming_private_msg(fulljid, message, NULL); } void sv_ev_outgoing_carbon(char *barejid, char *message) { ui_outgoing_chat_msg_carbon(barejid, message); } void sv_ev_incoming_carbon(char *barejid, char *resource, char *message) { gboolean new_win = FALSE; ProfChatWin *chatwin = wins_get_chat(barejid); if (!chatwin) { ProfWin *window = wins_new_chat(barejid); chatwin = (ProfChatWin*)window; new_win = TRUE; } ui_incoming_msg(chatwin, resource, message, NULL, new_win, PROF_MSG_PLAIN); chat_log_msg_in(barejid, message, NULL); } #ifdef HAVE_LIBGPGME static void _sv_ev_incoming_pgp(ProfChatWin *chatwin, gboolean new_win, char *barejid, char *resource, char *message, char *pgp_message, GDateTime *timestamp) { char *decrypted = p_gpg_decrypt(pgp_message); if (decrypted) { ui_incoming_msg(chatwin, resource, decrypted, timestamp, new_win, PROF_MSG_PGP); chat_log_pgp_msg_in(barejid, decrypted, timestamp); chatwin->pgp_recv = TRUE; p_gpg_free_decrypted(decrypted); } else { ui_incoming_msg(chatwin, resource, message, timestamp, new_win, PROF_MSG_PLAIN); chat_log_msg_in(barejid, message, timestamp); chatwin->pgp_recv = FALSE; } } #endif #ifdef HAVE_LIBOTR static void _sv_ev_incoming_otr(ProfChatWin *chatwin, gboolean new_win, char *barejid, char *resource, char *message, GDateTime *timestamp) { gboolean decrypted = FALSE; char *otr_res = otr_on_message_recv(barejid, resource, message, &decrypted); if (otr_res) { if (decrypted) { ui_incoming_msg(chatwin, resource, otr_res, timestamp, new_win, PROF_MSG_OTR); chatwin->pgp_send = FALSE; } else { ui_incoming_msg(chatwin, resource, otr_res, timestamp, new_win, PROF_MSG_PLAIN); } chat_log_otr_msg_in(barejid, otr_res, decrypted, timestamp); otr_free_message(otr_res); chatwin->pgp_recv = FALSE; } } #endif #ifndef HAVE_LIBOTR static void _sv_ev_incoming_plain(ProfChatWin *chatwin, gboolean new_win, char *barejid, char *resource, char *message, GDateTime *timestamp) { ui_incoming_msg(chatwin, resource, message, timestamp, new_win, PROF_MSG_PLAIN); chat_log_msg_in(barejid, message, timestamp); chatwin->pgp_recv = FALSE; } #endif void sv_ev_incoming_message(char *barejid, char *resource, char *message, char *pgp_message, GDateTime *timestamp) { gboolean new_win = FALSE; ProfChatWin *chatwin = wins_get_chat(barejid); if (!chatwin) { ProfWin *window = wins_new_chat(barejid); chatwin = (ProfChatWin*)window; new_win = TRUE; } // OTR suported, PGP supported #ifdef HAVE_LIBOTR #ifdef HAVE_LIBGPGME if (pgp_message) { if (chatwin->is_otr) { win_println((ProfWin*)chatwin, 0, "PGP encrypted message received whilst in OTR session."); } else { // PROF_ENC_NONE, PROF_ENC_PGP _sv_ev_incoming_pgp(chatwin, new_win, barejid, resource, message, pgp_message, timestamp); } } else { _sv_ev_incoming_otr(chatwin, new_win, barejid, resource, message, timestamp); } return; #endif #endif // OTR supported, PGP unsupported #ifdef HAVE_LIBOTR #ifndef HAVE_LIBGPGME _sv_ev_incoming_otr(chatwin, new_win, barejid, resource, message, timestamp); return; #endif #endif // OTR unsupported, PGP supported #ifndef HAVE_LIBOTR #ifdef HAVE_LIBGPGME if (pgp_message) { _sv_ev_incoming_pgp(chatwin, new_win, barejid, resource, message, pgp_message, timestamp); } else { _sv_ev_incoming_plain(chatwin, new_win, barejid, resource, message, timestamp); } return; #endif #endif // OTR unsupported, PGP unsupported #ifndef HAVE_LIBOTR #ifndef HAVE_LIBGPGME _sv_ev_incoming_plain(chatwin, new_win, barejid, resource, message, timestamp); return; #endif #endif } void sv_ev_delayed_private_message(const char * const fulljid, char *message, GDateTime *timestamp) { ui_incoming_private_msg(fulljid, message, timestamp); } void sv_ev_message_receipt(char *barejid, char *id) { ui_message_receipt(barejid, id); } void sv_ev_typing(char *barejid, char *resource) { ui_contact_typing(barejid, resource); if (ui_chat_win_exists(barejid)) { chat_session_recipient_typing(barejid, resource); } } void sv_ev_paused(char *barejid, char *resource) { if (ui_chat_win_exists(barejid)) { chat_session_recipient_paused(barejid, resource); } } void sv_ev_inactive(char *barejid, char *resource) { if (ui_chat_win_exists(barejid)) { chat_session_recipient_inactive(barejid, resource); } } void sv_ev_gone(const char * const barejid, const char * const resource) { ui_recipient_gone(barejid, resource); if (ui_chat_win_exists(barejid)) { chat_session_recipient_gone(barejid, resource); } } void sv_ev_activity(const char * const barejid, const char * const resource, gboolean send_states) { if (ui_chat_win_exists(barejid)) { chat_session_recipient_active(barejid, resource, send_states); } } void sv_ev_subscription(const char *barejid, jabber_subscr_t type) { switch (type) { case PRESENCE_SUBSCRIBE: /* TODO: auto-subscribe if needed */ cons_show("Received authorization request from %s", barejid); log_info("Received authorization request from %s", barejid); ui_print_system_msg_from_recipient(barejid, "Authorization request, type '/sub allow' to accept or '/sub deny' to reject"); if (prefs_get_boolean(PREF_NOTIFY_SUB)) { notify_subscription(barejid); } break; case PRESENCE_SUBSCRIBED: cons_show("Subscription received from %s", barejid); log_info("Subscription received from %s", barejid); ui_print_system_msg_from_recipient(barejid, "Subscribed"); break; case PRESENCE_UNSUBSCRIBED: cons_show("%s deleted subscription", barejid); log_info("%s deleted subscription", barejid); ui_print_system_msg_from_recipient(barejid, "Unsubscribed"); break; default: /* unknown type */ break; } } void sv_ev_contact_offline(char *barejid, char *resource, char *status) { gboolean updated = roster_contact_offline(barejid, resource, status); if (resource && updated) { ui_contact_offline(barejid, resource, status); } rosterwin_roster(); chat_session_remove(barejid); } void sv_ev_contact_online(char *barejid, Resource *resource, GDateTime *last_activity, char *pgpsig) { gboolean updated = roster_update_presence(barejid, resource, last_activity); if (updated) { ui_contact_online(barejid, resource, last_activity); } #ifdef HAVE_LIBGPGME if (pgpsig) { p_gpg_verify(barejid, pgpsig); } #endif rosterwin_roster(); chat_session_remove(barejid); } void sv_ev_leave_room(const char * const room) { muc_leave(room); ui_leave_room(room); } void sv_ev_room_destroy(const char * const room) { muc_leave(room); ui_room_destroy(room); } void sv_ev_room_destroyed(const char * const room, const char * const new_jid, const char * const password, const char * const reason) { muc_leave(room); ui_room_destroyed(room, reason, new_jid, password); } void sv_ev_room_kicked(const char * const room, const char * const actor, const char * const reason) { muc_leave(room); ui_room_kicked(room, actor, reason); } void sv_ev_room_banned(const char * const room, const char * const actor, const char * const reason) { muc_leave(room); ui_room_banned(room, actor, reason); } void sv_ev_room_occupant_offline(const char * const room, const char * const nick, const char * const show, const char * const status) { muc_roster_remove(room, nick); char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); if (g_strcmp0(muc_status_pref, "none") != 0) { ui_room_member_offline(room, nick); } prefs_free_string(muc_status_pref); occupantswin_occupants(room); } void sv_ev_room_occupent_kicked(const char * const room, const char * const nick, const char * const actor, const char * const reason) { muc_roster_remove(room, nick); ui_room_member_kicked(room, nick, actor, reason); occupantswin_occupants(room); } void sv_ev_room_occupent_banned(const char * const room, const char * const nick, const char * const actor, const char * const reason) { muc_roster_remove(room, nick); ui_room_member_banned(room, nick, actor, reason); occupantswin_occupants(room); } void sv_ev_roster_update(const char * const barejid, const char * const name, GSList *groups, const char * const subscription, gboolean pending_out) { roster_update(barejid, name, groups, subscription, pending_out); rosterwin_roster(); } void sv_ev_xmpp_stanza(const char * const msg) { ui_handle_stanza(msg); } void sv_ev_muc_self_online(const char * const room, const char * const nick, gboolean config_required, const char * const role, const char * const affiliation, const char * const actor, const char * const reason, const char * const jid, const char * const show, const char * const status) { muc_roster_add(room, nick, jid, role, affiliation, show, status); char *old_role = muc_role_str(room); char *old_affiliation = muc_affiliation_str(room); muc_set_role(room, role); muc_set_affiliation(room, affiliation); // handle self nick change if (muc_nick_change_pending(room)) { muc_nick_change_complete(room, nick); ui_room_nick_change(room, nick); // handle roster complete } else if (!muc_roster_complete(room)) { if (muc_autojoin(room)) { ui_room_join(room, FALSE); } else { ui_room_join(room, TRUE); } iq_room_info_request(room, FALSE); muc_invites_remove(room); muc_roster_set_complete(room); // show roster if occupants list disabled by default if (!prefs_get_boolean(PREF_OCCUPANTS)) { GList *occupants = muc_roster(room); ui_room_roster(room, occupants, NULL); g_list_free(occupants); } char *subject = muc_subject(room); if (subject) { ui_room_subject(room, NULL, subject); } GList *pending_broadcasts = muc_pending_broadcasts(room); if (pending_broadcasts) { GList *curr = pending_broadcasts; while (curr) { ui_room_broadcast(room, curr->data); curr = g_list_next(curr); } } // room configuration required if (config_required) { muc_set_requires_config(room, TRUE); ui_room_requires_config(room); } // check for change in role/affiliation } else { if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { // both changed if ((g_strcmp0(role, old_role) != 0) && (g_strcmp0(affiliation, old_affiliation) != 0)) { ui_room_role_and_affiliation_change(room, role, affiliation, actor, reason); // role changed } else if (g_strcmp0(role, old_role) != 0) { ui_room_role_change(room, role, actor, reason); // affiliation changed } else if (g_strcmp0(affiliation, old_affiliation) != 0) { ui_room_affiliation_change(room, affiliation, actor, reason); } } } occupantswin_occupants(room); } void sv_ev_muc_occupant_online(const char * const room, const char * const nick, const char * const jid, const char * const role, const char * const affiliation, const char * const actor, const char * const reason, const char * const show, const char * const status) { Occupant *occupant = muc_roster_item(room, nick); const char *old_role = NULL; const char *old_affiliation = NULL; if (occupant) { old_role = muc_occupant_role_str(occupant); old_affiliation = muc_occupant_affiliation_str(occupant); } gboolean updated = muc_roster_add(room, nick, jid, role, affiliation, show, status); // not yet finished joining room if (!muc_roster_complete(room)) { return; } // handle nickname change char *old_nick = muc_roster_nick_change_complete(room, nick); if (old_nick) { ui_room_member_nick_change(room, old_nick, nick); free(old_nick); occupantswin_occupants(room); return; } // joined room if (!occupant) { char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); if (g_strcmp0(muc_status_pref, "none") != 0) { ui_room_member_online(room, nick, role, affiliation, show, status); } prefs_free_string(muc_status_pref); occupantswin_occupants(room); return; } // presence updated if (updated) { char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); if (g_strcmp0(muc_status_pref, "all") == 0) { ui_room_member_presence(room, nick, show, status); } prefs_free_string(muc_status_pref); occupantswin_occupants(room); // presence unchanged, check for role/affiliation change } else { if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { // both changed if ((g_strcmp0(role, old_role) != 0) && (g_strcmp0(affiliation, old_affiliation) != 0)) { ui_room_occupant_role_and_affiliation_change(room, nick, role, affiliation, actor, reason); // role changed } else if (g_strcmp0(role, old_role) != 0) { ui_room_occupant_role_change(room, nick, role, actor, reason); // affiliation changed } else if (g_strcmp0(affiliation, old_affiliation) != 0) { ui_room_occupant_affiliation_change(room, nick, affiliation, actor, reason); } } occupantswin_occupants(room); } } profanity-0.4.7/src/event/server_events.h000066400000000000000000000116251257755232500205320ustar00rootroot00000000000000/* * server_events.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef SERVER_EVENTS_H #define SERVER_EVENTS_H #include "xmpp/xmpp.h" void sv_ev_login_account_success(char *account_name); void sv_ev_lost_connection(void); void sv_ev_failed_login(void); void sv_ev_room_invite(jabber_invite_t invite_type, const char * const invitor, const char * const room, const char * const reason, const char * const password); void sv_ev_room_broadcast(const char *const room_jid, const char * const message); void sv_ev_room_subject(const char * const room, const char * const nick, const char * const subject); void sv_ev_room_history(const char * const room_jid, const char * const nick, GDateTime *timestamp, const char * const message); void sv_ev_room_message(const char * const room_jid, const char * const nick, const char * const message); void sv_ev_incoming_message(char *barejid, char *resource, char *message, char *pgp_message, GDateTime *timestamp); void sv_ev_incoming_private_message(const char * const fulljid, char *message); void sv_ev_delayed_private_message(const char * const fulljid, char *message, GDateTime *timestamp); void sv_ev_typing(char *barejid, char *resource); void sv_ev_paused(char *barejid, char *resource); void sv_ev_inactive(char *barejid, char *resource); void sv_ev_activity(char *barejid, char *resource, gboolean send_states); void sv_ev_gone(const char * const barejid, const char * const resource); void sv_ev_subscription(const char *from, jabber_subscr_t type); void sv_ev_message_receipt(char *barejid, char *id); void sv_ev_contact_offline(char *contact, char *resource, char *status); void sv_ev_contact_online(char *contact, Resource *resource, GDateTime *last_activity, char *pgpkey); void sv_ev_leave_room(const char * const room); void sv_ev_room_destroy(const char * const room); void sv_ev_room_occupant_offline(const char * const room, const char * const nick, const char * const show, const char * const status); void sv_ev_room_destroyed(const char * const room, const char * const new_jid, const char * const password, const char * const reason); void sv_ev_room_kicked(const char * const room, const char * const actor, const char * const reason); void sv_ev_room_occupent_kicked(const char * const room, const char * const nick, const char * const actor, const char * const reason); void sv_ev_room_banned(const char * const room, const char * const actor, const char * const reason); void sv_ev_room_occupent_banned(const char * const room, const char * const nick, const char * const actor, const char * const reason); void sv_ev_outgoing_carbon(char *barejid, char *message); void sv_ev_incoming_carbon(char *barejid, char *resource, char *message); void sv_ev_xmpp_stanza(const char * const msg); void sv_ev_muc_self_online(const char * const room, const char * const nick, gboolean config_required, const char * const role, const char * const affiliation, const char * const actor, const char * const reason, const char * const jid, const char * const show, const char * const status); void sv_ev_muc_occupant_online(const char * const room, const char * const nick, const char * const jid, const char * const role, const char * const affiliation, const char * const actor, const char * const reason, const char * const show_str, const char * const status_str); void sv_ev_roster_update(const char * const barejid, const char * const name, GSList *groups, const char * const subscription, gboolean pending_out); void sv_ev_roster_received(void); #endif profanity-0.4.7/src/event/ui_events.c000066400000000000000000000035131257755232500176310ustar00rootroot00000000000000/* * ui_events.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "ui/ui.h" #include "window_list.h" void ui_ev_focus_win(ProfWin *win) { if (!wins_is_current(win)) { ui_switch_win(win); } } ProfChatWin* ui_ev_new_chat_win(const char * const barejid) { return ui_new_chat_win(barejid); } ProfPrivateWin* ui_ev_new_private_win(const char * const fulljid) { return ui_new_private_win(fulljid); } profanity-0.4.7/src/event/ui_events.h000066400000000000000000000032631257755232500176400ustar00rootroot00000000000000/* * ui_events.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef UI_EVENTS_H #define UI_EVENTS_H void ui_ev_focus_win(ProfWin *win); ProfChatWin* ui_ev_new_chat_win(const char * const barejid); ProfPrivateWin* ui_ev_new_private_win(const char * const fulljid); #endifprofanity-0.4.7/src/jid.c000066400000000000000000000117371257755232500152640ustar00rootroot00000000000000/* * jid.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include "jid.h" #include "common.h" Jid * jid_create(const gchar * const str) { Jid *result = NULL; /* if str is NULL g_strdup returns NULL */ gchar *trimmed = g_strdup(str); if (trimmed == NULL) { return NULL; } if (strlen(trimmed) == 0) { g_free(trimmed); return NULL; } if (g_str_has_prefix(trimmed, "/") || g_str_has_prefix(trimmed, "@")) { g_free(trimmed); return NULL; } if (!g_utf8_validate(trimmed, -1, NULL)) { g_free(trimmed); return NULL; } result = malloc(sizeof(struct jid_t)); result->str = NULL; result->localpart = NULL; result->domainpart = NULL; result->resourcepart = NULL; result->barejid = NULL; result->fulljid = NULL; gchar *atp = g_utf8_strchr(trimmed, -1, '@'); gchar *slashp = g_utf8_strchr(trimmed, -1, '/'); gchar *domain_start = trimmed; if (atp) { result->localpart = g_utf8_substring(trimmed, 0, g_utf8_pointer_to_offset(trimmed, atp)); domain_start = atp + 1; } if (slashp) { result->resourcepart = g_strdup(slashp + 1); result->domainpart = g_utf8_substring(domain_start, 0, g_utf8_pointer_to_offset(domain_start, slashp)); char *barejidraw = g_utf8_substring(trimmed, 0, g_utf8_pointer_to_offset(trimmed, slashp)); result->barejid = g_utf8_strdown(barejidraw, -1); result->fulljid = g_strdup(trimmed); g_free(barejidraw); } else { result->domainpart = g_strdup(domain_start); result->barejid = g_utf8_strdown(trimmed, -1); } if (result->domainpart == NULL) { jid_destroy(result); return NULL; } result->str = trimmed; return result; } Jid * jid_create_from_bare_and_resource(const char * const room, const char * const nick) { Jid *result; char *jid = create_fulljid(room, nick); result = jid_create(jid); free(jid); return result; } void jid_destroy(Jid *jid) { if (jid) { g_free(jid->str); g_free(jid->localpart); g_free(jid->domainpart); g_free(jid->resourcepart); g_free(jid->barejid); g_free(jid->fulljid); free(jid); } } gboolean jid_is_valid_room_form(Jid *jid) { return (jid->fulljid != NULL); } /* * Given a barejid, and resourcepart, create and return a full JID of the form * barejid/resourcepart * Will return a newly created string that must be freed by the caller */ char * create_fulljid(const char * const barejid, const char * const resource) { gchar *barejidlower = g_utf8_strdown(barejid, -1); GString *full_jid = g_string_new(barejidlower); g_free(barejidlower); g_string_append(full_jid, "/"); g_string_append(full_jid, resource); char *result = strdup(full_jid->str); g_string_free(full_jid, TRUE); return result; } /* * Get the nickname part of the full JID, e.g. * Full JID = "test@conference.server/person" * returns "person" */ char * get_nick_from_full_jid(const char * const full_room_jid) { char **tokens = g_strsplit(full_room_jid, "/", 0); char *nick_part = NULL; if (tokens) { if (tokens[0] && tokens[1]) { nick_part = strdup(tokens[1]); } g_strfreev(tokens); } return nick_part; } /* * get the fulljid, fall back to the barejid */ char * jid_fulljid_or_barejid(Jid *jid) { if (jid->fulljid) { return jid->fulljid; } else { return jid->barejid; } } profanity-0.4.7/src/jid.h000066400000000000000000000041001257755232500152530ustar00rootroot00000000000000/* * jid.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef JID_H #define JID_H #include struct jid_t { char *str; char *localpart; char *domainpart; char *resourcepart; char *barejid; char *fulljid; }; typedef struct jid_t Jid; Jid * jid_create(const gchar * const str); Jid * jid_create_from_bare_and_resource(const char * const room, const char * const nick); void jid_destroy(Jid *jid); gboolean jid_is_valid_room_form(Jid *jid); char * create_fulljid(const char * const barejid, const char * const resource); char * get_nick_from_full_jid(const char * const full_room_jid); char * jid_fulljid_or_barejid(Jid *jid); #endif profanity-0.4.7/src/log.c000066400000000000000000000521771257755232500153020ustar00rootroot00000000000000/* * log.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include #include #include #include "glib.h" #include "glib/gstdio.h" #include "log.h" #include "common.h" #include "config/preferences.h" #include "xmpp/xmpp.h" #define PROF "prof" static FILE *logp; GString *mainlogfile; static GTimeZone *tz; static GDateTime *dt; static log_level_t level_filter; static GHashTable *logs; static GHashTable *groupchat_logs; static GDateTime *session_started; enum { STDERR_BUFSIZE = 4000, STDERR_RETRY_NR = 5, }; static int stderr_inited; static log_level_t stderr_level; static int stderr_pipe[2]; static char *stderr_buf; static GString *stderr_msg; struct dated_chat_log { gchar *filename; GDateTime *date; }; static gboolean _log_roll_needed(struct dated_chat_log *dated_log); static struct dated_chat_log * _create_log(const char * const other, const char * const login); static struct dated_chat_log * _create_groupchat_log(char *room, const char * const login); static void _free_chat_log(struct dated_chat_log *dated_log); static gboolean _key_equals(void *key1, void *key2); static char * _get_log_filename(const char * const other, const char * const login, GDateTime *dt, gboolean create); static char * _get_groupchat_log_filename(const char * const room, const char * const login, GDateTime *dt, gboolean create); static gchar * _get_chatlog_dir(void); static gchar * _get_main_log_file(void); static void _rotate_log_file(void); static char* _log_string_from_level(log_level_t level); static void _chat_log_chat(const char * const login, const char * const other, const gchar * const msg, chat_log_direction_t direction, GDateTime *timestamp); void log_debug(const char * const msg, ...) { va_list arg; va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); log_msg(PROF_LEVEL_DEBUG, PROF, fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); } void log_info(const char * const msg, ...) { va_list arg; va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); log_msg(PROF_LEVEL_INFO, PROF, fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); } void log_warning(const char * const msg, ...) { va_list arg; va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); log_msg(PROF_LEVEL_WARN, PROF, fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); } void log_error(const char * const msg, ...) { va_list arg; va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); log_msg(PROF_LEVEL_ERROR, PROF, fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); } void log_init(log_level_t filter) { level_filter = filter; tz = g_time_zone_new_local(); gchar *log_file = _get_main_log_file(); logp = fopen(log_file, "a"); g_chmod(log_file, S_IRUSR | S_IWUSR); mainlogfile = g_string_new(log_file); free(log_file); } void log_reinit(void) { log_close(); log_init(level_filter); } char * get_log_file_location(void) { return mainlogfile->str; } log_level_t log_get_filter(void) { return level_filter; } void log_close(void) { g_string_free(mainlogfile, TRUE); g_time_zone_unref(tz); if (logp) { fclose(logp); } } void log_msg(log_level_t level, const char * const area, const char * const msg) { if (level >= level_filter && logp) { dt = g_date_time_new_now(tz); char *level_str = _log_string_from_level(level); gchar *date_fmt = g_date_time_format(dt, "%d/%m/%Y %H:%M:%S"); fprintf(logp, "%s: %s: %s: %s\n", date_fmt, area, level_str, msg); g_date_time_unref(dt); fflush(logp); g_free(date_fmt); if (prefs_get_boolean(PREF_LOG_ROTATE)) { long result = ftell(logp); if (result != -1 && result >= prefs_get_max_log_size()) { _rotate_log_file(); } } } } log_level_t log_level_from_string(char *log_level) { assert(log_level != NULL); if (strcmp(log_level, "DEBUG") == 0) { return PROF_LEVEL_DEBUG; } else if (strcmp(log_level, "INFO") == 0) { return PROF_LEVEL_INFO; } else if (strcmp(log_level, "WARN") == 0) { return PROF_LEVEL_WARN; } else if (strcmp(log_level, "ERROR") == 0) { return PROF_LEVEL_ERROR; } else { // default to info return PROF_LEVEL_INFO; } } static void _rotate_log_file(void) { gchar *log_file = _get_main_log_file(); size_t len = strlen(log_file); char *log_file_new = malloc(len + 3); strncpy(log_file_new, log_file, len); log_file_new[len] = '.'; log_file_new[len+1] = '1'; log_file_new[len+2] = 0; log_close(); rename(log_file, log_file_new); log_init(log_get_filter()); free(log_file_new); free(log_file); log_info("Log has been rotated"); } void chat_log_init(void) { session_started = g_date_time_new_now_local(); log_info("Initialising chat logs"); logs = g_hash_table_new_full(g_str_hash, (GEqualFunc) _key_equals, free, (GDestroyNotify)_free_chat_log); } void groupchat_log_init(void) { log_info("Initialising groupchat logs"); groupchat_logs = g_hash_table_new_full(g_str_hash, (GEqualFunc) _key_equals, free, (GDestroyNotify)_free_chat_log); } void chat_log_msg_out(const char * const barejid, const char * const msg) { if (prefs_get_boolean(PREF_CHLOG)) { const char *jid = jabber_get_fulljid(); Jid *jidp = jid_create(jid); _chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL); jid_destroy(jidp); } } void chat_log_otr_msg_out(const char * const barejid, const char * const msg) { if (prefs_get_boolean(PREF_CHLOG)) { const char *jid = jabber_get_fulljid(); Jid *jidp = jid_create(jid); char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); if (strcmp(pref_otr_log, "on") == 0) { _chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL); } else if (strcmp(pref_otr_log, "redact") == 0) { _chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_OUT_LOG, NULL); } prefs_free_string(pref_otr_log); jid_destroy(jidp); } } void chat_log_pgp_msg_out(const char * const barejid, const char * const msg) { if (prefs_get_boolean(PREF_CHLOG)) { const char *jid = jabber_get_fulljid(); Jid *jidp = jid_create(jid); char *pref_pgp_log = prefs_get_string(PREF_PGP_LOG); if (strcmp(pref_pgp_log, "on") == 0) { _chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL); } else if (strcmp(pref_pgp_log, "redact") == 0) { _chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_OUT_LOG, NULL); } prefs_free_string(pref_pgp_log); jid_destroy(jidp); } } void chat_log_otr_msg_in(const char * const barejid, const char * const msg, gboolean was_decrypted, GDateTime *timestamp) { if (prefs_get_boolean(PREF_CHLOG)) { const char *jid = jabber_get_fulljid(); Jid *jidp = jid_create(jid); char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); if (!was_decrypted || (strcmp(pref_otr_log, "on") == 0)) { _chat_log_chat(jidp->barejid, barejid, msg, PROF_IN_LOG, timestamp); } else if (strcmp(pref_otr_log, "redact") == 0) { _chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_IN_LOG, timestamp); } prefs_free_string(pref_otr_log); jid_destroy(jidp); } } void chat_log_pgp_msg_in(const char * const barejid, const char * const msg, GDateTime *timestamp) { if (prefs_get_boolean(PREF_CHLOG)) { const char *jid = jabber_get_fulljid(); Jid *jidp = jid_create(jid); char *pref_pgp_log = prefs_get_string(PREF_PGP_LOG); if (strcmp(pref_pgp_log, "on") == 0) { _chat_log_chat(jidp->barejid, barejid, msg, PROF_IN_LOG, timestamp); } else if (strcmp(pref_pgp_log, "redact") == 0) { _chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_IN_LOG, timestamp); } prefs_free_string(pref_pgp_log); jid_destroy(jidp); } } void chat_log_msg_in(const char * const barejid, const char * const msg, GDateTime *timestamp) { if (prefs_get_boolean(PREF_CHLOG)) { const char *jid = jabber_get_fulljid(); Jid *jidp = jid_create(jid); _chat_log_chat(jidp->barejid, barejid, msg, PROF_IN_LOG, timestamp); jid_destroy(jidp); } } static void _chat_log_chat(const char * const login, const char * const other, const char * const msg, chat_log_direction_t direction, GDateTime *timestamp) { struct dated_chat_log *dated_log = g_hash_table_lookup(logs, other); // no log for user if (dated_log == NULL) { dated_log = _create_log(other, login); g_hash_table_insert(logs, strdup(other), dated_log); // log exists but needs rolling } else if (_log_roll_needed(dated_log)) { dated_log = _create_log(other, login); g_hash_table_replace(logs, strdup(other), dated_log); } if (timestamp == NULL) { timestamp = g_date_time_new_now_local(); } else { g_date_time_ref(timestamp); } gchar *date_fmt = g_date_time_format(timestamp, "%H:%M:%S"); FILE *logp = fopen(dated_log->filename, "a"); g_chmod(dated_log->filename, S_IRUSR | S_IWUSR); if (logp) { if (direction == PROF_IN_LOG) { if (strncmp(msg, "/me ", 4) == 0) { fprintf(logp, "%s - *%s %s\n", date_fmt, other, msg + 4); } else { fprintf(logp, "%s - %s: %s\n", date_fmt, other, msg); } } else { if (strncmp(msg, "/me ", 4) == 0) { fprintf(logp, "%s - *me %s\n", date_fmt, msg + 4); } else { fprintf(logp, "%s - me: %s\n", date_fmt, msg); } } fflush(logp); int result = fclose(logp); if (result == EOF) { log_error("Error closing file %s, errno = %d", dated_log->filename, errno); } } g_free(date_fmt); g_date_time_unref(timestamp); } void groupchat_log_chat(const gchar * const login, const gchar * const room, const gchar * const nick, const gchar * const msg) { gchar *room_copy = strdup(room); struct dated_chat_log *dated_log = g_hash_table_lookup(groupchat_logs, room_copy); // no log for room if (dated_log == NULL) { dated_log = _create_groupchat_log(room_copy, login); g_hash_table_insert(groupchat_logs, room_copy, dated_log); // log exists but needs rolling } else if (_log_roll_needed(dated_log)) { dated_log = _create_groupchat_log(room_copy, login); g_hash_table_replace(logs, room_copy, dated_log); } GDateTime *dt = g_date_time_new_now_local(); gchar *date_fmt = g_date_time_format(dt, "%H:%M:%S"); FILE *logp = fopen(dated_log->filename, "a"); g_chmod(dated_log->filename, S_IRUSR | S_IWUSR); if (logp) { if (strncmp(msg, "/me ", 4) == 0) { fprintf(logp, "%s - *%s %s\n", date_fmt, nick, msg + 4); } else { fprintf(logp, "%s - %s: %s\n", date_fmt, nick, msg); } fflush(logp); int result = fclose(logp); if (result == EOF) { log_error("Error closing file %s, errno = %d", dated_log->filename, errno); } } g_free(date_fmt); g_date_time_unref(dt); } GSList * chat_log_get_previous(const gchar * const login, const gchar * const recipient) { GSList *history = NULL; GDateTime *now = g_date_time_new_now_local(); GDateTime *log_date = g_date_time_new(tz, g_date_time_get_year(session_started), g_date_time_get_month(session_started), g_date_time_get_day_of_month(session_started), g_date_time_get_hour(session_started), g_date_time_get_minute(session_started), g_date_time_get_second(session_started)); // get data from all logs from the day the session was started to today while (g_date_time_compare(log_date, now) != 1) { char *filename = _get_log_filename(recipient, login, log_date, FALSE); FILE *logp = fopen(filename, "r"); if (logp) { GString *header = g_string_new(""); g_string_append_printf(header, "%d/%d/%d:", g_date_time_get_day_of_month(log_date), g_date_time_get_month(log_date), g_date_time_get_year(log_date)); history = g_slist_append(history, header->str); g_string_free(header, FALSE); char *line; while ((line = prof_getline(logp)) != NULL) { history = g_slist_append(history, line); } fclose(logp); } free(filename); GDateTime *next = g_date_time_add_days(log_date, 1); g_date_time_unref(log_date); log_date = next; } g_date_time_unref(log_date); g_date_time_unref(now); return history; } void chat_log_close(void) { g_hash_table_destroy(logs); g_hash_table_destroy(groupchat_logs); g_date_time_unref(session_started); } static struct dated_chat_log * _create_log(const char * const other, const char * const login) { GDateTime *now = g_date_time_new_now_local(); char *filename = _get_log_filename(other, login, now, TRUE); struct dated_chat_log *new_log = malloc(sizeof(struct dated_chat_log)); new_log->filename = strdup(filename); new_log->date = now; free(filename); return new_log; } static struct dated_chat_log * _create_groupchat_log(char *room, const char * const login) { GDateTime *now = g_date_time_new_now_local(); char *filename = _get_groupchat_log_filename(room, login, now, TRUE); struct dated_chat_log *new_log = malloc(sizeof(struct dated_chat_log)); new_log->filename = strdup(filename); new_log->date = now; free(filename); return new_log; } static gboolean _log_roll_needed(struct dated_chat_log *dated_log) { gboolean result = FALSE; GDateTime *now = g_date_time_new_now_local(); if (g_date_time_get_day_of_year(dated_log->date) != g_date_time_get_day_of_year(now)) { result = TRUE; } g_date_time_unref(now); return result; } static void _free_chat_log(struct dated_chat_log *dated_log) { if (dated_log) { if (dated_log->filename) { g_free(dated_log->filename); dated_log->filename = NULL; } if (dated_log->date) { g_date_time_unref(dated_log->date); dated_log->date = NULL; } free(dated_log); } } static gboolean _key_equals(void *key1, void *key2) { gchar *str1 = (gchar *) key1; gchar *str2 = (gchar *) key2; return (g_strcmp0(str1, str2) == 0); } static char * _get_log_filename(const char * const other, const char * const login, GDateTime *dt, gboolean create) { gchar *chatlogs_dir = _get_chatlog_dir(); GString *log_file = g_string_new(chatlogs_dir); free(chatlogs_dir); gchar *login_dir = str_replace(login, "@", "_at_"); g_string_append_printf(log_file, "/%s", login_dir); if (create) { create_dir(log_file->str); } free(login_dir); gchar *other_file = str_replace(other, "@", "_at_"); g_string_append_printf(log_file, "/%s", other_file); if (create) { create_dir(log_file->str); } free(other_file); gchar *date = g_date_time_format(dt, "/%Y_%m_%d.log"); g_string_append(log_file, date); g_free(date); char *result = strdup(log_file->str); g_string_free(log_file, TRUE); return result; } static char * _get_groupchat_log_filename(const char * const room, const char * const login, GDateTime *dt, gboolean create) { gchar *chatlogs_dir = _get_chatlog_dir(); GString *log_file = g_string_new(chatlogs_dir); g_free(chatlogs_dir); gchar *login_dir = str_replace(login, "@", "_at_"); g_string_append_printf(log_file, "/%s", login_dir); if (create) { create_dir(log_file->str); } free(login_dir); g_string_append(log_file, "/rooms"); if (create) { create_dir(log_file->str); } gchar *room_file = str_replace(room, "@", "_at_"); g_string_append_printf(log_file, "/%s", room_file); if (create) { create_dir(log_file->str); } free(room_file); gchar *date = g_date_time_format(dt, "/%Y_%m_%d.log"); g_string_append(log_file, date); g_free(date); char *result = strdup(log_file->str); g_string_free(log_file, TRUE); return result; } static gchar * _get_chatlog_dir(void) { gchar *xdg_data = xdg_get_data_home(); GString *chatlogs_dir = g_string_new(xdg_data); g_string_append(chatlogs_dir, "/profanity/chatlogs"); gchar *result = strdup(chatlogs_dir->str); free(xdg_data); g_string_free(chatlogs_dir, TRUE); return result; } static gchar * _get_main_log_file(void) { gchar *xdg_data = xdg_get_data_home(); GString *logfile = g_string_new(xdg_data); g_string_append(logfile, "/profanity/logs/profanity"); if (!prefs_get_boolean(PREF_LOG_SHARED)) { g_string_append_printf(logfile, "%d", getpid()); } g_string_append(logfile, ".log"); gchar *result = strdup(logfile->str); free(xdg_data); g_string_free(logfile, TRUE); return result; } static char* _log_string_from_level(log_level_t level) { switch (level) { case PROF_LEVEL_ERROR: return "ERR"; case PROF_LEVEL_WARN: return "WRN"; case PROF_LEVEL_INFO: return "INF"; case PROF_LEVEL_DEBUG: return "DBG"; default: return "LOG"; } } void log_stderr_handler(void) { GString * const s = stderr_msg; char * const buf = stderr_buf; ssize_t size; int retry = 0; int i; if (!stderr_inited) return; do { size = read(stderr_pipe[0], buf, STDERR_BUFSIZE); if (size == -1 && errno == EINTR && retry++ < STDERR_RETRY_NR) continue; if (size <= 0 || retry++ >= STDERR_RETRY_NR) break; for (i = 0; i < size; ++i) { if (buf[i] == '\n') { log_msg(stderr_level, "stderr", s->str); g_string_assign(s, ""); } else g_string_append_c(s, buf[i]); } } while (1); if (s->len > 0 && s->str[0] != '\0') { log_msg(stderr_level, "stderr", s->str); g_string_assign(s, ""); } } void log_stderr_init(log_level_t level) { int rc; int flags; rc = pipe(stderr_pipe); if (rc != 0) goto err; flags = fcntl(stderr_pipe[0], F_GETFL); rc = fcntl(stderr_pipe[0], F_SETFL, flags | O_NONBLOCK); if (rc != 0) goto err_close; close(STDERR_FILENO); rc = dup2(stderr_pipe[1], STDERR_FILENO); if (rc < 0) goto err_close; stderr_buf = malloc(STDERR_BUFSIZE); stderr_msg = g_string_sized_new(STDERR_BUFSIZE); stderr_level = level; stderr_inited = 1; if (stderr_buf == NULL || stderr_msg == NULL) { errno = ENOMEM; goto err_free; } return; err_free: if (stderr_msg != NULL) g_string_free(stderr_msg, TRUE); free(stderr_buf); err_close: close(stderr_pipe[0]); close(stderr_pipe[1]); err: stderr_inited = 0; log_error("Unable to init stderr log handler: %s", strerror(errno)); } void log_stderr_close(void) { if (!stderr_inited) return; /* handle remaining logs before close */ log_stderr_handler(); stderr_inited = 0; free(stderr_buf); g_string_free(stderr_msg, TRUE); close(stderr_pipe[0]); close(stderr_pipe[1]); } profanity-0.4.7/src/log.h000066400000000000000000000061741257755232500153030ustar00rootroot00000000000000/* * log.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef LOG_H #define LOG_H #include "glib.h" // log levels typedef enum { PROF_LEVEL_DEBUG, PROF_LEVEL_INFO, PROF_LEVEL_WARN, PROF_LEVEL_ERROR } log_level_t; typedef enum { PROF_IN_LOG, PROF_OUT_LOG } chat_log_direction_t; void log_init(log_level_t filter); log_level_t log_get_filter(void); void log_close(void); void log_reinit(void); char * get_log_file_location(void); void log_debug(const char * const msg, ...); void log_info(const char * const msg, ...); void log_warning(const char * const msg, ...); void log_error(const char * const msg, ...); void log_msg(log_level_t level, const char * const area, const char * const msg); log_level_t log_level_from_string(char *log_level); void log_stderr_init(log_level_t level); void log_stderr_close(void); void log_stderr_handler(void); void chat_log_init(void); void chat_log_msg_out(const char * const barejid, const char * const msg); void chat_log_otr_msg_out(const char * const barejid, const char * const msg); void chat_log_pgp_msg_out(const char * const barejid, const char * const msg); void chat_log_msg_in(const char * const barejid, const char * const msg, GDateTime *timestamp); void chat_log_otr_msg_in(const char * const barejid, const char * const msg, gboolean was_decrypted, GDateTime *timestamp); void chat_log_pgp_msg_in(const char * const barejid, const char * const msg, GDateTime *timestamp); void chat_log_close(void); GSList * chat_log_get_previous(const gchar * const login, const gchar * const recipient); void groupchat_log_init(void); void groupchat_log_chat(const gchar * const login, const gchar * const room, const gchar * const nick, const gchar * const msg); #endif profanity-0.4.7/src/main.c000066400000000000000000000105261257755232500154350ustar00rootroot00000000000000/* * main.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include "config.h" #ifdef HAVE_GIT_VERSION #include "gitversion.h" #endif #include "profanity.h" #include "command/command.h" static gboolean disable_tls = FALSE; static gboolean version = FALSE; static char *log = "INFO"; static char *account_name = NULL; int main(int argc, char **argv) { if (argc == 2 && g_strcmp0(argv[1], "docgen") == 0 && g_strcmp0(PACKAGE_STATUS, "development") == 0) { command_docgen(); return 0; } static GOptionEntry entries[] = { { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Show version information", NULL }, { "disable-tls", 'd', 0, G_OPTION_ARG_NONE, &disable_tls, "Disable TLS", NULL }, { "account", 'a', 0, G_OPTION_ARG_STRING, &account_name, "Auto connect to an account on startup" }, { "log",'l', 0, G_OPTION_ARG_STRING, &log, "Set logging levels, DEBUG, INFO (default), WARN, ERROR", "LEVEL" }, { NULL } }; GError *error = NULL; GOptionContext *context; context = g_option_context_new(NULL); g_option_context_add_main_entries(context, entries, NULL); if (!g_option_context_parse(context, &argc, &argv, &error)) { g_print("%s\n", error->message); g_option_context_free(context); g_error_free(error); return 1; } g_option_context_free(context); if (version == TRUE) { if (strcmp(PACKAGE_STATUS, "development") == 0) { #ifdef HAVE_GIT_VERSION g_print("Profanity, version %sdev.%s.%s\n", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION); #else g_print("Profanity, version %sdev\n", PACKAGE_VERSION); #endif } else { g_print("Profanity, version %s\n", PACKAGE_VERSION); } g_print("Copyright (C) 2012 - 2015 James Booth <%s>.\n", PACKAGE_BUGREPORT); g_print("License GPLv3+: GNU GPL version 3 or later \n"); g_print("\n"); g_print("This is free software; you are free to change and redistribute it.\n"); g_print("There is NO WARRANTY, to the extent permitted by law.\n"); g_print("\n"); g_print("Build information:\n"); gboolean notify_enabled = FALSE; #ifdef HAVE_OSXNOTIFY notify_enabled = TRUE; #endif #ifdef HAVE_LIBNOTIFY notify_enabled = TRUE; #endif #ifdef PLATFORM_CYGWIN notify_enabled = TRUE; #endif if (notify_enabled) { g_print("Desktop notification support: Enabled\n"); } else { g_print("Desktop notification support: Disabled\n"); } #ifdef HAVE_LIBOTR g_print("OTR support: Enabled\n"); #else g_print("OTR support: Disabled\n"); #endif #ifdef HAVE_LIBGPGME g_print("PGP support: Enabled\n"); #else g_print("PGP support: Disabled\n"); #endif return 0; } prof_run(disable_tls, log, account_name); return 0; } profanity-0.4.7/src/muc.c000066400000000000000000000622651257755232500153040ustar00rootroot00000000000000/* * muc.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include "contact.h" #include "common.h" #include "jid.h" #include "tools/autocomplete.h" #include "ui/ui.h" #include "window_list.h" #include "muc.h" typedef struct _muc_room_t { char *room; // e.g. test@conference.server char *nick; // e.g. Some User muc_role_t role; muc_affiliation_t affiliation; char *password; char *subject; char *autocomplete_prefix; gboolean pending_config; GList *pending_broadcasts; gboolean autojoin; gboolean pending_nick_change; GHashTable *roster; Autocomplete nick_ac; Autocomplete jid_ac; GHashTable *nick_changes; gboolean roster_received; muc_member_type_t member_type; } ChatRoom; GHashTable *rooms = NULL; GHashTable *invite_passwords = NULL; Autocomplete invite_ac; static void _free_room(ChatRoom *room); static gint _compare_occupants(Occupant *a, Occupant *b); static muc_role_t _role_from_string(const char * const role); static muc_affiliation_t _affiliation_from_string(const char * const affiliation); static char* _role_to_string(muc_role_t role); static char* _affiliation_to_string(muc_affiliation_t affiliation); static Occupant* _muc_occupant_new(const char *const nick, const char * const jid, muc_role_t role, muc_affiliation_t affiliation, resource_presence_t presence, const char * const status); static void _occupant_free(Occupant *occupant); void muc_init(void) { invite_ac = autocomplete_new(); rooms = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_room); invite_passwords = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); } void muc_close(void) { autocomplete_free(invite_ac); g_hash_table_destroy(rooms); g_hash_table_destroy(invite_passwords); rooms = NULL; invite_passwords = NULL; } void muc_invites_add(const char * const room, const char * const password) { autocomplete_add(invite_ac, room); if (password) { g_hash_table_replace(invite_passwords, strdup(room), strdup(password)); } } void muc_invites_remove(const char * const room) { autocomplete_remove(invite_ac, room); g_hash_table_remove(invite_passwords, room); } gint muc_invites_count(void) { return autocomplete_length(invite_ac); } GSList * muc_invites(void) { return autocomplete_create_list(invite_ac); } char * muc_invite_password(const char * const room) { return g_hash_table_lookup(invite_passwords, room); } gboolean muc_invites_contain(const char * const room) { GSList *invites = autocomplete_create_list(invite_ac); GSList *curr = invites; while (curr) { if (strcmp(curr->data, room) == 0) { g_slist_free_full(invites, g_free); return TRUE; } else { curr = g_slist_next(curr); } } g_slist_free_full(invites, g_free); return FALSE; } void muc_invites_reset_ac(void) { autocomplete_reset(invite_ac); } char * muc_invites_find(const char * const search_str) { return autocomplete_complete(invite_ac, search_str, TRUE); } void muc_invites_clear(void) { autocomplete_clear(invite_ac); if (invite_passwords) { g_hash_table_remove_all(invite_passwords); } } void muc_join(const char * const room, const char * const nick, const char * const password, gboolean autojoin) { ChatRoom *new_room = malloc(sizeof(ChatRoom)); new_room->room = strdup(room); new_room->nick = strdup(nick); new_room->role = MUC_ROLE_NONE; new_room->affiliation = MUC_AFFILIATION_NONE; new_room->autocomplete_prefix = NULL; if (password) { new_room->password = strdup(password); } else { new_room->password = NULL; } new_room->subject = NULL; new_room->pending_broadcasts = NULL; new_room->pending_config = FALSE; new_room->roster = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_occupant_free); new_room->nick_ac = autocomplete_new(); new_room->jid_ac = autocomplete_new(); new_room->nick_changes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); new_room->roster_received = FALSE; new_room->pending_nick_change = FALSE; new_room->autojoin = autojoin; new_room->member_type = MUC_MEMBER_TYPE_UNKNOWN; g_hash_table_insert(rooms, strdup(room), new_room); } void muc_leave(const char * const room) { g_hash_table_remove(rooms, room); } gboolean muc_requires_config(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->pending_config; } else { return FALSE; } } void muc_set_requires_config(const char * const room, gboolean val) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { chat_room->pending_config = val; } } void muc_set_features(const char * const room, GSList *features) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room && features) { if (g_slist_find_custom(features, "muc_membersonly", (GCompareFunc)g_strcmp0)) { chat_room->member_type = MUC_MEMBER_TYPE_MEMBERS_ONLY; } else { chat_room->member_type = MUC_MEMBER_TYPE_PUBLIC; } } } /* * Returns TRUE if the user is currently in the room */ gboolean muc_active(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); return (chat_room != NULL); } gboolean muc_autojoin(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->autojoin; } else { return FALSE; } } void muc_set_subject(const char * const room, const char * const subject) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { free(chat_room->subject); if (subject) { chat_room->subject = strdup(subject); } else { chat_room->subject = NULL; } } } char * muc_subject(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->subject; } else { return NULL; } } void muc_pending_broadcasts_add(const char * const room, const char * const message) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { chat_room->pending_broadcasts = g_list_append(chat_room->pending_broadcasts, strdup(message)); } } GList * muc_pending_broadcasts(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->pending_broadcasts; } else { return NULL; } } char * muc_old_nick(const char * const room, const char * const new_nick) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room && chat_room->pending_nick_change) { return g_hash_table_lookup(chat_room->nick_changes, new_nick); } else { return NULL; } } /* * Flag that the user has sent a nick change to the service * and is awaiting the response */ void muc_nick_change_start(const char * const room, const char * const new_nick) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { chat_room->pending_nick_change = TRUE; g_hash_table_insert(chat_room->nick_changes, strdup(new_nick), strdup(chat_room->nick)); } } /* * Returns TRUE if the room is awaiting the result of a * nick change */ gboolean muc_nick_change_pending(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->pending_nick_change; } else { return FALSE; } } /* * Change the current nick name for the room, call once * the service has responded */ void muc_nick_change_complete(const char * const room, const char * const nick) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { g_hash_table_remove(chat_room->roster, chat_room->nick); autocomplete_remove(chat_room->nick_ac, chat_room->nick); free(chat_room->nick); chat_room->nick = strdup(nick); chat_room->pending_nick_change = FALSE; g_hash_table_remove(chat_room->nick_changes, nick); } } /* * Return a list of room names * The contents of the list are owned by the chat room and should not be * modified or freed. */ GList * muc_rooms(void) { return g_hash_table_get_keys(rooms); } /* * Return current users nickname for the specified room * The nickname is owned by the chat room and should not be modified or freed */ char * muc_nick(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->nick; } else { return NULL; } } /* * Return password for the specified room * The password is owned by the chat room and should not be modified or freed */ char * muc_password(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->password; } else { return NULL; } } /* * Returns TRUE if the specified nick exists in the room's roster */ gboolean muc_roster_contains_nick(const char * const room, const char * const nick) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { Occupant *occupant = g_hash_table_lookup(chat_room->roster, nick); return (occupant != NULL); } else { return FALSE; } } /* * Add a new chat room member to the room's roster */ gboolean muc_roster_add(const char * const room, const char * const nick, const char * const jid, const char * const role, const char * const affiliation, const char * const show, const char * const status) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); gboolean updated = FALSE; resource_presence_t new_presence = resource_presence_from_string(show); if (chat_room) { Occupant *old = g_hash_table_lookup(chat_room->roster, nick); if (!old) { updated = TRUE; autocomplete_add(chat_room->nick_ac, nick); } else if (old->presence != new_presence || (g_strcmp0(old->status, status) != 0)) { updated = TRUE; } resource_presence_t presence = resource_presence_from_string(show); muc_role_t role_t = _role_from_string(role); muc_affiliation_t affiliation_t = _affiliation_from_string(affiliation); Occupant *occupant = _muc_occupant_new(nick, jid, role_t, affiliation_t, presence, status); g_hash_table_replace(chat_room->roster, strdup(nick), occupant); if (jid) { Jid *jidp = jid_create(jid); if (jidp->barejid) { autocomplete_add(chat_room->jid_ac, jidp->barejid); } jid_destroy(jidp); } } return updated; } /* * Remove a room member from the room's roster */ void muc_roster_remove(const char * const room, const char * const nick) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { g_hash_table_remove(chat_room->roster, nick); autocomplete_remove(chat_room->nick_ac, nick); } } Occupant * muc_roster_item(const char * const room, const char * const nick) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { Occupant *occupant = g_hash_table_lookup(chat_room->roster, nick); return occupant; } else { return NULL; } } /* * Return a list of PContacts representing the room members in the room's roster */ GList * muc_roster(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { GList *result = NULL; GList *occupants = g_hash_table_get_values(chat_room->roster); GList *curr = occupants; while (curr) { result = g_list_insert_sorted(result, curr->data, (GCompareFunc)_compare_occupants); curr = g_list_next(curr); } g_list_free(occupants); return result; } else { return NULL; } } /* * Return a Autocomplete representing the room member's in the roster */ Autocomplete muc_roster_ac(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->nick_ac; } else { return NULL; } } Autocomplete muc_roster_jid_ac(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->jid_ac; } else { return NULL; } } /* * Set to TRUE when the rooms roster has been fully received */ void muc_roster_set_complete(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { chat_room->roster_received = TRUE; } } /* * Returns TRUE id the rooms roster has been fully received */ gboolean muc_roster_complete(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->roster_received; } else { return FALSE; } } gboolean muc_occupant_available(Occupant *occupant) { return (occupant->presence == RESOURCE_ONLINE || occupant->presence == RESOURCE_CHAT); } const char * muc_occupant_affiliation_str(Occupant *occupant) { return _affiliation_to_string(occupant->affiliation); } const char * muc_occupant_role_str(Occupant *occupant) { return _role_to_string(occupant->role); } GSList * muc_occupants_by_role(const char * const room, muc_role_t role) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { GSList *result = NULL; GHashTableIter iter; gpointer key; gpointer value; g_hash_table_iter_init(&iter, chat_room->roster); while (g_hash_table_iter_next(&iter, &key, &value)) { Occupant *occupant = (Occupant *)value; if (occupant->role == role) { result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_occupants); } } return result; } else { return NULL; } } GSList * muc_occupants_by_affiliation(const char * const room, muc_affiliation_t affiliation) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { GSList *result = NULL; GHashTableIter iter; gpointer key; gpointer value; g_hash_table_iter_init(&iter, chat_room->roster); while (g_hash_table_iter_next(&iter, &key, &value)) { Occupant *occupant = (Occupant *)value; if (occupant->affiliation == affiliation) { result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_occupants); } } return result; } else { return NULL; } } /* * Remove the old_nick from the roster, and flag that a pending nickname change * is in progress */ void muc_occupant_nick_change_start(const char * const room, const char * const new_nick, const char * const old_nick) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { g_hash_table_insert(chat_room->nick_changes, strdup(new_nick), strdup(old_nick)); muc_roster_remove(room, old_nick); } } /* * Complete the pending nick name change for a contact in the room's roster * The new nick name will be added to the roster * The old nick name will be returned in a new string which must be freed by * the caller */ char * muc_roster_nick_change_complete(const char * const room, const char * const nick) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { char *old_nick = g_hash_table_lookup(chat_room->nick_changes, nick); if (old_nick) { char *old_nick_cpy = strdup(old_nick); g_hash_table_remove(chat_room->nick_changes, nick); return old_nick_cpy; } } return NULL; } char * muc_autocomplete(ProfWin *window, const char * const input) { if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); ChatRoom *chat_room = g_hash_table_lookup(rooms, mucwin->roomjid); if (chat_room && chat_room->nick_ac) { const char * search_str = NULL; gchar *last_space = g_strrstr(input, " "); if (!last_space) { search_str = input; if (!chat_room->autocomplete_prefix) { chat_room->autocomplete_prefix = strdup(""); } } else { search_str = last_space+1; if (!chat_room->autocomplete_prefix) { chat_room->autocomplete_prefix = g_strndup(input, search_str - input); } } char *result = autocomplete_complete(chat_room->nick_ac, search_str, FALSE); if (result) { GString *replace_with = g_string_new(chat_room->autocomplete_prefix); g_string_append(replace_with, result); if (!last_space || (*(last_space+1) == '\0')) { g_string_append(replace_with, ": "); } g_free(result); result = replace_with->str; g_string_free(replace_with, FALSE); return result; } } } return NULL; } void muc_jid_autocomplete_reset(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { if (chat_room->jid_ac) { autocomplete_reset(chat_room->jid_ac); } } } void muc_jid_autocomplete_add_all(const char * const room, GSList *jids) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { if (chat_room->jid_ac) { GSList *curr_jid = jids; while (curr_jid) { char *jid = curr_jid->data; Jid *jidp = jid_create(jid); if (jidp) { if (jidp->barejid) { autocomplete_add(chat_room->jid_ac, jidp->barejid); } } jid_destroy(jidp); curr_jid = g_slist_next(curr_jid); } } } } void muc_autocomplete_reset(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { if (chat_room->nick_ac) { autocomplete_reset(chat_room->nick_ac); } if (chat_room->autocomplete_prefix) { free(chat_room->autocomplete_prefix); chat_room->autocomplete_prefix = NULL; } } } char * muc_role_str(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return _role_to_string(chat_room->role); } else { return "none"; } } void muc_set_role(const char * const room, const char * const role) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { chat_room->role = _role_from_string(role); } } char * muc_affiliation_str(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return _affiliation_to_string(chat_room->affiliation); } else { return "none"; } } void muc_set_affiliation(const char * const room, const char * const affiliation) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { chat_room->affiliation = _affiliation_from_string(affiliation); } } muc_member_type_t muc_member_type(const char * const room) { ChatRoom *chat_room = g_hash_table_lookup(rooms, room); if (chat_room) { return chat_room->member_type; } else { return MUC_MEMBER_TYPE_UNKNOWN; } } static void _free_room(ChatRoom *room) { if (room) { free(room->room); free(room->nick); free(room->subject); free(room->password); free(room->autocomplete_prefix); if (room->roster) { g_hash_table_destroy(room->roster); } autocomplete_free(room->nick_ac); autocomplete_free(room->jid_ac); if (room->nick_changes) { g_hash_table_destroy(room->nick_changes); } if (room->pending_broadcasts) { g_list_free_full(room->pending_broadcasts, free); } free(room); } } static gint _compare_occupants(Occupant *a, Occupant *b) { const char * utf8_str_a = a->nick_collate_key; const char * utf8_str_b = b->nick_collate_key; gint result = g_strcmp0(utf8_str_a, utf8_str_b); return result; } static muc_role_t _role_from_string(const char * const role) { if (role) { if (g_strcmp0(role, "visitor") == 0) { return MUC_ROLE_VISITOR; } else if (g_strcmp0(role, "participant") == 0) { return MUC_ROLE_PARTICIPANT; } else if (g_strcmp0(role, "moderator") == 0) { return MUC_ROLE_MODERATOR; } else { return MUC_ROLE_NONE; } } else { return MUC_ROLE_NONE; } } static char * _role_to_string(muc_role_t role) { char *result = NULL; switch (role) { case MUC_ROLE_NONE: result = "none"; break; case MUC_ROLE_VISITOR: result = "visitor"; break; case MUC_ROLE_PARTICIPANT: result = "participant"; break; case MUC_ROLE_MODERATOR: result = "moderator"; break; default: result = "none"; break; } return result; } static muc_affiliation_t _affiliation_from_string(const char * const affiliation) { if (affiliation) { if (g_strcmp0(affiliation, "outcast") == 0) { return MUC_AFFILIATION_OUTCAST; } else if (g_strcmp0(affiliation, "member") == 0) { return MUC_AFFILIATION_MEMBER; } else if (g_strcmp0(affiliation, "admin") == 0) { return MUC_AFFILIATION_ADMIN; } else if (g_strcmp0(affiliation, "owner") == 0) { return MUC_AFFILIATION_OWNER; } else { return MUC_AFFILIATION_NONE; } } else { return MUC_AFFILIATION_NONE; } } static char * _affiliation_to_string(muc_affiliation_t affiliation) { char *result = NULL; switch (affiliation) { case MUC_AFFILIATION_NONE: result = "none"; break; case MUC_AFFILIATION_OUTCAST: result = "outcast"; break; case MUC_AFFILIATION_MEMBER: result = "member"; break; case MUC_AFFILIATION_ADMIN: result = "admin"; break; case MUC_AFFILIATION_OWNER: result = "owner"; break; default: result = "none"; break; } return result; } static Occupant* _muc_occupant_new(const char *const nick, const char * const jid, muc_role_t role, muc_affiliation_t affiliation, resource_presence_t presence, const char * const status) { Occupant *occupant = malloc(sizeof(Occupant)); if (nick) { occupant->nick = strdup(nick); occupant->nick_collate_key = g_utf8_collate_key(occupant->nick, -1); } else { occupant->nick = NULL; occupant->nick_collate_key = NULL; } if (jid) { occupant->jid = strdup(jid); } else { occupant->jid = NULL; } occupant->presence = presence; if (status) { occupant->status = strdup(status); } else { occupant->status = NULL; } occupant->role = role; occupant->affiliation = affiliation; return occupant; } static void _occupant_free(Occupant *occupant) { if (occupant) { free(occupant->nick); free(occupant->nick_collate_key); free(occupant->jid); free(occupant->status); free(occupant); occupant = NULL; } } profanity-0.4.7/src/muc.h000066400000000000000000000130671257755232500153050ustar00rootroot00000000000000/* * muc.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef MUC_H #define MUC_H #include #include "contact.h" #include "jid.h" #include "tools/autocomplete.h" #include "ui/win_types.h" typedef enum { MUC_ROLE_NONE, MUC_ROLE_VISITOR, MUC_ROLE_PARTICIPANT, MUC_ROLE_MODERATOR } muc_role_t; typedef enum { MUC_AFFILIATION_NONE, MUC_AFFILIATION_OUTCAST, MUC_AFFILIATION_MEMBER, MUC_AFFILIATION_ADMIN, MUC_AFFILIATION_OWNER } muc_affiliation_t; typedef enum { MUC_MEMBER_TYPE_UNKNOWN, MUC_MEMBER_TYPE_PUBLIC, MUC_MEMBER_TYPE_MEMBERS_ONLY } muc_member_type_t; typedef struct _muc_occupant_t { char *nick; gchar *nick_collate_key; char *jid; muc_role_t role; muc_affiliation_t affiliation; resource_presence_t presence; char *status; } Occupant; void muc_init(void); void muc_close(void); void muc_join(const char * const room, const char * const nick, const char * const password, gboolean autojoin); void muc_leave(const char * const room); gboolean muc_active(const char * const room); gboolean muc_autojoin(const char * const room); GList* muc_rooms(void); void muc_set_features(const char * const room, GSList *features); char* muc_nick(const char * const room); char* muc_password(const char * const room); void muc_nick_change_start(const char * const room, const char * const new_nick); void muc_nick_change_complete(const char * const room, const char * const nick); gboolean muc_nick_change_pending(const char * const room); char* muc_old_nick(const char * const room, const char * const new_nick); gboolean muc_roster_contains_nick(const char * const room, const char * const nick); gboolean muc_roster_complete(const char * const room); gboolean muc_roster_add(const char * const room, const char * const nick, const char * const jid, const char * const role, const char * const affiliation, const char * const show, const char * const status); void muc_roster_remove(const char * const room, const char * const nick); void muc_roster_set_complete(const char * const room); GList * muc_roster(const char * const room); Autocomplete muc_roster_ac(const char * const room); Autocomplete muc_roster_jid_ac(const char * const room); void muc_jid_autocomplete_reset(const char * const room); void muc_jid_autocomplete_add_all(const char * const room, GSList *jids); Occupant* muc_roster_item(const char * const room, const char * const nick); gboolean muc_occupant_available(Occupant *occupant); const char * muc_occupant_affiliation_str(Occupant *occupant); const char * muc_occupant_role_str(Occupant *occupant); GSList * muc_occupants_by_role(const char * const room, muc_role_t role); GSList * muc_occupants_by_affiliation(const char * const room, muc_affiliation_t affiliation); void muc_occupant_nick_change_start(const char * const room, const char * const new_nick, const char * const old_nick); char* muc_roster_nick_change_complete(const char * const room, const char * const nick); void muc_invites_add(const char * const room, const char * const password); void muc_invites_remove(const char * const room); gint muc_invites_count(void); GSList* muc_invites(void); gboolean muc_invites_contain(const char * const room); void muc_invites_reset_ac(void); char* muc_invites_find(const char * const search_str); void muc_invites_clear(void); char* muc_invite_password(const char * const room); void muc_set_subject(const char * const room, const char * const subject); char* muc_subject(const char * const room); void muc_pending_broadcasts_add(const char * const room, const char * const message); GList * muc_pending_broadcasts(const char * const room); char* muc_autocomplete(ProfWin *window, const char * const input); void muc_autocomplete_reset(const char * const room); gboolean muc_requires_config(const char * const room); void muc_set_requires_config(const char * const room, gboolean val); void muc_set_role(const char * const room, const char * const role); void muc_set_affiliation(const char * const room, const char * const affiliation); char *muc_role_str(const char * const room); char *muc_affiliation_str(const char * const room); muc_member_type_t muc_member_type(const char * const room); #endif profanity-0.4.7/src/otr/000077500000000000000000000000001257755232500151455ustar00rootroot00000000000000profanity-0.4.7/src/otr/otr.c000066400000000000000000000520531257755232500161220ustar00rootroot00000000000000/* * otr.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include #include "otr/otr.h" #include "otr/otrlib.h" #include "log.h" #include "roster_list.h" #include "contact.h" #include "ui/ui.h" #include "config/preferences.h" #include "chat_session.h" #define PRESENCE_ONLINE 1 #define PRESENCE_OFFLINE 0 #define PRESENCE_UNKNOWN -1 static OtrlUserState user_state; static OtrlMessageAppOps ops; static char *jid; static gboolean data_loaded; static GHashTable *smp_initiators; OtrlUserState otr_userstate(void) { return user_state; } OtrlMessageAppOps * otr_messageops(void) { return &ops; } GHashTable * otr_smpinitators(void) { return smp_initiators; } // ops callbacks static OtrlPolicy cb_policy(void *opdata, ConnContext *context) { return otrlib_policy(); } static int cb_is_logged_in(void *opdata, const char *accountname, const char *protocol, const char *recipient) { PContact contact = roster_get_contact(recipient); // not in roster if (contact == NULL) { return PRESENCE_ONLINE; } // not subscribed if (p_contact_subscribed(contact) == FALSE) { return PRESENCE_ONLINE; } // subscribed if (g_strcmp0(p_contact_presence(contact), "offline") == 0) { return PRESENCE_OFFLINE; } else { return PRESENCE_ONLINE; } } static void cb_inject_message(void *opdata, const char *accountname, const char *protocol, const char *recipient, const char *message) { char *id = message_send_chat_otr(recipient, message); free(id); } static void cb_write_fingerprints(void *opdata) { gcry_error_t err = 0; gchar *data_home = xdg_get_data_home(); GString *basedir = g_string_new(data_home); free(data_home); gchar *account_dir = str_replace(jid, "@", "_at_"); g_string_append(basedir, "/profanity/otr/"); g_string_append(basedir, account_dir); g_string_append(basedir, "/"); free(account_dir); GString *fpsfilename = g_string_new(basedir->str); g_string_append(fpsfilename, "fingerprints.txt"); err = otrl_privkey_write_fingerprints(user_state, fpsfilename->str); if (!err == GPG_ERR_NO_ERROR) { log_error("Failed to write fingerprints file"); cons_show_error("Failed to create fingerprints file"); } g_string_free(basedir, TRUE); g_string_free(fpsfilename, TRUE); } static void cb_gone_secure(void *opdata, ConnContext *context) { ui_gone_secure(context->username, otr_is_trusted(context->username)); } char * otr_libotr_version(void) { return OTRL_VERSION; } char * otr_start_query(void) { return otrlib_start_query(); } void otr_init(void) { log_info("Initialising OTR"); OTRL_INIT; jid = NULL; ops.policy = cb_policy; ops.is_logged_in = cb_is_logged_in; ops.inject_message = cb_inject_message; ops.write_fingerprints = cb_write_fingerprints; ops.gone_secure = cb_gone_secure; otrlib_init_ops(&ops); otrlib_init_timer(); smp_initiators = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); data_loaded = FALSE; } void otr_shutdown(void) { if (jid) { free(jid); jid = NULL; } } void otr_poll(void) { otrlib_poll(); } void otr_on_connect(ProfAccount *account) { if (jid) { free(jid); } jid = strdup(account->jid); log_info("Loading OTR key for %s", jid); gchar *data_home = xdg_get_data_home(); GString *basedir = g_string_new(data_home); free(data_home); gchar *account_dir = str_replace(jid, "@", "_at_"); g_string_append(basedir, "/profanity/otr/"); g_string_append(basedir, account_dir); g_string_append(basedir, "/"); free(account_dir); if (!mkdir_recursive(basedir->str)) { log_error("Could not create %s for account %s.", basedir->str, jid); cons_show_error("Could not create %s for account %s.", basedir->str, jid); g_string_free(basedir, TRUE); return; } user_state = otrl_userstate_create(); gcry_error_t err = 0; GString *keysfilename = g_string_new(basedir->str); g_string_append(keysfilename, "keys.txt"); if (!g_file_test(keysfilename->str, G_FILE_TEST_IS_REGULAR)) { log_info("No private key file found %s", keysfilename->str); data_loaded = FALSE; } else { log_info("Loading OTR private key %s", keysfilename->str); err = otrl_privkey_read(user_state, keysfilename->str); if (!err == GPG_ERR_NO_ERROR) { g_string_free(basedir, TRUE); g_string_free(keysfilename, TRUE); log_error("Failed to load private key"); return; } else { log_info("Loaded private key"); data_loaded = TRUE; } } GString *fpsfilename = g_string_new(basedir->str); g_string_append(fpsfilename, "fingerprints.txt"); if (!g_file_test(fpsfilename->str, G_FILE_TEST_IS_REGULAR)) { log_info("No fingerprints file found %s", fpsfilename->str); data_loaded = FALSE; } else { log_info("Loading fingerprints %s", fpsfilename->str); err = otrl_privkey_read_fingerprints(user_state, fpsfilename->str, NULL, NULL); if (!err == GPG_ERR_NO_ERROR) { g_string_free(basedir, TRUE); g_string_free(keysfilename, TRUE); g_string_free(fpsfilename, TRUE); log_error("Failed to load fingerprints"); return; } else { log_info("Loaded fingerprints"); data_loaded = TRUE; } } if (data_loaded) { cons_show("Loaded OTR private key for %s", jid); } g_string_free(basedir, TRUE); g_string_free(keysfilename, TRUE); g_string_free(fpsfilename, TRUE); return; } char* otr_on_message_recv(const char * const barejid, const char * const resource, const char * const message, gboolean *decrypted) { prof_otrpolicy_t policy = otr_get_policy(barejid); char *whitespace_base = strstr(message, OTRL_MESSAGE_TAG_BASE); //check for OTR whitespace (opportunistic or always) if (policy == PROF_OTRPOLICY_OPPORTUNISTIC || policy == PROF_OTRPOLICY_ALWAYS) { if (whitespace_base) { if (strstr(message, OTRL_MESSAGE_TAG_V2) || strstr(message, OTRL_MESSAGE_TAG_V1)) { // Remove whitespace pattern for proper display in UI // Handle both BASE+TAGV1/2(16+8) and BASE+TAGV1+TAGV2(16+8+8) int tag_length = 24; if (strstr(message, OTRL_MESSAGE_TAG_V2) && strstr(message, OTRL_MESSAGE_TAG_V1)) { tag_length = 32; } memmove(whitespace_base, whitespace_base+tag_length, tag_length); char *otr_query_message = otr_start_query(); cons_show("OTR Whitespace pattern detected. Attempting to start OTR session..."); char *id = message_send_chat_otr(barejid, otr_query_message); free(id); } } } char *newmessage = otr_decrypt_message(barejid, message, decrypted); if (!newmessage) { // internal OTR message return NULL; } if (policy == PROF_OTRPOLICY_ALWAYS && *decrypted == FALSE && !whitespace_base) { char *otr_query_message = otr_start_query(); cons_show("Attempting to start OTR session..."); char *id = message_send_chat_otr(barejid, otr_query_message); free(id); } return newmessage; } gboolean otr_on_message_send(ProfChatWin *chatwin, const char * const message) { char *id = NULL; prof_otrpolicy_t policy = otr_get_policy(chatwin->barejid); // Send encrypted message if (otr_is_secure(chatwin->barejid)) { char *encrypted = otr_encrypt_message(chatwin->barejid, message); if (encrypted) { id = message_send_chat_otr(chatwin->barejid, encrypted); chat_log_otr_msg_out(chatwin->barejid, message); ui_outgoing_chat_msg(chatwin, message, id, PROF_MSG_OTR); otr_free_message(encrypted); free(id); return TRUE; } else { ui_win_error_line((ProfWin*)chatwin, "Failed to encrypt and send message."); return TRUE; } } // show error if not secure and policy always if (policy == PROF_OTRPOLICY_ALWAYS) { ui_win_error_line((ProfWin*)chatwin, "Failed to send message. OTR policy set to: always"); return TRUE; } // tag and send for policy opportunistic if (policy == PROF_OTRPOLICY_OPPORTUNISTIC) { char *otr_tagged_msg = otr_tag_message(message); id = message_send_chat_otr(chatwin->barejid, otr_tagged_msg); ui_outgoing_chat_msg(chatwin, message, id, PROF_MSG_PLAIN); chat_log_msg_out(chatwin->barejid, message); free(otr_tagged_msg); free(id); return TRUE; } return FALSE; } void otr_keygen(ProfAccount *account) { if (data_loaded) { cons_show("OTR key already generated."); return; } if (jid) { free(jid); } jid = strdup(account->jid); log_info("Generating OTR key for %s", jid); gchar *data_home = xdg_get_data_home(); GString *basedir = g_string_new(data_home); free(data_home); gchar *account_dir = str_replace(jid, "@", "_at_"); g_string_append(basedir, "/profanity/otr/"); g_string_append(basedir, account_dir); g_string_append(basedir, "/"); free(account_dir); if (!mkdir_recursive(basedir->str)) { log_error("Could not create %s for account %s.", basedir->str, jid); cons_show_error("Could not create %s for account %s.", basedir->str, jid); g_string_free(basedir, TRUE); return; } gcry_error_t err = 0; GString *keysfilename = g_string_new(basedir->str); g_string_append(keysfilename, "keys.txt"); log_debug("Generating private key file %s for %s", keysfilename->str, jid); cons_show("Generating private key, this may take some time."); cons_show("Moving the mouse randomly around the screen may speed up the process!"); ui_update(); err = otrl_privkey_generate(user_state, keysfilename->str, account->jid, "xmpp"); if (!err == GPG_ERR_NO_ERROR) { g_string_free(basedir, TRUE); g_string_free(keysfilename, TRUE); log_error("Failed to generate private key"); cons_show_error("Failed to generate private key"); return; } log_info("Private key generated"); cons_show(""); cons_show("Private key generation complete."); GString *fpsfilename = g_string_new(basedir->str); g_string_append(fpsfilename, "fingerprints.txt"); log_debug("Generating fingerprints file %s for %s", fpsfilename->str, jid); err = otrl_privkey_write_fingerprints(user_state, fpsfilename->str); if (!err == GPG_ERR_NO_ERROR) { g_string_free(basedir, TRUE); g_string_free(keysfilename, TRUE); log_error("Failed to create fingerprints file"); cons_show_error("Failed to create fingerprints file"); return; } log_info("Fingerprints file created"); err = otrl_privkey_read(user_state, keysfilename->str); if (!err == GPG_ERR_NO_ERROR) { g_string_free(basedir, TRUE); g_string_free(keysfilename, TRUE); log_error("Failed to load private key"); data_loaded = FALSE; return; } err = otrl_privkey_read_fingerprints(user_state, fpsfilename->str, NULL, NULL); if (!err == GPG_ERR_NO_ERROR) { g_string_free(basedir, TRUE); g_string_free(keysfilename, TRUE); log_error("Failed to load fingerprints"); data_loaded = FALSE; return; } data_loaded = TRUE; g_string_free(basedir, TRUE); g_string_free(keysfilename, TRUE); g_string_free(fpsfilename, TRUE); return; } gboolean otr_key_loaded(void) { return data_loaded; } char * otr_tag_message(const char * const msg) { GString *otr_message = g_string_new(msg); g_string_append(otr_message, OTRL_MESSAGE_TAG_BASE); g_string_append(otr_message, OTRL_MESSAGE_TAG_V2); char *result = otr_message->str; g_string_free(otr_message, FALSE); return result; } gboolean otr_is_secure(const char * const recipient) { ConnContext *context = otrlib_context_find(user_state, recipient, jid); if (context == NULL) { return FALSE; } if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) { return FALSE; } else { return TRUE; } } gboolean otr_is_trusted(const char * const recipient) { ConnContext *context = otrlib_context_find(user_state, recipient, jid); if (context == NULL) { return FALSE; } if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) { return TRUE; } if (context->active_fingerprint) { if (context->active_fingerprint->trust == NULL) { return FALSE; } else if (context->active_fingerprint->trust[0] == '\0') { return FALSE; } else { return TRUE; } } return FALSE; } void otr_trust(const char * const recipient) { ConnContext *context = otrlib_context_find(user_state, recipient, jid); if (context == NULL) { return; } if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) { return; } if (context->active_fingerprint) { if (context->active_fingerprint->trust) { free(context->active_fingerprint->trust); } context->active_fingerprint->trust = strdup("trusted"); cb_write_fingerprints(NULL); } return; } void otr_untrust(const char * const recipient) { ConnContext *context = otrlib_context_find(user_state, recipient, jid); if (context == NULL) { return; } if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) { return; } if (context->active_fingerprint) { if (context->active_fingerprint->trust) { free(context->active_fingerprint->trust); } context->active_fingerprint->trust = NULL; cb_write_fingerprints(NULL); } return; } void otr_smp_secret(const char * const recipient, const char *secret) { ConnContext *context = otrlib_context_find(user_state, recipient, jid); if (context == NULL) { return; } if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) { return; } // if recipient initiated SMP, send response, else initialise if (g_hash_table_contains(smp_initiators, recipient)) { otrl_message_respond_smp(user_state, &ops, NULL, context, (const unsigned char*)secret, strlen(secret)); ui_otr_authenticating(recipient); g_hash_table_remove(smp_initiators, context->username); } else { otrl_message_initiate_smp(user_state, &ops, NULL, context, (const unsigned char*)secret, strlen(secret)); ui_otr_authetication_waiting(recipient); } } void otr_smp_question(const char * const recipient, const char *question, const char *answer) { ConnContext *context = otrlib_context_find(user_state, recipient, jid); if (context == NULL) { return; } if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) { return; } otrl_message_initiate_smp_q(user_state, &ops, NULL, context, question, (const unsigned char*)answer, strlen(answer)); ui_otr_authetication_waiting(recipient); } void otr_smp_answer(const char * const recipient, const char *answer) { ConnContext *context = otrlib_context_find(user_state, recipient, jid); if (context == NULL) { return; } if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) { return; } // if recipient initiated SMP, send response, else initialise otrl_message_respond_smp(user_state, &ops, NULL, context, (const unsigned char*)answer, strlen(answer)); } void otr_end_session(const char * const recipient) { otrlib_end_session(user_state, recipient, jid, &ops); } char * otr_get_my_fingerprint(void) { char fingerprint[45]; otrl_privkey_fingerprint(user_state, fingerprint, jid, "xmpp"); char *result = strdup(fingerprint); return result; } char * otr_get_their_fingerprint(const char * const recipient) { ConnContext *context = otrlib_context_find(user_state, recipient, jid); if (context) { Fingerprint *fingerprint = context->active_fingerprint; char readable[45]; otrl_privkey_hash_to_human(readable, fingerprint->fingerprint); return strdup(readable); } else { return NULL; } } prof_otrpolicy_t otr_get_policy(const char * const recipient) { char *account_name = jabber_get_account_name(); ProfAccount *account = accounts_get_account(account_name); // check contact specific setting if (g_list_find_custom(account->otr_manual, recipient, (GCompareFunc)g_strcmp0)) { account_free(account); return PROF_OTRPOLICY_MANUAL; } if (g_list_find_custom(account->otr_opportunistic, recipient, (GCompareFunc)g_strcmp0)) { account_free(account); return PROF_OTRPOLICY_OPPORTUNISTIC; } if (g_list_find_custom(account->otr_always, recipient, (GCompareFunc)g_strcmp0)) { account_free(account); return PROF_OTRPOLICY_ALWAYS; } // check default account setting if (account->otr_policy) { prof_otrpolicy_t result; if (g_strcmp0(account->otr_policy, "manual") == 0) { result = PROF_OTRPOLICY_MANUAL; } if (g_strcmp0(account->otr_policy, "opportunistic") == 0) { result = PROF_OTRPOLICY_OPPORTUNISTIC; } if (g_strcmp0(account->otr_policy, "always") == 0) { result = PROF_OTRPOLICY_ALWAYS; } account_free(account); return result; } account_free(account); // check global setting char *pref_otr_policy = prefs_get_string(PREF_OTR_POLICY); // pref defaults to manual prof_otrpolicy_t result = PROF_OTRPOLICY_MANUAL; if (strcmp(pref_otr_policy, "opportunistic") == 0) { result = PROF_OTRPOLICY_OPPORTUNISTIC; } else if (strcmp(pref_otr_policy, "always") == 0) { result = PROF_OTRPOLICY_ALWAYS; } prefs_free_string(pref_otr_policy); return result; } char * otr_encrypt_message(const char * const to, const char * const message) { char *newmessage = NULL; gcry_error_t err = otrlib_encrypt_message(user_state, &ops, jid, to, message, &newmessage); if (err != 0) { return NULL; } else { return newmessage; } } static void _otr_tlv_free(OtrlTLV *tlvs) { if (tlvs) { otrl_tlv_free(tlvs); } } char * otr_decrypt_message(const char * const from, const char * const message, gboolean *decrypted) { char *newmessage = NULL; OtrlTLV *tlvs = NULL; int result = otrlib_decrypt_message(user_state, &ops, jid, from, message, &newmessage, &tlvs); // internal libotr message if (result == 1) { ConnContext *context = otrlib_context_find(user_state, from, jid); // common tlv handling OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED); if (tlv) { if (context) { otrl_context_force_plaintext(context); ui_gone_insecure(from); } } // library version specific tlv handling otrlib_handle_tlvs(user_state, &ops, context, tlvs, smp_initiators); _otr_tlv_free(tlvs); return NULL; // message was processed, return to user } else if (newmessage) { _otr_tlv_free(tlvs); if (g_str_has_prefix(message, "?OTR:")) { *decrypted = TRUE; } return newmessage; // normal non OTR message } else { _otr_tlv_free(tlvs); *decrypted = FALSE; return strdup(message); } } void otr_free_message(char *message) { otrl_message_free(message); } profanity-0.4.7/src/otr/otr.h000066400000000000000000000063011257755232500161220ustar00rootroot00000000000000/* * otr.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef OTR_H #define OTR_H #include #include #include "config/accounts.h" #include "ui/ui.h" typedef enum { PROF_OTRPOLICY_MANUAL, PROF_OTRPOLICY_OPPORTUNISTIC, PROF_OTRPOLICY_ALWAYS } prof_otrpolicy_t; OtrlUserState otr_userstate(void); OtrlMessageAppOps* otr_messageops(void); GHashTable* otr_smpinitators(void); void otr_init(void); void otr_shutdown(void); char* otr_libotr_version(void); char* otr_start_query(void); void otr_poll(void); void otr_on_connect(ProfAccount *account); char* otr_on_message_recv(const char * const barejid, const char * const resource, const char * const message, gboolean *decrypted); gboolean otr_on_message_send(ProfChatWin *chatwin, const char * const message); void otr_keygen(ProfAccount *account); char* otr_tag_message(const char * const msg); gboolean otr_key_loaded(void); gboolean otr_is_secure(const char * const recipient); gboolean otr_is_trusted(const char * const recipient); void otr_trust(const char * const recipient); void otr_untrust(const char * const recipient); void otr_smp_secret(const char * const recipient, const char *secret); void otr_smp_question(const char * const recipient, const char *question, const char *answer); void otr_smp_answer(const char * const recipient, const char *answer); void otr_end_session(const char * const recipient); char * otr_get_my_fingerprint(void); char * otr_get_their_fingerprint(const char * const recipient); char * otr_encrypt_message(const char * const to, const char * const message); char * otr_decrypt_message(const char * const from, const char * const message, gboolean *decrypted); void otr_free_message(char *message); prof_otrpolicy_t otr_get_policy(const char * const recipient); #endif profanity-0.4.7/src/otr/otrlib.h000066400000000000000000000045711257755232500166200ustar00rootroot00000000000000/* * otrlib.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef OTRLIB_H #define OTRLIB_H OtrlPolicy otrlib_policy(void); char* otrlib_start_query(void); void otrlib_init_ops(OtrlMessageAppOps *ops); void otrlib_init_timer(void); void otrlib_poll(void); ConnContext * otrlib_context_find(OtrlUserState user_state, const char * const recipient, char *jid); void otrlib_end_session(OtrlUserState user_state, const char * const recipient, char *jid, OtrlMessageAppOps *ops); gcry_error_t otrlib_encrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *jid, const char * const to, const char * const message, char **newmessage); int otrlib_decrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *jid, const char * const from, const char * const message, char **decrypted, OtrlTLV **tlvs); void otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext *context, OtrlTLV *tlvs, GHashTable *smp_initiators); #endif profanity-0.4.7/src/otr/otrlibv3.c000066400000000000000000000152061257755232500170610ustar00rootroot00000000000000/* * otrlibv3.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include "ui/ui.h" #include "otr/otr.h" #include "otr/otrlib.h" OtrlPolicy otrlib_policy(void) { return OTRL_POLICY_ALLOW_V1 | OTRL_POLICY_ALLOW_V2 ; } void otrlib_init_timer(void) { } void otrlib_poll(void) { } char * otrlib_start_query(void) { return "?OTR?v2? This user has requested an Off-the-Record private conversation. However, you do not have a plugin to support that. See http://otr.cypherpunks.ca/ for more information."; } static int cb_display_otr_message(void *opdata, const char *accountname, const char *protocol, const char *username, const char *msg) { cons_show_error("%s", msg); return 0; } void otrlib_init_ops(OtrlMessageAppOps *ops) { ops->display_otr_message = cb_display_otr_message; } ConnContext * otrlib_context_find(OtrlUserState user_state, const char * const recipient, char *jid) { return otrl_context_find(user_state, recipient, jid, "xmpp", 0, NULL, NULL, NULL); } void otrlib_end_session(OtrlUserState user_state, const char * const recipient, char *jid, OtrlMessageAppOps *ops) { ConnContext *context = otrl_context_find(user_state, recipient, jid, "xmpp", 0, NULL, NULL, NULL); if (context) { otrl_message_disconnect(user_state, ops, NULL, jid, "xmpp", recipient); } } gcry_error_t otrlib_encrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *jid, const char * const to, const char * const message, char **newmessage) { gcry_error_t err; err = otrl_message_sending( user_state, ops, NULL, jid, "xmpp", to, message, 0, newmessage, NULL, NULL); return err; } int otrlib_decrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *jid, const char * const from, const char * const message, char **decrypted, OtrlTLV **tlvs) { return otrl_message_receiving( user_state, ops, NULL, jid, "xmpp", from, message, decrypted, tlvs, NULL, NULL); } void otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext *context, OtrlTLV *tlvs, GHashTable *smp_initiators) { NextExpectedSMP nextMsg = context->smstate->nextExpected; OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1); if (tlv) { if (nextMsg != OTRL_SMP_EXPECT1) { otrl_message_abort_smp(user_state, ops, NULL, context); } else { ui_smp_recipient_initiated(context->username); g_hash_table_insert(smp_initiators, strdup(context->username), strdup(context->username)); } } tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q); if (tlv) { if (nextMsg != OTRL_SMP_EXPECT1) { otrl_message_abort_smp(user_state, ops, NULL, context); } else { char *question = (char *)tlv->data; char *eoq = memchr(question, '\0', tlv->len); if (eoq) { ui_smp_recipient_initiated_q(context->username, question); } } } tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2); if (tlv) { if (nextMsg != OTRL_SMP_EXPECT2) { otrl_message_abort_smp(user_state, ops, NULL, context); } else { context->smstate->nextExpected = OTRL_SMP_EXPECT4; } } tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3); if (tlv) { if (nextMsg != OTRL_SMP_EXPECT3) { otrl_message_abort_smp(user_state, ops, NULL, context); } else { context->smstate->nextExpected = OTRL_SMP_EXPECT1; if (context->smstate->received_question == 0) { if (context->active_fingerprint->trust && (context->active_fingerprint->trust[0] != '\0')) { ui_smp_successful(context->username); ui_trust(context->username); } else { ui_smp_unsuccessful_sender(context->username); ui_untrust(context->username); } } else { if (context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) { ui_smp_answer_success(context->username); } else { ui_smp_answer_failure(context->username); } } } } tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4); if (tlv) { if (nextMsg != OTRL_SMP_EXPECT4) { otrl_message_abort_smp(user_state, ops, NULL, context); } else { context->smstate->nextExpected = OTRL_SMP_EXPECT1; if (context->active_fingerprint->trust && (context->active_fingerprint->trust[0] != '\0')) { ui_smp_successful(context->username); ui_trust(context->username); } else { ui_smp_unsuccessful_receiver(context->username); ui_untrust(context->username); } } } tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT); if (tlv) { context->smstate->nextExpected = OTRL_SMP_EXPECT1; ui_smp_aborted(context->username); ui_untrust(context->username); otr_untrust(context->username); } } profanity-0.4.7/src/otr/otrlibv4.c000066400000000000000000000240531257755232500170620ustar00rootroot00000000000000/* * otrlibv4.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include "ui/ui.h" #include "log.h" #include "otr/otr.h" #include "otr/otrlib.h" static GTimer *timer; static unsigned int current_interval; OtrlPolicy otrlib_policy(void) { return OTRL_POLICY_ALLOW_V1 | OTRL_POLICY_ALLOW_V2; } void otrlib_init_timer(void) { OtrlUserState user_state = otr_userstate(); timer = g_timer_new(); current_interval = otrl_message_poll_get_default_interval(user_state); } void otrlib_poll(void) { gdouble elapsed = g_timer_elapsed(timer, NULL); if (current_interval != 0 && elapsed > current_interval) { OtrlUserState user_state = otr_userstate(); OtrlMessageAppOps *ops = otr_messageops(); otrl_message_poll(user_state, ops, NULL); g_timer_start(timer); } } char * otrlib_start_query(void) { return "?OTR?v2? This user has requested an Off-the-Record private conversation. However, you do not have a plugin to support that. See http://otr.cypherpunks.ca/ for more information."; } static const char* cb_otr_error_message(void *opdata, ConnContext *context, OtrlErrorCode err_code) { switch(err_code) { case OTRL_ERRCODE_ENCRYPTION_ERROR: return strdup("OTR Error: occurred while encrypting a message"); case OTRL_ERRCODE_MSG_NOT_IN_PRIVATE: return strdup("OTR Error: Sent encrypted message to somebody who is not in a mutual OTR session"); case OTRL_ERRCODE_MSG_UNREADABLE: return strdup("OTR Error: sent an unreadable encrypted message"); case OTRL_ERRCODE_MSG_MALFORMED: return strdup("OTR Error: message sent is malformed"); default: return strdup("OTR Error: unknown"); } } static void cb_otr_error_message_free(void *opdata, const char *err_msg) { free((char *)err_msg); } static void cb_timer_control(void *opdata, unsigned int interval) { current_interval = interval; } static void cb_handle_msg_event(void *opdata, OtrlMessageEvent msg_event, ConnContext *context, const char *message, gcry_error_t err) { GString *err_msg; switch (msg_event) { case OTRL_MSGEVENT_ENCRYPTION_REQUIRED: ui_handle_otr_error(context->username, "OTR: Policy requires encryption, but attempting to send an unencrypted message."); break; case OTRL_MSGEVENT_ENCRYPTION_ERROR: ui_handle_otr_error(context->username, "OTR: Error occured while encrypting a message, message not sent."); break; case OTRL_MSGEVENT_CONNECTION_ENDED: ui_handle_otr_error(context->username, "OTR: Message not sent because contact has ended the private conversation."); break; case OTRL_MSGEVENT_SETUP_ERROR: ui_handle_otr_error(context->username, "OTR: A private conversation could not be set up."); break; case OTRL_MSGEVENT_MSG_REFLECTED: ui_handle_otr_error(context->username, "OTR: Received our own OTR message."); break; case OTRL_MSGEVENT_MSG_RESENT: ui_handle_otr_error(context->username, "OTR: The previous message was resent."); break; case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE: ui_handle_otr_error(context->username, "OTR: Received an encrypted message but no private connection established."); break; case OTRL_MSGEVENT_RCVDMSG_UNREADABLE: ui_handle_otr_error(context->username, "OTR: Cannot read the received message."); break; case OTRL_MSGEVENT_RCVDMSG_MALFORMED: ui_handle_otr_error(context->username, "OTR: The message received contains malformed data."); break; case OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR: err_msg = g_string_new("OTR: Received error: "); g_string_append(err_msg, message); g_string_append(err_msg, "."); ui_handle_otr_error(context->username, err_msg->str); g_string_free(err_msg, TRUE); break; case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED: err_msg = g_string_new("OTR: Received an unencrypted message: "); g_string_append(err_msg, message); ui_handle_otr_error(context->username, err_msg->str); g_string_free(err_msg, TRUE); break; case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED: ui_handle_otr_error(context->username, "OTR: Cannot recognize the type of message received."); break; case OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE: ui_handle_otr_error(context->username, "OTR: Received and discarded a message intended for another instance."); break; default: break; } } static void cb_handle_smp_event(void *opdata, OtrlSMPEvent smp_event, ConnContext *context, unsigned short progress_percent, char *question) { NextExpectedSMP nextMsg = context->smstate->nextExpected; OtrlUserState user_state = otr_userstate(); OtrlMessageAppOps *ops = otr_messageops(); GHashTable *smp_initiators = otr_smpinitators(); switch(smp_event) { case OTRL_SMPEVENT_ASK_FOR_SECRET: ui_smp_recipient_initiated(context->username); g_hash_table_insert(smp_initiators, strdup(context->username), strdup(context->username)); break; case OTRL_SMPEVENT_ASK_FOR_ANSWER: ui_smp_recipient_initiated_q(context->username, question); break; case OTRL_SMPEVENT_SUCCESS: if (context->smstate->received_question == 0) { ui_smp_successful(context->username); ui_trust(context->username); } else { ui_smp_answer_success(context->username); } break; case OTRL_SMPEVENT_FAILURE: if (context->smstate->received_question == 0) { if (nextMsg == OTRL_SMP_EXPECT3) { ui_smp_unsuccessful_sender(context->username); } else if (nextMsg == OTRL_SMP_EXPECT4) { ui_smp_unsuccessful_receiver(context->username); } ui_untrust(context->username); } else { ui_smp_answer_failure(context->username); } break; case OTRL_SMPEVENT_ERROR: otrl_message_abort_smp(user_state, ops, NULL, context); break; case OTRL_SMPEVENT_CHEATED: otrl_message_abort_smp(user_state, ops, NULL, context); break; case OTRL_SMPEVENT_ABORT: ui_smp_aborted(context->username); ui_untrust(context->username); break; case OTRL_SMPEVENT_IN_PROGRESS: break; default: break; } } void otrlib_init_ops(OtrlMessageAppOps *ops) { ops->otr_error_message = cb_otr_error_message; ops->otr_error_message_free = cb_otr_error_message_free; ops->handle_msg_event = cb_handle_msg_event; ops->handle_smp_event = cb_handle_smp_event; ops->timer_control = cb_timer_control; } ConnContext * otrlib_context_find(OtrlUserState user_state, const char * const recipient, char *jid) { return otrl_context_find(user_state, recipient, jid, "xmpp", OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); } void otrlib_end_session(OtrlUserState user_state, const char * const recipient, char *jid, OtrlMessageAppOps *ops) { ConnContext *context = otrl_context_find(user_state, recipient, jid, "xmpp", OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); if (context) { otrl_message_disconnect(user_state, ops, NULL, jid, "xmpp", recipient, 0); } } gcry_error_t otrlib_encrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *jid, const char * const to, const char * const message, char **newmessage) { gcry_error_t err; err = otrl_message_sending( user_state, ops, NULL, jid, "xmpp", to, OTRL_INSTAG_MASTER, message, 0, newmessage, OTRL_FRAGMENT_SEND_SKIP, NULL, NULL, NULL); return err; } int otrlib_decrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *jid, const char * const from, const char * const message, char **decrypted, OtrlTLV **tlvs) { return otrl_message_receiving( user_state, ops, NULL, jid, "xmpp", from, message, decrypted, tlvs, NULL, NULL, NULL); } void otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext *context, OtrlTLV *tlvs, GHashTable *smp_initiators) { } profanity-0.4.7/src/pgp/000077500000000000000000000000001257755232500151275ustar00rootroot00000000000000profanity-0.4.7/src/pgp/gpg.c000066400000000000000000000524701257755232500160600ustar00rootroot00000000000000/* * gpg.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include #include #include #include #include #include #include "pgp/gpg.h" #include "log.h" #include "common.h" #include "tools/autocomplete.h" #include "ui/ui.h" #define PGP_SIGNATURE_HEADER "-----BEGIN PGP SIGNATURE-----" #define PGP_SIGNATURE_FOOTER "-----END PGP SIGNATURE-----" #define PGP_MESSAGE_HEADER "-----BEGIN PGP MESSAGE-----" #define PGP_MESSAGE_FOOTER "-----END PGP MESSAGE-----" static const char *libversion; static GHashTable *pubkeys; static gchar *pubsloc; static GKeyFile *pubkeyfile; static char *passphrase; static char *passphrase_attempt; static Autocomplete key_ac; static char* _remove_header_footer(char *str, const char * const footer); static char* _add_header_footer(const char * const str, const char * const header, const char * const footer); static void _save_pubkeys(void); void _p_gpg_free_pubkeyid(ProfPGPPubKeyId *pubkeyid) { if (pubkeyid) { free(pubkeyid->id); } free(pubkeyid); } static gpgme_error_t * _p_gpg_passphrase_cb(void *hook, const char *uid_hint, const char *passphrase_info, int prev_was_bad, int fd) { if (passphrase) { gpgme_io_write(fd, passphrase, strlen(passphrase)); } else { GString *pass_term = g_string_new(""); char *password = ui_ask_pgp_passphrase(uid_hint, prev_was_bad); if (password) { g_string_append(pass_term, password); free(password); } g_string_append(pass_term, "\n"); if (passphrase_attempt) { free(passphrase_attempt); } passphrase_attempt = pass_term->str; g_string_free(pass_term, FALSE); gpgme_io_write(fd, passphrase_attempt, strlen(passphrase_attempt)); } return 0; } void p_gpg_init(void) { libversion = gpgme_check_version(NULL); log_debug("GPG: Found gpgme version: %s", libversion); gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); pubkeys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_p_gpg_free_pubkeyid); key_ac = autocomplete_new(); GHashTable *keys = p_gpg_list_keys(); p_gpg_free_keys(keys); passphrase = NULL; passphrase_attempt = NULL; } void p_gpg_close(void) { if (pubkeys) { g_hash_table_destroy(pubkeys); pubkeys = NULL; } if (pubkeyfile) { g_key_file_free(pubkeyfile); pubkeyfile = NULL; } free(pubsloc); pubsloc = NULL; autocomplete_free(key_ac); key_ac = NULL; if (passphrase) { free(passphrase); passphrase = NULL; } if (passphrase_attempt) { free(passphrase_attempt); passphrase_attempt = NULL; } } void p_gpg_on_connect(const char * const barejid) { gchar *data_home = xdg_get_data_home(); GString *pubsfile = g_string_new(data_home); free(data_home); gchar *account_dir = str_replace(barejid, "@", "_at_"); g_string_append(pubsfile, "/profanity/pgp/"); g_string_append(pubsfile, account_dir); free(account_dir); // mkdir if doesn't exist for account errno = 0; int res = g_mkdir_with_parents(pubsfile->str, S_IRWXU); if (res == -1) { char *errmsg = strerror(errno); if (errmsg) { log_error("Error creating directory: %s, %s", pubsfile->str, errmsg); } else { log_error("Error creating directory: %s", pubsfile->str); } } // create or read publickeys g_string_append(pubsfile, "/pubkeys"); pubsloc = pubsfile->str; g_string_free(pubsfile, FALSE); if (g_file_test(pubsloc, G_FILE_TEST_EXISTS)) { g_chmod(pubsloc, S_IRUSR | S_IWUSR); } pubkeyfile = g_key_file_new(); g_key_file_load_from_file(pubkeyfile, pubsloc, G_KEY_FILE_KEEP_COMMENTS, NULL); // load each keyid gsize len = 0; gchar **jids = g_key_file_get_groups(pubkeyfile, &len); gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); g_strfreev(jids); return; } int i = 0; for (i = 0; i < len; i++) { GError *gerr = NULL; gchar *jid = jids[i]; gchar *keyid = g_key_file_get_string(pubkeyfile, jid, "keyid", &gerr); if (gerr) { log_error("Error loading PGP key id for %s", jid); g_error_free(gerr); g_free(keyid); } else { gpgme_key_t key = NULL; error = gpgme_get_key(ctx, keyid, &key, 0); if (error || key == NULL) { log_warning("GPG: Failed to get key for %s: %s %s", jid, gpgme_strsource(error), gpgme_strerror(error)); continue; } ProfPGPPubKeyId *pubkeyid = malloc(sizeof(ProfPGPPubKeyId)); pubkeyid->id = strdup(keyid); pubkeyid->received = FALSE; g_hash_table_replace(pubkeys, strdup(jid), pubkeyid); g_free(keyid); gpgme_key_unref(key); } } gpgme_release(ctx); g_strfreev(jids); _save_pubkeys(); } void p_gpg_on_disconnect(void) { if (pubkeys) { g_hash_table_destroy(pubkeys); pubkeys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_p_gpg_free_pubkeyid); } if (pubkeyfile) { g_key_file_free(pubkeyfile); pubkeyfile = NULL; } free(pubsloc); pubsloc = NULL; if (passphrase) { free(passphrase); passphrase = NULL; } if (passphrase_attempt) { free(passphrase_attempt); passphrase_attempt = NULL; } } gboolean p_gpg_addkey(const char * const jid, const char * const keyid) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return FALSE; } gpgme_key_t key = NULL; error = gpgme_get_key(ctx, keyid, &key, 0); gpgme_release(ctx); if (error || key == NULL) { log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return FALSE; } // save to public key file g_key_file_set_string(pubkeyfile, jid, "keyid", keyid); _save_pubkeys(); // update in memory pubkeys list ProfPGPPubKeyId *pubkeyid = malloc(sizeof(ProfPGPPubKeyId)); pubkeyid->id = strdup(keyid); pubkeyid->received = FALSE; g_hash_table_replace(pubkeys, strdup(jid), pubkeyid); gpgme_key_unref(key); return TRUE; } static ProfPGPKey * _p_gpg_key_new(void) { ProfPGPKey *p_pgpkey = malloc(sizeof(ProfPGPKey)); p_pgpkey->id = NULL; p_pgpkey->name = NULL; p_pgpkey->fp = NULL; p_pgpkey->encrypt = FALSE; p_pgpkey->sign = FALSE; p_pgpkey->certify = FALSE; p_pgpkey->authenticate = FALSE; p_pgpkey->secret = FALSE; return p_pgpkey; } static void _p_gpg_free_key(ProfPGPKey *key) { if (key) { free(key->id); free(key->name); free(key->fp); free(key); } } GHashTable * p_gpg_list_keys(void) { gpgme_error_t error; GHashTable *result = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_p_gpg_free_key); gpgme_ctx_t ctx; error = gpgme_new(&ctx); if (error) { log_error("GPG: Could not list keys. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } error = gpgme_op_keylist_start(ctx, NULL, 0); if (error == GPG_ERR_NO_ERROR) { gpgme_key_t key; error = gpgme_op_keylist_next(ctx, &key); while (!error) { gpgme_subkey_t sub = key->subkeys; ProfPGPKey *p_pgpkey = _p_gpg_key_new(); p_pgpkey->id = strdup(sub->keyid); p_pgpkey->name = strdup(key->uids->uid); p_pgpkey->fp = strdup(sub->fpr); if (sub->can_encrypt) p_pgpkey->encrypt = TRUE; if (sub->can_authenticate) p_pgpkey->authenticate = TRUE; if (sub->can_certify) p_pgpkey->certify = TRUE; if (sub->can_sign) p_pgpkey->sign = TRUE; sub = sub->next; while (sub) { if (sub->can_encrypt) p_pgpkey->encrypt = TRUE; if (sub->can_authenticate) p_pgpkey->authenticate = TRUE; if (sub->can_certify) p_pgpkey->certify = TRUE; if (sub->can_sign) p_pgpkey->sign = TRUE; sub = sub->next; } g_hash_table_insert(result, strdup(p_pgpkey->name), p_pgpkey); gpgme_key_unref(key); error = gpgme_op_keylist_next(ctx, &key); } } error = gpgme_op_keylist_start(ctx, NULL, 1); if (error == GPG_ERR_NO_ERROR) { gpgme_key_t key; error = gpgme_op_keylist_next(ctx, &key); while (!error) { gpgme_subkey_t sub = key->subkeys; while (sub) { if (sub->secret) { ProfPGPKey *p_pgpkey = g_hash_table_lookup(result, key->uids->uid); if (p_pgpkey) { p_pgpkey->secret = TRUE; } } sub = sub->next; } gpgme_key_unref(key); error = gpgme_op_keylist_next(ctx, &key); } } gpgme_release(ctx); autocomplete_clear(key_ac); GList *ids = g_hash_table_get_keys(result); GList *curr = ids; while (curr) { ProfPGPKey *key = g_hash_table_lookup(result, curr->data); autocomplete_add(key_ac, key->id); curr = curr->next; } g_list_free(ids); return result; } void p_gpg_free_keys(GHashTable *keys) { g_hash_table_destroy(keys); } GHashTable * p_gpg_pubkeys(void) { return pubkeys; } const char* p_gpg_libver(void) { return libversion; } gboolean p_gpg_valid_key(const char * const keyid) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return FALSE; } gpgme_key_t key = NULL; error = gpgme_get_key(ctx, keyid, &key, 1); if (error || key == NULL) { log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return FALSE; } if (key) { gpgme_release(ctx); gpgme_key_unref(key); return TRUE; } gpgme_release(ctx); return FALSE; } gboolean p_gpg_available(const char * const barejid) { char *pubkey = g_hash_table_lookup(pubkeys, barejid); return (pubkey != NULL); } void p_gpg_verify(const char * const barejid, const char *const sign) { if (!sign) { return; } gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return; } char *sign_with_header_footer = _add_header_footer(sign, PGP_SIGNATURE_HEADER, PGP_SIGNATURE_FOOTER); gpgme_data_t sign_data; gpgme_data_new_from_mem(&sign_data, sign_with_header_footer, strlen(sign_with_header_footer), 1); free(sign_with_header_footer); gpgme_data_t plain_data; gpgme_data_new(&plain_data); error = gpgme_op_verify(ctx, sign_data, NULL, plain_data); gpgme_data_release(sign_data); gpgme_data_release(plain_data); if (error) { log_error("GPG: Failed to verify. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return; } gpgme_verify_result_t result = gpgme_op_verify_result(ctx); if (result) { if (result->signatures) { gpgme_key_t key = NULL; error = gpgme_get_key(ctx, result->signatures->fpr, &key, 0); if (error) { log_debug("Could not find PGP key with ID %s for %s", result->signatures->fpr, barejid); } else { log_debug("Fingerprint found for %s: %s ", barejid, key->subkeys->fpr); ProfPGPPubKeyId *pubkeyid = malloc(sizeof(ProfPGPPubKeyId)); pubkeyid->id = strdup(key->subkeys->keyid); pubkeyid->received = TRUE; g_hash_table_replace(pubkeys, strdup(barejid), pubkeyid); } gpgme_key_unref(key); } } gpgme_release(ctx); } char* p_gpg_sign(const char * const str, const char * const fp) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL); gpgme_key_t key = NULL; error = gpgme_get_key(ctx, fp, &key, 1); if (error || key == NULL) { log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } gpgme_signers_clear(ctx); error = gpgme_signers_add(ctx, key); gpgme_key_unref(key); if (error) { log_error("GPG: Failed to load signer. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } char *str_or_empty = NULL; if (str) { str_or_empty = strdup(str); } else { str_or_empty = strdup(""); } gpgme_data_t str_data; gpgme_data_new_from_mem(&str_data, str_or_empty, strlen(str_or_empty), 1); free(str_or_empty); gpgme_data_t signed_data; gpgme_data_new(&signed_data); gpgme_set_armor(ctx,1); error = gpgme_op_sign(ctx, str_data, signed_data, GPGME_SIG_MODE_DETACH); gpgme_data_release(str_data); gpgme_release(ctx); if (error) { log_error("GPG: Failed to sign string. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_data_release(signed_data); return NULL; } char *result = NULL; size_t len = 0; char *signed_str = gpgme_data_release_and_get_mem(signed_data, &len); if (signed_str) { GString *signed_gstr = g_string_new(""); g_string_append_len(signed_gstr, signed_str, len); result = _remove_header_footer(signed_gstr->str, PGP_SIGNATURE_FOOTER); g_string_free(signed_gstr, TRUE); gpgme_free(signed_str); } if (passphrase_attempt) { passphrase = strdup(passphrase_attempt); } return result; } char * p_gpg_encrypt(const char * const barejid, const char * const message) { ProfPGPPubKeyId *pubkeyid = g_hash_table_lookup(pubkeys, barejid); if (!pubkeyid) { return NULL; } if (!pubkeyid->id) { return NULL; } gpgme_key_t keys[2]; keys[0] = NULL; keys[1] = NULL; gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } gpgme_key_t key; error = gpgme_get_key(ctx, pubkeyid->id, &key, 0); if (error || key == NULL) { log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } keys[0] = key; gpgme_data_t plain; gpgme_data_new_from_mem(&plain, message, strlen(message), 1); gpgme_data_t cipher; gpgme_data_new(&cipher); gpgme_set_armor(ctx, 1); error = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); gpgme_data_release(plain); gpgme_release(ctx); gpgme_key_unref(key); if (error) { log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } size_t len; char *cipher_str = gpgme_data_release_and_get_mem(cipher, &len); char *result = NULL; if (cipher_str) { GString *cipher_gstr = g_string_new(""); g_string_append_len(cipher_gstr, cipher_str, len); result = _remove_header_footer(cipher_gstr->str, PGP_MESSAGE_FOOTER); g_string_free(cipher_gstr, TRUE); gpgme_free(cipher_str); } return result; } char * p_gpg_decrypt(const char * const cipher) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL); char *cipher_with_headers = _add_header_footer(cipher, PGP_MESSAGE_HEADER, PGP_MESSAGE_FOOTER); gpgme_data_t cipher_data; gpgme_data_new_from_mem(&cipher_data, cipher_with_headers, strlen(cipher_with_headers), 1); free(cipher_with_headers); gpgme_data_t plain_data; gpgme_data_new(&plain_data); error = gpgme_op_decrypt(ctx, cipher_data, plain_data); gpgme_data_release(cipher_data); if (error) { log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_data_release(plain_data); gpgme_release(ctx); return NULL; } gpgme_decrypt_result_t res = gpgme_op_decrypt_result(ctx); if (res) { gpgme_recipient_t recipient = res->recipients; if (recipient) { gpgme_key_t key; error = gpgme_get_key(ctx, recipient->keyid, &key, 1); if (!error && key) { const char *addr = gpgme_key_get_string_attr(key, GPGME_ATTR_EMAIL, NULL, 0); if (addr) { log_debug("GPG: Decrypted message for recipient: %s", addr); } gpgme_key_unref(key); } } } gpgme_release(ctx); size_t len = 0; char *plain_str = gpgme_data_release_and_get_mem(plain_data, &len); char *result = NULL; if (plain_str) { plain_str[len] = 0; result = g_strdup(plain_str); } gpgme_free(plain_str); if (passphrase_attempt) { passphrase = strdup(passphrase_attempt); } return result; } void p_gpg_free_decrypted(char *decrypted) { g_free(decrypted); } char * p_gpg_autocomplete_key(const char * const search_str) { return autocomplete_complete(key_ac, search_str, TRUE); } void p_gpg_autocomplete_key_reset(void) { autocomplete_reset(key_ac); } char * p_gpg_format_fp_str(char *fp) { if (!fp) { return NULL; } GString *format = g_string_new(""); int i; int len = strlen(fp); for (i = 0; i < len; i++) { g_string_append_c(format, fp[i]); if (((i+1) % 4 == 0) && (i+1 < len)) { g_string_append_c(format, ' '); } } char *result = format->str; g_string_free(format, FALSE); return result; } static char* _remove_header_footer(char *str, const char * const footer) { int pos = 0; int newlines = 0; while (newlines < 3) { if (str[pos] == '\n') { newlines++; } pos++; if (str[pos] == '\0') { return NULL; } } char *stripped = strdup(&str[pos]); char *footer_start = g_strrstr(stripped, footer); footer_start[0] = '\0'; return stripped; } static char* _add_header_footer(const char * const str, const char * const header, const char * const footer) { GString *result_str = g_string_new(""); g_string_append(result_str, header); g_string_append(result_str, "\n\n"); g_string_append(result_str, str); g_string_append(result_str, "\n"); g_string_append(result_str, footer); char *result = result_str->str; g_string_free(result_str, FALSE); return result; } static void _save_pubkeys(void) { gsize g_data_size; gchar *g_pubkeys_data = g_key_file_to_data(pubkeyfile, &g_data_size, NULL); g_file_set_contents(pubsloc, g_pubkeys_data, g_data_size, NULL); g_chmod(pubsloc, S_IRUSR | S_IWUSR); g_free(g_pubkeys_data); } profanity-0.4.7/src/pgp/gpg.h000066400000000000000000000052321257755232500160570ustar00rootroot00000000000000/* * gpg.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef GPG_H #define GPG_H typedef struct pgp_key_t { char *id; char *name; char *fp; gboolean encrypt; gboolean sign; gboolean certify; gboolean authenticate; gboolean secret; } ProfPGPKey; typedef struct pgp_pubkeyid_t { char *id; gboolean received; } ProfPGPPubKeyId; void p_gpg_init(void); void p_gpg_close(void); void p_gpg_on_connect(const char * const barejid); void p_gpg_on_disconnect(void); GHashTable* p_gpg_list_keys(void); void p_gpg_free_keys(GHashTable *keys); gboolean p_gpg_addkey(const char * const jid, const char * const keyid); GHashTable* p_gpg_pubkeys(void); gboolean p_gpg_valid_key(const char * const keyid); gboolean p_gpg_available(const char * const barejid); const char* p_gpg_libver(void); char* p_gpg_sign(const char * const str, const char * const fp); void p_gpg_verify(const char * const barejid, const char *const sign); char* p_gpg_encrypt(const char * const barejid, const char * const message); char* p_gpg_decrypt(const char * const cipher); void p_gpg_free_decrypted(char *decrypted); char* p_gpg_autocomplete_key(const char * const search_str); void p_gpg_autocomplete_key_reset(void); char* p_gpg_format_fp_str(char *fp); #endif profanity-0.4.7/src/profanity.c000066400000000000000000000220471257755232500165250ustar00rootroot00000000000000/* * profanity.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #ifdef HAVE_GIT_VERSION #include "gitversion.h" #endif #include #include #include #include #include #include #include "profanity.h" #include "chat_session.h" #include "chat_state.h" #include "config/accounts.h" #include "config/preferences.h" #include "config/theme.h" #include "command/command.h" #include "common.h" #include "contact.h" #include "roster_list.h" #include "log.h" #include "muc.h" #ifdef HAVE_LIBOTR #include "otr/otr.h" #endif #ifdef HAVE_LIBGPGME #include "pgp/gpg.h" #endif #include "resource.h" #include "xmpp/xmpp.h" #include "ui/ui.h" #include "window_list.h" #include "event/client_events.h" static void _check_autoaway(void); static void _init(const int disable_tls, char *log_level); static void _shutdown(void); static void _create_directories(void); static void _connect_default(const char * const account); static gboolean idle = FALSE; static gboolean cont = TRUE; void prof_run(const int disable_tls, char *log_level, char *account_name) { _init(disable_tls, log_level); _connect_default(account_name); ui_update(); log_info("Starting main event loop"); char *line = NULL; while(cont) { log_stderr_handler(); _check_autoaway(); line = ui_readline(); if (line) { ProfWin *window = wins_get_current(); cont = cmd_process_input(window, line); free(line); line = NULL; } else { cont = TRUE; } #ifdef HAVE_LIBOTR otr_poll(); #endif notify_remind(); jabber_process_events(10); ui_update(); } } void prof_handle_idle(void) { jabber_conn_status_t status = jabber_get_connection_status(); if (status == JABBER_CONNECTED) { GSList *recipients = ui_get_chat_recipients(); GSList *curr = recipients; while (curr) { char *barejid = curr->data; ProfChatWin *chatwin = wins_get_chat(barejid); chat_state_handle_idle(chatwin->barejid, chatwin->state); curr = g_slist_next(curr); } if (recipients) { g_slist_free(recipients); } } } void prof_handle_activity(void) { jabber_conn_status_t status = jabber_get_connection_status(); ProfWin *current = wins_get_current(); if ((status == JABBER_CONNECTED) && (current->type == WIN_CHAT)) { ProfChatWin *chatwin = (ProfChatWin*)current; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); chat_state_handle_typing(chatwin->barejid, chatwin->state); } } static void _connect_default(const char * const account) { ProfWin *window = wins_get_current(); if (account) { cmd_execute_connect(window, account); } else { char *pref_connect_account = prefs_get_string(PREF_CONNECT_ACCOUNT); if (pref_connect_account) { cmd_execute_connect(window, pref_connect_account); prefs_free_string(pref_connect_account); } } } static void _check_autoaway() { jabber_conn_status_t conn_status = jabber_get_connection_status(); if (conn_status != JABBER_CONNECTED) { return; } gint prefs_time = prefs_get_autoaway_time() * 60000; unsigned long idle_ms = ui_get_idle_time(); char *pref_autoaway_mode = prefs_get_string(PREF_AUTOAWAY_MODE); if (!idle) { resource_presence_t current_presence = accounts_get_last_presence(jabber_get_account_name()); if ((current_presence == RESOURCE_ONLINE) || (current_presence == RESOURCE_CHAT)) { if (idle_ms >= prefs_time) { idle = TRUE; char *pref_autoaway_message = prefs_get_string(PREF_AUTOAWAY_MESSAGE); // handle away mode if (strcmp(pref_autoaway_mode, "away") == 0) { cl_ev_presence_send(RESOURCE_AWAY, pref_autoaway_message, 0); ui_auto_away(); // handle idle mode } else if (strcmp(pref_autoaway_mode, "idle") == 0) { cl_ev_presence_send(RESOURCE_ONLINE, pref_autoaway_message, idle_ms / 1000); } prefs_free_string(pref_autoaway_message); } } } else { if (idle_ms < prefs_time) { idle = FALSE; // handle check if (prefs_get_boolean(PREF_AUTOAWAY_CHECK)) { if (strcmp(pref_autoaway_mode, "away") == 0) { cl_ev_presence_send(RESOURCE_ONLINE, NULL, 0); ui_end_auto_away(); } else if (strcmp(pref_autoaway_mode, "idle") == 0) { cl_ev_presence_send(RESOURCE_ONLINE, NULL, 0); ui_titlebar_presence(CONTACT_ONLINE); } } } } prefs_free_string(pref_autoaway_mode); } static void _init(const int disable_tls, char *log_level) { setlocale(LC_ALL, ""); // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGWINCH, ui_sigwinch_handler); _create_directories(); log_level_t prof_log_level = log_level_from_string(log_level); prefs_load(); log_init(prof_log_level); log_stderr_init(PROF_LEVEL_ERROR); if (strcmp(PACKAGE_STATUS, "development") == 0) { #ifdef HAVE_GIT_VERSION log_info("Starting Profanity (%sdev.%s.%s)...", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION); #else log_info("Starting Profanity (%sdev)...", PACKAGE_VERSION); #endif } else { log_info("Starting Profanity (%s)...", PACKAGE_VERSION); } chat_log_init(); groupchat_log_init(); accounts_load(); char *theme = prefs_get_string(PREF_THEME); theme_init(theme); prefs_free_string(theme); ui_init(); jabber_init(disable_tls); cmd_init(); log_info("Initialising contact list"); roster_init(); muc_init(); #ifdef HAVE_LIBOTR otr_init(); #endif #ifdef HAVE_LIBGPGME p_gpg_init(); #endif atexit(_shutdown); ui_input_nonblocking(TRUE); } static void _shutdown(void) { if (prefs_get_boolean(PREF_TITLEBAR_SHOW)) { if (prefs_get_boolean(PREF_TITLEBAR_GOODBYE)) { ui_goodbye_title(); } else { ui_clear_win_title(); } } ui_close_all_wins(); jabber_disconnect(); jabber_shutdown(); roster_free(); muc_close(); caps_close(); ui_close(); #ifdef HAVE_LIBOTR otr_shutdown(); #endif #ifdef HAVE_LIBGPGME p_gpg_close(); #endif chat_log_close(); theme_close(); accounts_close(); cmd_uninit(); log_stderr_close(); log_close(); prefs_close(); } static void _create_directories(void) { gchar *xdg_config = xdg_get_config_home(); gchar *xdg_data = xdg_get_data_home(); GString *themes_dir = g_string_new(xdg_config); g_string_append(themes_dir, "/profanity/themes"); GString *chatlogs_dir = g_string_new(xdg_data); g_string_append(chatlogs_dir, "/profanity/chatlogs"); GString *logs_dir = g_string_new(xdg_data); g_string_append(logs_dir, "/profanity/logs"); if (!mkdir_recursive(themes_dir->str)) { log_error("Error while creating directory %s", themes_dir->str); } if (!mkdir_recursive(chatlogs_dir->str)) { log_error("Error while creating directory %s", chatlogs_dir->str); } if (!mkdir_recursive(logs_dir->str)) { log_error("Error while creating directory %s", logs_dir->str); } g_string_free(themes_dir, TRUE); g_string_free(chatlogs_dir, TRUE); g_string_free(logs_dir, TRUE); g_free(xdg_config); g_free(xdg_data); } profanity-0.4.7/src/profanity.h000066400000000000000000000033541257755232500165320ustar00rootroot00000000000000/* * profanity.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef PROFANITY_H #define PROFANITY_H #include "resource.h" #include "xmpp/xmpp.h" void prof_run(const int disable_tls, char *log_level, char *account_name); void prof_handle_idle(void); void prof_handle_activity(void); gboolean process_input(char *inp); #endif profanity-0.4.7/src/resource.c000066400000000000000000000061411257755232500163360ustar00rootroot00000000000000/* * resource.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include Resource * resource_new(const char * const name, resource_presence_t presence, const char * const status, const int priority) { assert(name != NULL); Resource *new_resource = malloc(sizeof(struct resource_t)); new_resource->name = strdup(name); new_resource->presence = presence; if (status) { new_resource->status = strdup(status); } else { new_resource->status = NULL; } new_resource->priority = priority; return new_resource; } int resource_compare_availability(Resource *first, Resource *second) { if (first->priority > second->priority) { return -1; } else if (first->priority < second->priority) { return 1; } else { // priorities equal if (first->presence == RESOURCE_CHAT) { return -1; } else if (second->presence == RESOURCE_CHAT) { return 1; } else if (first->presence == RESOURCE_ONLINE) { return -1; } else if (second->presence == RESOURCE_ONLINE) { return 1; } else if (first->presence == RESOURCE_AWAY) { return -1; } else if (second->presence == RESOURCE_AWAY) { return 1; } else if (first->presence == RESOURCE_XA) { return -1; } else if (second->presence == RESOURCE_XA) { return 1; } else { return -1; } } } void resource_destroy(Resource *resource) { if (resource) { free(resource->name); free(resource->status); free(resource); } } profanity-0.4.7/src/resource.h000066400000000000000000000036261257755232500163500ustar00rootroot00000000000000/* * resource.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef RESOURCE_H #define RESOURCE_H #include "common.h" typedef struct resource_t { char *name; resource_presence_t presence; char *status; int priority; } Resource; Resource * resource_new(const char * const name, resource_presence_t presence, const char * const status, const int priority); void resource_destroy(Resource *resource); int resource_compare_availability(Resource *first, Resource *second); #endif profanity-0.4.7/src/roster_list.c000066400000000000000000000333371257755232500170670ustar00rootroot00000000000000/* * roster_list.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include "roster_list.h" #include "resource.h" #include "contact.h" #include "jid.h" #include "tools/autocomplete.h" #include "config/preferences.h" // nicknames static Autocomplete name_ac; // barejids static Autocomplete barejid_ac; // fulljids static Autocomplete fulljid_ac; // groups static Autocomplete groups_ac; // contacts, indexed on barejid static GHashTable *contacts; // nickname to jid map static GHashTable *name_to_barejid; static gboolean _key_equals(void *key1, void *key2); static gboolean _datetimes_equal(GDateTime *dt1, GDateTime *dt2); static void _replace_name(const char * const current_name, const char * const new_name, const char * const barejid); static void _add_name_and_barejid(const char * const name, const char * const barejid); static gint _compare_contacts(PContact a, PContact b); void roster_clear(void) { autocomplete_clear(name_ac); autocomplete_clear(barejid_ac); autocomplete_clear(fulljid_ac); autocomplete_clear(groups_ac); g_hash_table_destroy(contacts); contacts = g_hash_table_new_full(g_str_hash, (GEqualFunc)_key_equals, g_free, (GDestroyNotify)p_contact_free); g_hash_table_destroy(name_to_barejid); name_to_barejid = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); } gboolean roster_update_presence(const char * const barejid, Resource *resource, GDateTime *last_activity) { assert(barejid != NULL); assert(resource != NULL); PContact contact = roster_get_contact(barejid); if (contact == NULL) { return FALSE; } if (!_datetimes_equal(p_contact_last_activity(contact), last_activity)) { p_contact_set_last_activity(contact, last_activity); } p_contact_set_presence(contact, resource); Jid *jid = jid_create_from_bare_and_resource(barejid, resource->name); autocomplete_add(fulljid_ac, jid->fulljid); jid_destroy(jid); return TRUE; } PContact roster_get_contact(const char * const barejid) { gchar *barejidlower = g_utf8_strdown(barejid, -1); PContact contact = g_hash_table_lookup(contacts, barejidlower); g_free(barejidlower); return contact; } char * roster_get_msg_display_name(const char * const barejid, const char * const resource) { GString *result = g_string_new(""); PContact contact = roster_get_contact(barejid); if (contact) { if (p_contact_name(contact)) { g_string_append(result, p_contact_name(contact)); } else { g_string_append(result, barejid); } } else { g_string_append(result, barejid); } if (resource && prefs_get_boolean(PREF_RESOURCE_MESSAGE)) { g_string_append(result, "/"); g_string_append(result, resource); } char *result_str = result->str; g_string_free(result, FALSE); return result_str; } gboolean roster_contact_offline(const char * const barejid, const char * const resource, const char * const status) { PContact contact = roster_get_contact(barejid); if (contact == NULL) { return FALSE; } if (resource == NULL) { return TRUE; } else { gboolean result = p_contact_remove_resource(contact, resource); if (result == TRUE) { Jid *jid = jid_create_from_bare_and_resource(barejid, resource); autocomplete_remove(fulljid_ac, jid->fulljid); jid_destroy(jid); } return result; } } void roster_reset_search_attempts(void) { autocomplete_reset(name_ac); autocomplete_reset(barejid_ac); autocomplete_reset(fulljid_ac); autocomplete_reset(groups_ac); } void roster_init(void) { name_ac = autocomplete_new(); barejid_ac = autocomplete_new(); fulljid_ac = autocomplete_new(); groups_ac = autocomplete_new(); contacts = g_hash_table_new_full(g_str_hash, (GEqualFunc)_key_equals, g_free, (GDestroyNotify)p_contact_free); name_to_barejid = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); } void roster_free(void) { autocomplete_free(name_ac); autocomplete_free(barejid_ac); autocomplete_free(fulljid_ac); autocomplete_free(groups_ac); } void roster_change_name(PContact contact, const char * const new_name) { assert(contact != NULL); const char *current_name = NULL; const char *barejid = p_contact_barejid(contact); if (p_contact_name(contact)) { current_name = strdup(p_contact_name(contact)); } p_contact_set_name(contact, new_name); _replace_name(current_name, new_name, barejid); } void roster_remove(const char * const name, const char * const barejid) { autocomplete_remove(barejid_ac, barejid); autocomplete_remove(name_ac, name); g_hash_table_remove(name_to_barejid, name); // remove each fulljid PContact contact = roster_get_contact(barejid); if (contact) { GList *resources = p_contact_get_available_resources(contact); while (resources) { GString *fulljid = g_string_new(strdup(barejid)); g_string_append(fulljid, "/"); g_string_append(fulljid, resources->data); autocomplete_remove(fulljid_ac, fulljid->str); g_string_free(fulljid, TRUE); resources = g_list_next(resources); } g_list_free(resources); } // remove the contact g_hash_table_remove(contacts, barejid); } void roster_update(const char * const barejid, const char * const name, GSList *groups, const char * const subscription, gboolean pending_out) { PContact contact = roster_get_contact(barejid); assert(contact != NULL); p_contact_set_subscription(contact, subscription); p_contact_set_pending_out(contact, pending_out); const char * const new_name = name; const char * current_name = NULL; if (p_contact_name(contact)) { current_name = strdup(p_contact_name(contact)); } p_contact_set_name(contact, new_name); p_contact_set_groups(contact, groups); _replace_name(current_name, new_name, barejid); // add groups while (groups) { autocomplete_add(groups_ac, groups->data); groups = g_slist_next(groups); } } gboolean roster_add(const char * const barejid, const char * const name, GSList *groups, const char * const subscription, gboolean pending_out) { PContact contact = roster_get_contact(barejid); if (contact) { return FALSE; } contact = p_contact_new(barejid, name, groups, subscription, NULL, pending_out); // add groups while (groups) { autocomplete_add(groups_ac, groups->data); groups = g_slist_next(groups); } g_hash_table_insert(contacts, strdup(barejid), contact); autocomplete_add(barejid_ac, barejid); _add_name_and_barejid(name, barejid); return TRUE; } char * roster_barejid_from_name(const char * const name) { if (name) { return g_hash_table_lookup(name_to_barejid, name); } else { return NULL; } } GSList * roster_get_contacts_by_presence(const char * const presence) { GSList *result = NULL; GHashTableIter iter; gpointer key; gpointer value; g_hash_table_iter_init(&iter, contacts); while (g_hash_table_iter_next(&iter, &key, &value)) { PContact contact = (PContact)value; if (g_strcmp0(p_contact_presence(contact), presence) == 0) { result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_contacts); } } // return all contact structs return result; } GSList * roster_get_contacts(void) { GSList *result = NULL; GHashTableIter iter; gpointer key; gpointer value; g_hash_table_iter_init(&iter, contacts); while (g_hash_table_iter_next(&iter, &key, &value)) { result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_contacts); } // return all contact structs return result; } GSList * roster_get_contacts_online(void) { GSList *result = NULL; GHashTableIter iter; gpointer key; gpointer value; g_hash_table_iter_init(&iter, contacts); while (g_hash_table_iter_next(&iter, &key, &value)) { if(strcmp(p_contact_presence(value), "offline")) result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_contacts); } // return all contact structs return result; } gboolean roster_has_pending_subscriptions(void) { GHashTableIter iter; gpointer key; gpointer value; g_hash_table_iter_init(&iter, contacts); while (g_hash_table_iter_next(&iter, &key, &value)) { PContact contact = (PContact) value; if (p_contact_pending_out(contact)) { return TRUE; } } return FALSE; } char * roster_contact_autocomplete(const char * const search_str) { return autocomplete_complete(name_ac, search_str, TRUE); } char * roster_fulljid_autocomplete(const char * const search_str) { return autocomplete_complete(fulljid_ac, search_str, TRUE); } GSList * roster_get_nogroup(void) { GSList *result = NULL; GHashTableIter iter; gpointer key; gpointer value; g_hash_table_iter_init(&iter, contacts); while (g_hash_table_iter_next(&iter, &key, &value)) { GSList *groups = p_contact_groups(value); if (groups == NULL) { result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_contacts); } } // return all contact structs return result; } GSList * roster_get_group(const char * const group) { GSList *result = NULL; GHashTableIter iter; gpointer key; gpointer value; g_hash_table_iter_init(&iter, contacts); while (g_hash_table_iter_next(&iter, &key, &value)) { GSList *groups = p_contact_groups(value); while (groups) { if (strcmp(groups->data, group) == 0) { result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_contacts); break; } groups = g_slist_next(groups); } } // return all contact structs return result; } GSList * roster_get_groups(void) { return autocomplete_create_list(groups_ac); } char * roster_group_autocomplete(const char * const search_str) { return autocomplete_complete(groups_ac, search_str, TRUE); } char * roster_barejid_autocomplete(const char * const search_str) { return autocomplete_complete(barejid_ac, search_str, TRUE); } static gboolean _key_equals(void *key1, void *key2) { gchar *str1 = (gchar *) key1; gchar *str2 = (gchar *) key2; return (g_strcmp0(str1, str2) == 0); } static gboolean _datetimes_equal(GDateTime *dt1, GDateTime *dt2) { if ((dt1 == NULL) && (dt2 == NULL)) { return TRUE; } else if ((dt1 == NULL) && (dt2 != NULL)) { return FALSE; } else if ((dt1 != NULL) && (dt2 == NULL)) { return FALSE; } else { return g_date_time_equal(dt1, dt2); } } static void _replace_name(const char * const current_name, const char * const new_name, const char * const barejid) { // current handle exists already if (current_name) { autocomplete_remove(name_ac, current_name); g_hash_table_remove(name_to_barejid, current_name); _add_name_and_barejid(new_name, barejid); // no current handle } else if (new_name) { autocomplete_remove(name_ac, barejid); g_hash_table_remove(name_to_barejid, barejid); _add_name_and_barejid(new_name, barejid); } } static void _add_name_and_barejid(const char * const name, const char * const barejid) { if (name) { autocomplete_add(name_ac, name); g_hash_table_insert(name_to_barejid, strdup(name), strdup(barejid)); } else { autocomplete_add(name_ac, barejid); g_hash_table_insert(name_to_barejid, strdup(barejid), strdup(barejid)); } } static gint _compare_contacts(PContact a, PContact b) { const char * utf8_str_a = NULL; const char * utf8_str_b = NULL; if (p_contact_name_collate_key(a)) { utf8_str_a = p_contact_name_collate_key(a); } else { utf8_str_a = p_contact_barejid_collate_key(a); } if (p_contact_name_collate_key(b)) { utf8_str_b = p_contact_name_collate_key(b); } else { utf8_str_b = p_contact_barejid_collate_key(b); } gint result = g_strcmp0(utf8_str_a, utf8_str_b); return result; } profanity-0.4.7/src/roster_list.h000066400000000000000000000062041257755232500170650ustar00rootroot00000000000000/* * roster_list.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef ROSTER_LIST_H #define ROSTER_LIST_H #include #include "resource.h" #include "contact.h" void roster_clear(void); gboolean roster_update_presence(const char * const barejid, Resource *resource, GDateTime *last_activity); PContact roster_get_contact(const char * const barejid); gboolean roster_contact_offline(const char * const barejid, const char * const resource, const char * const status); void roster_reset_search_attempts(void); void roster_init(void); void roster_free(void); void roster_change_name(PContact contact, const char * const new_name); void roster_remove(const char * const name, const char * const barejid); void roster_update(const char * const barejid, const char * const name, GSList *groups, const char * const subscription, gboolean pending_out); gboolean roster_add(const char * const barejid, const char * const name, GSList *groups, const char * const subscription, gboolean pending_out); char * roster_barejid_from_name(const char * const name); GSList * roster_get_contacts(void); GSList * roster_get_contacts_online(void); gboolean roster_has_pending_subscriptions(void); char * roster_contact_autocomplete(const char * const search_str); char * roster_fulljid_autocomplete(const char * const search_str); GSList * roster_get_group(const char * const group); GSList * roster_get_groups(void); char * roster_group_autocomplete(const char * const search_str); char * roster_barejid_autocomplete(const char * const search_str); GSList * roster_get_contacts_by_presence(const char * const presence); GSList * roster_get_nogroup(void); char * roster_get_msg_display_name(const char * const barejid, const char * const resource); #endif profanity-0.4.7/src/tools/000077500000000000000000000000001257755232500155015ustar00rootroot00000000000000profanity-0.4.7/src/tools/autocomplete.c000066400000000000000000000210331257755232500203450ustar00rootroot00000000000000/* * autocomplete.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include "common.h" #include "tools/autocomplete.h" #include "tools/parser.h" struct autocomplete_t { GSList *items; GSList *last_found; gchar *search_str; }; static gchar * _search_from(Autocomplete ac, GSList *curr, gboolean quote); Autocomplete autocomplete_new(void) { Autocomplete new = malloc(sizeof(struct autocomplete_t)); new->items = NULL; new->last_found = NULL; new->search_str = NULL; return new; } void autocomplete_clear(Autocomplete ac) { if (ac) { g_slist_free_full(ac->items, free); ac->items = NULL; autocomplete_reset(ac); } } void autocomplete_reset(Autocomplete ac) { ac->last_found = NULL; FREE_SET_NULL(ac->search_str); } void autocomplete_free(Autocomplete ac) { if (ac) { autocomplete_clear(ac); free(ac); } } gint autocomplete_length(Autocomplete ac) { if (!ac) { return 0; } else if (!ac->items) { return 0; } else { return g_slist_length(ac->items); } } void autocomplete_add(Autocomplete ac, const char *item) { if (ac) { char *item_cpy; GSList *curr = g_slist_find_custom(ac->items, item, (GCompareFunc)strcmp); // if item already exists if (curr) { return; } item_cpy = strdup(item); ac->items = g_slist_insert_sorted(ac->items, item_cpy, (GCompareFunc)strcmp); } return; } void autocomplete_remove(Autocomplete ac, const char * const item) { if (ac) { GSList *curr = g_slist_find_custom(ac->items, item, (GCompareFunc)strcmp); if (!curr) { return; } // reset last found if it points to the item to be removed if (ac->last_found == curr) { ac->last_found = NULL; } free(curr->data); ac->items = g_slist_delete_link(ac->items, curr); } return; } GSList * autocomplete_create_list(Autocomplete ac) { GSList *copy = NULL; GSList *curr = ac->items; while(curr) { copy = g_slist_append(copy, strdup(curr->data)); curr = g_slist_next(curr); } return copy; } gboolean autocomplete_contains(Autocomplete ac, const char *value) { GSList *curr = ac->items; while(curr) { if (strcmp(curr->data, value) == 0) { return TRUE; } curr = g_slist_next(curr); } return FALSE; } gchar * autocomplete_complete(Autocomplete ac, const gchar *search_str, gboolean quote) { gchar *found = NULL; // no autocomplete to search if (!ac) { return NULL; } // no items to search if (!ac->items) { return NULL; } // first search attempt if (!ac->last_found) { if (ac->search_str) { FREE_SET_NULL(ac->search_str); } ac->search_str = strdup(search_str); found = _search_from(ac, ac->items, quote); return found; // subsequent search attempt } else { // search from here+1 to end found = _search_from(ac, g_slist_next(ac->last_found), quote); if (found) { return found; } // search from beginning found = _search_from(ac, ac->items, quote); if (found) { return found; } // we found nothing, reset search autocomplete_reset(ac); return NULL; } } char * autocomplete_param_with_func(const char * const input, char *command, autocomplete_func func) { GString *auto_msg = NULL; char *result = NULL; char command_cpy[strlen(command) + 2]; sprintf(command_cpy, "%s ", command); int len = strlen(command_cpy); if ((strncmp(input, command_cpy, len) == 0) && (strlen(input) > len)) { int i; int inp_len = strlen(input); char prefix[inp_len]; for(i = len; i < inp_len; i++) { prefix[i-len] = input[i]; } prefix[inp_len - len] = '\0'; char *found = func(prefix); if (found) { auto_msg = g_string_new(command_cpy); g_string_append(auto_msg, found); free(found); result = auto_msg->str; g_string_free(auto_msg, FALSE); } } return result; } char * autocomplete_param_with_ac(const char * const input, char *command, Autocomplete ac, gboolean quote) { GString *auto_msg = NULL; char *result = NULL; char *command_cpy = malloc(strlen(command) + 2); sprintf(command_cpy, "%s ", command); int len = strlen(command_cpy); int inp_len = strlen(input); if ((strncmp(input, command_cpy, len) == 0) && (strlen(input) > len)) { int i; char prefix[inp_len]; for(i = len; i < inp_len; i++) { prefix[i-len] = input[i]; } prefix[inp_len - len] = '\0'; char *found = autocomplete_complete(ac, prefix, quote); if (found) { auto_msg = g_string_new(command_cpy); g_string_append(auto_msg, found); free(found); result = auto_msg->str; g_string_free(auto_msg, FALSE); } } free(command_cpy); return result; } char * autocomplete_param_no_with_func(const char * const input, char *command, int arg_number, autocomplete_func func) { if (strncmp(input, command, strlen(command)) == 0 && (strlen(input) > strlen(command))) { GString *result_str = NULL; // count tokens properly int num_tokens = count_tokens(input); // if correct number of tokens, then candidate for autocompletion of last param if (num_tokens == arg_number) { gchar *start_str = get_start(input, arg_number); gchar *comp_str = g_strdup(&input[strlen(start_str)]); // autocomplete param if (comp_str) { char *found = func(comp_str); if (found) { result_str = g_string_new(""); g_string_append(result_str, start_str); g_string_append(result_str, found); char *result = result_str->str; g_string_free(result_str, FALSE); return result; } } } } return NULL; } static gchar * _search_from(Autocomplete ac, GSList *curr, gboolean quote) { while(curr) { // match found if (strncmp(curr->data, ac->search_str, strlen(ac->search_str)) == 0) { // set pointer to last found ac->last_found = curr; // if contains space, quote before returning if (quote && g_strrstr(curr->data, " ")) { GString *quoted = g_string_new("\""); g_string_append(quoted, curr->data); g_string_append(quoted, "\""); gchar *result = quoted->str; g_string_free(quoted, FALSE); return result; // otherwise just return the string } else { return strdup(curr->data); } } curr = g_slist_next(curr); } return NULL; } profanity-0.4.7/src/tools/autocomplete.h000066400000000000000000000053041257755232500203550ustar00rootroot00000000000000/* * autocomplete.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef AUTOCOMPLETE_H #define AUTOCOMPLETE_H #include typedef char*(*autocomplete_func)(const char * const); typedef struct autocomplete_t *Autocomplete; // allocate new autocompleter with no items Autocomplete autocomplete_new(void); // Remove all items from the autocompleter void autocomplete_clear(Autocomplete ac); // free all memory used by the autocompleter void autocomplete_free(Autocomplete ac); void autocomplete_add(Autocomplete ac, const char *item); void autocomplete_remove(Autocomplete ac, const char * const item); // find the next item prefixed with search string gchar * autocomplete_complete(Autocomplete ac, const gchar *search_str, gboolean quote); GSList * autocomplete_create_list(Autocomplete ac); gint autocomplete_length(Autocomplete ac); char * autocomplete_param_with_func(const char * const input, char *command, autocomplete_func func); char * autocomplete_param_with_ac(const char * const input, char *command, Autocomplete ac, gboolean quote); char * autocomplete_param_no_with_func(const char * const input, char *command, int arg_number, autocomplete_func func); void autocomplete_reset(Autocomplete ac); gboolean autocomplete_contains(Autocomplete ac, const char *value); #endif profanity-0.4.7/src/tools/p_sha1.c000066400000000000000000000305601257755232500170240ustar00rootroot00000000000000/** @file * SHA-1 hash. */ /* SHA-1 in C By Steve Reid 100% Public Domain ----------------- Modified 7/98 By James H. Brown Still 100% Public Domain Corrected a problem which generated improper hash values on 16 bit machines Routine SHA1Update changed from void SHA1Update(P_SHA1_CTX* context, unsigned char* data, unsigned int len) to void SHA1Update(P_SHA1_CTX* context, unsigned char* data, unsigned long len) The 'len' parameter was declared an int which works fine on 32 bit machines. However, on 16 bit machines an int is too small for the shifts being done against it. This caused the hash function to generate incorrect values if len was greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). Since the file IO in main() reads 16K at a time, any file 8K or larger would be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million "a"s). I also changed the declaration of variables i & j in SHA1Update to unsigned long from unsigned int for the same reason. These changes should make no difference to any 32 bit implementations since an int and a long are the same size in those environments. -- I also corrected a few compiler warnings generated by Borland C. 1. Added #include for exit() prototype 2. Removed unused variable 'j' in SHA1Final 3. Changed exit(0) to return(0) at end of main. ALL changes I made can be located by searching for comments containing 'JHB' ----------------- Modified 8/98 By Steve Reid Still 100% public domain 1- Removed #include and used return() instead of exit() 2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) 3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net ----------------- Modified 4/01 By Saul Kravitz Still 100% PD Modified to run on Compaq Alpha hardware. ----------------- Modified 07/2002 By Ralph Giles Still 100% public domain modified for use with stdint types, autoconf code cleanup, removed attribution comments switched SHA1Final() argument order for consistency use SHA1_ prefix for public api move public api to sha1.h */ /* Test Vectors (from FIPS PUB 180-1) "abc" A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 A million repetitions of "a" 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ /* #define SHA1HANDSOFF */ #include #include /* make sure the stdint.h types are available */ #if defined(_MSC_VER) /* Microsoft Visual C++ */ typedef signed char int8_t; typedef short int int16_t; typedef int int32_t; typedef __int64 int64_t; typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned int uint32_t; /* no uint64_t */ #else #include #endif #include "p_sha1.h" static uint32_t host_to_be(uint32_t i); void P_SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ /* I got the idea of expanding during the round function from SSLeay */ #define blk0(i) (block->l[i] = host_to_be(block->l[i])) #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ ^block->l[(i+2)&15]^block->l[i&15],1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); #ifdef VERBOSE /* SAK */ void SHAPrintContext(P_P_SHA1_CTX *context, char *msg){ printf("%s (%d,%d) %x %x %x %x %x\n", msg, context->count[0], context->count[1], context->state[0], context->state[1], context->state[2], context->state[3], context->state[4]); } #endif /* VERBOSE */ static uint32_t host_to_be(uint32_t i) { #define le_to_be(i) ((rol((i),24) & 0xFF00FF00) | (rol((i),8) & 0x00FF00FF)) #if defined(__BIG_ENDIAN__) || \ (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) return i; #elif defined(__LITTLE_ENDIAN__) || \ (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) return le_to_be(i); #else /* fallback to run-time check */ static const union { uint32_t u; unsigned char c; } check = {1}; return check.c ? le_to_be(i) : i; #endif } /* Hash a single 512-bit block. This is the core of the algorithm. */ void P_SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) { uint32_t a, b, c, d, e; typedef union { uint8_t c[64]; uint32_t l[16]; } CHAR64LONG16; CHAR64LONG16* block; #ifdef SHA1HANDSOFF static uint8_t workspace[64]; block = (CHAR64LONG16*)workspace; memcpy(block, buffer, 64); #else block = (CHAR64LONG16*)buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } /* SHA1Init - Initialize new context */ void P_SHA1_Init(P_SHA1_CTX* context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } /* Run your data through this. */ void P_SHA1_Update(P_SHA1_CTX* context, const uint8_t* data, const size_t len) { size_t i, j; #ifdef VERBOSE SHAPrintContext(context, "before"); #endif j = (context->count[0] >> 3) & 63; if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; context->count[1] += (len >> 29); if ((j + len) > 63) { memcpy(&context->buffer[j], data, (i = 64-j)); P_SHA1_Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { P_SHA1_Transform(context->state, data + i); } j = 0; } else i = 0; memcpy(&context->buffer[j], &data[i], len - i); #ifdef VERBOSE SHAPrintContext(context, "after "); #endif } /* Add padding and return the message digest. */ void P_SHA1_Final(P_SHA1_CTX* context, uint8_t digest[P_SHA1_DIGEST_SIZE]) { uint32_t i; uint8_t finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } P_SHA1_Update(context, (uint8_t *)"\200", 1); while ((context->count[0] & 504) != 448) { P_SHA1_Update(context, (uint8_t *)"\0", 1); } P_SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ for (i = 0; i < P_SHA1_DIGEST_SIZE; i++) { digest[i] = (uint8_t) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } /* Wipe variables */ i = 0; memset(context->buffer, 0, 64); memset(context->state, 0, 20); memset(context->count, 0, 8); memset(finalcount, 0, 8); /* SWR */ #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ P_SHA1_Transform(context->state, context->buffer); #endif } /*************************************************************/ #if 0 int main(int argc, char** argv) { int i, j; P_SHA1_CTX context; unsigned char digest[P_SHA1_DIGEST_SIZE], buffer[16384]; FILE* file; if (argc > 2) { puts("Public domain SHA-1 implementation - by Steve Reid "); puts("Modified for 16 bit environments 7/98 - by James H. Brown "); /* JHB */ puts("Produces the SHA-1 hash of a file, or stdin if no file is specified."); return(0); } if (argc < 2) { file = stdin; } else { if (!(file = fopen(argv[1], "rb"))) { fputs("Unable to open file.", stderr); return(-1); } } SHA1_Init(&context); while (!feof(file)) { /* note: what if ferror(file) */ i = fread(buffer, 1, 16384, file); SHA1_Update(&context, buffer, i); } SHA1_Final(&context, digest); fclose(file); for (i = 0; i < P_SHA1_DIGEST_SIZE/4; i++) { for (j = 0; j < 4; j++) { printf("%02X", digest[i*4+j]); } putchar(' '); } putchar('\n'); return(0); /* JHB */ } #endif /* self test */ #ifdef TEST static char *test_data[] = { "abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "A million repetitions of 'a'"}; static char *test_results[] = { "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"}; void digest_to_hex(const uint8_t digest[P_SHA1_DIGEST_SIZE], char *output) { int i,j; char *c = output; for (i = 0; i < P_SHA1_DIGEST_SIZE/4; i++) { for (j = 0; j < 4; j++) { sprintf(c,"%02X", digest[i*4+j]); c += 2; } sprintf(c, " "); c += 1; } *(c - 1) = '\0'; } int main(int argc, char** argv) { int k; P_SHA1_CTX context; uint8_t digest[20]; char output[80]; fprintf(stdout, "verifying SHA-1 implementation... "); for (k = 0; k < 2; k++){ P_SHA1_Init(&context); P_SHA1_Update(&context, (uint8_t*)test_data[k], strlen(test_data[k])); P_SHA1_Final(&context, digest); digest_to_hex(digest, output); if (strcmp(output, test_results[k])) { fprintf(stdout, "FAIL\n"); fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]); fprintf(stderr,"\t%s returned\n", output); fprintf(stderr,"\t%s is correct\n", test_results[k]); return (1); } } /* million 'a' vector we feed separately */ P_SHA1_Init(&context); for (k = 0; k < 1000000; k++) P_SHA1_Update(&context, (uint8_t*)"a", 1); P_SHA1_Final(&context, digest); digest_to_hex(digest, output); if (strcmp(output, test_results[2])) { fprintf(stdout, "FAIL\n"); fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]); fprintf(stderr,"\t%s returned\n", output); fprintf(stderr,"\t%s is correct\n", test_results[2]); return (1); } /* success */ fprintf(stdout, "ok\n"); return(0); } #endif /* TEST */ profanity-0.4.7/src/tools/p_sha1.h000066400000000000000000000011371257755232500170270ustar00rootroot00000000000000/* public api for steve reid's public domain SHA-1 implementation */ /* this file is in the public domain */ /** @file * SHA-1 hash API. */ #ifndef __P_SHA1_H #define __P_SHA1_H #ifdef __cplusplus extern "C" { #endif typedef struct { uint32_t state[5]; uint32_t count[2]; uint8_t buffer[64]; } P_SHA1_CTX; #define P_SHA1_DIGEST_SIZE 20 void P_SHA1_Init(P_SHA1_CTX* context); void P_SHA1_Update(P_SHA1_CTX* context, const uint8_t* data, const size_t len); void P_SHA1_Final(P_SHA1_CTX* context, uint8_t digest[P_SHA1_DIGEST_SIZE]); #ifdef __cplusplus } #endif #endif /* __P_SHA1_H */ profanity-0.4.7/src/tools/parser.c000066400000000000000000000320051257755232500171410ustar00rootroot00000000000000/* * parser.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include "common.h" /* * Take a full line of input and return an array of strings representing * the arguments of a command. * If the number of arguments found is less than min, or more than max * NULL is returned. * * inp - The line of input * min - The minimum allowed number of arguments * max - The maximum allowed number of arguments * * Returns - An NULL terminated array of strings representing the arguments * of the command, or NULL if the validation fails. * * E.g. the following input line: * * /cmd arg1 arg2 * * Will return a pointer to the following array: * * { "arg1", "arg2", NULL } * */ gchar ** parse_args(const char * const inp, int min, int max, gboolean *result) { if (inp == NULL) { *result = FALSE; return NULL; } // copy and strip input of leading/trailing whitespace char *copy = strdup(inp); g_strstrip(copy); int inp_size = g_utf8_strlen(copy, -1); gboolean in_token = FALSE; gboolean in_quotes = FALSE; char *token_start = ©[0]; int token_size = 0; GSList *tokens = NULL; // add tokens to GSList int i; for (i = 0; i < inp_size; i++) { gchar *curr_ch = g_utf8_offset_to_pointer(copy, i); gunichar curr_uni = g_utf8_get_char(curr_ch); if (!in_token) { if (curr_uni == ' ') { continue; } else { in_token = TRUE; if (curr_uni == '"') { in_quotes = TRUE; i++; gchar *next_ch = g_utf8_next_char(curr_ch); gunichar next_uni = g_utf8_get_char(next_ch); token_start = next_ch; token_size += g_unichar_to_utf8(next_uni, NULL); } else { token_start = curr_ch; token_size += g_unichar_to_utf8(curr_uni, NULL); } } } else { if (in_quotes) { if (curr_uni == '"') { tokens = g_slist_append(tokens, g_strndup(token_start, token_size)); token_size = 0; in_token = FALSE; in_quotes = FALSE; } else { token_size += g_unichar_to_utf8(curr_uni, NULL); } } else { if (curr_uni == ' ') { tokens = g_slist_append(tokens, g_strndup(token_start, token_size)); token_size = 0; in_token = FALSE; } else { token_size += g_unichar_to_utf8(curr_uni, NULL); } } } } if (in_token) { tokens = g_slist_append(tokens, g_strndup(token_start, token_size)); } int num = g_slist_length(tokens) - 1; // if num args not valid return NULL if ((num < min) || (num > max)) { g_slist_free_full(tokens, free); g_free(copy); *result = FALSE; return NULL; // if min allowed is 0 and 0 found, return empty char* array } else if (min == 0 && num == 0) { g_slist_free_full(tokens, free); gchar **args = malloc((num + 1) * sizeof(*args)); args[0] = NULL; g_free(copy); *result = TRUE; return args; // otherwise return args array } else { gchar **args = malloc((num + 1) * sizeof(*args)); GSList *token = tokens; token = g_slist_next(token); int arg_count = 0; while (token) { args[arg_count++] = strdup(token->data); token = g_slist_next(token); } args[arg_count] = NULL; g_slist_free_full(tokens, free); g_free(copy); *result = TRUE; return args; } } /* * Take a full line of input and return an array of strings representing * the arguments of a command. This function handles when the last parameter * to the command is free text e.g. * * /msg user@host here is a message * * If the number of arguments found is less than min, or more than max * NULL is returned. * * inp - The line of input * min - The minimum allowed number of arguments * max - The maximum allowed number of arguments * * Returns - An NULL terminated array of strings representing the arguments * of the command, or NULL if the validation fails. * * E.g. the following input line: * * /cmd arg1 arg2 some free text * * Will return a pointer to the following array: * * { "arg1", "arg2", "some free text", NULL } * */ gchar ** parse_args_with_freetext(const char * const inp, int min, int max, gboolean *result) { if (inp == NULL) { *result = FALSE; return NULL; } // copy and strip input of leading/trailing whitepsace char *copy = strdup(inp); g_strstrip(copy); int inp_size = g_utf8_strlen(copy, -1); gboolean in_token = FALSE; gboolean in_freetext = FALSE; gboolean in_quotes = FALSE; char *token_start = ©[0]; int token_size = 0; int num_tokens = 0; GSList *tokens = NULL; // add tokens to GSList int i; for (i = 0; i < inp_size; i++) { gchar *curr_ch = g_utf8_offset_to_pointer(copy, i); gunichar curr_uni = g_utf8_get_char(curr_ch); if (!in_token) { if (curr_uni == ' ') { continue; } else { in_token = TRUE; num_tokens++; if ((num_tokens == max + 1) && (curr_uni != '"')) { in_freetext = TRUE; } else if (curr_uni == '"') { in_quotes = TRUE; i++; gchar *next_ch = g_utf8_next_char(curr_ch); gunichar next_uni = g_utf8_get_char(next_ch); token_start = next_ch; token_size += g_unichar_to_utf8(next_uni, NULL); } if (curr_uni == '"') { gchar *next_ch = g_utf8_next_char(curr_ch); token_start = next_ch; } else { token_start = curr_ch; token_size += g_unichar_to_utf8(curr_uni, NULL); } } } else { if (in_quotes) { if (curr_uni == '"') { tokens = g_slist_append(tokens, g_strndup(token_start, token_size)); token_size = 0; in_token = FALSE; in_quotes = FALSE; } else { if (curr_uni != '"') { token_size += g_unichar_to_utf8(curr_uni, NULL); } } } else { if (in_freetext) { token_size += g_unichar_to_utf8(curr_uni, NULL); } else if (curr_uni == ' ') { tokens = g_slist_append(tokens, g_strndup(token_start, token_size)); token_size = 0; in_token = FALSE; } else if (curr_uni != '"') { token_size += g_unichar_to_utf8(curr_uni, NULL); } } } } if (in_token) { tokens = g_slist_append(tokens, g_strndup(token_start, token_size)); } free(copy); int num = g_slist_length(tokens) - 1; // if num args not valid return NULL if ((num < min) || (num > max)) { g_slist_free_full(tokens, free); *result = FALSE; return NULL; // if min allowed is 0 and 0 found, return empty char* array } else if (min == 0 && num == 0) { g_slist_free_full(tokens, free); gchar **args = malloc((num + 1) * sizeof(*args)); args[0] = NULL; *result = TRUE; return args; // otherwise return args array } else { gchar **args = malloc((num + 1) * sizeof(*args)); GSList *token = tokens; token = g_slist_next(token); int arg_count = 0; while (token) { args[arg_count++] = strdup(token->data); token = g_slist_next(token); } args[arg_count] = NULL; g_slist_free_full(tokens, free); *result = TRUE; return args; } } int count_tokens(const char * const string) { int length = g_utf8_strlen(string, -1); gboolean in_quotes = FALSE; int num_tokens = 0; int i = 0; // include first token num_tokens++; for (i = 0; i < length; i++) { gchar *curr_ch = g_utf8_offset_to_pointer(string, i); gunichar curr_uni = g_utf8_get_char(curr_ch); if (curr_uni == ' ') { if (!in_quotes) { num_tokens++; } } else if (curr_uni == '"') { if (in_quotes) { in_quotes = FALSE; } else { in_quotes = TRUE; } } } return num_tokens; } char * get_start(const char * const string, int tokens) { GString *result = g_string_new(""); int length = g_utf8_strlen(string, -1); gboolean in_quotes = FALSE; char *result_str = NULL; int num_tokens = 0; int i = 0; // include first token num_tokens++; for (i = 0; i < length; i++) { gchar *curr_ch = g_utf8_offset_to_pointer(string, i); gunichar curr_uni = g_utf8_get_char(curr_ch); if (num_tokens < tokens) { gchar *uni_char = malloc(7); int len = g_unichar_to_utf8(curr_uni, uni_char); uni_char[len] = '\0'; g_string_append(result, uni_char); } if (curr_uni == ' ') { if (!in_quotes) { num_tokens++; } } else if (curr_uni == '"') { if (in_quotes) { in_quotes = FALSE; } else { in_quotes = TRUE; } } } result_str = result->str; g_string_free(result, FALSE); return result_str; } GHashTable * parse_options(gchar **args, gchar **opt_keys, gboolean *res) { GList *keys = NULL; int i; for (i = 0; i < g_strv_length(opt_keys); i++) { keys = g_list_append(keys, opt_keys[i]); } GHashTable *options = NULL; // no options found, success if (args[0] == NULL) { options = g_hash_table_new(g_str_hash, g_str_equal); *res = TRUE; g_list_free(keys); return options; } // validate options int curr; GList *found_keys = NULL; for (curr = 0; curr < g_strv_length(args); curr+= 2) { // check if option valid if (g_list_find_custom(keys, args[curr], (GCompareFunc)g_strcmp0) == NULL) { *res = FALSE; g_list_free(keys); return options; } // check if duplicate if (g_list_find_custom(found_keys, args[curr], (GCompareFunc)g_strcmp0)) { *res = FALSE; g_list_free(keys); return options; } // check value given if (args[curr+1] == NULL) { *res = FALSE; g_list_free(keys); return options; } found_keys = g_list_append(found_keys, args[curr]); } g_list_free(found_keys); g_list_free(keys); // create map options = g_hash_table_new(g_str_hash, g_str_equal); *res = TRUE; for (curr = 0; curr < g_strv_length(args); curr+=2) { g_hash_table_insert(options, args[curr], args[curr+1]); } return options; } void options_destroy(GHashTable *options) { if (options) { g_hash_table_destroy(options); } } profanity-0.4.7/src/tools/parser.h000066400000000000000000000036351257755232500171550ustar00rootroot00000000000000/* * parser.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef PARSER_H #define PARSER_H #include gchar** parse_args(const char * const inp, int min, int max, gboolean *result); gchar** parse_args_with_freetext(const char * const inp, int min, int max, gboolean *result); int count_tokens(const char * const string); char* get_start(const char * const string, int tokens); GHashTable* parse_options(gchar **args, gchar **keys, gboolean *res); void options_destroy(GHashTable *options); #endifprofanity-0.4.7/src/tools/tinyurl.c000066400000000000000000000057071257755232500173640ustar00rootroot00000000000000/* * tinyurl.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include struct curl_data_t { char *buffer; size_t size; }; static size_t _data_callback(void *ptr, size_t size, size_t nmemb, void *data); gboolean tinyurl_valid(char *url) { return (g_str_has_prefix(url, "http://") || g_str_has_prefix(url, "https://")); } char * tinyurl_get(char *url) { GString *full_url = g_string_new("http://tinyurl.com/api-create.php?url="); g_string_append(full_url, url); CURL *handle = curl_easy_init(); struct curl_data_t output; output.buffer = NULL; output.size = 0; curl_easy_setopt(handle, CURLOPT_URL, full_url->str); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, _data_callback); curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&output); curl_easy_perform(handle); curl_easy_cleanup(handle); g_string_free(full_url, TRUE); if (output.buffer) { output.buffer[output.size++] = '\0'; return output.buffer; } else { return NULL; } } static size_t _data_callback(void *ptr, size_t size, size_t nmemb, void *data) { size_t realsize = size * nmemb; struct curl_data_t *mem = (struct curl_data_t *) data; mem->buffer = realloc(mem->buffer, mem->size + realsize + 1); if ( mem->buffer ) { memcpy( &( mem->buffer[ mem->size ] ), ptr, realsize ); mem->size += realsize; mem->buffer[ mem->size ] = 0; } return realsize; } profanity-0.4.7/src/tools/tinyurl.h000066400000000000000000000031371257755232500173640ustar00rootroot00000000000000/* * tinyurl.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef TINYURL_H #define TINYURL_H #include gboolean tinyurl_valid(char *url); char * tinyurl_get(char *url); #endif profanity-0.4.7/src/ui/000077500000000000000000000000001257755232500147565ustar00rootroot00000000000000profanity-0.4.7/src/ui/buffer.c000066400000000000000000000074631257755232500164050ustar00rootroot00000000000000/* * buffer.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include #include #include #ifdef HAVE_NCURSESW_NCURSES_H #include #elif HAVE_NCURSES_H #include #endif #include "ui/window.h" #include "ui/buffer.h" #define BUFF_SIZE 1200 struct prof_buff_t { GSList *entries; }; static void _free_entry(ProfBuffEntry *entry); ProfBuff buffer_create() { ProfBuff new_buff = malloc(sizeof(struct prof_buff_t)); new_buff->entries = NULL; return new_buff; } int buffer_size(ProfBuff buffer) { return g_slist_length(buffer->entries); } void buffer_free(ProfBuff buffer) { g_slist_free_full(buffer->entries, (GDestroyNotify)_free_entry); free(buffer); buffer = NULL; } void buffer_push(ProfBuff buffer, const char show_char, int pad_indent, GDateTime *time, int flags, theme_item_t theme_item, const char * const from, const char * const message, DeliveryReceipt *receipt) { ProfBuffEntry *e = malloc(sizeof(struct prof_buff_entry_t)); e->show_char = show_char; e->pad_indent = pad_indent; e->flags = flags; e->theme_item = theme_item; e->time = g_date_time_ref(time); e->from = strdup(from); e->message = strdup(message); e->receipt = receipt; if (g_slist_length(buffer->entries) == BUFF_SIZE) { _free_entry(buffer->entries->data); buffer->entries = g_slist_delete_link(buffer->entries, buffer->entries); } buffer->entries = g_slist_append(buffer->entries, e); } gboolean buffer_mark_received(ProfBuff buffer, const char * const id) { GSList *entries = buffer->entries; while (entries) { ProfBuffEntry *entry = entries->data; if (entry->receipt && g_strcmp0(entry->receipt->id, id) == 0) { if (!entry->receipt->received) { entry->receipt->received = TRUE; return TRUE; } } entries = g_slist_next(entries); } return FALSE; } ProfBuffEntry* buffer_yield_entry(ProfBuff buffer, int entry) { GSList *node = g_slist_nth(buffer->entries, entry); return node->data; } static void _free_entry(ProfBuffEntry *entry) { free(entry->message); free(entry->from); g_date_time_unref(entry->time); if (entry->receipt) { free(entry->receipt->id); free(entry->receipt); } free(entry); } profanity-0.4.7/src/ui/buffer.h000066400000000000000000000045511257755232500164050ustar00rootroot00000000000000/* * buffer.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef UI_BUFFER_H #define UI_BUFFER_H #include "config.h" #include "config/theme.h" #include typedef struct delivery_receipt_t { char *id; gboolean received; } DeliveryReceipt; typedef struct prof_buff_entry_t { char show_char; int pad_indent; GDateTime *time; int flags; theme_item_t theme_item; char *from; char *message; DeliveryReceipt *receipt; } ProfBuffEntry; typedef struct prof_buff_t *ProfBuff; ProfBuff buffer_create(); void buffer_free(ProfBuff buffer); void buffer_push(ProfBuff buffer, const char show_char, int pad_indent, GDateTime *time, int flags, theme_item_t theme_item, const char * const from, const char * const message, DeliveryReceipt *receipt); int buffer_size(ProfBuff buffer); ProfBuffEntry* buffer_yield_entry(ProfBuff buffer, int entry); gboolean buffer_mark_received(ProfBuff buffer, const char * const id); #endif profanity-0.4.7/src/ui/console.c000066400000000000000000001525421257755232500165750ustar00rootroot00000000000000/* * console.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #ifdef HAVE_NCURSESW_NCURSES_H #include #elif HAVE_NCURSES_H #include #endif #include "command/command.h" #include "common.h" #include "log.h" #include "muc.h" #include "roster_list.h" #include "config/preferences.h" #include "config/theme.h" #include "ui/window.h" #include "window_list.h" #include "ui/ui.h" #include "ui/statusbar.h" #include "xmpp/xmpp.h" #include "xmpp/bookmark.h" #ifdef HAVE_GIT_VERSION #include "gitversion.h" #endif static void _cons_splash_logo(void); void _show_roster_contacts(GSList *list, gboolean show_groups); void cons_show_time(void) { ProfWin *console = wins_get_console(); win_print(console, '-', 0, NULL, NO_EOL, 0, "", ""); } void cons_show_word(const char * const word) { ProfWin *console = wins_get_console(); win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", word); } void cons_debug(const char * const msg, ...) { ProfWin *console = wins_get_console(); if (strcmp(PACKAGE_STATUS, "development") == 0) { va_list arg; va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); win_println(console, 0, fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); } } void cons_show(const char * const msg, ...) { ProfWin *console = wins_get_console(); va_list arg; va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); win_println(console, 0, fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); } void cons_show_padded(int pad, const char * const msg, ...) { ProfWin *console = wins_get_console(); va_list arg; va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); win_println(console, pad, fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); } void cons_show_help(Command *command) { ProfWin *console = wins_get_console(); cons_show(""); win_vprint(console, '-', 0, NULL, 0, THEME_WHITE_BOLD, "", "%s", &command->cmd[1]); win_print(console, '-', 0, NULL, NO_EOL, THEME_WHITE_BOLD, "", ""); int i; for (i = 0; i < strlen(command->cmd) - 1 ; i++) { win_print(console, '-', 0, NULL, NO_EOL | NO_DATE, THEME_WHITE_BOLD, "", "-"); } win_print(console, '-', 0, NULL, NO_DATE, THEME_WHITE_BOLD, "", ""); cons_show(""); win_print(console, '-', 0, NULL, 0, THEME_WHITE_BOLD, "", "Synopsis"); ui_show_lines(console, command->help.synopsis); cons_show(""); win_print(console, '-', 0, NULL, 0, THEME_WHITE_BOLD, "", "Description"); win_println(console, 0, command->help.desc); int maxlen = 0; for (i = 0; command->help.args[i][0] != NULL; i++) { if (strlen(command->help.args[i][0]) > maxlen) maxlen = strlen(command->help.args[i][0]); } if (i > 0) { cons_show(""); win_print(console, '-', 0, NULL, 0, THEME_WHITE_BOLD, "", "Arguments"); for (i = 0; command->help.args[i][0] != NULL; i++) { win_vprint(console, '-', maxlen + 3, NULL, 0, 0, "", "%-*s: %s", maxlen + 1, command->help.args[i][0], command->help.args[i][1]); } } if (g_strv_length((gchar**)command->help.examples) > 0) { cons_show(""); win_print(console, '-', 0, NULL, 0, THEME_WHITE_BOLD, "", "Examples"); ui_show_lines(console, command->help.examples); } } void cons_bad_cmd_usage(const char * const cmd) { GString *msg = g_string_new(""); g_string_printf(msg, "Invalid usage, see '/help %s' for details.", &cmd[1]); cons_show(""); cons_show(msg->str); g_string_free(msg, TRUE); } void cons_show_error(const char * const msg, ...) { ProfWin *console = wins_get_console(); va_list arg; va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); win_print(console, '-', 0, NULL, 0, THEME_ERROR, "", fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); cons_alert(); } void cons_show_typing(const char * const barejid) { ProfWin *console = wins_get_console(); const char * display_usr = NULL; PContact contact = roster_get_contact(barejid); if (contact) { if (p_contact_name(contact)) { display_usr = p_contact_name(contact); } else { display_usr = barejid; } } else { display_usr = barejid; } win_vprint(console, '-', 0, NULL, 0, THEME_TYPING, "", "!! %s is typing a message...", display_usr); cons_alert(); } void cons_show_incoming_message(const char * const short_from, const int win_index) { ProfWin *console = wins_get_console(); int ui_index = win_index; if (ui_index == 10) { ui_index = 0; } win_vprint(console, '-', 0, NULL, 0, THEME_INCOMING, "", "<< incoming from %s (%d)", short_from, ui_index); cons_alert(); } void cons_about(void) { ProfWin *console = wins_get_console(); int rows, cols; getmaxyx(stdscr, rows, cols); if (prefs_get_boolean(PREF_SPLASH)) { _cons_splash_logo(); } else { if (strcmp(PACKAGE_STATUS, "development") == 0) { #ifdef HAVE_GIT_VERSION win_vprint(console, '-', 0, NULL, 0, 0, "", "Welcome to Profanity, version %sdev.%s.%s", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION); #else win_vprint(console, '-', 0, NULL, 0, 0, "", "Welcome to Profanity, version %sdev", PACKAGE_VERSION); #endif } else { win_vprint(console, '-', 0, NULL, 0, 0, "", "Welcome to Profanity, version %s", PACKAGE_VERSION); } } win_vprint(console, '-', 0, NULL, 0, 0, "", "Copyright (C) 2012 - 2015 James Booth <%s>.", PACKAGE_BUGREPORT); win_println(console, 0, "License GPLv3+: GNU GPL version 3 or later "); win_println(console, 0, ""); win_println(console, 0, "This is free software; you are free to change and redistribute it."); win_println(console, 0, "There is NO WARRANTY, to the extent permitted by law."); win_println(console, 0, ""); win_println(console, 0, "Type '/help' to show complete help."); win_println(console, 0, ""); if (prefs_get_boolean(PREF_VERCHECK)) { cons_check_version(FALSE); } pnoutrefresh(console->layout->win, 0, 0, 1, 0, rows-3, cols-1); cons_alert(); } void cons_check_version(gboolean not_available_msg) { ProfWin *console = wins_get_console(); char *latest_release = release_get_latest(); if (latest_release) { gboolean relase_valid = g_regex_match_simple("^\\d+\\.\\d+\\.\\d+$", latest_release, 0, 0); if (relase_valid) { if (release_is_new(latest_release)) { win_vprint(console, '-', 0, NULL, 0, 0, "", "A new version of Profanity is available: %s", latest_release); win_println(console, 0, "Check for details."); win_println(console, 0, ""); } else { if (not_available_msg) { win_println(console, 0, "No new version available."); win_println(console, 0, ""); } } cons_alert(); } free(latest_release); } } void cons_show_login_success(ProfAccount *account) { ProfWin *console = wins_get_console(); win_vprint(console, '-', 0, NULL, NO_EOL, 0, "", "%s logged in successfully, ", account->jid); resource_presence_t presence = accounts_get_login_presence(account->name); const char *presence_str = string_from_resource_presence(presence); theme_item_t presence_colour = theme_main_presence_attrs(presence_str); win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", "%s", presence_str); win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " (priority %d)", accounts_get_priority_for_presence_type(account->name, presence)); win_print(console, '-', 0, NULL, NO_DATE, 0, "", "."); cons_alert(); } void cons_show_wins(void) { ProfWin *console = wins_get_console(); cons_show(""); cons_show("Active windows:"); GSList *window_strings = wins_create_summary(); GSList *curr = window_strings; while (curr) { win_println(console, 0, curr->data); curr = g_slist_next(curr); } g_slist_free_full(window_strings, free); cons_show(""); cons_alert(); } void cons_show_room_invites(GSList *invites) { cons_show(""); if (invites == NULL) { cons_show("No outstanding chat room invites."); } else { cons_show("Chat room invites, use /join or /decline commands:"); while (invites) { cons_show(" %s", invites->data); invites = g_slist_next(invites); } } cons_alert(); } void cons_show_info(PContact pcontact) { ProfWin *console = wins_get_console(); win_show_info(console, pcontact); cons_alert(); } void cons_show_caps(const char * const fulljid, resource_presence_t presence) { ProfWin *console = wins_get_console(); cons_show(""); Capabilities *caps = caps_lookup(fulljid); if (caps) { const char *resource_presence = string_from_resource_presence(presence); theme_item_t presence_colour = theme_main_presence_attrs(resource_presence); win_vprint(console, '-', 0, NULL, NO_EOL, presence_colour, "", "%s", fulljid); win_print(console, '-', 0, NULL, NO_DATE, 0, "", ":"); // show identity if (caps->category || caps->type || caps->name) { win_print(console, '-', 0, NULL, NO_EOL, 0, "", "Identity: "); if (caps->name) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->name); if (caps->category || caps->type) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (caps->type) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->type); if (caps->category) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (caps->category) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->category); } win_newline(console); } if (caps->software) { win_vprint(console, '-', 0, NULL, NO_EOL, 0, "", "Software: %s", caps->software); } if (caps->software_version) { win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); } if (caps->software || caps->software_version) { win_newline(console); } if (caps->os) { win_vprint(console, '-', 0, NULL, NO_EOL, 0, "", "OS: %s", caps->os); } if (caps->os_version) { win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); } if (caps->os || caps->os_version) { win_newline(console); } if (caps->features) { win_println(console, 0, "Features:"); GSList *feature = caps->features; while (feature) { win_vprint(console, '-', 0, NULL, 0, 0, "", " %s", feature->data); feature = g_slist_next(feature); } } caps_destroy(caps); } else { cons_show("No capabilities found for %s", fulljid); } cons_alert(); } void cons_show_received_subs(void) { GSList *received = presence_get_subscription_requests(); if (received == NULL) { cons_show("No outstanding subscription requests."); } else { cons_show("Outstanding subscription requests from:", g_slist_length(received)); while (received) { cons_show(" %s", received->data); received = g_slist_next(received); } g_slist_free_full(received, g_free); } cons_alert(); } void cons_show_sent_subs(void) { if (roster_has_pending_subscriptions()) { GSList *contacts = roster_get_contacts(); PContact contact = NULL; cons_show("Awaiting subscription responses from:"); GSList *curr = contacts; while (curr) { contact = (PContact) curr->data; if (p_contact_pending_out(contact)) { cons_show(" %s", p_contact_barejid(contact)); } curr = g_slist_next(curr); } g_slist_free(contacts); } else { cons_show("No pending requests sent."); } cons_alert(); } void cons_show_room_list(GSList *rooms, const char * const conference_node) { ProfWin *console = wins_get_console(); if (rooms && (g_slist_length(rooms) > 0)) { cons_show("Chat rooms at %s:", conference_node); while (rooms) { DiscoItem *room = rooms->data; win_vprint(console, '-', 0, NULL, NO_EOL, 0, "", " %s", room->jid); if (room->name) { win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ", (%s)", room->name); } win_newline(console); rooms = g_slist_next(rooms); } } else { cons_show("No chat rooms at %s", conference_node); } cons_alert(); } void cons_show_bookmarks(const GList *list) { ProfWin *console = wins_get_console(); if (list == NULL) { cons_show(""); cons_show("No bookmarks found."); } else { cons_show(""); cons_show("Bookmarks:"); while (list) { Bookmark *item = list->data; theme_item_t presence_colour = THEME_TEXT; if (muc_active(item->jid)) { presence_colour = THEME_ONLINE; } win_vprint(console, '-', 0, NULL, NO_EOL, presence_colour, "", " %s", item->jid); if (item->nick) { win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", "/%s", item->nick); } if (item->autojoin) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " (autojoin)"); } if (item->password) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " (private)"); } if (muc_active(item->jid)) { ProfWin *roomwin = (ProfWin*)wins_get_muc(item->jid); if (roomwin) { int num = wins_get_num(roomwin); win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " (%d)", num); } } win_newline(console); list = g_list_next(list); } } cons_alert(); } void cons_show_disco_info(const char *jid, GSList *identities, GSList *features) { if ((identities && (g_slist_length(identities) > 0)) || (features && (g_slist_length(features) > 0))) { cons_show(""); cons_show("Service discovery info for %s", jid); if (identities) { cons_show(" Identities"); } while (identities) { DiscoIdentity *identity = identities->data; // anme trpe, cat GString *identity_str = g_string_new(" "); if (identity->name) { identity_str = g_string_append(identity_str, identity->name); identity_str = g_string_append(identity_str, " "); } if (identity->type) { identity_str = g_string_append(identity_str, identity->type); identity_str = g_string_append(identity_str, " "); } if (identity->category) { identity_str = g_string_append(identity_str, identity->category); } cons_show(identity_str->str); g_string_free(identity_str, FALSE); identities = g_slist_next(identities); } if (features) { cons_show(" Features:"); } while (features) { cons_show(" %s", features->data); features = g_slist_next(features); } cons_alert(); } } void cons_show_disco_items(GSList *items, const char * const jid) { ProfWin *console = wins_get_console(); if (items && (g_slist_length(items) > 0)) { cons_show(""); cons_show("Service discovery items for %s:", jid); while (items) { DiscoItem *item = items->data; win_vprint(console, '-', 0, NULL, NO_EOL, 0, "", " %s", item->jid); if (item->name) { win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ", (%s)", item->name); } win_vprint(console, '-', 0, NULL, NO_DATE, 0, "", ""); items = g_slist_next(items); } } else { cons_show(""); cons_show("No service discovery items for %s", jid); } cons_alert(); } void cons_show_status(const char * const barejid) { ProfWin *console = wins_get_console(); PContact pcontact = roster_get_contact(barejid); if (pcontact) { win_show_contact(console, pcontact); } else { cons_show("No such contact \"%s\" in roster.", barejid); } cons_alert(); } void cons_show_room_invite(const char * const invitor, const char * const room, const char * const reason) { char *display_from = NULL; PContact contact = roster_get_contact(invitor); if (contact) { if (p_contact_name(contact)) { display_from = strdup(p_contact_name(contact)); } else { display_from = strdup(invitor); } } else { display_from = strdup(invitor); } cons_show(""); cons_show("Chat room invite received:"); cons_show(" From : %s", display_from); cons_show(" Room : %s", room); if (reason) { cons_show(" Message: %s", reason); } cons_show("Use /join or /decline"); if (prefs_get_boolean(PREF_NOTIFY_INVITE)) { notify_invite(display_from, room, reason); } free(display_from); cons_alert(); } void cons_show_account_list(gchar **accounts) { ProfWin *console = wins_get_console(); int size = g_strv_length(accounts); if (size > 0) { cons_show("Accounts:"); int i = 0; for (i = 0; i < size; i++) { if ((jabber_get_connection_status() == JABBER_CONNECTED) && (g_strcmp0(jabber_get_account_name(), accounts[i]) == 0)) { resource_presence_t presence = accounts_get_last_presence(accounts[i]); theme_item_t presence_colour = theme_main_presence_attrs(string_from_resource_presence(presence)); win_vprint(console, '-', 0, NULL, 0, presence_colour, "", "%s", accounts[i]); } else { cons_show(accounts[i]); } } cons_show(""); } else { cons_show("No accounts created yet."); cons_show(""); } cons_alert(); } void cons_show_account(ProfAccount *account) { ProfWin *console = wins_get_console(); cons_show(""); cons_show("Account %s:", account->name); if (account->enabled) { cons_show ("enabled : TRUE"); } else { cons_show ("enabled : FALSE"); } cons_show ("jid : %s", account->jid); if (account->eval_password) { cons_show ("eval_password : %s", account->eval_password); } else if (account->password) { cons_show ("password : [redacted]"); } if (account->resource) { cons_show ("resource : %s", account->resource); } if (account->server) { cons_show ("server : %s", account->server); } if (account->port != 0) { cons_show ("port : %d", account->port); } if (account->muc_service) { cons_show ("muc service : %s", account->muc_service); } if (account->muc_nick) { cons_show ("muc nick : %s", account->muc_nick); } if (account->last_presence) { cons_show ("Last presence : %s", account->last_presence); } if (account->login_presence) { cons_show ("Login presence : %s", account->login_presence); } if (account->otr_policy) { cons_show ("OTR policy : %s", account->otr_policy); } if (g_list_length(account->otr_manual) > 0) { GString *manual = g_string_new("OTR manual : "); GList *curr = account->otr_manual; while (curr) { g_string_append(manual, curr->data); if (curr->next) { g_string_append(manual, ", "); } curr = curr->next; } cons_show(manual->str); g_string_free(manual, TRUE); } if (g_list_length(account->otr_opportunistic) > 0) { GString *opportunistic = g_string_new("OTR opportunistic : "); GList *curr = account->otr_opportunistic; while (curr) { g_string_append(opportunistic, curr->data); if (curr->next) { g_string_append(opportunistic, ", "); } curr = curr->next; } cons_show(opportunistic->str); g_string_free(opportunistic, TRUE); } if (g_list_length(account->otr_always) > 0) { GString *always = g_string_new("OTR always : "); GList *curr = account->otr_always; while (curr) { g_string_append(always, curr->data); if (curr->next) { g_string_append(always, ", "); } curr = curr->next; } cons_show(always->str); g_string_free(always, TRUE); } if (account->pgp_keyid) { cons_show ("PGP Key ID : %s", account->pgp_keyid); } cons_show ("Priority : chat:%d, online:%d, away:%d, xa:%d, dnd:%d", account->priority_chat, account->priority_online, account->priority_away, account->priority_xa, account->priority_dnd); if ((jabber_get_connection_status() == JABBER_CONNECTED) && (g_strcmp0(jabber_get_account_name(), account->name) == 0)) { GList *resources = jabber_get_available_resources(); GList *ordered_resources = NULL; GList *curr = resources; if (curr) { win_println(console, 0, "Resources:"); // sort in order of availability while (curr) { Resource *resource = curr->data; ordered_resources = g_list_insert_sorted(ordered_resources, resource, (GCompareFunc)resource_compare_availability); curr = g_list_next(curr); } } g_list_free(resources); curr = ordered_resources; while (curr) { Resource *resource = curr->data; const char *resource_presence = string_from_resource_presence(resource->presence); theme_item_t presence_colour = theme_main_presence_attrs(resource_presence); win_vprint(console, '-', 0, NULL, NO_EOL, presence_colour, "", " %s (%d), %s", resource->name, resource->priority, resource_presence); if (resource->status) { win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", resource->status); } win_vprint(console, '-', 0, NULL, NO_DATE, 0, "", ""); Jid *jidp = jid_create_from_bare_and_resource(account->jid, resource->name); Capabilities *caps = caps_lookup(jidp->fulljid); jid_destroy(jidp); if (caps) { // show identity if (caps->category || caps->type || caps->name) { win_print(console, '-', 0, NULL, NO_EOL, 0, "", " Identity: "); if (caps->name) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->name); if (caps->category || caps->type) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (caps->type) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->type); if (caps->category) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (caps->category) { win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->category); } win_newline(console); } if (caps->software) { win_vprint(console, '-', 0, NULL, NO_EOL, 0, "", " Software: %s", caps->software); } if (caps->software_version) { win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); } if (caps->software || caps->software_version) { win_newline(console); } if (caps->os) { win_vprint(console, '-', 0, NULL, NO_EOL, 0, "", " OS: %s", caps->os); } if (caps->os_version) { win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); } if (caps->os || caps->os_version) { win_newline(console); } caps_destroy(caps); } curr = g_list_next(curr); } g_list_free(ordered_resources); } cons_alert(); } void cons_show_aliases(GList *aliases) { if (aliases == NULL) { cons_show("No aliases configured."); return; } GList *curr = aliases; if (curr) { cons_show("Command aliases:"); } while (curr) { ProfAlias *alias = curr->data; cons_show(" /%s -> %s", alias->name, alias->value); curr = g_list_next(curr); } cons_show(""); } void cons_theme_setting(void) { char *theme = prefs_get_string(PREF_THEME); if (theme == NULL) { cons_show("Theme (/theme) : default"); } else { cons_show("Theme (/theme) : %s", theme); } prefs_free_string(theme); } void cons_privileges_setting(void) { if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) cons_show("MUC privileges (/privileges) : ON"); else cons_show("MUC privileges (/privileges) : OFF"); } void cons_beep_setting(void) { if (prefs_get_boolean(PREF_BEEP)) cons_show("Terminal beep (/beep) : ON"); else cons_show("Terminal beep (/beep) : OFF"); } void cons_resource_setting(void) { if (prefs_get_boolean(PREF_RESOURCE_TITLE)) cons_show("Resource title (/resource) : ON"); else cons_show("Resource title (/resource) : OFF"); if (prefs_get_boolean(PREF_RESOURCE_MESSAGE)) cons_show("Resource message (/resource) : ON"); else cons_show("Resource message (/resource) : OFF"); } void cons_wrap_setting(void) { if (prefs_get_boolean(PREF_WRAP)) cons_show("Word wrap (/wrap) : ON"); else cons_show("Word wrap (/wrap) : OFF"); } void cons_winstidy_setting(void) { if (prefs_get_boolean(PREF_WINS_AUTO_TIDY)) cons_show("Window Auto Tidy (/wins) : ON"); else cons_show("Window Auto Tidy (/wins) : OFF"); } void cons_encwarn_setting(void) { if (prefs_get_boolean(PREF_ENC_WARN)) { cons_show("Warn unencrypted (/encwarn) : ON"); } else { cons_show("Warn unencrypted (/encwarn) : OFF"); } } void cons_presence_setting(void) { if (prefs_get_boolean(PREF_PRESENCE)) cons_show("Contact presence (/presence) : ON"); else cons_show("Contact presence (/presence) : OFF"); } void cons_flash_setting(void) { if (prefs_get_boolean(PREF_FLASH)) cons_show("Terminal flash (/flash) : ON"); else cons_show("Terminal flash (/flash) : OFF"); } void cons_splash_setting(void) { if (prefs_get_boolean(PREF_SPLASH)) cons_show("Splash screen (/splash) : ON"); else cons_show("Splash screen (/splash) : OFF"); } void cons_occupants_setting(void) { if (prefs_get_boolean(PREF_OCCUPANTS)) cons_show("Occupants (/occupants) : show"); else cons_show("Occupants (/occupants) : hide"); if (prefs_get_boolean(PREF_OCCUPANTS_JID)) cons_show("Occupant jids (/occupants) : show"); else cons_show("Occupant jids (/occupants) : hide"); int size = prefs_get_occupants_size(); cons_show("Occupants size (/occupants) : %d", size); } void cons_autoconnect_setting(void) { char *pref_connect_account = prefs_get_string(PREF_CONNECT_ACCOUNT); if (pref_connect_account) cons_show("Autoconnect (/autoconnect) : %s", pref_connect_account); else cons_show("Autoconnect (/autoconnect) : OFF"); prefs_free_string(pref_connect_account); } void cons_time_setting(void) { char *pref_time = prefs_get_string(PREF_TIME); if (g_strcmp0(pref_time, "off") == 0) cons_show("Time main (/time) : OFF"); else cons_show("Time main (/time) : %s", pref_time); prefs_free_string(pref_time); char *pref_time_statusbar = prefs_get_string(PREF_TIME_STATUSBAR); if (g_strcmp0(pref_time_statusbar, "off") == 0) cons_show("Time statusbar (/time) : OFF"); else cons_show("Time statusbar (/time) : %s", pref_time_statusbar); prefs_free_string(pref_time_statusbar); } void cons_vercheck_setting(void) { if (prefs_get_boolean(PREF_VERCHECK)) cons_show("Version checking (/vercheck) : ON"); else cons_show("Version checking (/vercheck) : OFF"); } void cons_statuses_setting(void) { char *console = prefs_get_string(PREF_STATUSES_CONSOLE); char *chat = prefs_get_string(PREF_STATUSES_CHAT); char *muc = prefs_get_string(PREF_STATUSES_MUC); cons_show("Console statuses (/statuses) : %s", console); cons_show("Chat statuses (/statuses) : %s", chat); cons_show("MUC statuses (/statuses) : %s", muc); prefs_free_string(console); prefs_free_string(chat); prefs_free_string(muc); } void cons_titlebar_setting(void) { if (prefs_get_boolean(PREF_TITLEBAR_SHOW)) { cons_show("Titlebar show (/titlebar) : ON"); } else { cons_show("Titlebar show (/titlebar) : OFF"); } if (prefs_get_boolean(PREF_TITLEBAR_GOODBYE)) { cons_show("Titlebar goodbye (/titlebar) : ON"); } else { cons_show("Titlebar goodbye (/titlebar) : OFF"); } } void cons_roster_setting(void) { if (prefs_get_boolean(PREF_ROSTER)) cons_show("Roster (/roster) : show"); else cons_show("Roster (/roster) : hide"); if (prefs_get_boolean(PREF_ROSTER_OFFLINE)) cons_show("Roster offline (/roster) : show"); else cons_show("Roster offline (/roster) : hide"); if (prefs_get_boolean(PREF_ROSTER_RESOURCE)) cons_show("Roster resource (/roster) : show"); else cons_show("Roster resource (/roster) : hide"); if (prefs_get_boolean(PREF_ROSTER_EMPTY)) cons_show("Roster empty (/roster) : show"); else cons_show("Roster empty (/roster) : hide"); char *by = prefs_get_string(PREF_ROSTER_BY); cons_show("Roster by (/roster) : %s", by); prefs_free_string(by); int size = prefs_get_roster_size(); cons_show("Roster size (/roster) : %d", size); } void cons_show_ui_prefs(void) { cons_show("UI preferences:"); cons_show(""); cons_theme_setting(); cons_beep_setting(); cons_flash_setting(); cons_splash_setting(); cons_wrap_setting(); cons_winstidy_setting(); cons_time_setting(); cons_resource_setting(); cons_vercheck_setting(); cons_statuses_setting(); cons_occupants_setting(); cons_roster_setting(); cons_privileges_setting(); cons_titlebar_setting(); cons_encwarn_setting(); cons_presence_setting(); cons_inpblock_setting(); cons_alert(); } void cons_notify_setting(void) { gboolean notify_enabled = FALSE; #ifdef HAVE_OSXNOTIFY notify_enabled = TRUE; #endif #ifdef HAVE_LIBNOTIFY notify_enabled = TRUE; #endif #ifdef PLATFORM_CYGWIN notify_enabled = TRUE; #endif if (notify_enabled) { if (prefs_get_boolean(PREF_NOTIFY_MESSAGE)) cons_show("Messages (/notify message) : ON"); else cons_show("Messages (/notify message) : OFF"); if (prefs_get_boolean(PREF_NOTIFY_MESSAGE_CURRENT)) cons_show("Messages current (/notify message) : ON"); else cons_show("Messages current (/notify message) : OFF"); if (prefs_get_boolean(PREF_NOTIFY_MESSAGE_TEXT)) cons_show("Messages text (/notify message) : ON"); else cons_show("Messages text (/notify message) : OFF"); char *room_setting = prefs_get_string(PREF_NOTIFY_ROOM); if (g_strcmp0(room_setting, "on") == 0) { cons_show ("Room messages (/notify room) : ON"); } else if (g_strcmp0(room_setting, "off") == 0) { cons_show ("Room messages (/notify room) : OFF"); } else { cons_show ("Room messages (/notify room) : %s", room_setting); } prefs_free_string(room_setting); if (prefs_get_boolean(PREF_NOTIFY_ROOM_CURRENT)) cons_show("Room current (/notify room) : ON"); else cons_show("Room current (/notify room) : OFF"); if (prefs_get_boolean(PREF_NOTIFY_ROOM_TEXT)) cons_show("Room text (/notify room) : ON"); else cons_show("Room text (/notify room) : OFF"); if (prefs_get_boolean(PREF_NOTIFY_TYPING)) cons_show("Composing (/notify typing) : ON"); else cons_show("Composing (/notify typing) : OFF"); if (prefs_get_boolean(PREF_NOTIFY_TYPING_CURRENT)) cons_show("Composing current (/notify typing) : ON"); else cons_show("Composing current (/notify typing) : OFF"); if (prefs_get_boolean(PREF_NOTIFY_INVITE)) cons_show("Room invites (/notify invite) : ON"); else cons_show("Room invites (/notify invite) : OFF"); if (prefs_get_boolean(PREF_NOTIFY_SUB)) cons_show("Subscription requests (/notify sub) : ON"); else cons_show("Subscription requests (/notify sub) : OFF"); gint remind_period = prefs_get_notify_remind(); if (remind_period == 0) { cons_show("Reminder period (/notify remind) : OFF"); } else if (remind_period == 1) { cons_show("Reminder period (/notify remind) : 1 second"); } else { cons_show("Reminder period (/notify remind) : %d seconds", remind_period); } } else { cons_show("Notification support was not included in this build."); } } void cons_show_desktop_prefs(void) { cons_show("Desktop notification preferences:"); cons_show(""); cons_notify_setting(); cons_alert(); } void cons_states_setting(void) { if (prefs_get_boolean(PREF_STATES)) cons_show("Send chat states (/states) : ON"); else cons_show("Send chat states (/states) : OFF"); } void cons_outtype_setting(void) { if (prefs_get_boolean(PREF_OUTTYPE)) cons_show("Send composing (/outtype) : ON"); else cons_show("Send composing (/outtype) : OFF"); } void cons_intype_setting(void) { if (prefs_get_boolean(PREF_INTYPE)) cons_show("Show typing (/intype) : ON"); else cons_show("Show typing (/intype) : OFF"); } void cons_gone_setting(void) { gint gone_time = prefs_get_gone(); if (gone_time == 0) { cons_show("Leave conversation (/gone) : OFF"); } else if (gone_time == 1) { cons_show("Leave conversation (/gone) : 1 minute"); } else { cons_show("Leave conversation (/gone) : %d minutes", gone_time); } } void cons_history_setting(void) { if (prefs_get_boolean(PREF_HISTORY)) cons_show("Chat history (/history) : ON"); else cons_show("Chat history (/history) : OFF"); } void cons_carbons_setting(void) { if (prefs_get_boolean(PREF_CARBONS)) cons_show("Message carbons (/carbons) : ON"); else cons_show("Message carbons (/carbons) : OFF"); } void cons_receipts_setting(void) { if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) cons_show("Request receipts (/receipts) : ON"); else cons_show("Request receipts (/receipts) : OFF"); if (prefs_get_boolean(PREF_RECEIPTS_SEND)) cons_show("Send receipts (/receipts) : ON"); else cons_show("Send receipts (/receipts) : OFF"); } void cons_show_chat_prefs(void) { cons_show("Chat preferences:"); cons_show(""); cons_states_setting(); cons_outtype_setting(); cons_intype_setting(); cons_gone_setting(); cons_history_setting(); cons_carbons_setting(); cons_receipts_setting(); cons_alert(); } void cons_inpblock_setting(void) { cons_show("Input timeout (/inpblock) : %d milliseconds", prefs_get_inpblock()); if (prefs_get_boolean(PREF_INPBLOCK_DYNAMIC)) { cons_show("Dynamic timeout (/inpblock) : ON"); } else { cons_show("Dynamic timeout (/inpblock) : OFF"); } } void cons_log_setting(void) { cons_show("Log file location : %s", get_log_file_location()); cons_show("Max log size (/log maxsize) : %d bytes", prefs_get_max_log_size()); if (prefs_get_boolean(PREF_LOG_ROTATE)) cons_show("Log rotation (/log rotate) : ON"); else cons_show("Log rotation (/log rotate) : OFF"); if (prefs_get_boolean(PREF_LOG_SHARED)) cons_show("Shared log (/log shared) : ON"); else cons_show("Shared log (/log shared) : OFF"); } void cons_chlog_setting(void) { if (prefs_get_boolean(PREF_CHLOG)) cons_show("Chat logging (/chlog) : ON"); else cons_show("Chat logging (/chlog) : OFF"); } void cons_grlog_setting(void) { if (prefs_get_boolean(PREF_GRLOG)) cons_show("Groupchat logging (/grlog) : ON"); else cons_show("Groupchat logging (/grlog) : OFF"); } void cons_show_log_prefs(void) { cons_show("Logging preferences:"); cons_show(""); cons_log_setting(); cons_chlog_setting(); cons_grlog_setting(); cons_alert(); } void cons_autoaway_setting(void) { char *pref_autoaway_mode = prefs_get_string(PREF_AUTOAWAY_MODE); if (strcmp(pref_autoaway_mode, "off") == 0) { cons_show("Autoaway (/autoaway mode) : OFF"); } else { cons_show("Autoaway (/autoaway mode) : %s", pref_autoaway_mode); } prefs_free_string(pref_autoaway_mode); cons_show("Autoaway minutes (/autoaway time) : %d minutes", prefs_get_autoaway_time()); char *pref_autoaway_message = prefs_get_string(PREF_AUTOAWAY_MESSAGE); if ((pref_autoaway_message == NULL) || (strcmp(pref_autoaway_message, "") == 0)) { cons_show("Autoaway message (/autoaway message) : OFF"); } else { cons_show("Autoaway message (/autoaway message) : \"%s\"", pref_autoaway_message); } prefs_free_string(pref_autoaway_message); if (prefs_get_boolean(PREF_AUTOAWAY_CHECK)) { cons_show("Autoaway check (/autoaway check) : ON"); } else { cons_show("Autoaway check (/autoaway check) : OFF"); } } void cons_show_presence_prefs(void) { cons_show("Presence preferences:"); cons_show(""); cons_autoaway_setting(); cons_alert(); } void cons_reconnect_setting(void) { gint reconnect_interval = prefs_get_reconnect(); if (reconnect_interval == 0) { cons_show("Reconnect interval (/reconnect) : OFF"); } else if (reconnect_interval == 1) { cons_show("Reconnect interval (/reconnect) : 1 second"); } else { cons_show("Reconnect interval (/reconnect) : %d seconds", reconnect_interval); } } void cons_autoping_setting(void) { gint autoping_interval = prefs_get_autoping(); if (autoping_interval == 0) { cons_show("Autoping interval (/autoping) : OFF"); } else if (autoping_interval == 1) { cons_show("Autoping interval (/autoping) : 1 second"); } else { cons_show("Autoping interval (/autoping) : %d seconds", autoping_interval); } } void cons_priority_setting(void) { gint priority = prefs_get_priority(); cons_show("Priority (/priority) : %d", priority); } void cons_show_connection_prefs(void) { cons_show("Connection preferences:"); cons_show(""); cons_reconnect_setting(); cons_autoping_setting(); cons_autoconnect_setting(); cons_alert(); } void cons_show_otr_prefs(void) { cons_show("OTR preferences:"); cons_show(""); char *policy_value = prefs_get_string(PREF_OTR_POLICY); cons_show("OTR policy (/otr policy) : %s", policy_value); prefs_free_string(policy_value); char *log_value = prefs_get_string(PREF_OTR_LOG); if (strcmp(log_value, "on") == 0) { cons_show("OTR logging (/otr log) : ON"); } else if (strcmp(log_value, "off") == 0) { cons_show("OTR logging (/otr log) : OFF"); } else { cons_show("OTR logging (/otr log) : Redacted"); } prefs_free_string(log_value); char ch = prefs_get_otr_char(); cons_show("OTR char (/otr char) : %c", ch); cons_alert(); } void cons_show_pgp_prefs(void) { cons_show("PGP preferences:"); cons_show(""); char *log_value = prefs_get_string(PREF_PGP_LOG); if (strcmp(log_value, "on") == 0) { cons_show("PGP logging (/pgp log) : ON"); } else if (strcmp(log_value, "off") == 0) { cons_show("PGP logging (/pgp log) : OFF"); } else { cons_show("PGP logging (/pgp log) : Redacted"); } prefs_free_string(log_value); char ch = prefs_get_pgp_char(); cons_show("PGP char (/pgp char) : %c", ch); cons_alert(); } void cons_show_themes(GSList *themes) { cons_show(""); if (themes == NULL) { cons_show("No available themes."); } else { cons_show("Available themes:"); while (themes) { cons_show(themes->data); themes = g_slist_next(themes); } } cons_alert(); } void cons_prefs(void) { cons_show(""); cons_show_ui_prefs(); cons_show(""); cons_show_desktop_prefs(); cons_show(""); cons_show_chat_prefs(); cons_show(""); cons_show_log_prefs(); cons_show(""); cons_show_presence_prefs(); cons_show(""); cons_show_connection_prefs(); cons_show(""); cons_show_otr_prefs(); cons_show(""); cons_show_pgp_prefs(); cons_show(""); cons_alert(); } void cons_help(void) { int pad = strlen("/help commands connection") + 3; cons_show(""); cons_show("Choose a help option:"); cons_show(""); cons_show_padded(pad, "/help commands : List all commands."); cons_show_padded(pad, "/help commands chat : List chat commands."); cons_show_padded(pad, "/help commands groupchat : List groupchat commands."); cons_show_padded(pad, "/help commands roster : List commands for manipulating your roster."); cons_show_padded(pad, "/help commands presence : List commands to change your presence."); cons_show_padded(pad, "/help commands discovery : List service discovery commands."); cons_show_padded(pad, "/help commands connection : List commands related to managing your connection."); cons_show_padded(pad, "/help commands ui : List commands for manipulating the user interface."); cons_show_padded(pad, "/help [command] : Detailed help on a specific command."); cons_show_padded(pad, "/help navigation : How to navigate around Profanity."); cons_show(""); cons_alert(); } void cons_navigation_help(void) { int pad = strlen("Alt-PAGEUP, Alt-PAGEDOWN") + 3; ProfWin *console = wins_get_console(); cons_show(""); win_print(console, '-', 0, NULL, 0, THEME_WHITE_BOLD, "", "Navigation"); cons_show_padded(pad, "Alt-1..Alt-0, F1..F10 : Choose window."); cons_show_padded(pad, "Alt-LEFT, Alt-RIGHT : Previous/next chat window"); cons_show_padded(pad, "PAGEUP, PAGEDOWN : Page the main window."); cons_show_padded(pad, "Alt-PAGEUP, Alt-PAGEDOWN : Page occupants/roster panel."); cons_show(""); cons_alert(); } void cons_show_roster_group(const char * const group, GSList *list) { cons_show(""); if (list) { cons_show("%s:", group); } else { cons_show("No group named %s exists.", group); } _show_roster_contacts(list, FALSE); cons_alert(); } void cons_show_roster(GSList *list) { cons_show(""); cons_show("Roster: jid (nick) - subscription - groups"); _show_roster_contacts(list, TRUE); cons_alert(); } void cons_show_contact_online(PContact contact, Resource *resource, GDateTime *last_activity) { const char *show = string_from_resource_presence(resource->presence); char *display_str = p_contact_create_display_string(contact, resource->name); ProfWin *console = wins_get_console(); win_show_status_string(console, display_str, show, resource->status, last_activity, "++", "online"); free(display_str); } void cons_show_contact_offline(PContact contact, char *resource, char *status) { char *display_str = p_contact_create_display_string(contact, resource); ProfWin *console = wins_get_console(); win_show_status_string(console, display_str, "offline", status, NULL, "--", "offline"); free(display_str); } void cons_show_contacts(GSList *list) { ProfWin *console = wins_get_console(); GSList *curr = list; while(curr) { PContact contact = curr->data; if ((strcmp(p_contact_subscription(contact), "to") == 0) || (strcmp(p_contact_subscription(contact), "both") == 0)) { win_show_contact(console, contact); } curr = g_slist_next(curr); } cons_alert(); } void cons_alert(void) { ProfWin *current = wins_get_current(); if (current->type != WIN_CONSOLE) { status_bar_new(1); } } void cons_theme_colours(void) { /* * { "default", -1 }, { "white", COLOR_WHITE }, { "green", COLOR_GREEN }, { "red", COLOR_RED }, { "yellow", COLOR_YELLOW }, { "blue", COLOR_BLUE }, { "cyan", COLOR_CYAN }, { "black", COLOR_BLACK }, { "magenta", COLOR_MAGENTA }, */ ProfWin *console = wins_get_console(); cons_show("Theme colours:"); win_print(console, '-', 0, NULL, NO_EOL, THEME_WHITE, "", " white "); win_print(console, '-', 0, NULL, NO_DATE, THEME_WHITE_BOLD, "", " bold_white"); win_print(console, '-', 0, NULL, NO_EOL, THEME_GREEN, "", " green "); win_print(console, '-', 0, NULL, NO_DATE, THEME_GREEN_BOLD, "", " bold_green"); win_print(console, '-', 0, NULL, NO_EOL, THEME_RED, "", " red "); win_print(console, '-', 0, NULL, NO_DATE, THEME_RED_BOLD, "", " bold_red"); win_print(console, '-', 0, NULL, NO_EOL, THEME_YELLOW, "", " yellow "); win_print(console, '-', 0, NULL, NO_DATE, THEME_YELLOW_BOLD, "", " bold_yellow"); win_print(console, '-', 0, NULL, NO_EOL, THEME_BLUE, "", " blue "); win_print(console, '-', 0, NULL, NO_DATE, THEME_BLUE_BOLD, "", " bold_blue"); win_print(console, '-', 0, NULL, NO_EOL, THEME_CYAN, "", " cyan "); win_print(console, '-', 0, NULL, NO_DATE, THEME_CYAN_BOLD, "", " bold_cyan"); win_print(console, '-', 0, NULL, NO_EOL, THEME_MAGENTA, "", " magenta "); win_print(console, '-', 0, NULL, NO_DATE, THEME_MAGENTA_BOLD, "", " bold_magenta"); win_print(console, '-', 0, NULL, NO_EOL, THEME_BLACK, "", " black "); win_print(console, '-', 0, NULL, NO_DATE, THEME_BLACK_BOLD, "", " bold_black"); cons_show(""); } static void _cons_splash_logo(void) { ProfWin *console = wins_get_console(); win_println(console, 0, "Welcome to"); win_print(console, '-', 0, NULL, 0, THEME_SPLASH, "", " ___ _ "); win_print(console, '-', 0, NULL, 0, THEME_SPLASH, "", " / __) (_)_ "); win_print(console, '-', 0, NULL, 0, THEME_SPLASH, "", " ____ ____ ___ | |__ ____ ____ _| |_ _ _ "); win_print(console, '-', 0, NULL, 0, THEME_SPLASH, "", "| _ \\ / ___) _ \\| __) _ | _ \\| | _) | | |"); win_print(console, '-', 0, NULL, 0, THEME_SPLASH, "", "| | | | | | |_| | | ( ( | | | | | | |_| |_| |"); win_print(console, '-', 0, NULL, 0, THEME_SPLASH, "", "| ||_/|_| \\___/|_| \\_||_|_| |_|_|\\___)__ |"); win_print(console, '-', 0, NULL, 0, THEME_SPLASH, "", "|_| (____/ "); win_print(console, '-', 0, NULL, 0, THEME_SPLASH, "", ""); if (strcmp(PACKAGE_STATUS, "development") == 0) { #ifdef HAVE_GIT_VERSION win_vprint(console, '-', 0, NULL, 0, 0, "", "Version %sdev.%s.%s", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION); #else win_vprint(console, '-', 0, NULL, 0, 0, "", "Version %sdev", PACKAGE_VERSION); #endif } else { win_vprint(console, '-', 0, NULL, 0, 0, "", "Version %s", PACKAGE_VERSION); } } void _show_roster_contacts(GSList *list, gboolean show_groups) { ProfWin *console = wins_get_console(); GSList *curr = list; while(curr) { PContact contact = curr->data; GString *title = g_string_new(" "); title = g_string_append(title, p_contact_barejid(contact)); if (p_contact_name(contact)) { title = g_string_append(title, " ("); title = g_string_append(title, p_contact_name(contact)); title = g_string_append(title, ")"); } const char *presence = p_contact_presence(contact); theme_item_t presence_colour = THEME_TEXT; if (p_contact_subscribed(contact)) { presence_colour = theme_main_presence_attrs(presence); } else { presence_colour = theme_main_presence_attrs("offline"); } win_vprint(console, '-', 0, NULL, NO_EOL, presence_colour, "", title->str); g_string_free(title, TRUE); win_print(console, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " - "); GString *sub = g_string_new(""); sub = g_string_append(sub, p_contact_subscription(contact)); if (p_contact_pending_out(contact)) { sub = g_string_append(sub, ", request sent"); } if (presence_sub_request_exists(p_contact_barejid(contact))) { sub = g_string_append(sub, ", request received"); } if (p_contact_subscribed(contact)) { presence_colour = THEME_SUBSCRIBED; } else { presence_colour = THEME_UNSUBSCRIBED; } if (show_groups) { win_vprint(console, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", "%s", sub->str); } else { win_vprint(console, '-', 0, NULL, NO_DATE, presence_colour, "", "%s", sub->str); } g_string_free(sub, TRUE); if (show_groups) { GSList *groups = p_contact_groups(contact); if (groups) { GString *groups_str = g_string_new(" - "); while (groups) { g_string_append(groups_str, groups->data); if (g_slist_next(groups)) { g_string_append(groups_str, ", "); } groups = g_slist_next(groups); } win_vprint(console, '-', 0, NULL, NO_DATE, 0, "", "%s", groups_str->str); g_string_free(groups_str, TRUE); } else { win_print(console, '-', 0, NULL, NO_DATE, 0, "", " "); } } curr = g_slist_next(curr); } } profanity-0.4.7/src/ui/core.c000066400000000000000000002605101257755232500160560ustar00rootroot00000000000000/* * core.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #ifdef HAVE_GIT_VERSION #include "gitversion.h" #endif #include #include #include #include #include #ifdef HAVE_LIBXSS #include #endif #include #ifdef HAVE_NCURSESW_NCURSES_H #include #elif HAVE_NCURSES_H #include #endif #include "chat_session.h" #include "command/command.h" #include "common.h" #include "config/preferences.h" #include "config/theme.h" #include "contact.h" #include "roster_list.h" #include "jid.h" #include "log.h" #include "muc.h" #ifdef HAVE_LIBOTR #include "otr/otr.h" #endif #include "ui/ui.h" #include "ui/titlebar.h" #include "ui/statusbar.h" #include "ui/inputwin.h" #include "ui/window.h" #include "window_list.h" #include "xmpp/xmpp.h" #include "event/ui_events.h" static char *win_title; static int inp_size; static gboolean perform_resize = FALSE; #ifdef HAVE_LIBXSS static Display *display; #endif static GTimer *ui_idle_time; //static void _win_handle_switch(const wint_t ch); static void _win_show_history(ProfChatWin *chatwin, const char * const contact); static void _ui_draw_term_title(void); void ui_init(void) { log_info("Initialising UI"); initscr(); nonl(); cbreak(); noecho(); keypad(stdscr, TRUE); ui_load_colours(); refresh(); create_title_bar(); create_status_bar(); status_bar_active(1); create_input_window(); wins_init(); notifier_initialise(); cons_about(); #ifdef HAVE_LIBXSS display = XOpenDisplay(0); #endif ui_idle_time = g_timer_new(); inp_size = 0; ProfWin *window = wins_get_current(); win_update_virtual(window); } void ui_sigwinch_handler(int sig) { perform_resize = TRUE; } void ui_update(void) { ProfWin *current = wins_get_current(); if (current->layout->paged == 0) { win_move_to_end(current); } win_update_virtual(current); if (prefs_get_boolean(PREF_TITLEBAR_SHOW)) { _ui_draw_term_title(); } title_bar_update_virtual(); status_bar_update_virtual(); inp_put_back(); doupdate(); if (perform_resize) { signal(SIGWINCH, SIG_IGN); ui_resize(); perform_resize = FALSE; signal(SIGWINCH, ui_sigwinch_handler); } } void ui_about(void) { cons_show(""); cons_about(); } unsigned long ui_get_idle_time(void) { // if compiled with libxss, get the x sessions idle time #ifdef HAVE_LIBXSS XScreenSaverInfo *info = XScreenSaverAllocInfo(); if (info && display) { XScreenSaverQueryInfo(display, DefaultRootWindow(display), info); unsigned long result = info->idle; XFree(info); return result; } if (info) { XFree(info); } // if no libxss or xss idle time failed, use profanity idle time #endif gdouble seconds_elapsed = g_timer_elapsed(ui_idle_time, NULL); unsigned long ms_elapsed = seconds_elapsed * 1000.0; return ms_elapsed; } void ui_reset_idle_time(void) { g_timer_start(ui_idle_time); } void ui_close(void) { notifier_uninit(); wins_destroy(); inp_close(); endwin(); } char * ui_readline(void) { return inp_readline(); } void ui_page_up(void) { ProfWin *current = wins_get_current(); win_page_up(current); } void ui_page_down(void) { ProfWin *current = wins_get_current(); win_page_down(current); } void ui_subwin_page_up(void) { ProfWin *current = wins_get_current(); win_sub_page_up(current); } void ui_subwin_page_down(void) { ProfWin *current = wins_get_current(); win_sub_page_down(current); } void ui_input_clear(void) { inp_win_clear(); } void ui_input_nonblocking(gboolean reset) { inp_nonblocking(reset); } void ui_resize(void) { struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); erase(); resizeterm(w.ws_row, w.ws_col); refresh(); log_debug("Resizing UI"); title_bar_resize(); wins_resize_all(); status_bar_resize(); inp_win_resize(); ProfWin *window = wins_get_current(); win_update_virtual(window); } void ui_redraw(void) { title_bar_resize(); wins_resize_all(); status_bar_resize(); inp_win_resize(); } void ui_load_colours(void) { if (has_colors()) { use_default_colors(); start_color(); theme_init_colours(); } } gboolean ui_xmlconsole_exists(void) { ProfXMLWin *xmlwin = wins_get_xmlconsole(); if (xmlwin) { return TRUE; } else { return FALSE; } } void ui_handle_stanza(const char * const msg) { if (ui_xmlconsole_exists()) { ProfXMLWin *xmlconsole = wins_get_xmlconsole(); ProfWin *window = (ProfWin*) xmlconsole; if (g_str_has_prefix(msg, "SENT:")) { win_print(window, '-', 0, NULL, 0, 0, "", "SENT:"); win_print(window, '-', 0, NULL, 0, THEME_ONLINE, "", &msg[6]); win_print(window, '-', 0, NULL, 0, THEME_ONLINE, "", ""); } else if (g_str_has_prefix(msg, "RECV:")) { win_print(window, '-', 0, NULL, 0, 0, "", "RECV:"); win_print(window, '-', 0, NULL, 0, THEME_AWAY, "", &msg[6]); win_print(window, '-', 0, NULL, 0, THEME_AWAY, "", ""); } } } gboolean ui_chat_win_exists(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); return (chatwin != NULL); } void ui_contact_online(char *barejid, Resource *resource, GDateTime *last_activity) { char *show_console = prefs_get_string(PREF_STATUSES_CONSOLE); char *show_chat_win = prefs_get_string(PREF_STATUSES_CHAT); PContact contact = roster_get_contact(barejid); // show nothing if (g_strcmp0(p_contact_subscription(contact), "none") == 0) { free(show_console); free(show_chat_win); return; } // show in console if "all" if (g_strcmp0(show_console, "all") == 0) { cons_show_contact_online(contact, resource, last_activity); // show in console of "online" and presence online } else if (g_strcmp0(show_console, "online") == 0 && resource->presence == RESOURCE_ONLINE) { cons_show_contact_online(contact, resource, last_activity); } // show in chat win if "all" if (g_strcmp0(show_chat_win, "all") == 0) { ui_chat_win_contact_online(contact, resource, last_activity); // show in char win if "online" and presence online } else if (g_strcmp0(show_chat_win, "online") == 0 && resource->presence == RESOURCE_ONLINE) { ui_chat_win_contact_online(contact, resource, last_activity); } free(show_console); free(show_chat_win); } void ui_contact_typing(const char * const barejid, const char * const resource) { ProfChatWin *chatwin = wins_get_chat(barejid); ProfWin *window = (ProfWin*) chatwin; ChatSession *session = chat_session_get(barejid); if (prefs_get_boolean(PREF_INTYPE)) { // no chat window for user if (chatwin == NULL) { cons_show_typing(barejid); // have chat window but not currently in it } else if (!wins_is_current(window)) { cons_show_typing(barejid); // in chat window with user, no session or session with resource } else if (!session || (session && g_strcmp0(session->resource, resource) == 0)) { title_bar_set_typing(TRUE); int num = wins_get_num(window); status_bar_active(num); } } if (prefs_get_boolean(PREF_NOTIFY_TYPING)) { gboolean is_current = FALSE; if (window) { is_current = wins_is_current(window); } if ( !is_current || (is_current && prefs_get_boolean(PREF_NOTIFY_TYPING_CURRENT)) ) { PContact contact = roster_get_contact(barejid); char const *display_usr = NULL; if (p_contact_name(contact)) { display_usr = p_contact_name(contact); } else { display_usr = barejid; } notify_typing(display_usr); } } } GSList * ui_get_chat_recipients(void) { GSList *recipients = wins_get_chat_recipients(); return recipients; } void ui_message_receipt(const char * const barejid, const char * const id) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { ProfWin *win = (ProfWin*) chatwin; win_mark_received(win, id); } } void ui_incoming_msg(ProfChatWin *chatwin, const char * const resource, const char * const message, GDateTime *timestamp, gboolean win_created, prof_enc_t enc_mode) { ProfWin *window = (ProfWin*)chatwin; int num = wins_get_num(window); char *display_name = roster_get_msg_display_name(chatwin->barejid, resource); // currently viewing chat window with sender if (wins_is_current(window)) { win_print_incoming_message(window, timestamp, display_name, message, enc_mode); title_bar_set_typing(FALSE); status_bar_active(num); // not currently viewing chat window with sender } else { status_bar_new(num); cons_show_incoming_message(display_name, num); if (prefs_get_boolean(PREF_FLASH)) { flash(); } chatwin->unread++; if (prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY)) { _win_show_history(chatwin, chatwin->barejid); } // show users status first, when receiving message via delayed delivery if (timestamp && win_created) { PContact pcontact = roster_get_contact(chatwin->barejid); if (pcontact) { win_show_contact(window, pcontact); } } win_print_incoming_message(window, timestamp, display_name, message, enc_mode); } if (prefs_get_boolean(PREF_BEEP)) { beep(); } if (prefs_get_boolean(PREF_NOTIFY_MESSAGE)) { notify_message(window, display_name, message); } free(display_name); } void ui_incoming_private_msg(const char * const fulljid, const char * const message, GDateTime *timestamp) { char *display_from = NULL; display_from = get_nick_from_full_jid(fulljid); ProfPrivateWin *privatewin = wins_get_private(fulljid); if (privatewin == NULL) { ProfWin *window = wins_new_private(fulljid); privatewin = (ProfPrivateWin*)window; } ProfWin *window = (ProfWin*) privatewin; int num = wins_get_num(window); // currently viewing chat window with sender if (wins_is_current(window)) { win_print_incoming_message(window, timestamp, display_from, message, PROF_MSG_PLAIN); title_bar_set_typing(FALSE); status_bar_active(num); // not currently viewing chat window with sender } else { privatewin->unread++; status_bar_new(num); cons_show_incoming_message(display_from, num); win_print_incoming_message(window, timestamp, display_from, message, PROF_MSG_PLAIN); if (prefs_get_boolean(PREF_FLASH)) { flash(); } } if (prefs_get_boolean(PREF_BEEP)) { beep(); } if (prefs_get_boolean(PREF_NOTIFY_MESSAGE)) { notify_message(window, display_from, message); } free(display_from); } void ui_roster_add(const char * const barejid, const char * const name) { if (name) { cons_show("Roster item added: %s (%s)", barejid, name); } else { cons_show("Roster item added: %s", barejid); } rosterwin_roster(); } void ui_roster_remove(const char * const barejid) { cons_show("Roster item removed: %s", barejid); rosterwin_roster(); } void ui_contact_already_in_group(const char * const contact, const char * const group) { cons_show("%s already in group %s", contact, group); rosterwin_roster(); } void ui_contact_not_in_group(const char * const contact, const char * const group) { cons_show("%s is not currently in group %s", contact, group); rosterwin_roster(); } void ui_group_added(const char * const contact, const char * const group) { cons_show("%s added to group %s", contact, group); rosterwin_roster(); } void ui_group_removed(const char * const contact, const char * const group) { cons_show("%s removed from group %s", contact, group); rosterwin_roster(); } void ui_auto_away(void) { char *pref_autoaway_message = prefs_get_string(PREF_AUTOAWAY_MESSAGE); if (pref_autoaway_message) { int pri = accounts_get_priority_for_presence_type(jabber_get_account_name(), RESOURCE_AWAY); cons_show("Idle for %d minutes, status set to away (priority %d), \"%s\".", prefs_get_autoaway_time(), pri, pref_autoaway_message); title_bar_set_presence(CONTACT_AWAY); } else { int pri = accounts_get_priority_for_presence_type(jabber_get_account_name(), RESOURCE_AWAY); cons_show("Idle for %d minutes, status set to away (priority %d).", prefs_get_autoaway_time(), pri); title_bar_set_presence(CONTACT_AWAY); } prefs_free_string(pref_autoaway_message); } void ui_end_auto_away(void) { int pri = accounts_get_priority_for_presence_type(jabber_get_account_name(), RESOURCE_ONLINE); cons_show("No longer idle, status set to online (priority %d).", pri); title_bar_set_presence(CONTACT_ONLINE); } void ui_titlebar_presence(contact_presence_t presence) { title_bar_set_presence(presence); } void ui_handle_login_account_success(ProfAccount *account) { resource_presence_t resource_presence = accounts_get_login_presence(account->name); contact_presence_t contact_presence = contact_presence_from_resource_presence(resource_presence); cons_show_login_success(account); title_bar_set_presence(contact_presence); GString *fulljid = g_string_new(account->jid); g_string_append(fulljid, "/"); g_string_append(fulljid, account->resource); status_bar_print_message(fulljid->str); g_string_free(fulljid, TRUE); status_bar_update_virtual(); } void ui_update_presence(const resource_presence_t resource_presence, const char * const message, const char * const show) { contact_presence_t contact_presence = contact_presence_from_resource_presence(resource_presence); title_bar_set_presence(contact_presence); gint priority = accounts_get_priority_for_presence_type(jabber_get_account_name(), resource_presence); if (message) { cons_show("Status set to %s (priority %d), \"%s\".", show, priority, message); } else { cons_show("Status set to %s (priority %d).", show, priority); } } void ui_handle_recipient_not_found(const char * const recipient, const char * const err_msg) { // intended recipient was invalid chat room ProfMucWin *mucwin = wins_get_muc(recipient); if (mucwin) { cons_show_error("Room %s not found: %s", recipient, err_msg); win_vprint((ProfWin*) mucwin, '!', 0, NULL, 0, THEME_ERROR, "", "Room %s not found: %s", recipient, err_msg); return; } } void ui_handle_recipient_error(const char * const recipient, const char * const err_msg) { // always show in console cons_show_error("Error from %s: %s", recipient, err_msg); ProfChatWin *chatwin = wins_get_chat(recipient); if (chatwin) { win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, THEME_ERROR, "", "Error from %s: %s", recipient, err_msg); return; } ProfMucWin *mucwin = wins_get_muc(recipient); if (mucwin) { win_vprint((ProfWin*)mucwin, '!', 0, NULL, 0, THEME_ERROR, "", "Error from %s: %s", recipient, err_msg); return; } ProfPrivateWin *privatewin = wins_get_private(recipient); if (privatewin) { win_vprint((ProfWin*)privatewin, '!', 0, NULL, 0, THEME_ERROR, "", "Error from %s: %s", recipient, err_msg); return; } } void ui_handle_error(const char * const err_msg) { GString *msg = g_string_new(""); g_string_printf(msg, "Error %s", err_msg); cons_show_error(msg->str); g_string_free(msg, TRUE); } void ui_invalid_command_usage(const char * const cmd, void (*setting_func)(void)) { GString *msg = g_string_new(""); g_string_printf(msg, "Invalid usage, see '/help %s' for details.", &cmd[1]); if (setting_func) { cons_show(""); (*setting_func)(); cons_show(msg->str); } else { cons_show(""); cons_show(msg->str); ProfWin *current = wins_get_current(); if (current->type == WIN_CHAT) { ui_current_print_line(msg->str); } } g_string_free(msg, TRUE); } void ui_disconnected(void) { wins_lost_connection(); title_bar_set_presence(CONTACT_OFFLINE); status_bar_clear_message(); status_bar_update_virtual(); ui_hide_roster(); } void ui_close_connected_win(int index) { ProfWin *window = wins_get_by_num(index); if (window) { if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*) window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); presence_leave_chat_room(mucwin->roomjid); muc_leave(mucwin->roomjid); ui_leave_room(mucwin->roomjid); } else if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*) window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); #ifdef HAVE_LIBOTR if (chatwin->is_otr) { otr_end_session(chatwin->barejid); } #endif chat_state_gone(chatwin->barejid, chatwin->state); chat_session_remove(chatwin->barejid); } } } int ui_close_all_wins(void) { int count = 0; jabber_conn_status_t conn_status = jabber_get_connection_status(); GList *win_nums = wins_get_nums(); GList *curr = win_nums; while (curr) { int num = GPOINTER_TO_INT(curr->data); if ((num != 1) && (!ui_win_has_unsaved_form(num))) { if (conn_status == JABBER_CONNECTED) { ui_close_connected_win(num); } ui_close_win(num); count++; } curr = g_list_next(curr); } g_list_free(curr); g_list_free(win_nums); return count; } int ui_close_read_wins(void) { int count = 0; jabber_conn_status_t conn_status = jabber_get_connection_status(); GList *win_nums = wins_get_nums(); GList *curr = win_nums; while (curr) { int num = GPOINTER_TO_INT(curr->data); if ((num != 1) && (ui_win_unread(num) == 0) && (!ui_win_has_unsaved_form(num))) { if (conn_status == JABBER_CONNECTED) { ui_close_connected_win(num); } ui_close_win(num); count++; } curr = g_list_next(curr); } g_list_free(curr); g_list_free(win_nums); return count; } void ui_redraw_all_room_rosters(void) { GList *win_nums = wins_get_nums(); GList *curr = win_nums; while (curr) { int num = GPOINTER_TO_INT(curr->data); ProfWin *window = wins_get_by_num(num); if (window->type == WIN_MUC && win_has_active_subwin(window)) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); occupantswin_occupants(mucwin->roomjid); } curr = g_list_next(curr); } g_list_free(curr); g_list_free(win_nums); } void ui_hide_all_room_rosters(void) { GList *win_nums = wins_get_nums(); GList *curr = win_nums; while (curr) { int num = GPOINTER_TO_INT(curr->data); ProfWin *window = wins_get_by_num(num); if (window->type == WIN_MUC && win_has_active_subwin(window)) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); ui_room_hide_occupants(mucwin->roomjid); } curr = g_list_next(curr); } g_list_free(curr); g_list_free(win_nums); } void ui_show_all_room_rosters(void) { GList *win_nums = wins_get_nums(); GList *curr = win_nums; while (curr) { int num = GPOINTER_TO_INT(curr->data); ProfWin *window = wins_get_by_num(num); if (window->type == WIN_MUC && !win_has_active_subwin(window)) { ProfMucWin *mucwin = (ProfMucWin*)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); ui_room_show_occupants(mucwin->roomjid); } curr = g_list_next(curr); } g_list_free(curr); g_list_free(win_nums); } gboolean ui_win_has_unsaved_form(int num) { ProfWin *window = wins_get_by_num(num); if (window->type == WIN_MUC_CONFIG) { ProfMucConfWin *confwin = (ProfMucConfWin*)window; assert(confwin->memcheck == PROFCONFWIN_MEMCHECK); return confwin->form->modified; } else { return FALSE; } } void ui_switch_win(ProfWin *window) { assert(window != NULL); ProfWin *old_current = wins_get_current(); if (old_current->type == WIN_MUC_CONFIG) { ProfMucConfWin *confwin = (ProfMucConfWin*)old_current; cmd_autocomplete_remove_form_fields(confwin->form); } if (window->type == WIN_MUC_CONFIG) { ProfMucConfWin *confwin = (ProfMucConfWin*)window; cmd_autocomplete_add_form_fields(confwin->form); } int i = wins_get_num(window); wins_set_current_by_num(i); if (i == 1) { title_bar_console(); } else { title_bar_switch(); } status_bar_current(i); status_bar_active(i); } void ui_gone_secure(const char * const barejid, gboolean trusted) { ProfWin *window = NULL; ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { window = (ProfWin*)chatwin; } else { window = wins_new_chat(barejid); chatwin = (ProfChatWin*)window; } chatwin->is_otr = TRUE; chatwin->otr_is_trusted = trusted; if (trusted) { win_print(window, '!', 0, NULL, 0, THEME_OTR_STARTED_TRUSTED, "", "OTR session started (trusted)."); } else { win_print(window, '!', 0, NULL, 0, THEME_OTR_STARTED_UNTRUSTED, "", "OTR session started (untrusted)."); } if (wins_is_current(window)) { title_bar_switch(); } else { int num = wins_get_num(window); status_bar_new(num); int ui_index = num; if (ui_index == 10) { ui_index = 0; } cons_show("%s started an OTR session (%d).", barejid, ui_index); cons_alert(); } } void ui_gone_insecure(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { chatwin->is_otr = FALSE; chatwin->otr_is_trusted = FALSE; ProfWin *window = (ProfWin*)chatwin; win_print(window, '!', 0, NULL, 0, THEME_OTR_ENDED, "", "OTR session ended."); if (wins_is_current(window)) { title_bar_switch(); } } } void ui_smp_recipient_initiated(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "%s wants to authenticate your identity, use '/otr secret '.", barejid); } } void ui_smp_recipient_initiated_q(const char * const barejid, const char *question) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "%s wants to authenticate your identity with the following question:", barejid); win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", " %s", question); win_print((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "use '/otr answer '."); } } void ui_smp_unsuccessful_sender(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "Authentication failed, the secret you entered does not match the secret entered by %s.", barejid); } } void ui_smp_unsuccessful_receiver(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "Authentication failed, the secret entered by %s does not match yours.", barejid); } } void ui_smp_aborted(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_print((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "SMP session aborted."); } } void ui_smp_successful(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_print((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "Authentication successful."); } } void ui_smp_answer_success(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "%s successfully authenticated you.", barejid); } } void ui_smp_answer_failure(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "%s failed to authenticate you.", barejid); } } void ui_otr_authenticating(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "Authenticating %s...", barejid); } } void ui_otr_authetication_waiting(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, 0, "", "Awaiting authentication from %s...", barejid); } } void ui_handle_otr_error(const char * const barejid, const char * const message) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { win_print((ProfWin*)chatwin, '!', 0, NULL, 0, THEME_ERROR, "", message); } else { cons_show_error("%s - %s", barejid, message); } } void ui_trust(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { chatwin->is_otr = TRUE; chatwin->otr_is_trusted = TRUE; ProfWin *window = (ProfWin*)chatwin; win_print(window, '!', 0, NULL, 0, THEME_OTR_TRUSTED, "", "OTR session trusted."); if (wins_is_current(window)) { title_bar_switch(); } } } void ui_untrust(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { chatwin->is_otr = TRUE; chatwin->otr_is_trusted = FALSE; ProfWin *window = (ProfWin*)chatwin; win_print(window, '!', 0, NULL, 0, THEME_OTR_UNTRUSTED, "", "OTR session untrusted."); if (wins_is_current(window)) { title_bar_switch(); } } } void ui_close_win(int index) { ProfWin *window = wins_get_by_num(index); if (window && window->type == WIN_MUC_CONFIG) { ProfMucConfWin *confwin = (ProfMucConfWin*)window; if (confwin->form) { cmd_autocomplete_remove_form_fields(confwin->form); } } wins_close_by_num(index); title_bar_console(); status_bar_current(1); status_bar_active(1); } gboolean ui_tidy_wins(void) { return wins_tidy(); } void ui_prune_wins(void) { jabber_conn_status_t conn_status = jabber_get_connection_status(); gboolean pruned = FALSE; GSList *wins = wins_get_prune_wins(); if (wins) { pruned = TRUE; } GSList *curr = wins; while (curr) { ProfWin *window = curr->data; if (window->type == WIN_CHAT) { if (conn_status == JABBER_CONNECTED) { ProfChatWin *chatwin = (ProfChatWin*)window; chat_session_remove(chatwin->barejid); } } int num = wins_get_num(window); ui_close_win(num); curr = g_slist_next(curr); } if (wins) { g_slist_free(wins); } wins_tidy(); if (pruned) { cons_show("Windows pruned."); } else { cons_show("No prune needed."); } } gboolean ui_swap_wins(int source_win, int target_win) { return wins_swap(source_win, target_win); } win_type_t ui_win_type(int index) { ProfWin *window = wins_get_by_num(index); return window->type; } void ui_current_print_line(const char * const msg, ...) { ProfWin *window = wins_get_current(); va_list arg; va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); win_println(window, 0, fmt_msg->str); va_end(arg); g_string_free(fmt_msg, TRUE); } void ui_current_print_formatted_line(const char show_char, int attrs, const char * const msg, ...) { ProfWin *current = wins_get_current(); va_list arg; va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); win_print(current, show_char, 0, NULL, 0, attrs, "", fmt_msg->str); va_end(arg); g_string_free(fmt_msg, TRUE); } void ui_win_error_line(ProfWin *window, const char * const msg) { win_print(window, '-', 0, NULL, 0, THEME_ERROR, "", msg); } void ui_current_error_line(const char * const msg) { ProfWin *current = wins_get_current(); win_print(current, '-', 0, NULL, 0, THEME_ERROR, "", msg); } void ui_print_system_msg_from_recipient(const char * const barejid, const char *message) { if (barejid == NULL || message == NULL) return; ProfWin *window = (ProfWin*)wins_get_chat(barejid); if (window == NULL) { int num = 0; window = wins_new_chat(barejid); if (window) { num = wins_get_num(window); status_bar_active(num); } else { num = 0; window = wins_get_console(); status_bar_active(1); } } win_vprint(window, '-', 0, NULL, 0, 0, "", "*%s %s", barejid, message); } void ui_recipient_gone(const char * const barejid, const char * const resource) { if (barejid == NULL) return; if (resource == NULL) return; gboolean show_message = TRUE; ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { ChatSession *session = chat_session_get(barejid); if (session && g_strcmp0(session->resource, resource) != 0) { show_message = FALSE; } if (show_message) { const char * display_usr = NULL; PContact contact = roster_get_contact(barejid); if (contact) { if (p_contact_name(contact)) { display_usr = p_contact_name(contact); } else { display_usr = barejid; } } else { display_usr = barejid; } win_vprint((ProfWin*)chatwin, '!', 0, NULL, 0, THEME_GONE, "", "<- %s has left the conversation.", display_usr); } } } ProfPrivateWin* ui_new_private_win(const char * const fulljid) { ProfWin *window = wins_new_private(fulljid); return (ProfPrivateWin*)window; } void ui_create_xmlconsole_win(void) { ProfWin *window = wins_new_xmlconsole(); ui_ev_focus_win(window); } void ui_open_xmlconsole_win(void) { ProfXMLWin *xmlwin = wins_get_xmlconsole(); if (xmlwin) { ui_ev_focus_win((ProfWin*)xmlwin); } } ProfChatWin* ui_new_chat_win(const char * const barejid) { ProfWin *window = wins_new_chat(barejid); ProfChatWin *chatwin = (ProfChatWin *)window; if (prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY)) { _win_show_history(chatwin, barejid); } // if the contact is offline, show a message PContact contact = roster_get_contact(barejid); if (contact) { if (strcmp(p_contact_presence(contact), "offline") == 0) { const char * const show = p_contact_presence(contact); const char * const status = p_contact_status(contact); win_show_status_string(window, barejid, show, status, NULL, "--", "offline"); } } return chatwin; } void ui_outgoing_chat_msg(ProfChatWin *chatwin, const char * const message, char *id, prof_enc_t enc_mode) { char enc_char = '-'; if (enc_mode == PROF_MSG_OTR) { enc_char = prefs_get_otr_char(); } else if (enc_mode == PROF_MSG_PGP) { enc_char = prefs_get_pgp_char(); } if (prefs_get_boolean(PREF_RECEIPTS_REQUEST) && id) { win_print_with_receipt((ProfWin*)chatwin, enc_char, 0, NULL, 0, THEME_TEXT_ME, "me", message, id); } else { win_print((ProfWin*)chatwin, enc_char, 0, NULL, 0, THEME_TEXT_ME, "me", message); } } void ui_outgoing_chat_msg_carbon(const char * const barejid, const char * const message) { ProfChatWin *chatwin = wins_get_chat(barejid); // create new window if (!chatwin) { chatwin = ui_new_chat_win(barejid); } chat_state_active(chatwin->state); win_print((ProfWin*)chatwin, '-', 0, NULL, 0, THEME_TEXT_ME, "me", message); int num = wins_get_num((ProfWin*)chatwin); status_bar_active(num); } void ui_outgoing_private_msg(ProfPrivateWin *privwin, const char * const message) { win_print((ProfWin*)privwin, '-', 0, NULL, 0, THEME_TEXT_ME, "me", message); } void ui_room_join(const char * const roomjid, gboolean focus) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (!window) { window = wins_new_muc(roomjid); } char *nick = muc_nick(roomjid); win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "-> You have joined the room as %s", nick); if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { char *role = muc_role_str(roomjid); char *affiliation = muc_affiliation_str(roomjid); if (role) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", role: %s", role); } if (affiliation) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", affiliation: %s", affiliation); } } win_print(window, '!', 0, NULL, NO_DATE, THEME_ROOMINFO, "", ""); if (focus) { ui_ev_focus_win(window); } else { int num = wins_get_num(window); status_bar_active(num); ProfWin *console = wins_get_console(); char *nick = muc_nick(roomjid); win_vprint(console, '!', 0, NULL, 0, THEME_TYPING, "", "-> Autojoined %s as %s (%d).", roomjid, nick, num); } } void ui_switch_to_room(const char * const roomjid) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); ui_ev_focus_win(window); } void ui_room_role_change(const char * const roomjid, const char * const role, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "Your role has been changed to: %s", role); if (actor) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } win_print(window, '!', 0, NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void ui_room_affiliation_change(const char * const roomjid, const char * const affiliation, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "Your affiliation has been changed to: %s", affiliation); if (actor) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } win_print(window, '!', 0, NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void ui_room_role_and_affiliation_change(const char * const roomjid, const char * const role, const char * const affiliation, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "Your role and affiliation have been changed, role: %s, affiliation: %s", role, affiliation); if (actor) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } win_print(window, '!', 0, NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void ui_room_occupant_role_change(const char * const roomjid, const char * const nick, const char * const role, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "%s's role has been changed to: %s", nick, role); if (actor) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } win_print(window, '!', 0, NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void ui_room_occupant_affiliation_change(const char * const roomjid, const char * const nick, const char * const affiliation, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "%s's affiliation has been changed to: %s", nick, affiliation); if (actor) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } win_print(window, '!', 0, NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void ui_room_occupant_role_and_affiliation_change(const char * const roomjid, const char * const nick, const char * const role, const char * const affiliation, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "%s's role and affiliation have been changed, role: %s, affiliation: %s", nick, role, affiliation); if (actor) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } win_print(window, '!', 0, NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void ui_handle_room_info_error(const char * const roomjid, const char * const error) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { win_vprint(window, '!', 0, NULL, 0, 0, "", "Room info request failed: %s", error); win_print(window, '-', 0, NULL, 0, 0, "", ""); } } void ui_show_room_disco_info(const char * const roomjid, GSList *identities, GSList *features) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { if ((identities && (g_slist_length(identities) > 0)) || (features && (g_slist_length(features) > 0))) { if (identities) { win_print(window, '!', 0, NULL, 0, 0, "", "Identities:"); } while (identities) { DiscoIdentity *identity = identities->data; // anme trpe, cat GString *identity_str = g_string_new(" "); if (identity->name) { identity_str = g_string_append(identity_str, identity->name); identity_str = g_string_append(identity_str, " "); } if (identity->type) { identity_str = g_string_append(identity_str, identity->type); identity_str = g_string_append(identity_str, " "); } if (identity->category) { identity_str = g_string_append(identity_str, identity->category); } win_print(window, '!', 0, NULL, 0, 0, "", identity_str->str); g_string_free(identity_str, TRUE); identities = g_slist_next(identities); } if (features) { win_print(window, '!', 0, NULL, 0, 0, "", "Features:"); } while (features) { win_vprint(window, '!', 0, NULL, 0, 0, "", " %s", features->data); features = g_slist_next(features); } win_print(window, '-', 0, NULL, 0, 0, "", ""); } } } void ui_room_roster(const char * const roomjid, GList *roster, const char * const presence) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received room roster but no window open for %s.", roomjid); } else { if ((roster == NULL) || (g_list_length(roster) == 0)) { if (presence == NULL) { win_print(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "Room is empty."); } else { win_vprint(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "No occupants %s.", presence); } } else { int length = g_list_length(roster); if (presence == NULL) { win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "%d occupants: ", length); } else { win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "%d %s: ", length, presence); } while (roster) { Occupant *occupant = roster->data; const char *presence_str = string_from_resource_presence(occupant->presence); theme_item_t presence_colour = theme_main_presence_attrs(presence_str); win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", "%s", occupant->nick); if (roster->next) { win_print(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", ", "); } roster = g_list_next(roster); } win_print(window, '!', 0, NULL, NO_DATE, THEME_ONLINE, "", ""); } } } void ui_handle_room_join_error(const char * const roomjid, const char * const err) { cons_show_error("Error joining room %s, reason: %s", roomjid, err); } void ui_room_member_offline(const char * const roomjid, const char * const nick) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received offline presence for room participant %s, but no window open for %s.", nick, roomjid); } else { win_vprint(window, '!', 0, NULL, 0, THEME_OFFLINE, "", "<- %s has left the room.", nick); } } void ui_room_member_kicked(const char * const roomjid, const char * const nick, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received kick for room participant %s, but no window open for %s.", nick, roomjid); } else { GString *message = g_string_new(nick); g_string_append(message, " has been kicked from the room"); if (actor) { g_string_append(message, " by "); g_string_append(message, actor); } if (reason) { g_string_append(message, ", reason: "); g_string_append(message, reason); } win_vprint(window, '!', 0, NULL, 0, THEME_OFFLINE, "", "<- %s", message->str); g_string_free(message, TRUE); } } void ui_room_member_banned(const char * const roomjid, const char * const nick, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received ban for room participant %s, but no window open for %s.", nick, roomjid); } else { GString *message = g_string_new(nick); g_string_append(message, " has been banned from the room"); if (actor) { g_string_append(message, " by "); g_string_append(message, actor); } if (reason) { g_string_append(message, ", reason: "); g_string_append(message, reason); } win_vprint(window, '!', 0, NULL, 0, THEME_OFFLINE, "", "<- %s", message->str); g_string_free(message, TRUE); } } void ui_room_member_online(const char * const roomjid, const char * const nick, const char * const role, const char * const affiliation, const char * const show, const char * const status) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received online presence for room participant %s, but no window open for %s.", nick, roomjid); } else { win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ONLINE, "", "-> %s has joined the room", nick); if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { if (role) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", ", role: %s", role); } if (affiliation) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", ", affiliation: %s", affiliation); } } win_print(window, '!', 0, NULL, NO_DATE, THEME_ROOMINFO, "", ""); } } void ui_room_member_presence(const char * const roomjid, const char * const nick, const char * const show, const char * const status) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received presence for room participant %s, but no window open for %s.", nick, roomjid); } else { win_show_status_string(window, nick, show, status, NULL, "++", "online"); } } void ui_room_member_nick_change(const char * const roomjid, const char * const old_nick, const char * const nick) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received nick change for room participant %s, but no window open for %s.", old_nick, roomjid); } else { win_vprint(window, '!', 0, NULL, 0, THEME_THEM, "", "** %s is now known as %s", old_nick, nick); } } void ui_room_nick_change(const char * const roomjid, const char * const nick) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received self nick change %s, but no window open for %s.", nick, roomjid); } else { win_vprint(window, '!', 0, NULL, 0, THEME_ME, "", "** You are now known as %s", nick); } } void ui_room_history(const char * const roomjid, const char * const nick, GDateTime *timestamp, const char * const message) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Room history message received from %s, but no window open for %s", nick, roomjid); } else { GString *line = g_string_new(""); if (strncmp(message, "/me ", 4) == 0) { g_string_append(line, "*"); g_string_append(line, nick); g_string_append(line, " "); g_string_append(line, message + 4); } else { g_string_append(line, nick); g_string_append(line, ": "); g_string_append(line, message); } win_print(window, '-', 0, timestamp, NO_COLOUR_DATE, 0, "", line->str); g_string_free(line, TRUE); } } void ui_room_message(const char * const roomjid, const char * const nick, const char * const message) { ProfMucWin *mucwin = wins_get_muc(roomjid); if (mucwin == NULL) { log_error("Room message received from %s, but no window open for %s", nick, roomjid); return; } ProfWin *window = (ProfWin*) mucwin; int num = wins_get_num(window); char *my_nick = muc_nick(roomjid); if (g_strcmp0(nick, my_nick) != 0) { if (g_strrstr(message, my_nick)) { win_print(window, '-', 0, NULL, NO_ME, THEME_ROOMMENTION, nick, message); } else { win_print(window, '-', 0, NULL, NO_ME, THEME_TEXT_THEM, nick, message); } } else { win_print(window, '-', 0, NULL, 0, THEME_TEXT_ME, nick, message); } // currently in groupchat window if (wins_is_current(window)) { status_bar_active(num); // not currently on groupchat window } else { status_bar_new(num); cons_show_incoming_message(nick, num); if (prefs_get_boolean(PREF_FLASH) && (strcmp(nick, my_nick) != 0)) { flash(); } mucwin->unread++; } int ui_index = num; if (ui_index == 10) { ui_index = 0; } // don't notify self messages if (strcmp(nick, my_nick) == 0) { return; } if (prefs_get_boolean(PREF_BEEP)) { beep(); } gboolean notify = FALSE; char *room_setting = prefs_get_string(PREF_NOTIFY_ROOM); if (g_strcmp0(room_setting, "on") == 0) { notify = TRUE; } if (g_strcmp0(room_setting, "mention") == 0) { char *message_lower = g_utf8_strdown(message, -1); char *nick_lower = g_utf8_strdown(nick, -1); if (g_strrstr(message_lower, nick_lower)) { notify = TRUE; } g_free(message_lower); g_free(nick_lower); } prefs_free_string(room_setting); if (notify) { gboolean is_current = wins_is_current(window); if ( !is_current || (is_current && prefs_get_boolean(PREF_NOTIFY_ROOM_CURRENT)) ) { Jid *jidp = jid_create(roomjid); if (prefs_get_boolean(PREF_NOTIFY_ROOM_TEXT)) { notify_room_message(nick, jidp->localpart, ui_index, message); } else { notify_room_message(nick, jidp->localpart, ui_index, NULL); } jid_destroy(jidp); } } } void ui_room_requires_config(const char * const roomjid) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received room config request, but no window open for %s.", roomjid); } else { int num = wins_get_num(window); int ui_index = num; if (ui_index == 10) { ui_index = 0; } win_print(window, '-', 0, NULL, 0, 0, "", ""); win_vprint(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "Room locked, requires configuration."); win_vprint(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "Use '/room accept' to accept the defaults"); win_vprint(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "Use '/room destroy' to cancel and destroy the room"); win_vprint(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "Use '/room config' to edit the room configuration"); win_print(window, '-', 0, NULL, 0, 0, "", ""); // currently in groupchat window if (wins_is_current(window)) { status_bar_active(num); // not currently on groupchat window } else { status_bar_new(num); } } } void ui_room_destroy(const char * const roomjid) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received room destroy result, but no window open for %s.", roomjid); } else { int num = wins_get_num(window); ui_close_win(num); cons_show("Room destroyed: %s", roomjid); } } void ui_leave_room(const char * const roomjid) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { int num = wins_get_num(window); ui_close_win(num); } } void ui_room_destroyed(const char * const roomjid, const char * const reason, const char * const new_jid, const char * const password) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received room destroy, but no window open for %s.", roomjid); } else { int num = wins_get_num(window); ui_close_win(num); ProfWin *console = wins_get_console(); if (reason) { win_vprint(console, '!', 0, NULL, 0, THEME_TYPING, "", "<- Room destroyed: %s, reason: %s", roomjid, reason); } else { win_vprint(console, '!', 0, NULL, 0, THEME_TYPING, "", "<- Room destroyed: %s", roomjid); } if (new_jid) { if (password) { win_vprint(console, '!', 0, NULL, 0, THEME_TYPING, "", "Replacement room: %s, password: %s", new_jid, password); } else { win_vprint(console, '!', 0, NULL, 0, THEME_TYPING, "", "Replacement room: %s", new_jid); } } } } void ui_room_kicked(const char * const roomjid, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received kick, but no window open for %s.", roomjid); } else { int num = wins_get_num(window); ui_close_win(num); GString *message = g_string_new("Kicked from "); g_string_append(message, roomjid); if (actor) { g_string_append(message, " by "); g_string_append(message, actor); } if (reason) { g_string_append(message, ", reason: "); g_string_append(message, reason); } ProfWin *console = wins_get_console(); win_vprint(console, '!', 0, NULL, 0, THEME_TYPING, "", "<- %s", message->str); g_string_free(message, TRUE); } } void ui_room_banned(const char * const roomjid, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received ban, but no window open for %s.", roomjid); } else { int num = wins_get_num(window); ui_close_win(num); GString *message = g_string_new("Banned from "); g_string_append(message, roomjid); if (actor) { g_string_append(message, " by "); g_string_append(message, actor); } if (reason) { g_string_append(message, ", reason: "); g_string_append(message, reason); } ProfWin *console = wins_get_console(); win_vprint(console, '!', 0, NULL, 0, THEME_TYPING, "", "<- %s", message->str); g_string_free(message, TRUE); } } void ui_room_subject(const char * const roomjid, const char * const nick, const char * const subject) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received room subject, but no window open for %s.", roomjid); } else { int num = wins_get_num(window); if (subject) { if (nick) { win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "*%s has set the room subject: ", nick); win_vprint(window, '!', 0, NULL, NO_DATE, 0, "", "%s", subject); } else { win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "Room subject: "); win_vprint(window, '!', 0, NULL, NO_DATE, 0, "", "%s", subject); } } else { if (nick) { win_vprint(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "*%s has cleared the room subject: ", nick); } else { win_vprint(window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "Room subject cleared"); } } // currently in groupchat window if (wins_is_current(window)) { status_bar_active(num); // not currently on groupchat window } else { status_bar_active(num); } } } void ui_handle_room_kick_error(const char * const roomjid, const char * const nick, const char * const error) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Kick error received for %s, but no window open for %s.", nick, roomjid); } else { win_vprint(window, '!', 0, NULL, 0, THEME_ERROR, "", "Error kicking %s: %s", nick, error); } } void ui_room_broadcast(const char * const roomjid, const char * const message) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window == NULL) { log_error("Received room broadcast, but no window open for %s.", roomjid); } else { int num = wins_get_num(window); win_vprint(window, '!', 0, NULL, NO_EOL, THEME_ROOMINFO, "", "Room message: "); win_vprint(window, '!', 0, NULL, NO_DATE, 0, "", "%s", message); // currently in groupchat window if (wins_is_current(window)) { status_bar_active(num); // not currently on groupchat window } else { status_bar_new(num); } } } void ui_handle_room_affiliation_list_error(const char * const roomjid, const char * const affiliation, const char * const error) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { win_vprint(window, '!', 0, NULL, 0, THEME_ERROR, "", "Error retrieving %s list: %s", affiliation, error); } } void ui_handle_room_affiliation_list(const char * const roomjid, const char * const affiliation, GSList *jids) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { if (jids) { win_vprint(window, '!', 0, NULL, 0, 0, "", "Affiliation: %s", affiliation); GSList *curr_jid = jids; while (curr_jid) { char *jid = curr_jid->data; win_vprint(window, '!', 0, NULL, 0, 0, "", " %s", jid); curr_jid = g_slist_next(curr_jid); } win_print(window, '!', 0, NULL, 0, 0, "", ""); } else { win_vprint(window, '!', 0, NULL, 0, 0, "", "No users found with affiliation: %s", affiliation); win_print(window, '!', 0, NULL, 0, 0, "", ""); } } } void ui_handle_room_role_list_error(const char * const roomjid, const char * const role, const char * const error) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { win_vprint(window, '!', 0, NULL, 0, THEME_ERROR, "", "Error retrieving %s list: %s", role, error); } } void ui_handle_room_role_list(const char * const roomjid, const char * const role, GSList *nicks) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { if (nicks) { win_vprint(window, '!', 0, NULL, 0, 0, "", "Role: %s", role); GSList *curr_nick = nicks; while (curr_nick) { char *nick = curr_nick->data; Occupant *occupant = muc_roster_item(roomjid, nick); if (occupant) { if (occupant->jid) { win_vprint(window, '!', 0, NULL, 0, 0, "", " %s (%s)", nick, occupant->jid); } else { win_vprint(window, '!', 0, NULL, 0, 0, "", " %s", nick); } } else { win_vprint(window, '!', 0, NULL, 0, 0, "", " %s", nick); } curr_nick = g_slist_next(curr_nick); } win_print(window, '!', 0, NULL, 0, 0, "", ""); } else { win_vprint(window, '!', 0, NULL, 0, 0, "", "No occupants found with role: %s", role); win_print(window, '!', 0, NULL, 0, 0, "", ""); } } } void ui_handle_room_affiliation_set_error(const char * const roomjid, const char * const jid, const char * const affiliation, const char * const error) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { win_vprint(window, '!', 0, NULL, 0, THEME_ERROR, "", "Error setting %s affiliation for %s: %s", affiliation, jid, error); } } void ui_handle_room_role_set_error(const char * const roomjid, const char * const nick, const char * const role, const char * const error) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { win_vprint(window, '!', 0, NULL, 0, THEME_ERROR, "", "Error setting %s role for %s: %s", role, nick, error); } } gint ui_unread(void) { return wins_get_total_unread(); } int ui_win_unread(int index) { ProfWin *window = wins_get_by_num(index); if (window) { return win_unread(window); } else { return 0; } } char * ui_ask_password(void) { status_bar_get_password(); status_bar_update_virtual(); return inp_get_password(); } char * ui_ask_pgp_passphrase(const char *hint, int prev_fail) { ProfWin *current = wins_get_current(); win_println(current, 0, ""); if (prev_fail) { win_print(current, '!', 0, NULL, 0, 0, "", "Incorrect passphrase"); } if (hint) { win_vprint(current, '!', 0, NULL, 0, 0, "", "Enter PGP key passphrase for %s", hint); } else { win_print(current, '!', 0, NULL, 0, 0, "", "Enter PGP key passphrase"); } ui_update(); status_bar_get_password(); status_bar_update_virtual(); return inp_get_password(); } void ui_chat_win_contact_online(PContact contact, Resource *resource, GDateTime *last_activity) { const char *show = string_from_resource_presence(resource->presence); char *display_str = p_contact_create_display_string(contact, resource->name); const char *barejid = p_contact_barejid(contact); ProfWin *window = (ProfWin*)wins_get_chat(barejid); if (window) { win_show_status_string(window, display_str, show, resource->status, last_activity, "++", "online"); } free(display_str); } void ui_chat_win_contact_offline(PContact contact, char *resource, char *status) { char *display_str = p_contact_create_display_string(contact, resource); const char *barejid = p_contact_barejid(contact); ProfWin *window = (ProfWin*)wins_get_chat(barejid); if (window) { win_show_status_string(window, display_str, "offline", status, NULL, "--", "offline"); } free(display_str); } void ui_contact_offline(char *barejid, char *resource, char *status) { char *show_console = prefs_get_string(PREF_STATUSES_CONSOLE); char *show_chat_win = prefs_get_string(PREF_STATUSES_CHAT); Jid *jid = jid_create_from_bare_and_resource(barejid, resource); PContact contact = roster_get_contact(barejid); if (p_contact_subscription(contact)) { if (strcmp(p_contact_subscription(contact), "none") != 0) { // show in console if "all" if (g_strcmp0(show_console, "all") == 0) { cons_show_contact_offline(contact, resource, status); // show in console of "online" } else if (g_strcmp0(show_console, "online") == 0) { cons_show_contact_offline(contact, resource, status); } // show in chat win if "all" if (g_strcmp0(show_chat_win, "all") == 0) { ui_chat_win_contact_offline(contact, resource, status); // show in char win if "online" and presence online } else if (g_strcmp0(show_chat_win, "online") == 0) { ui_chat_win_contact_offline(contact, resource, status); } } } ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin && chatwin->resource_override && (g_strcmp0(resource, chatwin->resource_override) == 0)) { FREE_SET_NULL(chatwin->resource_override); } prefs_free_string(show_console); prefs_free_string(show_chat_win); jid_destroy(jid); } void ui_clear_win_title(void) { printf("%c]0;%c", '\033', '\007'); } void ui_clear_win(ProfWin *window) { win_clear(window); } void ui_goodbye_title(void) { int result = system("/bin/echo -ne \"\033]0;Thanks for using Profanity\007\""); if(result == -1) log_error("Error printing title on shutdown"); } void ui_statusbar_new(const int win) { status_bar_new(win); } static void _ui_draw_term_title(void) { char new_win_title[100]; jabber_conn_status_t status = jabber_get_connection_status(); if (status == JABBER_CONNECTED) { const char * const jid = jabber_get_fulljid(); gint unread = ui_unread(); if (unread != 0) { snprintf(new_win_title, sizeof(new_win_title), "/bin/echo -n \"%c]0;%s (%d) - %s%c\"", '\033', "Profanity", unread, jid, '\007'); } else { snprintf(new_win_title, sizeof(new_win_title), "/bin/echo -n \"%c]0;%s - %s%c\"", '\033', "Profanity", jid, '\007'); } } else { snprintf(new_win_title, sizeof(new_win_title), "/bin/echo -n \"%c]0;%s%c\"", '\033', "Profanity", '\007'); } if (g_strcmp0(win_title, new_win_title) != 0) { // print to x-window title bar int res = system(new_win_title); if (res == -1) { log_error("Error writing terminal window title."); } if (win_title) { free(win_title); } win_title = strdup(new_win_title); } } void ui_show_room_info(ProfMucWin *mucwin) { char *role = muc_role_str(mucwin->roomjid); char *affiliation = muc_affiliation_str(mucwin->roomjid); ProfWin *window = (ProfWin*) mucwin; win_vprint(window, '!', 0, NULL, 0, 0, "", "Room: %s", mucwin->roomjid); win_vprint(window, '!', 0, NULL, 0, 0, "", "Affiliation: %s", affiliation); win_vprint(window, '!', 0, NULL, 0, 0, "", "Role: %s", role); win_print(window, '-', 0, NULL, 0, 0, "", ""); } void ui_show_room_role_list(ProfMucWin *mucwin, muc_role_t role) { ProfWin *window = (ProfWin*) mucwin; GSList *occupants = muc_occupants_by_role(mucwin->roomjid, role); if (!occupants) { switch (role) { case MUC_ROLE_MODERATOR: win_print(window, '!', 0, NULL, 0, 0, "", "No moderators found."); break; case MUC_ROLE_PARTICIPANT: win_print(window, '!', 0, NULL, 0, 0, "", "No participants found."); break; case MUC_ROLE_VISITOR: win_print(window, '!', 0, NULL, 0, 0, "", "No visitors found."); break; default: break; } win_print(window, '-', 0, NULL, 0, 0, "", ""); } else { switch (role) { case MUC_ROLE_MODERATOR: win_print(window, '!', 0, NULL, 0, 0, "", "Moderators:"); break; case MUC_ROLE_PARTICIPANT: win_print(window, '!', 0, NULL, 0, 0, "", "Participants:"); break; case MUC_ROLE_VISITOR: win_print(window, '!', 0, NULL, 0, 0, "", "Visitors:"); break; default: break; } GSList *curr_occupant = occupants; while(curr_occupant) { Occupant *occupant = curr_occupant->data; if (occupant->role == role) { if (occupant->jid) { win_vprint(window, '!', 0, NULL, 0, 0, "", " %s (%s)", occupant->nick, occupant->jid); } else { win_vprint(window, '!', 0, NULL, 0, 0, "", " %s", occupant->nick); } } curr_occupant = g_slist_next(curr_occupant); } win_print(window, '-', 0, NULL, 0, 0, "", ""); } } void ui_show_room_affiliation_list(ProfMucWin *mucwin, muc_affiliation_t affiliation) { ProfWin *window = (ProfWin*) mucwin; GSList *occupants = muc_occupants_by_affiliation(mucwin->roomjid, affiliation); if (!occupants) { switch (affiliation) { case MUC_AFFILIATION_OWNER: win_print(window, '!', 0, NULL, 0, 0, "", "No owners found."); break; case MUC_AFFILIATION_ADMIN: win_print(window, '!', 0, NULL, 0, 0, "", "No admins found."); break; case MUC_AFFILIATION_MEMBER: win_print(window, '!', 0, NULL, 0, 0, "", "No members found."); break; case MUC_AFFILIATION_OUTCAST: win_print(window, '!', 0, NULL, 0, 0, "", "No outcasts found."); break; default: break; } win_print(window, '-', 0, NULL, 0, 0, "", ""); } else { switch (affiliation) { case MUC_AFFILIATION_OWNER: win_print(window, '!', 0, NULL, 0, 0, "", "Owners:"); break; case MUC_AFFILIATION_ADMIN: win_print(window, '!', 0, NULL, 0, 0, "", "Admins:"); break; case MUC_AFFILIATION_MEMBER: win_print(window, '!', 0, NULL, 0, 0, "", "Members:"); break; case MUC_AFFILIATION_OUTCAST: win_print(window, '!', 0, NULL, 0, 0, "", "Outcasts:"); break; default: break; } GSList *curr_occupant = occupants; while(curr_occupant) { Occupant *occupant = curr_occupant->data; if (occupant->affiliation == affiliation) { if (occupant->jid) { win_vprint(window, '!', 0, NULL, 0, 0, "", " %s (%s)", occupant->nick, occupant->jid); } else { win_vprint(window, '!', 0, NULL, 0, 0, "", " %s", occupant->nick); } } curr_occupant = g_slist_next(curr_occupant); } win_print(window, '-', 0, NULL, 0, 0, "", ""); } } static void _ui_handle_form_field(ProfWin *window, char *tag, FormField *field) { win_vprint(window, '-', 0, NULL, NO_EOL, THEME_AWAY, "", "[%s] ", tag); win_vprint(window, '-', 0, NULL, NO_EOL | NO_DATE, 0, "", "%s", field->label); if (field->required) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " (required): "); } else { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ": "); } GSList *values = field->values; GSList *curr_value = values; switch (field->type_t) { case FIELD_HIDDEN: break; case FIELD_TEXT_SINGLE: if (curr_value) { char *value = curr_value->data; if (value) { if (g_strcmp0(field->var, "muc#roomconfig_roomsecret") == 0) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", "[hidden]"); } else { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", value); } } } win_newline(window); break; case FIELD_TEXT_PRIVATE: if (curr_value) { char *value = curr_value->data; if (value) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", "[hidden]"); } } win_newline(window); break; case FIELD_TEXT_MULTI: win_newline(window); int index = 1; while (curr_value) { char *value = curr_value->data; GString *val_tag = g_string_new(""); g_string_printf(val_tag, "val%d", index++); win_vprint(window, '-', 0, NULL, 0, THEME_ONLINE, "", " [%s] %s", val_tag->str, value); g_string_free(val_tag, TRUE); curr_value = g_slist_next(curr_value); } break; case FIELD_BOOLEAN: if (curr_value == NULL) { win_print(window, '-', 0, NULL, NO_DATE, THEME_OFFLINE, "", "FALSE"); } else { char *value = curr_value->data; if (value == NULL) { win_print(window, '-', 0, NULL, NO_DATE, THEME_OFFLINE, "", "FALSE"); } else { if (g_strcmp0(value, "0") == 0) { win_print(window, '-', 0, NULL, NO_DATE, THEME_OFFLINE, "", "FALSE"); } else { win_print(window, '-', 0, NULL, NO_DATE, THEME_ONLINE, "", "TRUE"); } } } break; case FIELD_LIST_SINGLE: if (curr_value) { win_newline(window); char *value = curr_value->data; GSList *options = field->options; GSList *curr_option = options; while (curr_option) { FormOption *option = curr_option->data; if (g_strcmp0(option->value, value) == 0) { win_vprint(window, '-', 0, NULL, 0, THEME_ONLINE, "", " [%s] %s", option->value, option->label); } else { win_vprint(window, '-', 0, NULL, 0, THEME_OFFLINE, "", " [%s] %s", option->value, option->label); } curr_option = g_slist_next(curr_option); } } break; case FIELD_LIST_MULTI: if (curr_value) { win_newline(window); GSList *options = field->options; GSList *curr_option = options; while (curr_option) { FormOption *option = curr_option->data; if (g_slist_find_custom(curr_value, option->value, (GCompareFunc)g_strcmp0)) { win_vprint(window, '-', 0, NULL, 0, THEME_ONLINE, "", " [%s] %s", option->value, option->label); } else { win_vprint(window, '-', 0, NULL, 0, THEME_OFFLINE, "", " [%s] %s", option->value, option->label); } curr_option = g_slist_next(curr_option); } } break; case FIELD_JID_SINGLE: if (curr_value) { char *value = curr_value->data; if (value) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", value); } } win_newline(window); break; case FIELD_JID_MULTI: win_newline(window); while (curr_value) { char *value = curr_value->data; win_vprint(window, '-', 0, NULL, 0, THEME_ONLINE, "", " %s", value); curr_value = g_slist_next(curr_value); } break; case FIELD_FIXED: if (curr_value) { char *value = curr_value->data; if (value) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", value); } } win_newline(window); break; default: break; } } void ui_show_form(ProfMucConfWin *confwin) { ProfWin *window = (ProfWin*) confwin; if (confwin->form->title) { win_print(window, '-', 0, NULL, NO_EOL, 0, "", "Form title: "); win_print(window, '-', 0, NULL, NO_DATE, 0, "", confwin->form->title); } else { win_vprint(window, '-', 0, NULL, 0, 0, "", "Configuration for room %s.", confwin->roomjid); } win_print(window, '-', 0, NULL, 0, 0, "", ""); ui_show_form_help(confwin); GSList *fields = confwin->form->fields; GSList *curr_field = fields; while (curr_field) { FormField *field = curr_field->data; if ((g_strcmp0(field->type, "fixed") == 0) && field->values) { if (field->values) { char *value = field->values->data; win_print(window, '-', 0, NULL, 0, 0, "", value); } } else if (g_strcmp0(field->type, "hidden") != 0 && field->var) { char *tag = g_hash_table_lookup(confwin->form->var_to_tag, field->var); _ui_handle_form_field(window, tag, field); } curr_field = g_slist_next(curr_field); } } void ui_show_form_field(ProfWin *window, DataForm *form, char *tag) { FormField *field = form_get_field_by_tag(form, tag); _ui_handle_form_field(window, tag, field); win_println(window, 0, ""); } void ui_handle_room_configuration(const char * const roomjid, DataForm *form) { ProfWin *window = wins_new_muc_config(roomjid, form); ProfMucConfWin *confwin = (ProfMucConfWin*)window; assert(confwin->memcheck == PROFCONFWIN_MEMCHECK); ui_ev_focus_win(window); ui_show_form(confwin); win_print(window, '-', 0, NULL, 0, 0, "", ""); win_print(window, '-', 0, NULL, 0, 0, "", "Use '/form submit' to save changes."); win_print(window, '-', 0, NULL, 0, 0, "", "Use '/form cancel' to cancel changes."); win_print(window, '-', 0, NULL, 0, 0, "", "See '/form help' for more information."); win_print(window, '-', 0, NULL, 0, 0, "", ""); } void ui_handle_room_configuration_form_error(const char * const roomjid, const char * const message) { ProfWin *window = NULL; GString *message_str = g_string_new(""); if (roomjid) { window = (ProfWin*)wins_get_muc(roomjid); g_string_printf(message_str, "Could not get room configuration for %s", roomjid); } else { window = wins_get_console(); g_string_printf(message_str, "Could not get room configuration"); } if (message) { g_string_append(message_str, ": "); g_string_append(message_str, message); } win_print(window, '-', 0, NULL, 0, THEME_ERROR, "", message_str->str); g_string_free(message_str, TRUE); } void ui_handle_room_config_submit_result(const char * const roomjid) { ProfWin *muc_window = NULL; ProfWin *form_window = NULL; int num; if (roomjid) { muc_window = (ProfWin*)wins_get_muc(roomjid); GString *form_recipient = g_string_new(roomjid); g_string_append(form_recipient, " config"); form_window = (ProfWin*) wins_get_muc_conf(form_recipient->str); g_string_free(form_recipient, TRUE); if (form_window) { num = wins_get_num(form_window); wins_close_by_num(num); } if (muc_window) { ui_ev_focus_win((ProfWin*)muc_window); win_print(muc_window, '!', 0, NULL, 0, THEME_ROOMINFO, "", "Room configuration successful"); } else { ProfWin *console = wins_get_console(); ui_ev_focus_win(console); cons_show("Room configuration successful: %s", roomjid); } } else { cons_show("Room configuration successful"); } } void ui_handle_room_config_submit_result_error(const char * const roomjid, const char * const message) { ProfWin *console = wins_get_console(); ProfWin *muc_window = NULL; ProfWin *form_window = NULL; if (roomjid) { muc_window = (ProfWin*)wins_get_muc(roomjid); GString *form_recipient = g_string_new(roomjid); g_string_append(form_recipient, " config"); form_window = (ProfWin*) wins_get_muc_conf(form_recipient->str); g_string_free(form_recipient, TRUE); if (form_window) { if (message) { win_vprint(form_window, '!', 0, NULL, 0, THEME_ERROR, "", "Configuration error: %s", message); } else { win_print(form_window, '!', 0, NULL, 0, THEME_ERROR, "", "Configuration error"); } } else if (muc_window) { if (message) { win_vprint(muc_window, '!', 0, NULL, 0, THEME_ERROR, "", "Configuration error: %s", message); } else { win_print(muc_window, '!', 0, NULL, 0, THEME_ERROR, "", "Configuration error"); } } else { if (message) { win_vprint(console, '!', 0, NULL, 0, THEME_ERROR, "", "Configuration error for %s: %s", roomjid, message); } else { win_vprint(console, '!', 0, NULL, 0, THEME_ERROR, "", "Configuration error for %s", roomjid); } } } else { win_print(console, '!', 0, NULL, 0, THEME_ERROR, "", "Configuration error"); } } void ui_show_form_field_help(ProfMucConfWin *confwin, char *tag) { ProfWin *window = (ProfWin*) confwin; FormField *field = form_get_field_by_tag(confwin->form, tag); if (field) { win_print(window, '-', 0, NULL, NO_EOL, 0, "", field->label); if (field->required) { win_print(window, '-', 0, NULL, NO_DATE, 0, "", " (Required):"); } else { win_print(window, '-', 0, NULL, NO_DATE, 0, "", ":"); } if (field->description) { win_vprint(window, '-', 0, NULL, 0, 0, "", " Description : %s", field->description); } win_vprint(window, '-', 0, NULL, 0, 0, "", " Type : %s", field->type); int num_values = 0; GSList *curr_option = NULL; FormOption *option = NULL; switch (field->type_t) { case FIELD_TEXT_SINGLE: case FIELD_TEXT_PRIVATE: win_vprint(window, '-', 0, NULL, 0, 0, "", " Set : /%s ", tag); win_print(window, '-', 0, NULL, 0, 0, "", " Where : is any text"); break; case FIELD_TEXT_MULTI: num_values = form_get_value_count(confwin->form, tag); win_vprint(window, '-', 0, NULL, 0, 0, "", " Add : /%s add ", tag); win_print(window, '-', 0, NULL, 0, 0, "", " Where : is any text"); if (num_values > 0) { win_vprint(window, '-', 0, NULL, 0, 0, "", " Remove : /%s remove ", tag); win_vprint(window, '-', 0, NULL, 0, 0, "", " Where : between 'val1' and 'val%d'", num_values); } break; case FIELD_BOOLEAN: win_vprint(window, '-', 0, NULL, 0, 0, "", " Set : /%s ", tag); win_print(window, '-', 0, NULL, 0, 0, "", " Where : is either 'on' or 'off'"); break; case FIELD_LIST_SINGLE: win_vprint(window, '-', 0, NULL, 0, 0, "", " Set : /%s ", tag); win_print(window, '-', 0, NULL, 0, 0, "", " Where : is one of"); curr_option = field->options; while (curr_option) { option = curr_option->data; win_vprint(window, '-', 0, NULL, 0, 0, "", " %s", option->value); curr_option = g_slist_next(curr_option); } break; case FIELD_LIST_MULTI: win_vprint(window, '-', 0, NULL, 0, 0, "", " Add : /%s add ", tag); win_vprint(window, '-', 0, NULL, 0, 0, "", " Remove : /%s remove ", tag); win_print(window, '-', 0, NULL, 0, 0, "", " Where : is one of"); curr_option = field->options; while (curr_option) { option = curr_option->data; win_vprint(window, '-', 0, NULL, 0, 0, "", " %s", option->value); curr_option = g_slist_next(curr_option); } break; case FIELD_JID_SINGLE: win_vprint(window, '-', 0, NULL, 0, 0, "", " Set : /%s ", tag); win_print(window, '-', 0, NULL, 0, 0, "", " Where : is a valid Jabber ID"); break; case FIELD_JID_MULTI: win_vprint(window, '-', 0, NULL, 0, 0, "", " Add : /%s add ", tag); win_vprint(window, '-', 0, NULL, 0, 0, "", " Remove : /%s remove ", tag); win_print(window, '-', 0, NULL, 0, 0, "", " Where : is a valid Jabber ID"); break; case FIELD_FIXED: case FIELD_UNKNOWN: case FIELD_HIDDEN: default: break; } } else { win_vprint(window, '-', 0, NULL, 0, 0, "", "No such field %s", tag); } } void ui_show_form_help(ProfMucConfWin *confwin) { if (confwin->form->instructions) { ProfWin *window = (ProfWin*) confwin; win_print(window, '-', 0, NULL, 0, 0, "", "Supplied instructions:"); win_print(window, '-', 0, NULL, 0, 0, "", confwin->form->instructions); win_print(window, '-', 0, NULL, 0, 0, "", ""); } } void ui_show_lines(ProfWin *window, const gchar** lines) { if (lines) { int i; for (i = 0; lines[i] != NULL; i++) { win_print(window, '-', 0, NULL, 0, 0, "", lines[i]); } } } void ui_room_update_occupants(const char * const roomjid) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window && win_has_active_subwin(window)) { occupantswin_occupants(roomjid); } } void ui_room_show_occupants(const char * const roomjid) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window && !win_has_active_subwin(window)) { wins_show_subwin(window); occupantswin_occupants(roomjid); } } void ui_room_hide_occupants(const char * const roomjid) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window && win_has_active_subwin(window)) { wins_hide_subwin(window); } } void ui_show_roster(void) { ProfWin *window = wins_get_console(); if (window && !win_has_active_subwin(window)) { wins_show_subwin(window); rosterwin_roster(); } } void ui_hide_roster(void) { ProfWin *window = wins_get_console(); if (window && win_has_active_subwin(window)) { wins_hide_subwin(window); } } void ui_handle_software_version_error(const char * const roomjid, const char * const message) { GString *message_str = g_string_new(""); ProfWin *window = wins_get_console(); g_string_printf(message_str, "Could not get software version"); if (message) { g_string_append(message_str, ": "); g_string_append(message_str, message); } win_print(window, '-', 0, NULL, 0, THEME_ERROR, "", message_str->str); g_string_free(message_str, TRUE); } void ui_show_software_version(const char * const jid, const char * const presence, const char * const name, const char * const version, const char * const os) { Jid *jidp = jid_create(jid); ProfWin *window = NULL; ProfWin *chatwin = (ProfWin*)wins_get_chat(jidp->barejid); ProfWin *mucwin = (ProfWin*)wins_get_muc(jidp->barejid); ProfWin *privwin = (ProfWin*)wins_get_private(jidp->fulljid); ProfWin *console = wins_get_console(); jid_destroy(jidp); if (chatwin) { if (wins_is_current(chatwin)) { window = chatwin; } else { window = console; } } else if (privwin) { if (wins_is_current(privwin)) { window = privwin; } else { window = console; } } else if (mucwin) { if (wins_is_current(mucwin)) { window = mucwin; } else { window = console; } } else { window = console; } if (name || version || os) { win_println(window, 0, ""); theme_item_t presence_colour = theme_main_presence_attrs(presence); win_vprint(window, '-', 0, NULL, NO_EOL, presence_colour, "", "%s", jid); win_print(window, '-', 0, NULL, NO_DATE, 0, "", ":"); } if (name) { win_vprint(window, '-', 0, NULL, 0, 0, "", "Name : %s", name); } if (version) { win_vprint(window, '-', 0, NULL, 0, 0, "", "Version : %s", version); } if (os) { win_vprint(window, '-', 0, NULL, 0, 0, "", "OS : %s", os); } } static void _win_show_history(ProfChatWin *chatwin, const char * const contact) { if (!chatwin->history_shown) { Jid *jid = jid_create(jabber_get_fulljid()); GSList *history = chat_log_get_previous(jid->barejid, contact); jid_destroy(jid); GSList *curr = history; while (curr) { char *line = curr->data; // entry if (line[2] == ':') { char hh[3]; memcpy(hh, &line[0], 2); hh[2] = '\0'; int ihh = atoi(hh); char mm[3]; memcpy(mm, &line[3], 2); mm[2] = '\0'; int imm = atoi(mm); char ss[3]; memcpy(ss, &line[6], 2); ss[2] = '\0'; int iss = atoi(ss); GDateTime *timestamp = g_date_time_new_local(2000, 1, 1, ihh, imm, iss); win_print((ProfWin*)chatwin, '-', 0, timestamp, NO_COLOUR_DATE, 0, "", curr->data+11); g_date_time_unref(timestamp); // header } else { win_print((ProfWin*)chatwin, '-', 0, NULL, 0, 0, "", curr->data); } curr = g_slist_next(curr); } chatwin->history_shown = TRUE; g_slist_free_full(history, free); } } profanity-0.4.7/src/ui/inputwin.c000066400000000000000000000323741257755232500170100ustar00rootroot00000000000000/* * inputwin.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #define _XOPEN_SOURCE_EXTENDED #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_NCURSESW_NCURSES_H #include #elif HAVE_NCURSES_H #include #endif #include "command/command.h" #include "common.h" #include "config/accounts.h" #include "config/preferences.h" #include "config/theme.h" #include "log.h" #include "muc.h" #include "profanity.h" #include "roster_list.h" #include "ui/ui.h" #include "ui/statusbar.h" #include "ui/inputwin.h" #include "ui/window.h" #include "window_list.h" #include "event/ui_events.h" #include "xmpp/xmpp.h" static WINDOW *inp_win; static int pad_start = 0; static struct timeval p_rl_timeout; /* Timeout in ms. Shows how long select() may block. */ static gint inp_timeout = 0; static gint no_input_count = 0; static fd_set fds; static int r; static char *inp_line = NULL; static gboolean get_password = FALSE; static void _inp_win_update_virtual(void); static int _inp_printable(const wint_t ch); static void _inp_win_handle_scroll(void); static int _inp_offset_to_col(char *str, int offset); static void _inp_write(char *line, int offset); static int _inp_rl_getc(FILE *stream); static void _inp_rl_linehandler(char *line); static int _inp_rl_tab_handler(int count, int key); static int _inp_rl_clear_handler(int count, int key); static int _inp_rl_win1_handler(int count, int key); static int _inp_rl_win2_handler(int count, int key); static int _inp_rl_win3_handler(int count, int key); static int _inp_rl_win4_handler(int count, int key); static int _inp_rl_win5_handler(int count, int key); static int _inp_rl_win6_handler(int count, int key); static int _inp_rl_win7_handler(int count, int key); static int _inp_rl_win8_handler(int count, int key); static int _inp_rl_win9_handler(int count, int key); static int _inp_rl_win0_handler(int count, int key); static int _inp_rl_altleft_handler(int count, int key); static int _inp_rl_altright_handler(int count, int key); static int _inp_rl_pageup_handler(int count, int key); static int _inp_rl_pagedown_handler(int count, int key); static int _inp_rl_altpageup_handler(int count, int key); static int _inp_rl_altpagedown_handler(int count, int key); static int _inp_rl_startup_hook(void); void create_input_window(void) { #ifdef NCURSES_REENTRANT set_escdelay(25); #else ESCDELAY = 25; #endif rl_readline_name = "profanity"; rl_getc_function = _inp_rl_getc; rl_startup_hook = _inp_rl_startup_hook; rl_callback_handler_install(NULL, _inp_rl_linehandler); inp_win = newpad(1, INP_WIN_MAX); wbkgd(inp_win, theme_attrs(THEME_INPUT_TEXT));; keypad(inp_win, TRUE); wmove(inp_win, 0, 0); _inp_win_update_virtual(); } char * inp_readline(void) { free(inp_line); inp_line = NULL; p_rl_timeout.tv_sec = inp_timeout / 1000; p_rl_timeout.tv_usec = inp_timeout % 1000 * 1000; FD_ZERO(&fds); FD_SET(fileno(rl_instream), &fds); errno = 0; r = select(FD_SETSIZE, &fds, NULL, NULL, &p_rl_timeout); if (r < 0) { if (errno != EINTR) { char *err_msg = strerror(errno); log_error("Readline failed: %s", err_msg); } return NULL; } if (FD_ISSET(fileno(rl_instream), &fds)) { rl_callback_read_char(); if (rl_line_buffer && rl_line_buffer[0] != '/' && rl_line_buffer[0] != '\0' && rl_line_buffer[0] != '\n') { prof_handle_activity(); } ui_reset_idle_time(); if (!get_password) { _inp_write(rl_line_buffer, rl_point); } inp_nonblocking(TRUE); } else { inp_nonblocking(FALSE); prof_handle_idle(); } if (inp_line) { return strdup(inp_line); } else { return NULL; } } void inp_win_resize(void) { int col = getcurx(inp_win); int wcols = getmaxx(stdscr); // if lost cursor off screen, move contents to show it if (col >= pad_start + wcols) { pad_start = col - (wcols / 2); if (pad_start < 0) { pad_start = 0; } } wbkgd(inp_win, theme_attrs(THEME_INPUT_TEXT));; _inp_win_update_virtual(); } void inp_nonblocking(gboolean reset) { if (! prefs_get_boolean(PREF_INPBLOCK_DYNAMIC)) { inp_timeout = prefs_get_inpblock(); return; } if (reset) { inp_timeout = 0; no_input_count = 0; } if (inp_timeout < prefs_get_inpblock()) { no_input_count++; if (no_input_count % 10 == 0) { inp_timeout += no_input_count; if (inp_timeout > prefs_get_inpblock()) { inp_timeout = prefs_get_inpblock(); } } } } void inp_close(void) { rl_callback_handler_remove(); } char* inp_get_password(void) { werase(inp_win); wmove(inp_win, 0, 0); _inp_win_update_virtual(); doupdate(); char *password = NULL; get_password = TRUE; while (!password) { password = inp_readline(); } get_password = FALSE; status_bar_clear(); return password; } void inp_put_back(void) { _inp_win_update_virtual(); } void inp_win_clear(void) { werase(inp_win); wmove(inp_win, 0, 0); pad_start = 0; _inp_win_update_virtual(); } static void _inp_win_update_virtual(void) { int wrows, wcols; getmaxyx(stdscr, wrows, wcols); pnoutrefresh(inp_win, 0, pad_start, wrows-1, 0, wrows-1, wcols-2); } static void _inp_write(char *line, int offset) { int col = _inp_offset_to_col(line, offset); werase(inp_win); waddstr(inp_win, line); wmove(inp_win, 0, col); _inp_win_handle_scroll(); _inp_win_update_virtual(); } static int _inp_printable(const wint_t ch) { char bytes[MB_CUR_MAX+1]; size_t utf_len = wcrtomb(bytes, ch, NULL); bytes[utf_len] = '\0'; gunichar unichar = g_utf8_get_char(bytes); return g_unichar_isprint(unichar); } static int _inp_offset_to_col(char *str, int offset) { int i = 0; int col = 0; while (i < offset && str[i] != '\0') { gunichar uni = g_utf8_get_char(&str[i]); size_t ch_len = mbrlen(&str[i], 4, NULL); i += ch_len; col++; if (g_unichar_iswide(uni)) { col++; } } return col; } static void _inp_win_handle_scroll(void) { int col = getcurx(inp_win); int wcols = getmaxx(stdscr); if (col == 0) { pad_start = 0; } else if (col >= pad_start + (wcols -2)) { pad_start = col - (wcols / 2); if (pad_start < 0) { pad_start = 0; } } else if (col <= pad_start) { pad_start = pad_start - (wcols / 2); if (pad_start < 0) { pad_start = 0; } } } // Readline callbacks static int _inp_rl_startup_hook(void) { rl_bind_keyseq("\\e1", _inp_rl_win1_handler); rl_bind_keyseq("\\e2", _inp_rl_win2_handler); rl_bind_keyseq("\\e3", _inp_rl_win3_handler); rl_bind_keyseq("\\e4", _inp_rl_win4_handler); rl_bind_keyseq("\\e5", _inp_rl_win5_handler); rl_bind_keyseq("\\e6", _inp_rl_win6_handler); rl_bind_keyseq("\\e7", _inp_rl_win7_handler); rl_bind_keyseq("\\e8", _inp_rl_win8_handler); rl_bind_keyseq("\\e9", _inp_rl_win9_handler); rl_bind_keyseq("\\e0", _inp_rl_win0_handler); rl_bind_keyseq("\\eOP", _inp_rl_win1_handler); rl_bind_keyseq("\\eOQ", _inp_rl_win2_handler); rl_bind_keyseq("\\eOR", _inp_rl_win3_handler); rl_bind_keyseq("\\eOS", _inp_rl_win4_handler); rl_bind_keyseq("\\e[15~", _inp_rl_win5_handler); rl_bind_keyseq("\\e[17~", _inp_rl_win6_handler); rl_bind_keyseq("\\e[18~", _inp_rl_win7_handler); rl_bind_keyseq("\\e[19~", _inp_rl_win8_handler); rl_bind_keyseq("\\e[20~", _inp_rl_win9_handler); rl_bind_keyseq("\\e[21~", _inp_rl_win0_handler); rl_bind_keyseq("\\e[1;9D", _inp_rl_altleft_handler); rl_bind_keyseq("\\e[1;3D", _inp_rl_altleft_handler); rl_bind_keyseq("\\e\\e[D", _inp_rl_altleft_handler); rl_bind_keyseq("\\e[1;9C", _inp_rl_altright_handler); rl_bind_keyseq("\\e[1;3C", _inp_rl_altright_handler); rl_bind_keyseq("\\e\\e[C", _inp_rl_altright_handler); rl_bind_keyseq("\\e\\e[5~", _inp_rl_altpageup_handler); rl_bind_keyseq("\\e[5;3~", _inp_rl_altpageup_handler); rl_bind_keyseq("\\e\\eOy", _inp_rl_altpageup_handler); rl_bind_keyseq("\\e\\e[6~", _inp_rl_altpagedown_handler); rl_bind_keyseq("\\e[6;3~", _inp_rl_altpagedown_handler); rl_bind_keyseq("\\e\\eOs", _inp_rl_altpagedown_handler); rl_bind_keyseq("\\e[5~", _inp_rl_pageup_handler); rl_bind_keyseq("\\eOy", _inp_rl_pageup_handler); rl_bind_keyseq("\\e[6~", _inp_rl_pagedown_handler); rl_bind_keyseq("\\eOs", _inp_rl_pagedown_handler); rl_bind_key('\t', _inp_rl_tab_handler); rl_bind_key(CTRL('L'), _inp_rl_clear_handler); return 0; } static void _inp_rl_linehandler(char *line) { if (line && *line) { if (!get_password) { add_history(line); } } inp_line = line; } static int _inp_rl_getc(FILE *stream) { int ch = rl_getc(stream); if (_inp_printable(ch)) { ProfWin *window = wins_get_current(); cmd_reset_autocomplete(window); } return ch; } static int _inp_rl_clear_handler(int count, int key) { ProfWin *win = wins_get_current(); win_clear(win); return 0; } static int _inp_rl_tab_handler(int count, int key) { if (rl_point != rl_end || !rl_line_buffer) { return 0; } ProfWin *current = wins_get_current(); if ((strncmp(rl_line_buffer, "/", 1) != 0) && (current->type == WIN_MUC)) { char *result = muc_autocomplete(current, rl_line_buffer); if (result) { rl_replace_line(result, 0); rl_point = rl_end; free(result); } } else if (strncmp(rl_line_buffer, "/", 1) == 0) { ProfWin *window = wins_get_current(); char *result = cmd_autocomplete(window, rl_line_buffer); if (result) { rl_replace_line(result, 0); rl_point = rl_end; free(result); } } return 0; } static void _go_to_win(int i) { ProfWin *window = wins_get_by_num(i); if (window) { ui_ev_focus_win(window); } } static int _inp_rl_win1_handler(int count, int key) { _go_to_win(1); return 0; } static int _inp_rl_win2_handler(int count, int key) { _go_to_win(2); return 0; } static int _inp_rl_win3_handler(int count, int key) { _go_to_win(3); return 0; } static int _inp_rl_win4_handler(int count, int key) { _go_to_win(4); return 0; } static int _inp_rl_win5_handler(int count, int key) { _go_to_win(5); return 0; } static int _inp_rl_win6_handler(int count, int key) { _go_to_win(6); return 0; } static int _inp_rl_win7_handler(int count, int key) { _go_to_win(7); return 0; } static int _inp_rl_win8_handler(int count, int key) { _go_to_win(8); return 0; } static int _inp_rl_win9_handler(int count, int key) { _go_to_win(9); return 0; } static int _inp_rl_win0_handler(int count, int key) { _go_to_win(0); return 0; } static int _inp_rl_altleft_handler(int count, int key) { ProfWin *window = wins_get_previous(); if (window) { ui_ev_focus_win(window); } return 0; } static int _inp_rl_altright_handler(int count, int key) { ProfWin *window = wins_get_next(); if (window) { ui_ev_focus_win(window); } return 0; } static int _inp_rl_pageup_handler(int count, int key) { ui_page_up(); return 0; } static int _inp_rl_pagedown_handler(int count, int key) { ui_page_down(); return 0; } static int _inp_rl_altpageup_handler(int count, int key) { ui_subwin_page_up(); return 0; } static int _inp_rl_altpagedown_handler(int count, int key) { ui_subwin_page_down(); return 0; } profanity-0.4.7/src/ui/inputwin.h000066400000000000000000000034421257755232500170070ustar00rootroot00000000000000/* * inputwin.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef UI_INPUTWIN_H #define UI_INPUTWIN_H #include #define INP_WIN_MAX 1000 void create_input_window(void); char* inp_readline(void); void inp_nonblocking(gboolean reset); void inp_close(void); void inp_win_clear(void); void inp_win_resize(void); void inp_put_back(void); char* inp_get_password(void); #endif profanity-0.4.7/src/ui/notifier.c000066400000000000000000000214461257755232500167500ustar00rootroot00000000000000/* * notifier.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include #include #ifdef HAVE_LIBNOTIFY #include #endif #ifdef PLATFORM_CYGWIN #include #endif #include "log.h" #include "muc.h" #include "ui/ui.h" #include "window_list.h" #include "config/preferences.h" static void _notify(const char * const message, int timeout, const char * const category); static GTimer *remind_timer; void notifier_initialise(void) { remind_timer = g_timer_new(); } void notifier_uninit(void) { #ifdef HAVE_LIBNOTIFY if (notify_is_initted()) { notify_uninit(); } #endif g_timer_destroy(remind_timer); } void notify_typing(const char * const handle) { char message[strlen(handle) + 1 + 11]; sprintf(message, "%s: typing...", handle); _notify(message, 10000, "Incoming message"); } void notify_invite(const char * const from, const char * const room, const char * const reason) { GString *message = g_string_new("Room invite\nfrom: "); g_string_append(message, from); g_string_append(message, "\nto: "); g_string_append(message, room); if (reason) { g_string_append_printf(message, "\n\"%s\"", reason); } _notify(message->str, 10000, "Incoming message"); g_string_free(message, TRUE); } void notify_message(ProfWin *window, const char * const name, const char * const text) { int num = wins_get_num(window); if (num == 10) { num = 0; } gboolean is_current = wins_is_current(window); if (!is_current || (is_current && prefs_get_boolean(PREF_NOTIFY_MESSAGE_CURRENT)) ) { GString *message = g_string_new(""); g_string_append_printf(message, "%s (win %d)", name, num); if (prefs_get_boolean(PREF_NOTIFY_MESSAGE_TEXT) && text) { g_string_append_printf(message, "\n%s", text); } _notify(message->str, 10000, "incoming message"); g_string_free(message, TRUE); } } void notify_room_message(const char * const handle, const char * const room, int win, const char * const text) { GString *message = g_string_new(""); g_string_append_printf(message, "%s in %s (win %d)", handle, room, win); if (text) { g_string_append_printf(message, "\n%s", text); } _notify(message->str, 10000, "incoming message"); g_string_free(message, TRUE); } void notify_subscription(const char * const from) { GString *message = g_string_new("Subscription request: \n"); g_string_append(message, from); _notify(message->str, 10000, "Incoming message"); g_string_free(message, TRUE); } void notify_remind(void) { gdouble elapsed = g_timer_elapsed(remind_timer, NULL); gint remind_period = prefs_get_notify_remind(); if (remind_period > 0 && elapsed >= remind_period) { gint unread = ui_unread(); gint open = muc_invites_count(); gint subs = presence_sub_request_count(); GString *text = g_string_new(""); if (unread > 0) { if (unread == 1) { g_string_append(text, "1 unread message"); } else { g_string_append_printf(text, "%d unread messages", unread); } } if (open > 0) { if (unread > 0) { g_string_append(text, "\n"); } if (open == 1) { g_string_append(text, "1 room invite"); } else { g_string_append_printf(text, "%d room invites", open); } } if (subs > 0) { if ((unread > 0) || (open > 0)) { g_string_append(text, "\n"); } if (subs == 1) { g_string_append(text, "1 subscription request"); } else { g_string_append_printf(text, "%d subscription requests", subs); } } if ((unread > 0) || (open > 0) || (subs > 0)) { _notify(text->str, 5000, "Incoming message"); } g_string_free(text, TRUE); g_timer_start(remind_timer); } } static void _notify(const char * const message, int timeout, const char * const category) { #ifdef HAVE_LIBNOTIFY log_debug("Attempting notification: %s", message); if (notify_is_initted()) { log_debug("Reinitialising libnotify"); notify_uninit(); notify_init("Profanity"); } else { log_debug("Initialising libnotify"); notify_init("Profanity"); } if (notify_is_initted()) { NotifyNotification *notification; notification = notify_notification_new("Profanity", message, NULL); notify_notification_set_timeout(notification, timeout); notify_notification_set_category(notification, category); notify_notification_set_urgency(notification, NOTIFY_URGENCY_NORMAL); GError *error = NULL; gboolean notify_success = notify_notification_show(notification, &error); if (!notify_success) { log_error("Error sending desktop notification:"); log_error(" -> Message : %s", message); log_error(" -> Error : %s", error->message); } else { log_debug("Notification sent."); } } else { log_error("Libnotify not initialised."); } #endif #ifdef PLATFORM_CYGWIN NOTIFYICONDATA nid; nid.cbSize = sizeof(NOTIFYICONDATA); //nid.hWnd = hWnd; nid.uID = 100; nid.uVersion = NOTIFYICON_VERSION; //nid.uCallbackMessage = WM_MYMESSAGE; nid.hIcon = LoadIcon(NULL, IDI_APPLICATION); strncpy(nid.szTip, "Tray Icon", 10); nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; Shell_NotifyIcon(NIM_ADD, &nid); // For a Ballon Tip nid.uFlags = NIF_INFO; strncpy(nid.szInfoTitle, "Profanity", 10); // Title strncpy(nid.szInfo, message, 256); // Copy Tip nid.uTimeout = timeout; // 3 Seconds nid.dwInfoFlags = NIIF_INFO; Shell_NotifyIcon(NIM_MODIFY, &nid); #endif #ifdef HAVE_OSXNOTIFY GString *notify_command = g_string_new("terminal-notifier -title \"Profanity\" -message '"); char *escaped_single = str_replace(message, "'", "'\\''"); if (escaped_single[0] == '<') { g_string_append(notify_command, "\\<"); g_string_append(notify_command, &escaped_single[1]); } else if (escaped_single[0] == '[') { g_string_append(notify_command, "\\["); g_string_append(notify_command, &escaped_single[1]); } else if (escaped_single[0] == '(') { g_string_append(notify_command, "\\("); g_string_append(notify_command, &escaped_single[1]); } else if (escaped_single[0] == '{') { g_string_append(notify_command, "\\{"); g_string_append(notify_command, &escaped_single[1]); } else { g_string_append(notify_command, escaped_single); } g_string_append(notify_command, "'"); free(escaped_single); char *term_name = getenv("TERM_PROGRAM"); char *app_id = NULL; if (g_strcmp0(term_name, "Apple_Terminal") == 0) { app_id = "com.apple.Terminal"; } else if (g_strcmp0(term_name, "iTerm.app") == 0) { app_id = "com.googlecode.iterm2"; } if (app_id) { g_string_append(notify_command, " -sender "); g_string_append(notify_command, app_id); } int res = system(notify_command->str); if (res == -1) { log_error("Could not send desktop notificaion."); } g_string_free(notify_command, TRUE); #endif } profanity-0.4.7/src/ui/occupantswin.c000066400000000000000000000122661257755232500176460ustar00rootroot00000000000000/* * occupantswin.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include "ui/ui.h" #include "ui/window.h" #include "window_list.h" #include "config/preferences.h" static void _occuptantswin_occupant(ProfLayoutSplit *layout, Occupant *occupant, gboolean showjid) { const char *presence_str = string_from_resource_presence(occupant->presence); theme_item_t presence_colour = theme_main_presence_attrs(presence_str); wattron(layout->subwin, theme_attrs(presence_colour)); GString *msg = g_string_new(" "); g_string_append(msg, occupant->nick); win_printline_nowrap(layout->subwin, msg->str); g_string_free(msg, TRUE); if (showjid && occupant->jid) { GString *msg = g_string_new(" "); g_string_append(msg, occupant->jid); win_printline_nowrap(layout->subwin, msg->str); g_string_free(msg, TRUE); } wattroff(layout->subwin, theme_attrs(presence_colour)); } void occupantswin_occupants(const char * const roomjid) { ProfMucWin *mucwin = wins_get_muc(roomjid); if (mucwin) { GList *occupants = muc_roster(roomjid); if (occupants) { ProfLayoutSplit *layout = (ProfLayoutSplit*)mucwin->window.layout; assert(layout->memcheck == LAYOUT_SPLIT_MEMCHECK); werase(layout->subwin); if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { wattron(layout->subwin, theme_attrs(THEME_OCCUPANTS_HEADER)); win_printline_nowrap(layout->subwin, " -Moderators"); wattroff(layout->subwin, theme_attrs(THEME_OCCUPANTS_HEADER)); GList *roster_curr = occupants; while (roster_curr) { Occupant *occupant = roster_curr->data; if (occupant->role == MUC_ROLE_MODERATOR) { _occuptantswin_occupant(layout, occupant, mucwin->showjid); } roster_curr = g_list_next(roster_curr); } wattron(layout->subwin, theme_attrs(THEME_OCCUPANTS_HEADER)); win_printline_nowrap(layout->subwin, " -Participants"); wattroff(layout->subwin, theme_attrs(THEME_OCCUPANTS_HEADER)); roster_curr = occupants; while (roster_curr) { Occupant *occupant = roster_curr->data; if (occupant->role == MUC_ROLE_PARTICIPANT) { _occuptantswin_occupant(layout, occupant, mucwin->showjid); } roster_curr = g_list_next(roster_curr); } wattron(layout->subwin, theme_attrs(THEME_OCCUPANTS_HEADER)); win_printline_nowrap(layout->subwin, " -Visitors"); wattroff(layout->subwin, theme_attrs(THEME_OCCUPANTS_HEADER)); roster_curr = occupants; while (roster_curr) { Occupant *occupant = roster_curr->data; if (occupant->role == MUC_ROLE_VISITOR) { _occuptantswin_occupant(layout, occupant, mucwin->showjid); } roster_curr = g_list_next(roster_curr); } } else { wattron(layout->subwin, theme_attrs(THEME_OCCUPANTS_HEADER)); win_printline_nowrap(layout->subwin, " -Occupants\n"); wattroff(layout->subwin, theme_attrs(THEME_OCCUPANTS_HEADER)); GList *roster_curr = occupants; while (roster_curr) { Occupant *occupant = roster_curr->data; _occuptantswin_occupant(layout, occupant, mucwin->showjid); roster_curr = g_list_next(roster_curr); } } } g_list_free(occupants); } } profanity-0.4.7/src/ui/rosterwin.c000066400000000000000000000166231257755232500171660ustar00rootroot00000000000000/* * rosterwin.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include "contact.h" #include "ui/ui.h" #include "ui/window.h" #include "window_list.h" #include "config/preferences.h" #include "roster_list.h" static void _rosterwin_contact(ProfLayoutSplit *layout, PContact contact) { const char *name = p_contact_name_or_jid(contact); const char *presence = p_contact_presence(contact); if ((g_strcmp0(presence, "offline") != 0) || ((g_strcmp0(presence, "offline") == 0) && (prefs_get_boolean(PREF_ROSTER_OFFLINE)))) { theme_item_t presence_colour = theme_main_presence_attrs(presence); wattron(layout->subwin, theme_attrs(presence_colour)); GString *msg = g_string_new(" "); g_string_append(msg, name); win_printline_nowrap(layout->subwin, msg->str); g_string_free(msg, TRUE); wattroff(layout->subwin, theme_attrs(presence_colour)); if (prefs_get_boolean(PREF_ROSTER_RESOURCE)) { GList *resources = p_contact_get_available_resources(contact); GList *curr_resource = resources; while (curr_resource) { Resource *resource = curr_resource->data; const char *resource_presence = string_from_resource_presence(resource->presence); theme_item_t resource_presence_colour = theme_main_presence_attrs(resource_presence); wattron(layout->subwin, theme_attrs(resource_presence_colour)); GString *msg = g_string_new(" "); g_string_append(msg, resource->name); win_printline_nowrap(layout->subwin, msg->str); g_string_free(msg, TRUE); wattroff(layout->subwin, theme_attrs(resource_presence_colour)); curr_resource = g_list_next(curr_resource); } g_list_free(resources); } } } static void _rosterwin_contacts_by_presence(ProfLayoutSplit *layout, const char * const presence, char *title) { GSList *contacts = roster_get_contacts_by_presence(presence); // if this group has contacts, or if we want to show empty groups if (contacts || prefs_get_boolean(PREF_ROSTER_EMPTY)) { wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER)); win_printline_nowrap(layout->subwin, title); wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER)); } if (contacts) { GSList *curr_contact = contacts; while (curr_contact) { PContact contact = curr_contact->data; _rosterwin_contact(layout, contact); curr_contact = g_slist_next(curr_contact); } } g_slist_free(contacts); } static void _rosterwin_contacts_by_group(ProfLayoutSplit *layout, char *group) { wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER)); GString *title = g_string_new(" -"); g_string_append(title, group); win_printline_nowrap(layout->subwin, title->str); g_string_free(title, TRUE); wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER)); GSList *contacts = roster_get_group(group); if (contacts) { GSList *curr_contact = contacts; while (curr_contact) { PContact contact = curr_contact->data; _rosterwin_contact(layout, contact); curr_contact = g_slist_next(curr_contact); } } g_slist_free(contacts); } static void _rosterwin_contacts_by_no_group(ProfLayoutSplit *layout) { GSList *contacts = roster_get_nogroup(); if (contacts) { wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER)); win_printline_nowrap(layout->subwin, " -no group"); wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER)); GSList *curr_contact = contacts; while (curr_contact) { PContact contact = curr_contact->data; _rosterwin_contact(layout, contact); curr_contact = g_slist_next(curr_contact); } } g_slist_free(contacts); } void rosterwin_roster(void) { ProfWin *console = wins_get_console(); if (console) { ProfLayoutSplit *layout = (ProfLayoutSplit*)console->layout; assert(layout->memcheck == LAYOUT_SPLIT_MEMCHECK); char *by = prefs_get_string(PREF_ROSTER_BY); if (g_strcmp0(by, "presence") == 0) { werase(layout->subwin); _rosterwin_contacts_by_presence(layout, "chat", " -Available for chat"); _rosterwin_contacts_by_presence(layout, "online", " -Online"); _rosterwin_contacts_by_presence(layout, "away", " -Away"); _rosterwin_contacts_by_presence(layout, "xa", " -Extended Away"); _rosterwin_contacts_by_presence(layout, "dnd", " -Do not disturb"); if (prefs_get_boolean(PREF_ROSTER_OFFLINE)) { _rosterwin_contacts_by_presence(layout, "offline", " -Offline"); } } else if (g_strcmp0(by, "group") == 0) { werase(layout->subwin); GSList *groups = roster_get_groups(); GSList *curr_group = groups; while (curr_group) { _rosterwin_contacts_by_group(layout, curr_group->data); curr_group = g_slist_next(curr_group); } g_slist_free_full(groups, free); _rosterwin_contacts_by_no_group(layout); } else { GSList *contacts = roster_get_contacts(); if (contacts) { werase(layout->subwin); wattron(layout->subwin, theme_attrs(THEME_ROSTER_HEADER)); win_printline_nowrap(layout->subwin, " -Roster"); wattroff(layout->subwin, theme_attrs(THEME_ROSTER_HEADER)); GSList *curr_contact = contacts; while (curr_contact) { PContact contact = curr_contact->data; _rosterwin_contact(layout, contact); curr_contact = g_slist_next(curr_contact); } } g_slist_free(contacts); } free(by); } } profanity-0.4.7/src/ui/statusbar.c000066400000000000000000000274651257755232500171500ustar00rootroot00000000000000/* * statusbar.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include #ifdef HAVE_NCURSESW_NCURSES_H #include #elif HAVE_NCURSES_H #include #endif #include "config/theme.h" #include "ui/ui.h" #include "ui/statusbar.h" #include "ui/inputwin.h" #include "config/preferences.h" #define TIME_CHECK 60000000 static WINDOW *status_bar; static char *message = NULL; // 1 2 3 4 5 6 7 8 9 0 > static char _active[34] = "[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]"; static char *bracket = "- -"; static int is_active[12]; static GHashTable *remaining_active; static int is_new[12]; static GHashTable *remaining_new; static GDateTime *last_time; static int current; static void _update_win_statuses(void); static void _mark_new(int num); static void _mark_active(int num); static void _mark_inactive(int num); static void _status_bar_draw(void); void create_status_bar(void) { int rows, cols, i; getmaxyx(stdscr, rows, cols); is_active[1] = TRUE; is_new[1] = FALSE; for (i = 2; i < 12; i++) { is_active[i] = FALSE; is_new[i] = FALSE; } remaining_active = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); remaining_new = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); current = 1; int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET); status_bar = newwin(1, cols, rows-2, 0); wbkgd(status_bar, theme_attrs(THEME_STATUS_TEXT)); wattron(status_bar, bracket_attrs); mvwprintw(status_bar, 0, cols - 34, _active); mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket); wattroff(status_bar, bracket_attrs); if (last_time) { g_date_time_unref(last_time); } last_time = g_date_time_new_now_local(); _status_bar_draw(); } void status_bar_update_virtual(void) { _status_bar_draw(); } void status_bar_resize(void) { int rows, cols; getmaxyx(stdscr, rows, cols); werase(status_bar); int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET); mvwin(status_bar, rows-2, 0); wresize(status_bar, 1, cols); wbkgd(status_bar, theme_attrs(THEME_STATUS_TEXT)); wattron(status_bar, bracket_attrs); mvwprintw(status_bar, 0, cols - 34, _active); mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket); wattroff(status_bar, bracket_attrs); if (message) { char *time_pref = prefs_get_string(PREF_TIME_STATUSBAR); gchar *date_fmt = g_date_time_format(last_time, time_pref); assert(date_fmt != NULL); size_t len = strlen(date_fmt); g_free(date_fmt); if (g_strcmp0(time_pref, "") != 0) { /* 01234567890123456 * [HH:MM] message */ mvwprintw(status_bar, 0, 5 + len, message); } else { mvwprintw(status_bar, 0, 1, message); } prefs_free_string(time_pref); } if (last_time) { g_date_time_unref(last_time); } last_time = g_date_time_new_now_local(); _status_bar_draw(); } void status_bar_set_all_inactive(void) { int i = 0; for (i = 0; i < 12; i++) { is_active[i] = FALSE; is_new[i] = FALSE; _mark_inactive(i); } g_hash_table_remove_all(remaining_active); g_hash_table_remove_all(remaining_new); _status_bar_draw(); } void status_bar_current(int i) { if (i == 0) { current = 10; } else if (i > 10) { current = 11; } else { current = i; } int cols = getmaxx(stdscr); int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET); wattron(status_bar, bracket_attrs); mvwprintw(status_bar, 0, cols - 34, _active); mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket); wattroff(status_bar, bracket_attrs); _status_bar_draw(); } void status_bar_inactive(const int win) { int true_win = win; if (true_win == 0) { true_win = 10; } // extra windows if (true_win > 10) { g_hash_table_remove(remaining_active, GINT_TO_POINTER(true_win)); g_hash_table_remove(remaining_new, GINT_TO_POINTER(true_win)); // still have new windows if (g_hash_table_size(remaining_new) != 0) { is_active[11] = TRUE; is_new[11] = TRUE; _mark_new(11); // still have active windows } else if (g_hash_table_size(remaining_active) != 0) { is_active[11] = TRUE; is_new[11] = FALSE; _mark_active(11); // no active or new windows } else { is_active[11] = FALSE; is_new[11] = FALSE; _mark_inactive(11); } // visible window indicators } else { is_active[true_win] = FALSE; is_new[true_win] = FALSE; _mark_inactive(true_win); } _status_bar_draw(); } void status_bar_active(const int win) { int true_win = win; if (true_win == 0) { true_win = 10; } // extra windows if (true_win > 10) { g_hash_table_add(remaining_active, GINT_TO_POINTER(true_win)); g_hash_table_remove(remaining_new, GINT_TO_POINTER(true_win)); // still have new windows if (g_hash_table_size(remaining_new) != 0) { is_active[11] = TRUE; is_new[11] = TRUE; _mark_new(11); // only active windows } else { is_active[11] = TRUE; is_new[11] = FALSE; _mark_active(11); } // visible window indicators } else { is_active[true_win] = TRUE; is_new[true_win] = FALSE; _mark_active(true_win); } _status_bar_draw(); } void status_bar_new(const int win) { int true_win = win; if (true_win == 0) { true_win = 10; } if (true_win > 10) { g_hash_table_add(remaining_active, GINT_TO_POINTER(true_win)); g_hash_table_add(remaining_new, GINT_TO_POINTER(true_win)); is_active[11] = TRUE; is_new[11] = TRUE; _mark_new(11); } else { is_active[true_win] = TRUE; is_new[true_win] = TRUE; _mark_new(true_win); } _status_bar_draw(); } void status_bar_get_password(void) { status_bar_print_message("Enter password:"); _status_bar_draw(); } void status_bar_print_message(const char * const msg) { werase(status_bar); if (message) { free(message); } message = strdup(msg); char *time_pref = prefs_get_string(PREF_TIME_STATUSBAR); gchar *date_fmt = g_date_time_format(last_time, time_pref); assert(date_fmt != NULL); size_t len = strlen(date_fmt); g_free(date_fmt); if (g_strcmp0(time_pref, "") != 0) { mvwprintw(status_bar, 0, 5 + len, message); } else { mvwprintw(status_bar, 0, 1, message); } prefs_free_string(time_pref); int cols = getmaxx(stdscr); int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET); wattron(status_bar, bracket_attrs); mvwprintw(status_bar, 0, cols - 34, _active); mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket); wattroff(status_bar, bracket_attrs); _status_bar_draw(); } void status_bar_clear(void) { if (message) { free(message); message = NULL; } werase(status_bar); int cols = getmaxx(stdscr); int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET); wattron(status_bar, bracket_attrs); mvwprintw(status_bar, 0, cols - 34, _active); mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket); wattroff(status_bar, bracket_attrs); _status_bar_draw(); } void status_bar_clear_message(void) { if (message) { free(message); message = NULL; } werase(status_bar); int cols = getmaxx(stdscr); int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET); wattron(status_bar, bracket_attrs); mvwprintw(status_bar, 0, cols - 34, _active); mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket); wattroff(status_bar, bracket_attrs); _status_bar_draw(); } static void _update_win_statuses(void) { int i; for(i = 1; i < 12; i++) { if (is_new[i]) { _mark_new(i); } else if (is_active[i]) { _mark_active(i); } else { _mark_inactive(i); } } } static void _mark_new(int num) { int active_pos = 1 + ((num-1) * 3); int cols = getmaxx(stdscr); int status_attrs = theme_attrs(THEME_STATUS_NEW); wattron(status_bar, status_attrs); wattron(status_bar, A_BLINK); if (num == 10) { mvwprintw(status_bar, 0, cols - 34 + active_pos, "0"); } else if (num > 10) { mvwprintw(status_bar, 0, cols - 34 + active_pos, ">"); } else { mvwprintw(status_bar, 0, cols - 34 + active_pos, "%d", num); } wattroff(status_bar, status_attrs); wattroff(status_bar, A_BLINK); } static void _mark_active(int num) { int active_pos = 1 + ((num-1) * 3); int cols = getmaxx(stdscr); int status_attrs = theme_attrs(THEME_STATUS_ACTIVE); wattron(status_bar, status_attrs); if (num == 10) { mvwprintw(status_bar, 0, cols - 34 + active_pos, "0"); } else if (num > 10) { mvwprintw(status_bar, 0, cols - 34 + active_pos, ">"); } else { mvwprintw(status_bar, 0, cols - 34 + active_pos, "%d", num); } wattroff(status_bar, status_attrs); } static void _mark_inactive(int num) { int active_pos = 1 + ((num-1) * 3); int cols = getmaxx(stdscr); mvwaddch(status_bar, 0, cols - 34 + active_pos, ' '); } static void _status_bar_draw(void) { if (last_time) { g_date_time_unref(last_time); } last_time = g_date_time_new_now_local(); int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET); char *time_pref = prefs_get_string(PREF_TIME_STATUSBAR); if (g_strcmp0(time_pref, "") != 0) { gchar *date_fmt = g_date_time_format(last_time, time_pref); assert(date_fmt != NULL); size_t len = strlen(date_fmt); wattron(status_bar, bracket_attrs); mvwaddch(status_bar, 0, 1, '['); wattroff(status_bar, bracket_attrs); mvwprintw(status_bar, 0, 2, date_fmt); wattron(status_bar, bracket_attrs); mvwaddch(status_bar, 0, 2 + len, ']'); wattroff(status_bar, bracket_attrs); g_free(date_fmt); } prefs_free_string(time_pref); _update_win_statuses(); wnoutrefresh(status_bar); inp_put_back(); } profanity-0.4.7/src/ui/statusbar.h000066400000000000000000000034651257755232500171470ustar00rootroot00000000000000/* * statusbar.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef UI_STATUSBAR_H #define UI_STATUSBAR_H void create_status_bar(void); void status_bar_update_virtual(void); void status_bar_resize(void); void status_bar_clear(void); void status_bar_clear_message(void); void status_bar_get_password(void); void status_bar_print_message(const char * const msg); void status_bar_current(int i); #endif profanity-0.4.7/src/ui/titlebar.c000066400000000000000000000257071257755232500167430ustar00rootroot00000000000000/* * titlebar.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include "config.h" #include "common.h" #include "config/theme.h" #include "config/preferences.h" #include "ui/ui.h" #include "ui/titlebar.h" #include "ui/inputwin.h" #include "window_list.h" #include "ui/window.h" #include "roster_list.h" #include "chat_session.h" static WINDOW *win; static contact_presence_t current_presence; static gboolean typing; static GTimer *typing_elapsed; static void _title_bar_draw(void); static void _show_self_presence(void); static void _show_contact_presence(ProfChatWin *chatwin); static void _show_privacy(ProfChatWin *chatwin); void create_title_bar(void) { int cols = getmaxx(stdscr); win = newwin(1, cols, 0, 0); wbkgd(win, theme_attrs(THEME_TITLE_TEXT)); title_bar_console(); title_bar_set_presence(CONTACT_OFFLINE); wnoutrefresh(win); inp_put_back(); } void title_bar_update_virtual(void) { ProfWin *window = wins_get_current(); if (window->type != WIN_CONSOLE) { if (typing_elapsed) { gdouble seconds = g_timer_elapsed(typing_elapsed, NULL); if (seconds >= 10) { typing = FALSE; g_timer_destroy(typing_elapsed); typing_elapsed = NULL; } } } _title_bar_draw(); } void title_bar_resize(void) { int cols = getmaxx(stdscr); wresize(win, 1, cols); wbkgd(win, theme_attrs(THEME_TITLE_TEXT)); _title_bar_draw(); } void title_bar_console(void) { werase(win); if (typing_elapsed) { g_timer_destroy(typing_elapsed); } typing_elapsed = NULL; typing = FALSE; _title_bar_draw(); } void title_bar_set_presence(contact_presence_t presence) { current_presence = presence; _title_bar_draw(); } void title_bar_switch(void) { if (typing_elapsed) { g_timer_destroy(typing_elapsed); typing_elapsed = NULL; typing = FALSE; } _title_bar_draw(); } void title_bar_set_typing(gboolean is_typing) { if (is_typing) { if (typing_elapsed) { g_timer_start(typing_elapsed); } else { typing_elapsed = g_timer_new(); } } typing = is_typing; _title_bar_draw(); } static void _title_bar_draw(void) { ProfWin *current = wins_get_current(); werase(win); wmove(win, 0, 0); int i; for (i = 0; i < 45; i++) { waddch(win, ' '); } char *title = win_get_title(current); mvwprintw(win, 0, 0, " %s", title); free(title); if (current && current->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*) current; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); _show_contact_presence(chatwin); _show_privacy(chatwin); if (typing) { wprintw(win, " (typing...)"); } } _show_self_presence(); wnoutrefresh(win); inp_put_back(); } static void _show_self_presence(void) { int presence_attrs = 0; int bracket_attrs = theme_attrs(THEME_TITLE_BRACKET); int cols = getmaxx(stdscr); wattron(win, bracket_attrs); mvwaddch(win, 0, cols - 14, '['); wattroff(win, bracket_attrs); switch (current_presence) { case CONTACT_ONLINE: presence_attrs = theme_attrs(THEME_TITLE_ONLINE); wattron(win, presence_attrs); mvwprintw(win, 0, cols - 13, " ...online "); wattroff(win, presence_attrs); break; case CONTACT_AWAY: presence_attrs = theme_attrs(THEME_TITLE_AWAY); wattron(win, presence_attrs); mvwprintw(win, 0, cols - 13, " .....away "); wattroff(win, presence_attrs); break; case CONTACT_DND: presence_attrs = theme_attrs(THEME_TITLE_DND); wattron(win, presence_attrs); mvwprintw(win, 0, cols - 13, " ......dnd "); wattroff(win, presence_attrs); break; case CONTACT_CHAT: presence_attrs = theme_attrs(THEME_TITLE_CHAT); wattron(win, presence_attrs); mvwprintw(win, 0, cols - 13, " .....chat "); wattroff(win, presence_attrs); break; case CONTACT_XA: presence_attrs = theme_attrs(THEME_TITLE_XA); wattron(win, presence_attrs); mvwprintw(win, 0, cols - 13, " .......xa "); wattroff(win, presence_attrs); break; case CONTACT_OFFLINE: presence_attrs = theme_attrs(THEME_TITLE_OFFLINE); wattron(win, presence_attrs); mvwprintw(win, 0, cols - 13, " ..offline "); wattroff(win, presence_attrs); break; } wattron(win, bracket_attrs); mvwaddch(win, 0, cols - 2, ']'); wattroff(win, bracket_attrs); } static void _show_privacy(ProfChatWin *chatwin) { int bracket_attrs = theme_attrs(THEME_TITLE_BRACKET); int encrypted_attrs = theme_attrs(THEME_TITLE_ENCRYPTED); int unencrypted_attrs = theme_attrs(THEME_TITLE_UNENCRYPTED); int trusted_attrs = theme_attrs(THEME_TITLE_TRUSTED); int untrusted_attrs = theme_attrs(THEME_TITLE_UNTRUSTED); if (chatwin->is_otr) { wprintw(win, " "); wattron(win, bracket_attrs); wprintw(win, "["); wattroff(win, bracket_attrs); wattron(win, encrypted_attrs); wprintw(win, "OTR"); wattroff(win, encrypted_attrs); wattron(win, bracket_attrs); wprintw(win, "]"); wattroff(win, bracket_attrs); if (chatwin->otr_is_trusted) { wprintw(win, " "); wattron(win, bracket_attrs); wprintw(win, "["); wattroff(win, bracket_attrs); wattron(win, trusted_attrs); wprintw(win, "trusted"); wattroff(win, trusted_attrs); wattron(win, bracket_attrs); wprintw(win, "]"); wattroff(win, bracket_attrs); } else { wprintw(win, " "); wattron(win, bracket_attrs); wprintw(win, "["); wattroff(win, bracket_attrs); wattron(win, untrusted_attrs); wprintw(win, "untrusted"); wattroff(win, untrusted_attrs); wattron(win, bracket_attrs); wprintw(win, "]"); wattroff(win, bracket_attrs); } } else if (chatwin->pgp_send || chatwin->pgp_recv) { GString *pgpmsg = g_string_new("PGP "); if (chatwin->pgp_send && !chatwin->pgp_recv) { g_string_append(pgpmsg, "send"); } else if (!chatwin->pgp_send && chatwin->pgp_recv) { g_string_append(pgpmsg, "recv"); } else { g_string_append(pgpmsg, "send/recv"); } wprintw(win, " "); wattron(win, bracket_attrs); wprintw(win, "["); wattroff(win, bracket_attrs); wattron(win, encrypted_attrs); wprintw(win, pgpmsg->str); wattroff(win, encrypted_attrs); wattron(win, bracket_attrs); wprintw(win, "]"); wattroff(win, bracket_attrs); g_string_free(pgpmsg, TRUE); } else { if (prefs_get_boolean(PREF_ENC_WARN)) { wprintw(win, " "); wattron(win, bracket_attrs); wprintw(win, "["); wattroff(win, bracket_attrs); wattron(win, unencrypted_attrs); wprintw(win, "unencrypted"); wattroff(win, unencrypted_attrs); wattron(win, bracket_attrs); wprintw(win, "]"); wattroff(win, bracket_attrs); } } } static void _show_contact_presence(ProfChatWin *chatwin) { int bracket_attrs = theme_attrs(THEME_TITLE_BRACKET); char *resource = NULL; ChatSession *session = chat_session_get(chatwin->barejid); if (chatwin->resource_override) { resource = chatwin->resource_override; } else if (session && session->resource) { resource = session->resource; } if (resource && prefs_get_boolean(PREF_RESOURCE_TITLE)) { wprintw(win, "/"); wprintw(win, resource); } if (prefs_get_boolean(PREF_PRESENCE)) { theme_item_t presence_colour = THEME_TITLE_OFFLINE; const char *presence = "offline"; PContact contact = roster_get_contact(chatwin->barejid); if (contact) { if (resource) { Resource *resourcep = p_contact_get_resource(contact, resource); if (resourcep) { presence = string_from_resource_presence(resourcep->presence); } } else { presence = p_contact_presence(contact); } } presence_colour = THEME_TITLE_ONLINE; if (g_strcmp0(presence, "offline") == 0) { presence_colour = THEME_TITLE_OFFLINE; } else if (g_strcmp0(presence, "away") == 0) { presence_colour = THEME_TITLE_AWAY; } else if (g_strcmp0(presence, "xa") == 0) { presence_colour = THEME_TITLE_XA; } else if (g_strcmp0(presence, "chat") == 0) { presence_colour = THEME_TITLE_CHAT; } else if (g_strcmp0(presence, "dnd") == 0) { presence_colour = THEME_TITLE_DND; } int presence_attrs = theme_attrs(presence_colour); wprintw(win, " "); wattron(win, bracket_attrs); wprintw(win, "["); wattroff(win, bracket_attrs); wattron(win, presence_attrs); wprintw(win, presence); wattroff(win, presence_attrs); wattron(win, bracket_attrs); wprintw(win, "]"); wattroff(win, bracket_attrs); } } profanity-0.4.7/src/ui/titlebar.h000066400000000000000000000034251257755232500167410ustar00rootroot00000000000000/* * titlebar.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef UI_TITLEBAR_H #define UI_TITLEBAR_H void create_title_bar(void); void title_bar_update_virtual(void); void title_bar_resize(void); void title_bar_console(void); void title_bar_set_presence(contact_presence_t presence); void title_bar_switch(void); void title_bar_set_typing(gboolean is_typing); #endifprofanity-0.4.7/src/ui/ui.h000066400000000000000000000436151257755232500155550ustar00rootroot00000000000000/* * ui.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef UI_UI_H #define UI_UI_H #include "command/commands.h" #include "ui/win_types.h" #include "muc.h" #define NO_ME 1 #define NO_DATE 2 #define NO_EOL 4 #define NO_COLOUR_FROM 8 #define NO_COLOUR_DATE 16 typedef enum { PROF_MSG_PLAIN, PROF_MSG_OTR, PROF_MSG_PGP } prof_enc_t; // ui startup and control void ui_init(void); void ui_load_colours(void); void ui_update(void); void ui_close(void); void ui_redraw(void); void ui_resize(void); GSList* ui_get_chat_recipients(void); void ui_switch_win(ProfWin *window); void ui_sigwinch_handler(int sig); void ui_gone_secure(const char * const barejid, gboolean trusted); void ui_gone_insecure(const char * const barejid); void ui_trust(const char * const barejid); void ui_untrust(const char * const barejid); void ui_smp_recipient_initiated(const char * const barejid); void ui_smp_recipient_initiated_q(const char * const barejid, const char *question); void ui_smp_successful(const char * const barejid); void ui_smp_unsuccessful_sender(const char * const barejid); void ui_smp_unsuccessful_receiver(const char * const barejid); void ui_smp_aborted(const char * const barejid); void ui_smp_answer_success(const char * const barejid); void ui_smp_answer_failure(const char * const barejid); void ui_otr_authenticating(const char * const barejid); void ui_otr_authetication_waiting(const char * const recipient); void ui_handle_otr_error(const char * const barejid, const char * const message); unsigned long ui_get_idle_time(void); void ui_reset_idle_time(void); ProfPrivateWin* ui_new_private_win(const char * const fulljid); ProfChatWin* ui_new_chat_win(const char * const barejid); void ui_print_system_msg_from_recipient(const char * const barejid, const char *message); gint ui_unread(void); void ui_close_connected_win(int index); int ui_close_all_wins(void); int ui_close_read_wins(void); // current window actions void ui_current_print_line(const char * const msg, ...); void ui_current_print_formatted_line(const char show_char, int attrs, const char * const msg, ...); void ui_current_error_line(const char * const msg); void ui_win_error_line(ProfWin *window, const char * const msg); win_type_t ui_win_type(int index); void ui_close_win(int index); int ui_win_unread(int index); char * ui_ask_password(void); char * ui_ask_pgp_passphrase(const char *hint, int prev_fail); void ui_handle_stanza(const char * const msg); // ui events void ui_contact_online(char *barejid, Resource *resource, GDateTime *last_activity); void ui_contact_typing(const char * const barejid, const char * const resource); void ui_incoming_msg(ProfChatWin *chatwin, const char * const resource, const char * const message, GDateTime *timestamp, gboolean win_created, prof_enc_t enc_mode); void ui_incoming_private_msg(const char * const fulljid, const char * const message, GDateTime *timestamp); void ui_message_receipt(const char * const barejid, const char * const id); void ui_disconnected(void); void ui_recipient_gone(const char * const barejid, const char * const resource); void ui_outgoing_chat_msg(ProfChatWin *chatwin, const char * const message, char *id, prof_enc_t enc_mode); void ui_outgoing_chat_msg_carbon(const char * const barejid, const char * const message); void ui_outgoing_private_msg(ProfPrivateWin *privwin, const char * const message); void ui_room_join(const char * const roomjid, gboolean focus); void ui_switch_to_room(const char * const roomjid); void ui_room_role_change(const char * const roomjid, const char * const role, const char * const actor, const char * const reason); void ui_room_affiliation_change(const char * const roomjid, const char * const affiliation, const char * const actor, const char * const reason); void ui_room_role_and_affiliation_change(const char * const roomjid, const char * const role, const char * const affiliation, const char * const actor, const char * const reason); void ui_room_occupant_role_change(const char * const roomjid, const char * const nick, const char * const role, const char * const actor, const char * const reason); void ui_room_occupant_affiliation_change(const char * const roomjid, const char * const nick, const char * const affiliation, const char * const actor, const char * const reason); void ui_room_occupant_role_and_affiliation_change(const char * const roomjid, const char * const nick, const char * const role, const char * const affiliation, const char * const actor, const char * const reason); void ui_room_roster(const char * const roomjid, GList *occupants, const char * const presence); void ui_room_history(const char * const roomjid, const char * const nick, GDateTime *timestamp, const char * const message); void ui_room_message(const char * const roomjid, const char * const nick, const char * const message); void ui_room_subject(const char * const roomjid, const char * const nick, const char * const subject); void ui_room_requires_config(const char * const roomjid); void ui_room_destroy(const char * const roomjid); void ui_show_room_info(ProfMucWin *mucwin); void ui_show_room_role_list(ProfMucWin *mucwin, muc_role_t role); void ui_show_room_affiliation_list(ProfMucWin *mucwin, muc_affiliation_t affiliation); void ui_handle_room_info_error(const char * const roomjid, const char * const error); void ui_show_room_disco_info(const char * const roomjid, GSList *identities, GSList *features); void ui_room_destroyed(const char * const roomjid, const char * const reason, const char * const new_jid, const char * const password); void ui_room_kicked(const char * const roomjid, const char * const actor, const char * const reason); void ui_room_member_kicked(const char * const roomjid, const char * const nick, const char * const actor, const char * const reason); void ui_room_banned(const char * const roomjid, const char * const actor, const char * const reason); void ui_room_member_banned(const char * const roomjid, const char * const nick, const char * const actor, const char * const reason); void ui_leave_room(const char * const roomjid); void ui_room_broadcast(const char * const roomjid, const char * const message); void ui_room_member_offline(const char * const roomjid, const char * const nick); void ui_room_member_online(const char * const roomjid, const char * const nick, const char * const roles, const char * const affiliation, const char * const show, const char * const status); void ui_room_member_nick_change(const char * const roomjid, const char * const old_nick, const char * const nick); void ui_room_nick_change(const char * const roomjid, const char * const nick); void ui_room_member_presence(const char * const roomjid, const char * const nick, const char * const show, const char * const status); void ui_room_update_occupants(const char * const roomjid); void ui_room_show_occupants(const char * const roomjid); void ui_room_hide_occupants(const char * const roomjid); void ui_show_roster(void); void ui_hide_roster(void); void ui_roster_add(const char * const barejid, const char * const name); void ui_roster_remove(const char * const barejid); void ui_contact_already_in_group(const char * const contact, const char * const group); void ui_contact_not_in_group(const char * const contact, const char * const group); void ui_group_added(const char * const contact, const char * const group); void ui_group_removed(const char * const contact, const char * const group); void ui_chat_win_contact_online(PContact contact, Resource *resource, GDateTime *last_activity); void ui_chat_win_contact_offline(PContact contact, char *resource, char *status); void ui_contact_offline(char *barejid, char *resource, char *status); void ui_handle_recipient_not_found(const char * const recipient, const char * const err_msg); void ui_handle_recipient_error(const char * const recipient, const char * const err_msg); void ui_handle_error(const char * const err_msg); void ui_clear_win_title(void); void ui_goodbye_title(void); void ui_handle_room_join_error(const char * const roomjid, const char * const err); void ui_handle_room_configuration(const char * const roomjid, DataForm *form); void ui_handle_room_configuration_form_error(const char * const roomjid, const char * const message); void ui_handle_room_config_submit_result(const char * const roomjid); void ui_handle_room_config_submit_result_error(const char * const roomjid, const char * const message); void ui_handle_room_affiliation_list_error(const char * const roomjid, const char * const affiliation, const char * const error); void ui_handle_room_affiliation_list(const char * const roomjid, const char * const affiliation, GSList *jids); void ui_handle_room_affiliation_set_error(const char * const roomjid, const char * const jid, const char * const affiliation, const char * const error); void ui_handle_room_role_set_error(const char * const roomjid, const char * const nick, const char * const role, const char * const error); void ui_handle_room_role_list_error(const char * const roomjid, const char * const role, const char * const error); void ui_handle_room_role_list(const char * const roomjid, const char * const role, GSList *nicks); void ui_handle_room_kick_error(const char * const roomjid, const char * const nick, const char * const error); void ui_show_form(ProfMucConfWin *confwin); void ui_show_form_field(ProfWin *window, DataForm *form, char *tag); void ui_show_form_help(ProfMucConfWin *confwin); void ui_show_form_field_help(ProfMucConfWin *confwin, char *tag); void ui_show_lines(ProfWin *window, const gchar** lines); void ui_redraw_all_room_rosters(void); void ui_show_all_room_rosters(void); void ui_hide_all_room_rosters(void); gboolean ui_chat_win_exists(const char * const barejid); void ui_handle_software_version_error(const char * const roomjid, const char * const message); void ui_show_software_version(const char * const jid, const char * const presence, const char * const name, const char * const version, const char * const os); gboolean ui_tidy_wins(void); void ui_prune_wins(void); gboolean ui_swap_wins(int source_win, int target_win); void ui_page_up(void); void ui_page_down(void); void ui_subwin_page_up(void); void ui_subwin_page_down(void); void ui_clear_win(ProfWin *window); void ui_auto_away(void); void ui_end_auto_away(void); void ui_titlebar_presence(contact_presence_t presence); void ui_handle_login_account_success(ProfAccount *account); void ui_update_presence(const resource_presence_t resource_presence, const char * const message, const char * const show); void ui_about(void); void ui_statusbar_new(const int win); char* ui_readline(void); void ui_input_clear(void); void ui_input_nonblocking(gboolean); void ui_write(char *line, int offset); void ui_invalid_command_usage(const char * const cmd, void (*setting_func)(void)); void ui_create_xmlconsole_win(void); gboolean ui_xmlconsole_exists(void); void ui_open_xmlconsole_win(void); gboolean ui_win_has_unsaved_form(int num); void ui_inp_history_append(char *inp); // console window actions void cons_show(const char * const msg, ...); void cons_show_padded(int pad, const char * const msg, ...); void cons_about(void); void cons_help(void); void cons_show_help(Command *command); void cons_bad_cmd_usage(const char * const cmd); void cons_navigation_help(void); void cons_prefs(void); void cons_show_ui_prefs(void); void cons_show_desktop_prefs(void); void cons_show_chat_prefs(void); void cons_show_log_prefs(void); void cons_show_presence_prefs(void); void cons_show_connection_prefs(void); void cons_show_otr_prefs(void); void cons_show_pgp_prefs(void); void cons_show_account(ProfAccount *account); void cons_debug(const char * const msg, ...); void cons_show_time(void); void cons_show_word(const char * const word); void cons_show_error(const char * const cmd, ...); void cons_show_contacts(GSList * list); void cons_show_roster(GSList * list); void cons_show_roster_group(const char * const group, GSList * list); void cons_show_wins(void); void cons_show_status(const char * const barejid); void cons_show_info(PContact pcontact); void cons_show_caps(const char * const fulljid, resource_presence_t presence); void cons_show_themes(GSList *themes); void cons_show_aliases(GList *aliases); void cons_show_login_success(ProfAccount *account); void cons_show_software_version(const char * const jid, const char * const presence, const char * const name, const char * const version, const char * const os); void cons_show_account_list(gchar **accounts); void cons_show_room_list(GSList *room, const char * const conference_node); void cons_show_bookmarks(const GList *list); void cons_show_disco_items(GSList *items, const char * const jid); void cons_show_disco_info(const char *from, GSList *identities, GSList *features); void cons_show_room_invite(const char * const invitor, const char * const room, const char * const reason); void cons_check_version(gboolean not_available_msg); void cons_show_typing(const char * const barejid); void cons_show_incoming_message(const char * const short_from, const int win_index); void cons_show_room_invites(GSList *invites); void cons_show_received_subs(void); void cons_show_sent_subs(void); void cons_alert(void); void cons_theme_setting(void); void cons_resource_setting(void); void cons_privileges_setting(void); void cons_beep_setting(void); void cons_flash_setting(void); void cons_splash_setting(void); void cons_encwarn_setting(void); void cons_vercheck_setting(void); void cons_occupants_setting(void); void cons_roster_setting(void); void cons_presence_setting(void); void cons_wrap_setting(void); void cons_winstidy_setting(void); void cons_time_setting(void); void cons_statuses_setting(void); void cons_titlebar_setting(void); void cons_notify_setting(void); void cons_show_desktop_prefs(void); void cons_states_setting(void); void cons_outtype_setting(void); void cons_intype_setting(void); void cons_gone_setting(void); void cons_history_setting(void); void cons_carbons_setting(void); void cons_receipts_setting(void); void cons_log_setting(void); void cons_chlog_setting(void); void cons_grlog_setting(void); void cons_autoaway_setting(void); void cons_reconnect_setting(void); void cons_autoping_setting(void); void cons_priority_setting(void); void cons_autoconnect_setting(void); void cons_inpblock_setting(void); void cons_show_contact_online(PContact contact, Resource *resource, GDateTime *last_activity); void cons_show_contact_offline(PContact contact, char *resource, char *status); void cons_theme_colours(void); // status bar void status_bar_inactive(const int win); void status_bar_active(const int win); void status_bar_new(const int win); void status_bar_set_all_inactive(void); // roster window void rosterwin_roster(void); // occupants window void occupantswin_occupants(const char * const room); // window interface ProfWin* win_create_console(void); ProfWin* win_create_xmlconsole(void); ProfWin* win_create_chat(const char * const barejid); ProfWin* win_create_muc(const char * const roomjid); ProfWin* win_create_muc_config(const char * const title, DataForm *form); ProfWin* win_create_private(const char * const fulljid); void win_update_virtual(ProfWin *window); void win_free(ProfWin *window); int win_unread(ProfWin *window); void win_resize(ProfWin *window); void win_hide_subwin(ProfWin *window); void win_show_subwin(ProfWin *window); void win_refresh_without_subwin(ProfWin *window); void win_refresh_with_subwin(ProfWin *window); void win_print(ProfWin *window, const char show_char, int pad_indent, GDateTime *timestamp, int flags, theme_item_t theme_item, const char * const from, const char * const message); void win_vprint(ProfWin *window, const char show_char, int pad_indent, GDateTime *timestamp, int flags, theme_item_t theme_item, const char * const from, const char * const message, ...); char* win_get_title(ProfWin *window); void win_show_occupant(ProfWin *window, Occupant *occupant); void win_show_occupant_info(ProfWin *window, const char * const room, Occupant *occupant); void win_show_contact(ProfWin *window, PContact contact); void win_show_info(ProfWin *window, PContact contact); void win_println(ProfWin *window, int pad, const char * const message); // desktop notifier actions void notifier_initialise(void); void notifier_uninit(void); void notify_typing(const char * const handle); void notify_message(ProfWin *window, const char * const name, const char * const text); void notify_room_message(const char * const handle, const char * const room, int win, const char * const text); void notify_remind(void); void notify_invite(const char * const from, const char * const room, const char * const reason); void notify_subscription(const char * const from); #endif profanity-0.4.7/src/ui/win_types.h000066400000000000000000000070411257755232500171520ustar00rootroot00000000000000/* * win_types.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef UI_WIN_TYPES_H #define UI_WIN_TYPES_H #include "config.h" #include #include #ifdef HAVE_NCURSESW_NCURSES_H #include #elif HAVE_NCURSES_H #include #endif #include "xmpp/xmpp.h" #include "ui/buffer.h" #include "chat_state.h" #define LAYOUT_SPLIT_MEMCHECK 12345671 #define PROFCHATWIN_MEMCHECK 22374522 #define PROFMUCWIN_MEMCHECK 52345276 #define PROFPRIVATEWIN_MEMCHECK 77437483 #define PROFCONFWIN_MEMCHECK 64334685 #define PROFXMLWIN_MEMCHECK 87333463 typedef enum { LAYOUT_SIMPLE, LAYOUT_SPLIT } layout_type_t; typedef struct prof_layout_t { layout_type_t type; WINDOW *win; ProfBuff buffer; int y_pos; int paged; } ProfLayout; typedef struct prof_layout_simple_t { ProfLayout base; } ProfLayoutSimple; typedef struct prof_layout_split_t { ProfLayout base; WINDOW *subwin; int sub_y_pos; unsigned long memcheck; } ProfLayoutSplit; typedef enum { WIN_CONSOLE, WIN_CHAT, WIN_MUC, WIN_MUC_CONFIG, WIN_PRIVATE, WIN_XML } win_type_t; typedef struct prof_win_t { win_type_t type; ProfLayout *layout; } ProfWin; typedef struct prof_console_win_t { ProfWin window; } ProfConsoleWin; typedef struct prof_chat_win_t { ProfWin window; char *barejid; int unread; ChatState *state; gboolean is_otr; gboolean otr_is_trusted; gboolean pgp_send; gboolean pgp_recv; char *resource_override; gboolean history_shown; unsigned long memcheck; } ProfChatWin; typedef struct prof_muc_win_t { ProfWin window; char *roomjid; int unread; gboolean showjid; unsigned long memcheck; } ProfMucWin; typedef struct prof_mucconf_win_t { ProfWin window; char *roomjid; DataForm *form; unsigned long memcheck; } ProfMucConfWin; typedef struct prof_private_win_t { ProfWin window; char *fulljid; int unread; unsigned long memcheck; } ProfPrivateWin; typedef struct prof_xml_win_t { ProfWin window; unsigned long memcheck; } ProfXMLWin; #endif profanity-0.4.7/src/ui/window.c000066400000000000000000001152061257755232500164360ustar00rootroot00000000000000/* * window.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include #include #include #include #ifdef HAVE_NCURSESW_NCURSES_H #include #elif HAVE_NCURSES_H #include #endif #include "config/theme.h" #include "config/preferences.h" #include "roster_list.h" #include "ui/ui.h" #include "ui/window.h" #include "xmpp/xmpp.h" #define CONS_WIN_TITLE "Profanity. Type /help for help information." #define XML_WIN_TITLE "XML Console" #define CEILING(X) (X-(int)(X) > 0 ? (int)(X+1) : (int)(X)) static void _win_print(ProfWin *window, const char show_char, int pad_indent, GDateTime *time, int flags, theme_item_t theme_item, const char * const from, const char * const message, DeliveryReceipt *receipt); static void _win_print_wrapped(WINDOW *win, const char * const message, size_t indent, int pad_indent); int win_roster_cols(void) { int roster_win_percent = prefs_get_roster_size(); int cols = getmaxx(stdscr); return CEILING( (((double)cols) / 100) * roster_win_percent); } int win_occpuants_cols(void) { int occupants_win_percent = prefs_get_occupants_size(); int cols = getmaxx(stdscr); return CEILING( (((double)cols) / 100) * occupants_win_percent); } static ProfLayout* _win_create_simple_layout(void) { int cols = getmaxx(stdscr); ProfLayoutSimple *layout = malloc(sizeof(ProfLayoutSimple)); layout->base.type = LAYOUT_SIMPLE; layout->base.win = newpad(PAD_SIZE, cols); wbkgd(layout->base.win, theme_attrs(THEME_TEXT)); layout->base.buffer = buffer_create(); layout->base.y_pos = 0; layout->base.paged = 0; scrollok(layout->base.win, TRUE); return &layout->base; } static ProfLayout* _win_create_split_layout(void) { int cols = getmaxx(stdscr); ProfLayoutSplit *layout = malloc(sizeof(ProfLayoutSplit)); layout->base.type = LAYOUT_SPLIT; layout->base.win = newpad(PAD_SIZE, cols); wbkgd(layout->base.win, theme_attrs(THEME_TEXT)); layout->base.buffer = buffer_create(); layout->base.y_pos = 0; layout->base.paged = 0; scrollok(layout->base.win, TRUE); layout->subwin = NULL; layout->sub_y_pos = 0; layout->memcheck = LAYOUT_SPLIT_MEMCHECK; return &layout->base; } ProfWin* win_create_console(void) { ProfConsoleWin *new_win = malloc(sizeof(ProfConsoleWin)); new_win->window.type = WIN_CONSOLE; new_win->window.layout = _win_create_split_layout(); return &new_win->window; } ProfWin* win_create_chat(const char * const barejid) { ProfChatWin *new_win = malloc(sizeof(ProfChatWin)); new_win->window.type = WIN_CHAT; new_win->window.layout = _win_create_simple_layout(); new_win->barejid = strdup(barejid); new_win->resource_override = NULL; new_win->is_otr = FALSE; new_win->otr_is_trusted = FALSE; new_win->pgp_recv = FALSE; new_win->pgp_send = FALSE; new_win->history_shown = FALSE; new_win->unread = 0; new_win->state = chat_state_new(); new_win->memcheck = PROFCHATWIN_MEMCHECK; return &new_win->window; } ProfWin* win_create_muc(const char * const roomjid) { ProfMucWin *new_win = malloc(sizeof(ProfMucWin)); int cols = getmaxx(stdscr); new_win->window.type = WIN_MUC; ProfLayoutSplit *layout = malloc(sizeof(ProfLayoutSplit)); layout->base.type = LAYOUT_SPLIT; if (prefs_get_boolean(PREF_OCCUPANTS)) { int subwin_cols = win_occpuants_cols(); layout->base.win = newpad(PAD_SIZE, cols - subwin_cols); wbkgd(layout->base.win, theme_attrs(THEME_TEXT)); layout->subwin = newpad(PAD_SIZE, subwin_cols);; wbkgd(layout->subwin, theme_attrs(THEME_TEXT)); } else { layout->base.win = newpad(PAD_SIZE, (cols)); wbkgd(layout->base.win, theme_attrs(THEME_TEXT)); layout->subwin = NULL; } layout->sub_y_pos = 0; layout->memcheck = LAYOUT_SPLIT_MEMCHECK; layout->base.buffer = buffer_create(); layout->base.y_pos = 0; layout->base.paged = 0; scrollok(layout->base.win, TRUE); new_win->window.layout = (ProfLayout*)layout; new_win->roomjid = strdup(roomjid); new_win->unread = 0; if (prefs_get_boolean(PREF_OCCUPANTS_JID)) { new_win->showjid = TRUE; } else { new_win->showjid = FALSE; } new_win->memcheck = PROFMUCWIN_MEMCHECK; return &new_win->window; } ProfWin* win_create_muc_config(const char * const roomjid, DataForm *form) { ProfMucConfWin *new_win = malloc(sizeof(ProfMucConfWin)); new_win->window.type = WIN_MUC_CONFIG; new_win->window.layout = _win_create_simple_layout(); new_win->roomjid = strdup(roomjid); new_win->form = form; new_win->memcheck = PROFCONFWIN_MEMCHECK; return &new_win->window; } ProfWin* win_create_private(const char * const fulljid) { ProfPrivateWin *new_win = malloc(sizeof(ProfPrivateWin)); new_win->window.type = WIN_PRIVATE; new_win->window.layout = _win_create_simple_layout(); new_win->fulljid = strdup(fulljid); new_win->unread = 0; new_win->memcheck = PROFPRIVATEWIN_MEMCHECK; return &new_win->window; } ProfWin* win_create_xmlconsole(void) { ProfXMLWin *new_win = malloc(sizeof(ProfXMLWin)); new_win->window.type = WIN_XML; new_win->window.layout = _win_create_simple_layout(); new_win->memcheck = PROFXMLWIN_MEMCHECK; return &new_win->window; } char * win_get_title(ProfWin *window) { if (window == NULL) { return strdup(CONS_WIN_TITLE); } if (window->type == WIN_CONSOLE) { return strdup(CONS_WIN_TITLE); } if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*) window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); PContact contact = roster_get_contact(chatwin->barejid); if (contact) { const char *name = p_contact_name_or_jid(contact); return strdup(name); } else { return strdup(chatwin->barejid); } } if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*) window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); return strdup(mucwin->roomjid); } if (window->type == WIN_MUC_CONFIG) { ProfMucConfWin *confwin = (ProfMucConfWin*) window; assert(confwin->memcheck == PROFCONFWIN_MEMCHECK); GString *title = g_string_new(confwin->roomjid); g_string_append(title, " config"); if (confwin->form->modified) { g_string_append(title, " *"); } char *title_str = title->str; g_string_free(title, FALSE); return title_str; } if (window->type == WIN_PRIVATE) { ProfPrivateWin *privatewin = (ProfPrivateWin*) window; assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); return strdup(privatewin->fulljid); } if (window->type == WIN_XML) { return strdup(XML_WIN_TITLE); } return NULL; } void win_hide_subwin(ProfWin *window) { if (window->layout->type == LAYOUT_SPLIT) { ProfLayoutSplit *layout = (ProfLayoutSplit*)window->layout; if (layout->subwin) { delwin(layout->subwin); } layout->subwin = NULL; layout->sub_y_pos = 0; int cols = getmaxx(stdscr); wresize(layout->base.win, PAD_SIZE, cols); win_redraw(window); } else { int cols = getmaxx(stdscr); wresize(window->layout->win, PAD_SIZE, cols); win_redraw(window); } } void win_show_subwin(ProfWin *window) { int cols = getmaxx(stdscr); int subwin_cols = 0; if (window->layout->type != LAYOUT_SPLIT) { return; } if (window->type == WIN_MUC) { subwin_cols = win_occpuants_cols(); } else if (window->type == WIN_CONSOLE) { subwin_cols = win_roster_cols(); } ProfLayoutSplit *layout = (ProfLayoutSplit*)window->layout; layout->subwin = newpad(PAD_SIZE, subwin_cols); wbkgd(layout->subwin, theme_attrs(THEME_TEXT)); wresize(layout->base.win, PAD_SIZE, cols - subwin_cols); win_redraw(window); } void win_free(ProfWin* window) { if (window->layout->type == LAYOUT_SPLIT) { ProfLayoutSplit *layout = (ProfLayoutSplit*)window->layout; if (layout->subwin) { delwin(layout->subwin); } buffer_free(layout->base.buffer); delwin(layout->base.win); } else { buffer_free(window->layout->buffer); delwin(window->layout->win); } free(window->layout); if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)window; free(chatwin->barejid); free(chatwin->resource_override); chat_state_free(chatwin->state); } if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; free(mucwin->roomjid); } if (window->type == WIN_MUC_CONFIG) { ProfMucConfWin *mucconf = (ProfMucConfWin*)window; free(mucconf->roomjid); form_destroy(mucconf->form); } if (window->type == WIN_PRIVATE) { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; free(privatewin->fulljid); } free(window); } void win_page_up(ProfWin *window) { int rows = getmaxy(stdscr); int y = getcury(window->layout->win); int page_space = rows - 4; int *page_start = &(window->layout->y_pos); *page_start -= page_space; // went past beginning, show first page if (*page_start < 0) *page_start = 0; window->layout->paged = 1; win_update_virtual(window); // switch off page if last line and space line visible if ((y) - *page_start == page_space) { window->layout->paged = 0; } } void win_page_down(ProfWin *window) { int rows = getmaxy(stdscr); int y = getcury(window->layout->win); int page_space = rows - 4; int *page_start = &(window->layout->y_pos); *page_start += page_space; // only got half a screen, show full screen if ((y - (*page_start)) < page_space) *page_start = y - page_space; // went past end, show full screen else if (*page_start >= y) *page_start = y - page_space - 1; window->layout->paged = 1; win_update_virtual(window); // switch off page if last line and space line visible if ((y) - *page_start == page_space) { window->layout->paged = 0; } } void win_sub_page_down(ProfWin *window) { if (window->layout->type == LAYOUT_SPLIT) { int rows = getmaxy(stdscr); int page_space = rows - 4; ProfLayoutSplit *split_layout = (ProfLayoutSplit*)window->layout; int sub_y = getcury(split_layout->subwin); int *sub_y_pos = &(split_layout->sub_y_pos); *sub_y_pos += page_space; // only got half a screen, show full screen if ((sub_y- (*sub_y_pos)) < page_space) *sub_y_pos = sub_y - page_space; // went past end, show full screen else if (*sub_y_pos >= sub_y) *sub_y_pos = sub_y - page_space - 1; win_update_virtual(window); } } void win_sub_page_up(ProfWin *window) { if (window->layout->type == LAYOUT_SPLIT) { int rows = getmaxy(stdscr); int page_space = rows - 4; ProfLayoutSplit *split_layout = (ProfLayoutSplit*)window->layout; int *sub_y_pos = &(split_layout->sub_y_pos); *sub_y_pos -= page_space; // went past beginning, show first page if (*sub_y_pos < 0) *sub_y_pos = 0; win_update_virtual(window); } } void win_clear(ProfWin *window) { werase(window->layout->win); win_update_virtual(window); } void win_resize(ProfWin *window) { int subwin_cols = 0; int cols = getmaxx(stdscr); if (window->layout->type == LAYOUT_SPLIT) { ProfLayoutSplit *layout = (ProfLayoutSplit*)window->layout; if (layout->subwin) { if (window->type == WIN_CONSOLE) { subwin_cols = win_roster_cols(); } else if (window->type == WIN_MUC) { subwin_cols = win_occpuants_cols(); } wresize(layout->base.win, PAD_SIZE, cols - subwin_cols); wresize(layout->subwin, PAD_SIZE, subwin_cols); if (window->type == WIN_CONSOLE) { rosterwin_roster(); } else if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin *)window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); occupantswin_occupants(mucwin->roomjid); } } else { wresize(layout->base.win, PAD_SIZE, cols); } } else { wresize(window->layout->win, PAD_SIZE, cols); } win_redraw(window); } void win_update_virtual(ProfWin *window) { int rows, cols; getmaxyx(stdscr, rows, cols); int subwin_cols = 0; if (window->layout->type == LAYOUT_SPLIT) { ProfLayoutSplit *layout = (ProfLayoutSplit*)window->layout; if (layout->subwin) { if (window->type == WIN_MUC) { subwin_cols = win_occpuants_cols(); } else { subwin_cols = win_roster_cols(); } pnoutrefresh(layout->base.win, layout->base.y_pos, 0, 1, 0, rows-3, (cols-subwin_cols)-1); pnoutrefresh(layout->subwin, layout->sub_y_pos, 0, 1, (cols-subwin_cols), rows-3, cols-1); } else { pnoutrefresh(layout->base.win, layout->base.y_pos, 0, 1, 0, rows-3, cols-1); } } else { pnoutrefresh(window->layout->win, window->layout->y_pos, 0, 1, 0, rows-3, cols-1); } } void win_refresh_without_subwin(ProfWin *window) { int rows, cols; getmaxyx(stdscr, rows, cols); if ((window->type == WIN_MUC) || (window->type == WIN_CONSOLE)) { pnoutrefresh(window->layout->win, window->layout->y_pos, 0, 1, 0, rows-3, cols-1); } } void win_refresh_with_subwin(ProfWin *window) { int rows, cols; getmaxyx(stdscr, rows, cols); int subwin_cols = 0; if (window->type == WIN_MUC) { ProfLayoutSplit *layout = (ProfLayoutSplit*)window->layout; subwin_cols = win_occpuants_cols(); pnoutrefresh(layout->base.win, layout->base.y_pos, 0, 1, 0, rows-3, (cols-subwin_cols)-1); pnoutrefresh(layout->subwin, layout->sub_y_pos, 0, 1, (cols-subwin_cols), rows-3, cols-1); } else if (window->type == WIN_CONSOLE) { ProfLayoutSplit *layout = (ProfLayoutSplit*)window->layout; subwin_cols = win_roster_cols(); pnoutrefresh(layout->base.win, layout->base.y_pos, 0, 1, 0, rows-3, (cols-subwin_cols)-1); pnoutrefresh(layout->subwin, layout->sub_y_pos, 0, 1, (cols-subwin_cols), rows-3, cols-1); } } void win_move_to_end(ProfWin *window) { window->layout->paged = 0; int rows = getmaxy(stdscr); int y = getcury(window->layout->win); int size = rows - 3; window->layout->y_pos = y - (size - 1); if (window->layout->y_pos < 0) { window->layout->y_pos = 0; } } void win_show_occupant(ProfWin *window, Occupant *occupant) { const char *presence_str = string_from_resource_presence(occupant->presence); theme_item_t presence_colour = theme_main_presence_attrs(presence_str); win_print(window, '-', 0, NULL, NO_EOL, presence_colour, "", occupant->nick); win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", presence_str); if (occupant->status) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", occupant->status); } win_print(window, '-', 0, NULL, NO_DATE, presence_colour, "", ""); } void win_show_contact(ProfWin *window, PContact contact) { const char *barejid = p_contact_barejid(contact); const char *name = p_contact_name(contact); const char *presence = p_contact_presence(contact); const char *status = p_contact_status(contact); GDateTime *last_activity = p_contact_last_activity(contact); theme_item_t presence_colour = theme_main_presence_attrs(presence); if (name) { win_print(window, '-', 0, NULL, NO_EOL, presence_colour, "", name); } else { win_print(window, '-', 0, NULL, NO_EOL, presence_colour, "", barejid); } win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", presence); if (last_activity) { GDateTime *now = g_date_time_new_now_local(); GTimeSpan span = g_date_time_difference(now, last_activity); int hours = span / G_TIME_SPAN_HOUR; span = span - hours * G_TIME_SPAN_HOUR; int minutes = span / G_TIME_SPAN_MINUTE; span = span - minutes * G_TIME_SPAN_MINUTE; int seconds = span / G_TIME_SPAN_SECOND; if (hours > 0) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dh%dm%ds", hours, minutes, seconds); } else { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dm%ds", minutes, seconds); } } if (status) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", p_contact_status(contact)); } win_print(window, '-', 0, NULL, NO_DATE, presence_colour, "", ""); } void win_show_occupant_info(ProfWin *window, const char * const room, Occupant *occupant) { const char *presence_str = string_from_resource_presence(occupant->presence); const char *occupant_affiliation = muc_occupant_affiliation_str(occupant); const char *occupant_role = muc_occupant_role_str(occupant); theme_item_t presence_colour = theme_main_presence_attrs(presence_str); win_print(window, '!', 0, NULL, NO_EOL, presence_colour, "", occupant->nick); win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", presence_str); if (occupant->status) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", occupant->status); } win_newline(window); if (occupant->jid) { win_vprint(window, '!', 0, NULL, 0, 0, "", " Jid: %s", occupant->jid); } win_vprint(window, '!', 0, NULL, 0, 0, "", " Affiliation: %s", occupant_affiliation); win_vprint(window, '!', 0, NULL, 0, 0, "", " Role: %s", occupant_role); Jid *jidp = jid_create_from_bare_and_resource(room, occupant->nick); Capabilities *caps = caps_lookup(jidp->fulljid); jid_destroy(jidp); if (caps) { // show identity if (caps->category || caps->type || caps->name) { win_print(window, '!', 0, NULL, NO_EOL, 0, "", " Identity: "); if (caps->name) { win_print(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->name); if (caps->category || caps->type) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (caps->type) { win_print(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->type); if (caps->category) { win_print(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (caps->category) { win_print(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->category); } win_newline(window); } if (caps->software) { win_vprint(window, '!', 0, NULL, NO_EOL, 0, "", " Software: %s", caps->software); } if (caps->software_version) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); } if (caps->software || caps->software_version) { win_newline(window); } if (caps->os) { win_vprint(window, '!', 0, NULL, NO_EOL, 0, "", " OS: %s", caps->os); } if (caps->os_version) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); } if (caps->os || caps->os_version) { win_newline(window); } caps_destroy(caps); } win_print(window, '-', 0, NULL, 0, 0, "", ""); } void win_show_info(ProfWin *window, PContact contact) { const char *barejid = p_contact_barejid(contact); const char *name = p_contact_name(contact); const char *presence = p_contact_presence(contact); const char *sub = p_contact_subscription(contact); GDateTime *last_activity = p_contact_last_activity(contact); theme_item_t presence_colour = theme_main_presence_attrs(presence); win_print(window, '-', 0, NULL, 0, 0, "", ""); win_print(window, '-', 0, NULL, NO_EOL, presence_colour, "", barejid); if (name) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " (%s)", name); } win_print(window, '-', 0, NULL, NO_DATE, 0, "", ":"); if (sub) { win_vprint(window, '-', 0, NULL, 0, 0, "", "Subscription: %s", sub); } if (last_activity) { GDateTime *now = g_date_time_new_now_local(); GTimeSpan span = g_date_time_difference(now, last_activity); int hours = span / G_TIME_SPAN_HOUR; span = span - hours * G_TIME_SPAN_HOUR; int minutes = span / G_TIME_SPAN_MINUTE; span = span - minutes * G_TIME_SPAN_MINUTE; int seconds = span / G_TIME_SPAN_SECOND; if (hours > 0) { win_vprint(window, '-', 0, NULL, 0, 0, "", "Last activity: %dh%dm%ds", hours, minutes, seconds); } else { win_vprint(window, '-', 0, NULL, 0, 0, "", "Last activity: %dm%ds", minutes, seconds); } g_date_time_unref(now); } GList *resources = p_contact_get_available_resources(contact); GList *ordered_resources = NULL; if (resources) { win_print(window, '-', 0, NULL, 0, 0, "", "Resources:"); // sort in order of availability GList *curr = resources; while (curr) { Resource *resource = curr->data; ordered_resources = g_list_insert_sorted(ordered_resources, resource, (GCompareFunc)resource_compare_availability); curr = g_list_next(curr); } } g_list_free(resources); GList *curr = ordered_resources; while (curr) { Resource *resource = curr->data; const char *resource_presence = string_from_resource_presence(resource->presence); theme_item_t presence_colour = theme_main_presence_attrs(resource_presence); win_vprint(window, '-', 0, NULL, NO_EOL, presence_colour, "", " %s (%d), %s", resource->name, resource->priority, resource_presence); if (resource->status) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", resource->status); } win_newline(window); Jid *jidp = jid_create_from_bare_and_resource(barejid, resource->name); Capabilities *caps = caps_lookup(jidp->fulljid); jid_destroy(jidp); if (caps) { // show identity if (caps->category || caps->type || caps->name) { win_print(window, '-', 0, NULL, NO_EOL, 0, "", " Identity: "); if (caps->name) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->name); if (caps->category || caps->type) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (caps->type) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->type); if (caps->category) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (caps->category) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", caps->category); } win_newline(window); } if (caps->software) { win_vprint(window, '-', 0, NULL, NO_EOL, 0, "", " Software: %s", caps->software); } if (caps->software_version) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); } if (caps->software || caps->software_version) { win_newline(window); } if (caps->os) { win_vprint(window, '-', 0, NULL, NO_EOL, 0, "", " OS: %s", caps->os); } if (caps->os_version) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); } if (caps->os || caps->os_version) { win_newline(window); } caps_destroy(caps); } curr = g_list_next(curr); } g_list_free(ordered_resources); } void win_show_status_string(ProfWin *window, const char * const from, const char * const show, const char * const status, GDateTime *last_activity, const char * const pre, const char * const default_show) { theme_item_t presence_colour; if (show) { presence_colour = theme_main_presence_attrs(show); } else if (strcmp(default_show, "online") == 0) { presence_colour = THEME_ONLINE; } else { presence_colour = THEME_OFFLINE; } win_vprint(window, '-', 0, NULL, NO_EOL, presence_colour, "", "%s %s", pre, from); if (show) win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", show); else win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", default_show); if (last_activity) { GDateTime *now = g_date_time_new_now_local(); GTimeSpan span = g_date_time_difference(now, last_activity); g_date_time_unref(now); int hours = span / G_TIME_SPAN_HOUR; span = span - hours * G_TIME_SPAN_HOUR; int minutes = span / G_TIME_SPAN_MINUTE; span = span - minutes * G_TIME_SPAN_MINUTE; int seconds = span / G_TIME_SPAN_SECOND; if (hours > 0) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dh%dm%ds", hours, minutes, seconds); } else { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dm%ds", minutes, seconds); } } if (status) win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", status); win_print(window, '-', 0, NULL, NO_DATE, presence_colour, "", ""); } void win_print_incoming_message(ProfWin *window, GDateTime *timestamp, const char * const from, const char * const message, prof_enc_t enc_mode) { char enc_char = '-'; switch (window->type) { case WIN_CHAT: if (enc_mode == PROF_MSG_OTR) { enc_char = prefs_get_otr_char(); } else if (enc_mode == PROF_MSG_PGP) { enc_char = prefs_get_pgp_char(); } win_print(window, enc_char, 0, timestamp, NO_ME, THEME_TEXT_THEM, from, message); break; case WIN_PRIVATE: win_print(window, '-', 0, timestamp, NO_ME, THEME_TEXT_THEM, from, message); break; default: assert(FALSE); break; } } void win_vprint(ProfWin *window, const char show_char, int pad_indent, GDateTime *timestamp, int flags, theme_item_t theme_item, const char * const from, const char * const message, ...) { va_list arg; va_start(arg, message); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, message, arg); win_print(window, show_char, pad_indent, timestamp, flags, theme_item, from, fmt_msg->str); g_string_free(fmt_msg, TRUE); } void win_print(ProfWin *window, const char show_char, int pad_indent, GDateTime *timestamp, int flags, theme_item_t theme_item, const char * const from, const char * const message) { if (timestamp == NULL) { timestamp = g_date_time_new_now_local(); } else { g_date_time_ref(timestamp); } buffer_push(window->layout->buffer, show_char, pad_indent, timestamp, flags, theme_item, from, message, NULL); _win_print(window, show_char, pad_indent, timestamp, flags, theme_item, from, message, NULL); // TODO: cross-reference.. this should be replaced by a real event-based system ui_input_nonblocking(TRUE); g_date_time_unref(timestamp); } void win_print_with_receipt(ProfWin *window, const char show_char, int pad_indent, GTimeVal *tstamp, int flags, theme_item_t theme_item, const char * const from, const char * const message, char *id) { GDateTime *time; if (tstamp == NULL) { time = g_date_time_new_now_local(); } else { time = g_date_time_new_from_timeval_utc(tstamp); } DeliveryReceipt *receipt = malloc(sizeof(struct delivery_receipt_t)); receipt->id = strdup(id); receipt->received = FALSE; buffer_push(window->layout->buffer, show_char, pad_indent, time, flags, theme_item, from, message, receipt); _win_print(window, show_char, pad_indent, time, flags, theme_item, from, message, receipt); // TODO: cross-reference.. this should be replaced by a real event-based system ui_input_nonblocking(TRUE); g_date_time_unref(time); } void win_mark_received(ProfWin *window, const char * const id) { gboolean received = buffer_mark_received(window->layout->buffer, id); if (received) { win_redraw(window); } } void win_println(ProfWin *window, int pad, const char * const message) { win_print(window, '-', pad, NULL, 0, 0, "", message); } void win_newline(ProfWin *window) { win_print(window, '-', 0, NULL, NO_DATE, 0, "", ""); } static void _win_print(ProfWin *window, const char show_char, int pad_indent, GDateTime *time, int flags, theme_item_t theme_item, const char * const from, const char * const message, DeliveryReceipt *receipt) { // flags : 1st bit = 0/1 - me/not me // 2nd bit = 0/1 - date/no date // 3rd bit = 0/1 - eol/no eol // 4th bit = 0/1 - color from/no color from // 5th bit = 0/1 - color date/no date gboolean me_message = FALSE; int offset = 0; int colour = theme_attrs(THEME_ME); size_t indent = 0; gchar *date_fmt = NULL; char *time_pref = prefs_get_string(PREF_TIME); date_fmt = g_date_time_format(time, time_pref); prefs_free_string(time_pref); assert(date_fmt != NULL); if(strlen(date_fmt) != 0){ indent = 3 + strlen(date_fmt); } if ((flags & NO_DATE) == 0) { if (date_fmt && strlen(date_fmt)) { if ((flags & NO_COLOUR_DATE) == 0) { wattron(window->layout->win, theme_attrs(THEME_TIME)); } wprintw(window->layout->win, "%s %c ", date_fmt, show_char); if ((flags & NO_COLOUR_DATE) == 0) { wattroff(window->layout->win, theme_attrs(THEME_TIME)); } } } if (strlen(from) > 0) { if (flags & NO_ME) { colour = theme_attrs(THEME_THEM); } if (flags & NO_COLOUR_FROM) { colour = 0; } if (receipt && !receipt->received) { colour = theme_attrs(THEME_RECEIPT_SENT); } wattron(window->layout->win, colour); if (strncmp(message, "/me ", 4) == 0) { wprintw(window->layout->win, "*%s ", from); offset = 4; me_message = TRUE; } else { wprintw(window->layout->win, "%s: ", from); wattroff(window->layout->win, colour); } } if (!me_message) { if (receipt && !receipt->received) { wattron(window->layout->win, theme_attrs(THEME_RECEIPT_SENT)); } else { wattron(window->layout->win, theme_attrs(theme_item)); } } if (prefs_get_boolean(PREF_WRAP)) { _win_print_wrapped(window->layout->win, message+offset, indent, pad_indent); } else { wprintw(window->layout->win, "%s", message+offset); } if ((flags & NO_EOL) == 0) { int curx = getcurx(window->layout->win); if (curx != 0) { wprintw(window->layout->win, "\n"); } } if (me_message) { wattroff(window->layout->win, colour); } else { if (receipt && !receipt->received) { wattroff(window->layout->win, theme_attrs(THEME_RECEIPT_SENT)); } else { wattroff(window->layout->win, theme_attrs(theme_item)); } } g_free(date_fmt); } static void _win_indent(WINDOW *win, int size) { int i = 0; for (i = 0; i < size; i++) { waddch(win, ' '); } } static void _win_print_wrapped(WINDOW *win, const char * const message, size_t indent, int pad_indent) { int starty = getcury(win); int wordi = 0; char *word = malloc(strlen(message) + 1); gchar *curr_ch = g_utf8_offset_to_pointer(message, 0); while (*curr_ch != '\0') { // handle space if (*curr_ch == ' ') { waddch(win, ' '); curr_ch = g_utf8_next_char(curr_ch); // handle newline } else if (*curr_ch == '\n') { waddch(win, '\n'); _win_indent(win, indent + pad_indent); curr_ch = g_utf8_next_char(curr_ch); // handle word } else { wordi = 0; int wordlen = 0; while (*curr_ch != ' ' && *curr_ch != '\n' && *curr_ch != '\0') { size_t ch_len = mbrlen(curr_ch, 4, NULL); int offset = 0; while (offset < ch_len) { word[wordi++] = curr_ch[offset++]; } curr_ch = g_utf8_next_char(curr_ch); } word[wordi] = '\0'; wordlen = utf8_display_len(word); int curx = getcurx(win); int cury = getcury(win); int maxx = getmaxx(win); // wrap required if (curx + wordlen > maxx) { int linelen = maxx - (indent + pad_indent); // word larger than line if (wordlen > linelen) { gchar *word_ch = g_utf8_offset_to_pointer(word, 0); while(*word_ch != '\0') { curx = getcurx(win); cury = getcury(win); gboolean firstline = cury == starty; if (firstline && curx < indent) { _win_indent(win, indent); } if (!firstline && curx < (indent + pad_indent)) { _win_indent(win, indent + pad_indent); } gchar copy[wordi+1]; g_utf8_strncpy(copy, word_ch, 1); waddstr(win, copy); word_ch = g_utf8_next_char(word_ch); } // newline and print word } else { waddch(win, '\n'); curx = getcurx(win); cury = getcury(win); gboolean firstline = cury == starty; if (firstline && curx < indent) { _win_indent(win, indent); } if (!firstline && curx < (indent + pad_indent)) { _win_indent(win, indent + pad_indent); } waddstr(win, word); } // no wrap required } else { curx = getcurx(win); cury = getcury(win); gboolean firstline = cury == starty; if (firstline && curx < indent) { _win_indent(win, indent); } if (!firstline && curx < (indent + pad_indent)) { _win_indent(win, indent + pad_indent); } waddstr(win, word); } } // consume first space of next line int curx = getcurx(win); int cury = getcury(win); gboolean firstline = (cury == starty); if (!firstline && curx == 0 && *curr_ch == ' ') { curr_ch = g_utf8_next_char(curr_ch); } } free(word); } void win_redraw(ProfWin *window) { int i, size; werase(window->layout->win); size = buffer_size(window->layout->buffer); for (i = 0; i < size; i++) { ProfBuffEntry *e = buffer_yield_entry(window->layout->buffer, i); _win_print(window, e->show_char, e->pad_indent, e->time, e->flags, e->theme_item, e->from, e->message, e->receipt); } } gboolean win_has_active_subwin(ProfWin *window) { if (window->layout->type == LAYOUT_SPLIT) { ProfLayoutSplit *layout = (ProfLayoutSplit*)window->layout; return (layout->subwin != NULL); } else { return FALSE; } } int win_unread(ProfWin *window) { if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*) window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); return chatwin->unread; } else if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*) window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); return mucwin->unread; } else if (window->type == WIN_PRIVATE) { ProfPrivateWin *privatewin = (ProfPrivateWin*) window; assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); return privatewin->unread; } else { return 0; } } void win_printline_nowrap(WINDOW *win, char *msg) { int maxx = getmaxx(win); int cury = getcury(win); waddnstr(win, msg, maxx); wmove(win, cury+1, 0); } profanity-0.4.7/src/ui/window.h000066400000000000000000000055761257755232500164530ustar00rootroot00000000000000/* * window.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef UI_WINDOW_H #define UI_WINDOW_H #include "config.h" #include #include "contact.h" #include "muc.h" #include "ui/ui.h" #include "ui/buffer.h" #include "xmpp/xmpp.h" #include "chat_state.h" #ifdef HAVE_NCURSESW_NCURSES_H #include #elif HAVE_NCURSES_H #include #endif #define PAD_SIZE 1000 void win_move_to_end(ProfWin *window); void win_show_status_string(ProfWin *window, const char * const from, const char * const show, const char * const status, GDateTime *last_activity, const char * const pre, const char * const default_show); void win_print_incoming_message(ProfWin *window, GDateTime *timestamp, const char * const from, const char * const message, prof_enc_t enc_mode); void win_print_with_receipt(ProfWin *window, const char show_char, int pad_indent, GTimeVal *tstamp, int flags, theme_item_t theme_item, const char * const from, const char * const message, char *id); void win_newline(ProfWin *window); void win_redraw(ProfWin *window); int win_roster_cols(void); int win_occpuants_cols(void); void win_printline_nowrap(WINDOW *win, char *msg); void win_mark_received(ProfWin *window, const char * const id); gboolean win_has_active_subwin(ProfWin *window); void win_clear(ProfWin *window); void win_page_up(ProfWin *window); void win_page_down(ProfWin *window); void win_sub_page_down(ProfWin *window); void win_sub_page_up(ProfWin *window); #endif profanity-0.4.7/src/window_list.c000066400000000000000000000501011257755232500170440ustar00rootroot00000000000000/* * window_list.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include #include #include "common.h" #include "roster_list.h" #include "config/theme.h" #include "ui/ui.h" #include "ui/statusbar.h" #include "window_list.h" #include "event/ui_events.h" static GHashTable *windows; static int current; void wins_init(void) { windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)win_free); ProfWin *console = win_create_console(); g_hash_table_insert(windows, GINT_TO_POINTER(1), console); current = 1; } ProfWin * wins_get_console(void) { return g_hash_table_lookup(windows, GINT_TO_POINTER(1)); } ProfChatWin * wins_get_chat(const char * const barejid) { GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)window; if (g_strcmp0(chatwin->barejid, barejid) == 0) { g_list_free(values); return chatwin; } } curr = g_list_next(curr); } g_list_free(values); return NULL; } ProfMucConfWin * wins_get_muc_conf(const char * const roomjid) { GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; if (window->type == WIN_MUC_CONFIG) { ProfMucConfWin *confwin = (ProfMucConfWin*)window; if (g_strcmp0(confwin->roomjid, roomjid) == 0) { g_list_free(values); return confwin; } } curr = g_list_next(curr); } g_list_free(values); return NULL; } ProfMucWin * wins_get_muc(const char * const roomjid) { GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; if (g_strcmp0(mucwin->roomjid, roomjid) == 0) { g_list_free(values); return mucwin; } } curr = g_list_next(curr); } g_list_free(values); return NULL; } ProfPrivateWin * wins_get_private(const char * const fulljid) { GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; if (window->type == WIN_PRIVATE) { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; if (g_strcmp0(privatewin->fulljid, fulljid) == 0) { g_list_free(values); return privatewin; } } curr = g_list_next(curr); } g_list_free(values); return NULL; } ProfWin * wins_get_current(void) { if (windows) { return g_hash_table_lookup(windows, GINT_TO_POINTER(current)); } else { return NULL; } } GList * wins_get_nums(void) { return g_hash_table_get_keys(windows); } void wins_set_current_by_num(int i) { ProfWin *window = g_hash_table_lookup(windows, GINT_TO_POINTER(i)); if (window) { current = i; if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*) window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); chatwin->unread = 0; } else if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*) window; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); mucwin->unread = 0; } else if (window->type == WIN_PRIVATE) { ProfPrivateWin *privatewin = (ProfPrivateWin*) window; privatewin->unread = 0; } } } ProfWin * wins_get_by_num(int i) { return g_hash_table_lookup(windows, GINT_TO_POINTER(i)); } ProfWin * wins_get_next(void) { // get and sort win nums GList *keys = g_hash_table_get_keys(windows); keys = g_list_sort(keys, cmp_win_num); GList *curr = keys; // find our place in the list while (curr) { if (current == GPOINTER_TO_INT(curr->data)) { break; } curr = g_list_next(curr); } // if there is a next window return it curr = g_list_next(curr); if (curr) { int next = GPOINTER_TO_INT(curr->data); g_list_free(keys); return wins_get_by_num(next); // otherwise return the first window (console) } else { g_list_free(keys); return wins_get_console(); } } ProfWin * wins_get_previous(void) { // get and sort win nums GList *keys = g_hash_table_get_keys(windows); keys = g_list_sort(keys, cmp_win_num); GList *curr = keys; // find our place in the list while (curr) { if (current == GPOINTER_TO_INT(curr->data)) { break; } curr = g_list_next(curr); } // if there is a previous window return it curr = g_list_previous(curr); if (curr) { int previous = GPOINTER_TO_INT(curr->data); g_list_free(keys); return wins_get_by_num(previous); // otherwise return the last window } else { int new_num = GPOINTER_TO_INT(g_list_last(keys)->data); g_list_free(keys); return wins_get_by_num(new_num); } } int wins_get_num(ProfWin *window) { GList *keys = g_hash_table_get_keys(windows); GList *curr = keys; while (curr) { gconstpointer num_p = curr->data; ProfWin *curr_win = g_hash_table_lookup(windows, num_p); if (curr_win == window) { g_list_free(keys); return GPOINTER_TO_INT(num_p); } curr = g_list_next(curr); } g_list_free(keys); return -1; } int wins_get_current_num(void) { return current; } void wins_close_current(void) { wins_close_by_num(current); } void wins_close_by_num(int i) { // console cannot be closed if (i != 1) { // go to console if closing current window if (i == current) { current = 1; ProfWin *window = wins_get_current(); win_update_virtual(window); } g_hash_table_remove(windows, GINT_TO_POINTER(i)); status_bar_inactive(i); } } gboolean wins_is_current(ProfWin *window) { ProfWin *current_window = wins_get_current(); if (current_window == window) { return TRUE; } else { return FALSE; } } ProfWin * wins_new_xmlconsole(void) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); g_list_free(keys); ProfWin *newwin = win_create_xmlconsole(); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); return newwin; } ProfWin * wins_new_chat(const char * const barejid) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); g_list_free(keys); ProfWin *newwin = win_create_chat(barejid); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); return newwin; } ProfWin * wins_new_muc(const char * const roomjid) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); g_list_free(keys); ProfWin *newwin = win_create_muc(roomjid); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); return newwin; } ProfWin * wins_new_muc_config(const char * const roomjid, DataForm *form) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); g_list_free(keys); ProfWin *newwin = win_create_muc_config(roomjid, form); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); return newwin; } ProfWin * wins_new_private(const char * const fulljid) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); g_list_free(keys); ProfWin *newwin = win_create_private(fulljid); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); return newwin; } int wins_get_total_unread(void) { int result = 0; GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; result += win_unread(window); curr = g_list_next(curr); } g_list_free(values); return result; } void wins_resize_all(void) { GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; win_resize(window); curr = g_list_next(curr); } g_list_free(values); ProfWin *current_win = wins_get_current(); win_update_virtual(current_win); } void wins_hide_subwin(ProfWin *window) { win_hide_subwin(window); ProfWin *current_win = wins_get_current(); win_refresh_without_subwin(current_win); } void wins_show_subwin(ProfWin *window) { win_show_subwin(window); ProfWin *current_win = wins_get_current(); win_refresh_with_subwin(current_win); } ProfXMLWin * wins_get_xmlconsole(void) { GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; if (window->type == WIN_XML) { ProfXMLWin *xmlwin = (ProfXMLWin*)window; assert(xmlwin->memcheck == PROFXMLWIN_MEMCHECK); g_list_free(values); return xmlwin; } curr = g_list_next(curr); } g_list_free(values); return NULL; } GSList * wins_get_chat_recipients(void) { GSList *result = NULL; GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)window; result = g_slist_append(result, chatwin->barejid); } curr = g_list_next(curr); } g_list_free(values); return result; } GSList * wins_get_prune_wins(void) { GSList *result = NULL; GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; if (win_unread(window) == 0 && window->type != WIN_MUC && window->type != WIN_MUC_CONFIG && window->type != WIN_XML && window->type != WIN_CONSOLE) { result = g_slist_append(result, window); } curr = g_list_next(curr); } g_list_free(values); return result; } void wins_lost_connection(void) { GList *values = g_hash_table_get_values(windows); GList *curr = values; while (curr) { ProfWin *window = curr->data; if (window->type != WIN_CONSOLE) { win_print(window, '-', 0, NULL, 0, THEME_ERROR, "", "Lost connection."); // if current win, set current_win_dirty if (wins_is_current(window)) { win_update_virtual(window); } } curr = g_list_next(curr); } g_list_free(values); } gboolean wins_swap(int source_win, int target_win) { ProfWin *source = g_hash_table_lookup(windows, GINT_TO_POINTER(source_win)); ProfWin *console = wins_get_console(); if (source) { ProfWin *target = g_hash_table_lookup(windows, GINT_TO_POINTER(target_win)); // target window empty if (!target) { g_hash_table_steal(windows, GINT_TO_POINTER(source_win)); g_hash_table_insert(windows, GINT_TO_POINTER(target_win), source); status_bar_inactive(source_win); if (win_unread(source) > 0) { status_bar_new(target_win); } else { status_bar_active(target_win); } if (wins_get_current_num() == source_win) { wins_set_current_by_num(target_win); ui_ev_focus_win(console); } return TRUE; // target window occupied } else { g_hash_table_steal(windows, GINT_TO_POINTER(source_win)); g_hash_table_steal(windows, GINT_TO_POINTER(target_win)); g_hash_table_insert(windows, GINT_TO_POINTER(source_win), target); g_hash_table_insert(windows, GINT_TO_POINTER(target_win), source); if (win_unread(source) > 0) { status_bar_new(target_win); } else { status_bar_active(target_win); } if (win_unread(target) > 0) { status_bar_new(source_win); } else { status_bar_active(source_win); } if ((wins_get_current_num() == source_win) || (wins_get_current_num() == target_win)) { ui_ev_focus_win(console); } return TRUE; } } else { return FALSE; } } gboolean wins_tidy(void) { gboolean tidy_required = FALSE; // check for gaps GList *keys = g_hash_table_get_keys(windows); keys = g_list_sort(keys, cmp_win_num); // get last used GList *last = g_list_last(keys); int last_num = GPOINTER_TO_INT(last->data); // find first free num TODO - Will sort again int next_available = get_next_available_win_num(keys); // found gap (next available before last window) if (cmp_win_num(GINT_TO_POINTER(next_available), GINT_TO_POINTER(last_num)) < 0) { tidy_required = TRUE; } if (tidy_required) { status_bar_set_all_inactive(); GHashTable *new_windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)win_free); int num = 1; GList *curr = keys; while (curr) { ProfWin *window = g_hash_table_lookup(windows, curr->data); if (num == 10) { g_hash_table_insert(new_windows, GINT_TO_POINTER(0), window); if (win_unread(window) > 0) { status_bar_new(0); } else { status_bar_active(0); } } else { g_hash_table_insert(new_windows, GINT_TO_POINTER(num), window); if (win_unread(window) > 0) { status_bar_new(num); } else { status_bar_active(num); } } num++; curr = g_list_next(curr); } windows = new_windows; current = 1; ProfWin *console = wins_get_console(); ui_ev_focus_win(console); g_list_free(keys); return TRUE; } else { g_list_free(keys); return FALSE; } } GSList * wins_create_summary(void) { GSList *result = NULL; GList *keys = g_hash_table_get_keys(windows); keys = g_list_sort(keys, cmp_win_num); GList *curr = keys; while (curr) { ProfWin *window = g_hash_table_lookup(windows, curr->data); int ui_index = GPOINTER_TO_INT(curr->data); GString *chat_string; GString *priv_string; GString *muc_string; GString *muc_config_string; GString *xml_string; switch (window->type) { case WIN_CONSOLE: result = g_slist_append(result, strdup("1: Console")); break; case WIN_CHAT: chat_string = g_string_new(""); ProfChatWin *chatwin = (ProfChatWin*)window; PContact contact = roster_get_contact(chatwin->barejid); if (contact == NULL) { g_string_printf(chat_string, "%d: Chat %s", ui_index, chatwin->barejid); } else { const char *display_name = p_contact_name_or_jid(contact); g_string_printf(chat_string, "%d: Chat %s", ui_index, display_name); GString *chat_presence = g_string_new(""); g_string_printf(chat_presence, " - %s", p_contact_presence(contact)); g_string_append(chat_string, chat_presence->str); g_string_free(chat_presence, TRUE); } if (chatwin->unread > 0) { GString *chat_unread = g_string_new(""); g_string_printf(chat_unread, ", %d unread", chatwin->unread); g_string_append(chat_string, chat_unread->str); g_string_free(chat_unread, TRUE); } result = g_slist_append(result, strdup(chat_string->str)); g_string_free(chat_string, TRUE); break; case WIN_PRIVATE: priv_string = g_string_new(""); ProfPrivateWin *privatewin = (ProfPrivateWin*)window; g_string_printf(priv_string, "%d: Private %s", ui_index, privatewin->fulljid); if (privatewin->unread > 0) { GString *priv_unread = g_string_new(""); g_string_printf(priv_unread, ", %d unread", privatewin->unread); g_string_append(priv_string, priv_unread->str); g_string_free(priv_unread, TRUE); } result = g_slist_append(result, strdup(priv_string->str)); g_string_free(priv_string, TRUE); break; case WIN_MUC: muc_string = g_string_new(""); ProfMucWin *mucwin = (ProfMucWin*)window; g_string_printf(muc_string, "%d: Room %s", ui_index, mucwin->roomjid); if (mucwin->unread > 0) { GString *muc_unread = g_string_new(""); g_string_printf(muc_unread, ", %d unread", mucwin->unread); g_string_append(muc_string, muc_unread->str); g_string_free(muc_unread, TRUE); } result = g_slist_append(result, strdup(muc_string->str)); g_string_free(muc_string, TRUE); break; case WIN_MUC_CONFIG: muc_config_string = g_string_new(""); char *title = win_get_title(window); g_string_printf(muc_config_string, "%d: %s", ui_index, title); result = g_slist_append(result, strdup(muc_config_string->str)); g_string_free(muc_config_string, TRUE); free(title); break; case WIN_XML: xml_string = g_string_new(""); g_string_printf(xml_string, "%d: XML console", ui_index); result = g_slist_append(result, strdup(xml_string->str)); g_string_free(xml_string, TRUE); break; default: break; } curr = g_list_next(curr); } g_list_free(keys); return result; } void wins_destroy(void) { g_hash_table_destroy(windows); } profanity-0.4.7/src/window_list.h000066400000000000000000000056101257755232500170560ustar00rootroot00000000000000/* * window_list.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef WINDOW_LIST_H #define WINDOW_LIST_H #include "ui/ui.h" void wins_init(void); ProfWin * wins_new_xmlconsole(void); ProfWin * wins_new_chat(const char * const barejid); ProfWin * wins_new_muc(const char * const roomjid); ProfWin * wins_new_muc_config(const char * const roomjid, DataForm *form); ProfWin * wins_new_private(const char * const fulljid); ProfWin * wins_get_console(void); ProfChatWin *wins_get_chat(const char * const barejid); ProfMucWin * wins_get_muc(const char * const roomjid); ProfMucConfWin * wins_get_muc_conf(const char * const roomjid); ProfPrivateWin *wins_get_private(const char * const fulljid); ProfXMLWin * wins_get_xmlconsole(void); ProfWin * wins_get_current(void); void wins_set_current_by_num(int i); ProfWin * wins_get_by_num(int i); ProfWin * wins_get_next(void); ProfWin * wins_get_previous(void); int wins_get_num(ProfWin *window); int wins_get_current_num(void); void wins_close_current(void); void wins_close_by_num(int i); gboolean wins_is_current(ProfWin *window); int wins_get_total_unread(void); void wins_resize_all(void); GSList * wins_get_chat_recipients(void); GSList * wins_get_prune_wins(void); void wins_lost_connection(void); gboolean wins_tidy(void); GSList * wins_create_summary(void); void wins_destroy(void); GList * wins_get_nums(void); gboolean wins_swap(int source_win, int target_win); void wins_hide_subwin(ProfWin *window); void wins_show_subwin(ProfWin *window); #endif profanity-0.4.7/src/xmpp/000077500000000000000000000000001257755232500153255ustar00rootroot00000000000000profanity-0.4.7/src/xmpp/bookmark.c000066400000000000000000000323221257755232500173000ustar00rootroot00000000000000/* * bookmark.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include #include #include "common.h" #include "log.h" #include "muc.h" #include "event/server_events.h" #include "xmpp/connection.h" #include "xmpp/stanza.h" #include "xmpp/xmpp.h" #include "xmpp/bookmark.h" #include "ui/ui.h" #define BOOKMARK_TIMEOUT 5000 static Autocomplete bookmark_ac; static GList *bookmark_list; static int _bookmark_handle_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _bookmark_handle_delete(xmpp_conn_t * const conn, void * const userdata); static void _bookmark_item_destroy(gpointer item); static int _match_bookmark_by_jid(gconstpointer a, gconstpointer b); static void _send_bookmarks(void); void bookmark_request(void) { char *id; xmpp_conn_t *conn = connection_get_conn(); xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *iq; id = strdup("bookmark_init_request"); autocomplete_free(bookmark_ac); bookmark_ac = autocomplete_new(); if (bookmark_list) { g_list_free_full(bookmark_list, _bookmark_item_destroy); bookmark_list = NULL; } xmpp_timed_handler_add(conn, _bookmark_handle_delete, BOOKMARK_TIMEOUT, id); xmpp_id_handler_add(conn, _bookmark_handle_result, id, id); iq = stanza_create_bookmarks_storage_request(ctx); xmpp_stanza_set_id(iq, id); xmpp_send(conn, iq); xmpp_stanza_release(iq); } gboolean bookmark_add(const char *jid, const char *nick, const char *password, const char *autojoin_str) { if (autocomplete_contains(bookmark_ac, jid)) { return FALSE; } else { Bookmark *item = malloc(sizeof(*item)); item->jid = strdup(jid); if (nick) { item->nick = strdup(nick); } else { item->nick = NULL; } if (password) { item->password = strdup(password); } else { item->password = NULL; } if (g_strcmp0(autojoin_str, "on") == 0) { item->autojoin = TRUE; } else { item->autojoin = FALSE; } bookmark_list = g_list_append(bookmark_list, item); autocomplete_add(bookmark_ac, jid); _send_bookmarks(); return TRUE; } } gboolean bookmark_update(const char *jid, const char *nick, const char *password, const char *autojoin_str) { Bookmark *item = malloc(sizeof(*item)); item->jid = strdup(jid); item->nick = NULL; item->password = NULL; item->autojoin = FALSE; GList *found = g_list_find_custom(bookmark_list, item, _match_bookmark_by_jid); _bookmark_item_destroy(item); if (found == NULL) { return FALSE; } else { Bookmark *bm = found->data; if (nick) { free(bm->nick); bm->nick = strdup(nick); } if (password) { free(bm->password); bm->password = strdup(password); } if (autojoin_str) { if (g_strcmp0(autojoin_str, "on") == 0) { bm->autojoin = TRUE; } else if (g_strcmp0(autojoin_str, "off") == 0) { bm->autojoin = FALSE; } } _send_bookmarks(); return TRUE; } } gboolean bookmark_join(const char *jid) { Bookmark *item = malloc(sizeof(*item)); item->jid = strdup(jid); item->nick = NULL; item->password = NULL; item->autojoin = FALSE; GList *found = g_list_find_custom(bookmark_list, item, _match_bookmark_by_jid); _bookmark_item_destroy(item); if (found == NULL) { return FALSE; } else { char *account_name = jabber_get_account_name(); ProfAccount *account = accounts_get_account(account_name); Bookmark *item = found->data; if (!muc_active(item->jid)) { char *nick = item->nick; if (nick == NULL) { nick = account->muc_nick; } presence_join_room(item->jid, nick, item->password); muc_join(item->jid, nick, item->password, FALSE); account_free(account); } else if (muc_roster_complete(item->jid)) { ui_room_join(item->jid, TRUE); } return TRUE; } } gboolean bookmark_remove(const char *jid) { Bookmark *item = malloc(sizeof(*item)); item->jid = strdup(jid); item->nick = NULL; item->password = NULL; item->autojoin = FALSE; GList *found = g_list_find_custom(bookmark_list, item, _match_bookmark_by_jid); _bookmark_item_destroy(item); gboolean removed = found != NULL; if (removed) { bookmark_list = g_list_remove_link(bookmark_list, found); _bookmark_item_destroy(found->data); g_list_free(found); autocomplete_remove(bookmark_ac, jid); _send_bookmarks(); return TRUE; } else { return FALSE; } } const GList * bookmark_get_list(void) { return bookmark_list; } char * bookmark_find(const char * const search_str) { return autocomplete_complete(bookmark_ac, search_str, TRUE); } void bookmark_autocomplete_reset(void) { if (bookmark_ac) { autocomplete_reset(bookmark_ac); } } static int _bookmark_handle_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); char *id = (char *)userdata; xmpp_stanza_t *ptr; xmpp_stanza_t *nick; xmpp_stanza_t *password_st; char *name; char *jid; char *autojoin; char *password; gboolean autojoin_val; Jid *my_jid; Bookmark *item; xmpp_timed_handler_delete(conn, _bookmark_handle_delete); g_free(id); name = xmpp_stanza_get_name(stanza); if (!name || strcmp(name, STANZA_NAME_IQ) != 0) { return 0; } ptr = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (!ptr) { return 0; } ptr = xmpp_stanza_get_child_by_name(ptr, STANZA_NAME_STORAGE); if (!ptr) { return 0; } if (bookmark_ac == NULL) { bookmark_ac = autocomplete_new(); } my_jid = jid_create(jabber_get_fulljid()); ptr = xmpp_stanza_get_children(ptr); while (ptr) { name = xmpp_stanza_get_name(ptr); if (!name || strcmp(name, STANZA_NAME_CONFERENCE) != 0) { ptr = xmpp_stanza_get_next(ptr); continue; } jid = xmpp_stanza_get_attribute(ptr, STANZA_ATTR_JID); if (!jid) { ptr = xmpp_stanza_get_next(ptr); continue; } log_debug("Handle bookmark for %s", jid); name = NULL; nick = xmpp_stanza_get_child_by_name(ptr, "nick"); if (nick) { char *tmp; tmp = xmpp_stanza_get_text(nick); if (tmp) { name = strdup(tmp); xmpp_free(ctx, tmp); } } password = NULL; password_st = xmpp_stanza_get_child_by_name(ptr, "password"); if (password_st) { char *tmp; tmp = xmpp_stanza_get_text(password_st); if (tmp) { password = strdup(tmp); xmpp_free(ctx, tmp); } } autojoin = xmpp_stanza_get_attribute(ptr, "autojoin"); if (autojoin && (strcmp(autojoin, "1") == 0 || strcmp(autojoin, "true") == 0)) { autojoin_val = TRUE; } else { autojoin_val = FALSE; } autocomplete_add(bookmark_ac, jid); item = malloc(sizeof(*item)); item->jid = strdup(jid); item->nick = name; item->password = password; item->autojoin = autojoin_val; bookmark_list = g_list_append(bookmark_list, item); if (autojoin_val) { Jid *room_jid; char *account_name = jabber_get_account_name(); ProfAccount *account = accounts_get_account(account_name); if (name == NULL) { name = account->muc_nick; } log_debug("Autojoin %s with nick=%s", jid, name); room_jid = jid_create_from_bare_and_resource(jid, name); if (!muc_active(room_jid->barejid)) { presence_join_room(jid, name, password); muc_join(jid, name, password, TRUE); } jid_destroy(room_jid); account_free(account); } ptr = xmpp_stanza_get_next(ptr); } jid_destroy(my_jid); return 0; } static int _bookmark_handle_delete(xmpp_conn_t * const conn, void * const userdata) { char *id = (char *)userdata; assert(id != NULL); log_debug("Timeout for handler with id=%s", id); xmpp_id_handler_delete(conn, _bookmark_handle_result, id); g_free(id); return 0; } static void _bookmark_item_destroy(gpointer item) { Bookmark *p = (Bookmark *)item; if (p == NULL) { return; } free(p->jid); free(p->nick); free(p->password); free(p); } static int _match_bookmark_by_jid(gconstpointer a, gconstpointer b) { Bookmark *bookmark_a = (Bookmark *) a; Bookmark *bookmark_b = (Bookmark *) b; return strcmp(bookmark_a->jid, bookmark_b->jid); } static void _send_bookmarks(void) { xmpp_conn_t *conn = connection_get_conn(); xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); char *id = create_unique_id("bookmarks_update"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, "jabber:iq:private"); xmpp_stanza_t *storage = xmpp_stanza_new(ctx); xmpp_stanza_set_name(storage, STANZA_NAME_STORAGE); xmpp_stanza_set_ns(storage, "storage:bookmarks"); GList *curr = bookmark_list; while (curr) { Bookmark *bookmark = curr->data; xmpp_stanza_t *conference = xmpp_stanza_new(ctx); xmpp_stanza_set_name(conference, STANZA_NAME_CONFERENCE); xmpp_stanza_set_attribute(conference, STANZA_ATTR_JID, bookmark->jid); Jid *jidp = jid_create(bookmark->jid); if (jidp->localpart) { xmpp_stanza_set_attribute(conference, STANZA_ATTR_NAME, jidp->localpart); } jid_destroy(jidp); if (bookmark->autojoin) { xmpp_stanza_set_attribute(conference, STANZA_ATTR_AUTOJOIN, "true"); } else { xmpp_stanza_set_attribute(conference, STANZA_ATTR_AUTOJOIN, "false"); } if (bookmark->nick) { xmpp_stanza_t *nick_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(nick_st, STANZA_NAME_NICK); xmpp_stanza_t *nick_text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(nick_text, bookmark->nick); xmpp_stanza_add_child(nick_st, nick_text); xmpp_stanza_add_child(conference, nick_st); xmpp_stanza_release(nick_text); xmpp_stanza_release(nick_st); } if (bookmark->password) { xmpp_stanza_t *password_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(password_st, STANZA_NAME_PASSWORD); xmpp_stanza_t *password_text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(password_text, bookmark->password); xmpp_stanza_add_child(password_st, password_text); xmpp_stanza_add_child(conference, password_st); xmpp_stanza_release(password_text); xmpp_stanza_release(password_st); } xmpp_stanza_add_child(storage, conference); xmpp_stanza_release(conference); curr = curr->next; } xmpp_stanza_add_child(query, storage); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(storage); xmpp_stanza_release(query); xmpp_send(conn, iq); xmpp_stanza_release(iq); }profanity-0.4.7/src/xmpp/bookmark.h000066400000000000000000000033161257755232500173060ustar00rootroot00000000000000/* * bookmark.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef XMPP_BOOKMARK_H #define XMPP_BOOKMARK_H #include struct bookmark_t { char *jid; char *nick; char *password; gboolean autojoin; }; typedef struct bookmark_t Bookmark; void bookmark_request(void); #endif profanity-0.4.7/src/xmpp/capabilities.c000066400000000000000000000531411257755232500201260ustar00rootroot00000000000000/* * capabilities.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #ifdef HAVE_GIT_VERSION #include "gitversion.h" #endif #include #include #include #include #include #include "common.h" #include "log.h" #include "xmpp/xmpp.h" #include "xmpp/stanza.h" #include "xmpp/form.h" #include "xmpp/capabilities.h" static gchar *cache_loc; static GKeyFile *cache; static GHashTable *jid_to_ver; static GHashTable *jid_to_caps; static char *my_sha1; static gchar* _get_cache_file(void); static void _save_cache(void); static Capabilities * _caps_by_ver(const char * const ver); static Capabilities * _caps_by_jid(const char * const jid); Capabilities * _caps_copy(Capabilities *caps); void caps_init(void) { log_info("Loading capabilities cache"); cache_loc = _get_cache_file(); if (g_file_test(cache_loc, G_FILE_TEST_EXISTS)) { g_chmod(cache_loc, S_IRUSR | S_IWUSR); } cache = g_key_file_new(); g_key_file_load_from_file(cache, cache_loc, G_KEY_FILE_KEEP_COMMENTS, NULL); jid_to_ver = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); jid_to_caps = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)caps_destroy); my_sha1 = NULL; } void caps_add_by_ver(const char * const ver, Capabilities *caps) { gboolean cached = g_key_file_has_group(cache, ver); if (!cached) { if (caps->name) { g_key_file_set_string(cache, ver, "name", caps->name); } if (caps->category) { g_key_file_set_string(cache, ver, "category", caps->category); } if (caps->type) { g_key_file_set_string(cache, ver, "type", caps->type); } if (caps->software) { g_key_file_set_string(cache, ver, "software", caps->software); } if (caps->software_version) { g_key_file_set_string(cache, ver, "software_version", caps->software_version); } if (caps->os) { g_key_file_set_string(cache, ver, "os", caps->os); } if (caps->os_version) { g_key_file_set_string(cache, ver, "os_version", caps->os_version); } if (caps->features) { GSList *curr_feature = caps->features; int num = g_slist_length(caps->features); const gchar* features_list[num]; int curr = 0; while (curr_feature) { features_list[curr++] = curr_feature->data; curr_feature = g_slist_next(curr_feature); } g_key_file_set_string_list(cache, ver, "features", features_list, num); } _save_cache(); } } void caps_add_by_jid(const char * const jid, Capabilities *caps) { g_hash_table_insert(jid_to_caps, strdup(jid), caps); } void caps_map_jid_to_ver(const char * const jid, const char * const ver) { g_hash_table_insert(jid_to_ver, strdup(jid), strdup(ver)); } gboolean caps_contains(const char * const ver) { return (g_key_file_has_group(cache, ver)); } static Capabilities * _caps_by_ver(const char * const ver) { if (g_key_file_has_group(cache, ver)) { Capabilities *new_caps = malloc(sizeof(struct capabilities_t)); char *category = g_key_file_get_string(cache, ver, "category", NULL); if (category) { new_caps->category = category; } else { new_caps->category = NULL; } char *type = g_key_file_get_string(cache, ver, "type", NULL); if (type) { new_caps->type = type; } else { new_caps->type = NULL; } char *name = g_key_file_get_string(cache, ver, "name", NULL); if (name) { new_caps->name = name; } else { new_caps->name = NULL; } char *software = g_key_file_get_string(cache, ver, "software", NULL); if (software) { new_caps->software = software; } else { new_caps->software = NULL; } char *software_version = g_key_file_get_string(cache, ver, "software_version", NULL); if (software_version) { new_caps->software_version = software_version; } else { new_caps->software_version = NULL; } char *os = g_key_file_get_string(cache, ver, "os", NULL); if (os) { new_caps->os = os; } else { new_caps->os = NULL; } char *os_version = g_key_file_get_string(cache, ver, "os_version", NULL); if (os_version) { new_caps->os_version = os_version; } else { new_caps->os_version = NULL; } gsize features_len = 0; gchar **features = g_key_file_get_string_list(cache, ver, "features", &features_len, NULL); if (features && features_len > 0) { GSList *features_list = NULL; int i; for (i = 0; i < features_len; i++) { features_list = g_slist_append(features_list, strdup(features[i])); } new_caps->features = features_list; g_strfreev(features); } else { new_caps->features = NULL; } return new_caps; } else { return NULL; } } static Capabilities * _caps_by_jid(const char * const jid) { return g_hash_table_lookup(jid_to_caps, jid); } Capabilities * caps_lookup(const char * const jid) { char *ver = g_hash_table_lookup(jid_to_ver, jid); if (ver) { Capabilities *caps = _caps_by_ver(ver); if (caps) { log_debug("Capabilities lookup %s, found by verification string %s.", jid, ver); return caps; } } else { Capabilities *caps = _caps_by_jid(jid); if (caps) { log_debug("Capabilities lookup %s, found by JID.", jid); return _caps_copy(caps); } } log_debug("Capabilities lookup %s, none found.", jid); return NULL; } Capabilities * _caps_copy(Capabilities *caps) { if (!caps) { return NULL; } else { Capabilities *result = (Capabilities *)malloc(sizeof(Capabilities)); result->category = caps->category ? strdup(caps->category) : NULL; result->type = caps->type ? strdup(caps->type) : NULL; result->name = caps->name ? strdup(caps->name) : NULL; result->software = caps->software ? strdup(caps->software) : NULL; result->software_version = caps->software_version ? strdup(caps->software_version) : NULL; result->os = caps->os ? strdup(caps->os) : NULL; result->os_version = caps->os_version ? strdup(caps->os_version) : NULL; result->features = NULL; GSList *curr = caps->features; while (curr) { result->features = g_slist_append(result->features, strdup(curr->data)); curr = g_slist_next(curr); } return result; } } char * caps_create_sha1_str(xmpp_stanza_t * const query) { char *category = NULL; char *type = NULL; char *lang = NULL; char *name = NULL; char *feature_str = NULL; GSList *identities = NULL; GSList *features = NULL; GSList *form_names = NULL; DataForm *form = NULL; FormField *field = NULL; GHashTable *forms = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)form_destroy); xmpp_stanza_t *child = xmpp_stanza_get_children(query); while (child) { if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_IDENTITY) == 0) { category = xmpp_stanza_get_attribute(child, "category"); type = xmpp_stanza_get_attribute(child, "type"); lang = xmpp_stanza_get_attribute(child, "xml:lang"); name = xmpp_stanza_get_attribute(child, "name"); GString *identity_str = g_string_new(category); g_string_append(identity_str, "/"); if (type) { g_string_append(identity_str, type); } g_string_append(identity_str, "/"); if (lang) { g_string_append(identity_str, lang); } g_string_append(identity_str, "/"); if (name) { g_string_append(identity_str, name); } g_string_append(identity_str, "<"); identities = g_slist_insert_sorted(identities, g_strdup(identity_str->str), (GCompareFunc)strcmp); g_string_free(identity_str, TRUE); } else if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_FEATURE) == 0) { feature_str = xmpp_stanza_get_attribute(child, "var"); features = g_slist_insert_sorted(features, g_strdup(feature_str), (GCompareFunc)strcmp); } else if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_X) == 0) { if (g_strcmp0(xmpp_stanza_get_ns(child), STANZA_NS_DATA) == 0) { form = form_create(child); char *form_type = form_get_form_type_field(form); form_names = g_slist_insert_sorted(form_names, g_strdup(form_type), (GCompareFunc)strcmp); g_hash_table_insert(forms, g_strdup(form_type), form); } } child = xmpp_stanza_get_next(child); } GString *s = g_string_new(""); GSList *curr = identities; while (curr) { g_string_append(s, curr->data); curr = g_slist_next(curr); } curr = features; while (curr) { g_string_append(s, curr->data); g_string_append(s, "<"); curr = g_slist_next(curr); } curr = form_names; while (curr) { form = g_hash_table_lookup(forms, curr->data); char *form_type = form_get_form_type_field(form); g_string_append(s, form_type); g_string_append(s, "<"); GSList *sorted_fields = form_get_non_form_type_fields_sorted(form); GSList *curr_field = sorted_fields; while (curr_field) { field = curr_field->data; g_string_append(s, field->var); g_string_append(s, "<"); GSList *sorted_values = form_get_field_values_sorted(field); GSList *curr_value = sorted_values; while (curr_value) { g_string_append(s, curr_value->data); g_string_append(s, "<"); curr_value = g_slist_next(curr_value); } g_slist_free(sorted_values); curr_field = g_slist_next(curr_field); } g_slist_free(sorted_fields); curr = g_slist_next(curr); } char *result = p_sha1_hash(s->str); g_string_free(s, TRUE); g_slist_free_full(identities, g_free); g_slist_free_full(features, g_free); g_slist_free_full(form_names, g_free); g_hash_table_destroy(forms); return result; } Capabilities * caps_create(xmpp_stanza_t *query) { char *category = NULL; char *type = NULL; char *name = NULL; char *software = NULL; char *software_version = NULL; char *os = NULL; char *os_version = NULL; GSList *features = NULL; xmpp_stanza_t *softwareinfo = xmpp_stanza_get_child_by_ns(query, STANZA_NS_DATA); if (softwareinfo) { DataForm *form = form_create(softwareinfo); FormField *formField = NULL; char *form_type = form_get_form_type_field(form); if (g_strcmp0(form_type, STANZA_DATAFORM_SOFTWARE) == 0) { GSList *field = form->fields; while (field) { formField = field->data; if (formField->values) { if (strcmp(formField->var, "software") == 0) { software = strdup(formField->values->data); } else if (strcmp(formField->var, "software_version") == 0) { software_version = strdup(formField->values->data); } else if (strcmp(formField->var, "os") == 0) { os = strdup(formField->values->data); } else if (strcmp(formField->var, "os_version") == 0) { os_version = strdup(formField->values->data); } } field = g_slist_next(field); } } form_destroy(form); } xmpp_stanza_t *child = xmpp_stanza_get_children(query); GSList *identity_stanzas = NULL; while (child) { if (g_strcmp0(xmpp_stanza_get_name(child), "feature") == 0) { features = g_slist_append(features, strdup(xmpp_stanza_get_attribute(child, "var"))); } if (g_strcmp0(xmpp_stanza_get_name(child), "identity") == 0) { identity_stanzas = g_slist_append(identity_stanzas, child); } child = xmpp_stanza_get_next(child); } // find identity by locale const gchar* const *langs = g_get_language_names(); int num_langs = g_strv_length((gchar**)langs); xmpp_stanza_t *found = NULL; GSList *curr_identity = identity_stanzas; while (curr_identity) { xmpp_stanza_t *id_stanza = curr_identity->data; char *stanza_lang = xmpp_stanza_get_attribute(id_stanza, "xml:lang"); if (stanza_lang) { int i = 0; for (i = 0; i < num_langs; i++) { if (g_strcmp0(langs[i], stanza_lang) == 0) { found = id_stanza; break; } } } if (found) { break; } curr_identity = g_slist_next(curr_identity); } // not lang match, use default with no lang if (!found) { curr_identity = identity_stanzas; while (curr_identity) { xmpp_stanza_t *id_stanza = curr_identity->data; char *stanza_lang = xmpp_stanza_get_attribute(id_stanza, "xml:lang"); if (!stanza_lang) { found = id_stanza; break; } curr_identity = g_slist_next(curr_identity); } } // no matching lang, no identity without lang, use first if (!found) { if (identity_stanzas) { found = identity_stanzas->data; } } g_slist_free(identity_stanzas); if (found) { category = xmpp_stanza_get_attribute(found, "category"); type = xmpp_stanza_get_attribute(found, "type"); name = xmpp_stanza_get_attribute(found, "name"); } Capabilities *new_caps = malloc(sizeof(struct capabilities_t)); if (category) { new_caps->category = strdup(category); } else { new_caps->category = NULL; } if (type) { new_caps->type = strdup(type); } else { new_caps->type = NULL; } if (name) { new_caps->name = strdup(name); } else { new_caps->name = NULL; } if (software) { new_caps->software = software; } else { new_caps->software = NULL; } if (software_version) { new_caps->software_version = software_version; } else { new_caps->software_version = NULL; } if (os) { new_caps->os = os; } else { new_caps->os = NULL; } if (os_version) { new_caps->os_version = os_version; } else { new_caps->os_version = NULL; } if (features) { new_caps->features = features; } else { new_caps->features = NULL; } return new_caps; } char* caps_get_my_sha1(xmpp_ctx_t * const ctx) { if (my_sha1 == NULL) { xmpp_stanza_t *query = caps_create_query_response_stanza(ctx); my_sha1 = caps_create_sha1_str(query); xmpp_stanza_release(query); } return my_sha1; } xmpp_stanza_t * caps_create_query_response_stanza(xmpp_ctx_t * const ctx) { xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, XMPP_NS_DISCO_INFO); xmpp_stanza_t *identity = xmpp_stanza_new(ctx); xmpp_stanza_set_name(identity, "identity"); xmpp_stanza_set_attribute(identity, "category", "client"); xmpp_stanza_set_attribute(identity, "type", "console"); GString *name_str = g_string_new("Profanity "); g_string_append(name_str, PACKAGE_VERSION); if (strcmp(PACKAGE_STATUS, "development") == 0) { #ifdef HAVE_GIT_VERSION g_string_append(name_str, "dev."); g_string_append(name_str, PROF_GIT_BRANCH); g_string_append(name_str, "."); g_string_append(name_str, PROF_GIT_REVISION); #else g_string_append(name_str, "dev"); #endif } xmpp_stanza_set_attribute(identity, "name", name_str->str); g_string_free(name_str, TRUE); xmpp_stanza_t *feature_caps = xmpp_stanza_new(ctx); xmpp_stanza_set_name(feature_caps, STANZA_NAME_FEATURE); xmpp_stanza_set_attribute(feature_caps, STANZA_ATTR_VAR, STANZA_NS_CAPS); xmpp_stanza_t *feature_discoinfo = xmpp_stanza_new(ctx); xmpp_stanza_set_name(feature_discoinfo, STANZA_NAME_FEATURE); xmpp_stanza_set_attribute(feature_discoinfo, STANZA_ATTR_VAR, XMPP_NS_DISCO_INFO); xmpp_stanza_t *feature_discoitems = xmpp_stanza_new(ctx); xmpp_stanza_set_name(feature_discoitems, STANZA_NAME_FEATURE); xmpp_stanza_set_attribute(feature_discoitems, STANZA_ATTR_VAR, XMPP_NS_DISCO_ITEMS); xmpp_stanza_t *feature_muc = xmpp_stanza_new(ctx); xmpp_stanza_set_name(feature_muc, STANZA_NAME_FEATURE); xmpp_stanza_set_attribute(feature_muc, STANZA_ATTR_VAR, STANZA_NS_MUC); xmpp_stanza_t *feature_conference = xmpp_stanza_new(ctx); xmpp_stanza_set_name(feature_conference, STANZA_NAME_FEATURE); xmpp_stanza_set_attribute(feature_conference, STANZA_ATTR_VAR, STANZA_NS_CONFERENCE); xmpp_stanza_t *feature_version = xmpp_stanza_new(ctx); xmpp_stanza_set_name(feature_version, STANZA_NAME_FEATURE); xmpp_stanza_set_attribute(feature_version, STANZA_ATTR_VAR, STANZA_NS_VERSION); xmpp_stanza_t *feature_chatstates = xmpp_stanza_new(ctx); xmpp_stanza_set_name(feature_chatstates, STANZA_NAME_FEATURE); xmpp_stanza_set_attribute(feature_chatstates, STANZA_ATTR_VAR, STANZA_NS_CHATSTATES); xmpp_stanza_t *feature_ping = xmpp_stanza_new(ctx); xmpp_stanza_set_name(feature_ping, STANZA_NAME_FEATURE); xmpp_stanza_set_attribute(feature_ping, STANZA_ATTR_VAR, STANZA_NS_PING); xmpp_stanza_t *feature_receipts = xmpp_stanza_new(ctx); xmpp_stanza_set_name(feature_receipts, STANZA_NAME_FEATURE); xmpp_stanza_set_attribute(feature_receipts, STANZA_ATTR_VAR, STANZA_NS_RECEIPTS); xmpp_stanza_add_child(query, identity); xmpp_stanza_add_child(query, feature_caps); xmpp_stanza_add_child(query, feature_chatstates); xmpp_stanza_add_child(query, feature_discoinfo); xmpp_stanza_add_child(query, feature_discoitems); xmpp_stanza_add_child(query, feature_muc); xmpp_stanza_add_child(query, feature_conference); xmpp_stanza_add_child(query, feature_version); xmpp_stanza_add_child(query, feature_ping); xmpp_stanza_add_child(query, feature_receipts); xmpp_stanza_release(feature_receipts); xmpp_stanza_release(feature_ping); xmpp_stanza_release(feature_version); xmpp_stanza_release(feature_conference); xmpp_stanza_release(feature_muc); xmpp_stanza_release(feature_discoitems); xmpp_stanza_release(feature_discoinfo); xmpp_stanza_release(feature_chatstates); xmpp_stanza_release(feature_caps); xmpp_stanza_release(identity); return query; } void caps_close(void) { g_key_file_free(cache); cache = NULL; g_hash_table_destroy(jid_to_ver); g_hash_table_destroy(jid_to_caps); } void caps_destroy(Capabilities *caps) { if (caps) { free(caps->category); free(caps->type); free(caps->name); free(caps->software); free(caps->software_version); free(caps->os); free(caps->os_version); if (caps->features) { g_slist_free_full(caps->features, free); } free(caps); } } static gchar * _get_cache_file(void) { gchar *xdg_data = xdg_get_data_home(); GString *cache_file = g_string_new(xdg_data); g_string_append(cache_file, "/profanity/capscache"); gchar *result = strdup(cache_file->str); g_free(xdg_data); g_string_free(cache_file, TRUE); return result; } static void _save_cache(void) { gsize g_data_size; gchar *g_cache_data = g_key_file_to_data(cache, &g_data_size, NULL); g_file_set_contents(cache_loc, g_cache_data, g_data_size, NULL); g_chmod(cache_loc, S_IRUSR | S_IWUSR); g_free(g_cache_data); }profanity-0.4.7/src/xmpp/capabilities.h000066400000000000000000000041131257755232500201260ustar00rootroot00000000000000/* * capabilities.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef XMPP_CAPABILITIES_H #define XMPP_CAPABILITIES_H #include #include "xmpp/xmpp.h" void caps_init(void); void caps_add_by_ver(const char * const ver, Capabilities *caps); void caps_add_by_jid(const char * const jid, Capabilities *caps); void caps_map_jid_to_ver(const char * const jid, const char * const ver); gboolean caps_contains(const char * const ver); char* caps_create_sha1_str(xmpp_stanza_t * const query); xmpp_stanza_t* caps_create_query_response_stanza(xmpp_ctx_t * const ctx); Capabilities* caps_create(xmpp_stanza_t *query); char* caps_get_my_sha1(xmpp_ctx_t * const ctx); #endif profanity-0.4.7/src/xmpp/connection.c000066400000000000000000000407221257755232500176350ustar00rootroot00000000000000/* * connection.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include "chat_session.h" #include "common.h" #include "config/preferences.h" #include "jid.h" #include "log.h" #include "muc.h" #include "profanity.h" #include "event/server_events.h" #include "xmpp/bookmark.h" #include "xmpp/capabilities.h" #include "xmpp/connection.h" #include "xmpp/iq.h" #include "xmpp/message.h" #include "xmpp/presence.h" #include "xmpp/roster.h" #include "xmpp/stanza.h" #include "xmpp/xmpp.h" static struct _jabber_conn_t { xmpp_log_t *log; xmpp_ctx_t *ctx; xmpp_conn_t *conn; jabber_conn_status_t conn_status; char *presence_message; int priority; int tls_disabled; char *domain; } jabber_conn; static GHashTable *available_resources; // for auto reconnect static struct { char *name; char *passwd; } saved_account; static struct { char *name; char *jid; char *passwd; char *altdomain; int port; } saved_details; static GTimer *reconnect_timer; static log_level_t _get_log_level(xmpp_log_level_t xmpp_level); static xmpp_log_level_t _get_xmpp_log_level(); static void _xmpp_file_logger(void * const userdata, const xmpp_log_level_t level, const char * const area, const char * const msg); static xmpp_log_t * _xmpp_get_file_logger(); static jabber_conn_status_t _jabber_connect(const char * const fulljid, const char * const passwd, const char * const altdomain, int port); static void _jabber_reconnect(void); static void _connection_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status, const int error, xmpp_stream_error_t * const stream_error, void * const userdata); void _connection_free_saved_account(void); void _connection_free_saved_details(void); void _connection_free_session_data(void); void jabber_init(const int disable_tls) { log_info("Initialising XMPP"); jabber_conn.conn_status = JABBER_STARTED; jabber_conn.presence_message = NULL; jabber_conn.conn = NULL; jabber_conn.ctx = NULL; jabber_conn.tls_disabled = disable_tls; jabber_conn.domain = NULL; presence_sub_requests_init(); caps_init(); available_resources = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)resource_destroy); xmpp_initialize(); } jabber_conn_status_t jabber_connect_with_account(const ProfAccount * const account) { assert(account != NULL); log_info("Connecting using account: %s", account->name); // save account name and password for reconnect if (saved_account.name) { free(saved_account.name); } saved_account.name = strdup(account->name); if (saved_account.passwd) { free(saved_account.passwd); } saved_account.passwd = strdup(account->password); // connect with fulljid Jid *jidp = jid_create_from_bare_and_resource(account->jid, account->resource); jabber_conn_status_t result = _jabber_connect(jidp->fulljid, account->password, account->server, account->port); jid_destroy(jidp); return result; } jabber_conn_status_t jabber_connect_with_details(const char * const jid, const char * const passwd, const char * const altdomain, const int port) { assert(jid != NULL); assert(passwd != NULL); // save details for reconnect, remember name for account creating on success saved_details.name = strdup(jid); saved_details.passwd = strdup(passwd); if (altdomain) { saved_details.altdomain = strdup(altdomain); } else { saved_details.altdomain = NULL; } if (port != 0) { saved_details.port = port; } else { saved_details.port = 0; } // use 'profanity' when no resourcepart in provided jid Jid *jidp = jid_create(jid); if (jidp->resourcepart == NULL) { jid_destroy(jidp); jidp = jid_create_from_bare_and_resource(jid, "profanity"); saved_details.jid = strdup(jidp->fulljid); } else { saved_details.jid = strdup(jid); } jid_destroy(jidp); // connect with fulljid log_info("Connecting without account, JID: %s", saved_details.jid); return _jabber_connect(saved_details.jid, passwd, saved_details.altdomain, saved_details.port); } void jabber_disconnect(void) { // if connected, send end stream and wait for response if (jabber_conn.conn_status == JABBER_CONNECTED) { log_info("Closing connection"); jabber_conn.conn_status = JABBER_DISCONNECTING; xmpp_disconnect(jabber_conn.conn); while (jabber_get_connection_status() == JABBER_DISCONNECTING) { jabber_process_events(10); } _connection_free_saved_account(); _connection_free_saved_details(); _connection_free_session_data(); if (jabber_conn.conn) { xmpp_conn_release(jabber_conn.conn); jabber_conn.conn = NULL; } if (jabber_conn.ctx) { xmpp_ctx_free(jabber_conn.ctx); jabber_conn.ctx = NULL; } } jabber_conn.conn_status = JABBER_STARTED; FREE_SET_NULL(jabber_conn.presence_message); FREE_SET_NULL(jabber_conn.domain); } void jabber_shutdown(void) { _connection_free_saved_account(); _connection_free_saved_details(); _connection_free_session_data(); xmpp_shutdown(); free(jabber_conn.log); jabber_conn.log = NULL; } void jabber_process_events(int millis) { int reconnect_sec; switch (jabber_conn.conn_status) { case JABBER_CONNECTED: case JABBER_CONNECTING: case JABBER_DISCONNECTING: xmpp_run_once(jabber_conn.ctx, millis); break; case JABBER_DISCONNECTED: reconnect_sec = prefs_get_reconnect(); if ((reconnect_sec != 0) && reconnect_timer) { int elapsed_sec = g_timer_elapsed(reconnect_timer, NULL); if (elapsed_sec > reconnect_sec) { _jabber_reconnect(); } } break; default: break; } } GList * jabber_get_available_resources(void) { return g_hash_table_get_values(available_resources); } jabber_conn_status_t jabber_get_connection_status(void) { return (jabber_conn.conn_status); } xmpp_conn_t * connection_get_conn(void) { return jabber_conn.conn; } xmpp_ctx_t * connection_get_ctx(void) { return jabber_conn.ctx; } const char * jabber_get_fulljid(void) { return xmpp_conn_get_jid(jabber_conn.conn); } const char * jabber_get_domain(void) { return jabber_conn.domain; } char * jabber_get_presence_message(void) { return jabber_conn.presence_message; } char * jabber_get_account_name(void) { return saved_account.name; } void connection_set_presence_message(const char * const message) { FREE_SET_NULL(jabber_conn.presence_message); if (message) { jabber_conn.presence_message = strdup(message); } } void connection_set_priority(const int priority) { jabber_conn.priority = priority; } void connection_add_available_resource(Resource *resource) { g_hash_table_replace(available_resources, strdup(resource->name), resource); } void connection_remove_available_resource(const char * const resource) { g_hash_table_remove(available_resources, resource); } void _connection_free_saved_account(void) { FREE_SET_NULL(saved_account.name); FREE_SET_NULL(saved_account.passwd); } void _connection_free_saved_details(void) { FREE_SET_NULL(saved_details.name); FREE_SET_NULL(saved_details.jid); FREE_SET_NULL(saved_details.passwd); FREE_SET_NULL(saved_details.altdomain); } void _connection_free_session_data(void) { g_hash_table_remove_all(available_resources); chat_sessions_clear(); presence_clear_sub_requests(); } static jabber_conn_status_t _jabber_connect(const char * const fulljid, const char * const passwd, const char * const altdomain, int port) { assert(fulljid != NULL); assert(passwd != NULL); Jid *jid = jid_create(fulljid); if (jid == NULL) { log_error("Malformed JID not able to connect: %s", fulljid); jabber_conn.conn_status = JABBER_DISCONNECTED; return jabber_conn.conn_status; } else if (jid->fulljid == NULL) { log_error("Full JID required to connect, received: %s", fulljid); jabber_conn.conn_status = JABBER_DISCONNECTED; jid_destroy(jid); return jabber_conn.conn_status; } jid_destroy(jid); log_info("Connecting as %s", fulljid); if (jabber_conn.log) { free(jabber_conn.log); } jabber_conn.log = _xmpp_get_file_logger(); if (jabber_conn.conn) { xmpp_conn_release(jabber_conn.conn); } if (jabber_conn.ctx) { xmpp_ctx_free(jabber_conn.ctx); } jabber_conn.ctx = xmpp_ctx_new(NULL, jabber_conn.log); if (jabber_conn.ctx == NULL) { log_warning("Failed to get libstrophe ctx during connect"); return JABBER_DISCONNECTED; } jabber_conn.conn = xmpp_conn_new(jabber_conn.ctx); if (jabber_conn.conn == NULL) { log_warning("Failed to get libstrophe conn during connect"); return JABBER_DISCONNECTED; } xmpp_conn_set_jid(jabber_conn.conn, fulljid); xmpp_conn_set_pass(jabber_conn.conn, passwd); if (jabber_conn.tls_disabled) { xmpp_conn_disable_tls(jabber_conn.conn); } int connect_status = xmpp_connect_client(jabber_conn.conn, altdomain, port, _connection_handler, jabber_conn.ctx); if (connect_status == 0) jabber_conn.conn_status = JABBER_CONNECTING; else jabber_conn.conn_status = JABBER_DISCONNECTED; return jabber_conn.conn_status; } static void _jabber_reconnect(void) { // reconnect with account. ProfAccount *account = accounts_get_account(saved_account.name); if (account == NULL) { log_error("Unable to reconnect, account no longer exists: %s", saved_account.name); } else { char *fulljid = create_fulljid(account->jid, account->resource); log_debug("Attempting reconnect with account %s", account->name); _jabber_connect(fulljid, saved_account.passwd, account->server, account->port); free(fulljid); g_timer_start(reconnect_timer); } } static void _connection_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status, const int error, xmpp_stream_error_t * const stream_error, void * const userdata) { // login success if (status == XMPP_CONN_CONNECT) { log_debug("Connection handler: XMPP_CONN_CONNECT"); // logged in with account if (saved_account.name) { log_debug("Connection handler: logged in with account name: %s", saved_account.name); sv_ev_login_account_success(saved_account.name); // logged in without account, use details to create new account } else { log_debug("Connection handler: logged in with jid: %s", saved_details.name); accounts_add(saved_details.name, saved_details.altdomain, saved_details.port); accounts_set_jid(saved_details.name, saved_details.jid); sv_ev_login_account_success(saved_details.name); saved_account.name = strdup(saved_details.name); saved_account.passwd = strdup(saved_details.passwd); _connection_free_saved_details(); } Jid *my_jid = jid_create(jabber_get_fulljid()); jabber_conn.domain = strdup(my_jid->domainpart); jid_destroy(my_jid); chat_sessions_init(); roster_add_handlers(); message_add_handlers(); presence_add_handlers(); iq_add_handlers(); roster_request(); bookmark_request(); if (prefs_get_boolean(PREF_CARBONS)){ iq_enable_carbons(); } jabber_conn.conn_status = JABBER_CONNECTED; if (prefs_get_reconnect() != 0) { if (reconnect_timer) { g_timer_destroy(reconnect_timer); reconnect_timer = NULL; } } } else if (status == XMPP_CONN_DISCONNECT) { log_debug("Connection handler: XMPP_CONN_DISCONNECT"); // lost connection for unknown reason if (jabber_conn.conn_status == JABBER_CONNECTED) { log_debug("Connection handler: Lost connection for unknown reason"); sv_ev_lost_connection(); if (prefs_get_reconnect() != 0) { assert(reconnect_timer == NULL); reconnect_timer = g_timer_new(); // free resources but leave saved_user untouched _connection_free_session_data(); } else { _connection_free_saved_account(); _connection_free_saved_details(); _connection_free_session_data(); } // login attempt failed } else if (jabber_conn.conn_status != JABBER_DISCONNECTING) { log_debug("Connection handler: Login failed"); if (reconnect_timer == NULL) { log_debug("Connection handler: No reconnect timer"); sv_ev_failed_login(); _connection_free_saved_account(); _connection_free_saved_details(); _connection_free_session_data(); } else { log_debug("Connection handler: Restarting reconnect timer"); if (prefs_get_reconnect() != 0) { g_timer_start(reconnect_timer); } // free resources but leave saved_user untouched _connection_free_session_data(); } } // close stream response from server after disconnect is handled too jabber_conn.conn_status = JABBER_DISCONNECTED; } else if (status == XMPP_CONN_FAIL) { log_debug("Connection handler: XMPP_CONN_FAIL"); } else { log_error("Connection handler: Unknown status"); } } static log_level_t _get_log_level(const xmpp_log_level_t xmpp_level) { if (xmpp_level == XMPP_LEVEL_DEBUG) { return PROF_LEVEL_DEBUG; } else if (xmpp_level == XMPP_LEVEL_INFO) { return PROF_LEVEL_INFO; } else if (xmpp_level == XMPP_LEVEL_WARN) { return PROF_LEVEL_WARN; } else { return PROF_LEVEL_ERROR; } } static xmpp_log_level_t _get_xmpp_log_level() { log_level_t prof_level = log_get_filter(); if (prof_level == PROF_LEVEL_DEBUG) { return XMPP_LEVEL_DEBUG; } else if (prof_level == PROF_LEVEL_INFO) { return XMPP_LEVEL_INFO; } else if (prof_level == PROF_LEVEL_WARN) { return XMPP_LEVEL_WARN; } else { return XMPP_LEVEL_ERROR; } } static void _xmpp_file_logger(void * const userdata, const xmpp_log_level_t level, const char * const area, const char * const msg) { log_level_t prof_level = _get_log_level(level); log_msg(prof_level, area, msg); if ((g_strcmp0(area, "xmpp") == 0) || (g_strcmp0(area, "conn")) == 0) { sv_ev_xmpp_stanza(msg); } } static xmpp_log_t * _xmpp_get_file_logger() { xmpp_log_level_t level = _get_xmpp_log_level(); xmpp_log_t *file_log = malloc(sizeof(xmpp_log_t)); file_log->handler = _xmpp_file_logger; file_log->userdata = &level; return file_log; } profanity-0.4.7/src/xmpp/connection.h000066400000000000000000000036121257755232500176370ustar00rootroot00000000000000/* * connection.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef XMPP_CONNECTION_H #define XMPP_CONNECTION_H #include #include "resource.h" xmpp_conn_t *connection_get_conn(void); xmpp_ctx_t *connection_get_ctx(void); void connection_set_priority(int priority); void connection_set_presence_message(const char * const message); void connection_add_available_resource(Resource *resource); void connection_remove_available_resource(const char * const resource); #endif profanity-0.4.7/src/xmpp/form.c000066400000000000000000000526171257755232500164470ustar00rootroot00000000000000/* * form.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include "log.h" #include "xmpp/xmpp.h" #include "xmpp/stanza.h" #include "xmpp/connection.h" static gboolean _is_valid_form_element(xmpp_stanza_t *stanza) { char *name = xmpp_stanza_get_name(stanza); if (g_strcmp0(name, STANZA_NAME_X) != 0) { log_error("Error parsing form, root element not ."); return FALSE; } char *ns = xmpp_stanza_get_ns(stanza); if (g_strcmp0(ns, STANZA_NS_DATA) != 0) { log_error("Error parsing form, namespace not %s.", STANZA_NS_DATA); return FALSE; } char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); if ((g_strcmp0(type, "form") != 0) && (g_strcmp0(type, "submit") != 0) && (g_strcmp0(type, "cancel") != 0) && (g_strcmp0(type, "result") != 0)) { log_error("Error parsing form, unknown type."); return FALSE; } return TRUE; } static DataForm * _form_new(void) { DataForm *form = malloc(sizeof(DataForm)); form->type = NULL; form->title = NULL; form->instructions = NULL; form->fields = NULL; form->var_to_tag = NULL; form->tag_to_var = NULL; form->tag_ac = NULL; return form; } static FormField * _field_new(void) { FormField *field = malloc(sizeof(FormField)); field->label = NULL; field->type = NULL; field->var = NULL; field->description = NULL; field->required = FALSE; field->values = NULL; field->options = NULL; return field; } static char * _get_property(xmpp_stanza_t * const stanza, const char * const property) { char *result = NULL; xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *child = xmpp_stanza_get_child_by_name(stanza, property); if (child) { char *child_text = xmpp_stanza_get_text(child); if (child_text) { result = strdup(child_text); xmpp_free(ctx, child_text); } } return result; } static char * _get_attr(xmpp_stanza_t * const stanza, const char * const attr) { char *result = xmpp_stanza_get_attribute(stanza, attr); if (result) { return strdup(result); } else { return NULL; } } static gboolean _is_required(xmpp_stanza_t * const stanza) { xmpp_stanza_t *child = xmpp_stanza_get_child_by_name(stanza, "required"); if (child) { return TRUE; } else { return FALSE; } } static form_field_type_t _get_field_type(const char * const type) { if (g_strcmp0(type, "hidden") == 0) { return FIELD_HIDDEN; } if (g_strcmp0(type, "text-single") == 0) { return FIELD_TEXT_SINGLE; } if (g_strcmp0(type, "text-private") == 0) { return FIELD_TEXT_PRIVATE; } if (g_strcmp0(type, "text-multi") == 0) { return FIELD_TEXT_MULTI; } if (g_strcmp0(type, "boolean") == 0) { return FIELD_BOOLEAN; } if (g_strcmp0(type, "list-single") == 0) { return FIELD_LIST_SINGLE; } if (g_strcmp0(type, "list-multi") == 0) { return FIELD_LIST_MULTI; } if (g_strcmp0(type, "jid-single") == 0) { return FIELD_JID_SINGLE; } if (g_strcmp0(type, "jid-multi") == 0) { return FIELD_JID_MULTI; } if (g_strcmp0(type, "fixed") == 0) { return FIELD_FIXED; } return FIELD_UNKNOWN; } DataForm * form_create(xmpp_stanza_t * const form_stanza) { xmpp_ctx_t *ctx = connection_get_ctx(); if (!_is_valid_form_element(form_stanza)) { return NULL; } DataForm *form = _form_new(); form->type = _get_attr(form_stanza, "type"); form->title = _get_property(form_stanza, "title"); form->instructions = _get_property(form_stanza, "instructions"); form->var_to_tag = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); form->tag_to_var = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); form->tag_ac = autocomplete_new(); form->modified = FALSE; int tag_num = 1; // get fields xmpp_stanza_t *form_child = xmpp_stanza_get_children(form_stanza); while (form_child) { char *child_name = xmpp_stanza_get_name(form_child); if (g_strcmp0(child_name, "field") == 0) { xmpp_stanza_t *field_stanza = form_child; FormField *field = _field_new(); field->label = _get_attr(field_stanza, "label"); field->type = _get_attr(field_stanza, "type"); field->type_t = _get_field_type(field->type); field->value_ac = autocomplete_new(); field->var = _get_attr(field_stanza, "var"); if (field->type_t != FIELD_HIDDEN && field->var) { GString *tag = g_string_new(""); g_string_printf(tag, "field%d", tag_num++); g_hash_table_insert(form->var_to_tag, strdup(field->var), strdup(tag->str)); g_hash_table_insert(form->tag_to_var, strdup(tag->str), strdup(field->var)); autocomplete_add(form->tag_ac, tag->str); g_string_free(tag, TRUE); } field->description = _get_property(field_stanza, "desc"); field->required = _is_required(field_stanza); // handle repeated field children xmpp_stanza_t *field_child = xmpp_stanza_get_children(field_stanza); int value_index = 1; while (field_child) { child_name = xmpp_stanza_get_name(field_child); // handle values if (g_strcmp0(child_name, "value") == 0) { char *value = xmpp_stanza_get_text(field_child); if (value) { field->values = g_slist_append(field->values, strdup(value)); if (field->type_t == FIELD_TEXT_MULTI) { GString *ac_val = g_string_new(""); g_string_printf(ac_val, "val%d", value_index++); autocomplete_add(field->value_ac, ac_val->str); g_string_free(ac_val, TRUE); } if (field->type_t == FIELD_JID_MULTI) { autocomplete_add(field->value_ac, value); } xmpp_free(ctx, value); } // handle options } else if (g_strcmp0(child_name, "option") == 0) { FormOption *option = malloc(sizeof(FormOption)); option->label = _get_attr(field_child, "label"); option->value = _get_property(field_child, "value"); if ((field->type_t == FIELD_LIST_SINGLE) || (field->type_t == FIELD_LIST_MULTI)) { autocomplete_add(field->value_ac, option->value); } field->options = g_slist_append(field->options, option); } field_child = xmpp_stanza_get_next(field_child); } form->fields = g_slist_append(form->fields, field); } form_child = xmpp_stanza_get_next(form_child); } return form; } xmpp_stanza_t * form_create_submission(DataForm *form) { xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *x = xmpp_stanza_new(ctx); xmpp_stanza_set_name(x, STANZA_NAME_X); xmpp_stanza_set_ns(x, STANZA_NS_DATA); xmpp_stanza_set_type(x, "submit"); GSList *curr_field = form->fields; while (curr_field) { FormField *field = curr_field->data; if (field->type_t != FIELD_FIXED) { xmpp_stanza_t *field_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_name(field_stanza, "field"); xmpp_stanza_set_attribute(field_stanza, "var", field->var); xmpp_stanza_t *value_stanza = NULL; GSList *curr_value = NULL; switch (field->type_t) { case FIELD_HIDDEN: case FIELD_TEXT_SINGLE: case FIELD_TEXT_PRIVATE: case FIELD_BOOLEAN: case FIELD_LIST_SINGLE: case FIELD_JID_SINGLE: value_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_name(value_stanza, "value"); if (field->values) { if (field->values->data) { xmpp_stanza_t *text_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_text(text_stanza, field->values->data); xmpp_stanza_add_child(value_stanza, text_stanza); xmpp_stanza_release(text_stanza); } } xmpp_stanza_add_child(field_stanza, value_stanza); xmpp_stanza_release(value_stanza); break; case FIELD_TEXT_MULTI: case FIELD_LIST_MULTI: case FIELD_JID_MULTI: curr_value = field->values; while (curr_value) { char *value = curr_value->data; value_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_name(value_stanza, "value"); if (value) { xmpp_stanza_t *text_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_text(text_stanza, value); xmpp_stanza_add_child(value_stanza, text_stanza); xmpp_stanza_release(text_stanza); } xmpp_stanza_add_child(field_stanza, value_stanza); xmpp_stanza_release(value_stanza); curr_value = g_slist_next(curr_value); } break; case FIELD_FIXED: default: break; } xmpp_stanza_add_child(x, field_stanza); xmpp_stanza_release(field_stanza); } curr_field = g_slist_next(curr_field); } return x; } static void _free_option(FormOption *option) { if (option) { free(option->label); free(option->value); free(option); } } static void _free_field(FormField *field) { if (field) { free(field->label); free(field->type); free(field->var); free(field->description); g_slist_free_full(field->values, free); g_slist_free_full(field->options, (GDestroyNotify)_free_option); autocomplete_free(field->value_ac); free(field); } } void form_destroy(DataForm *form) { if (form) { free(form->type); free(form->title); free(form->instructions); g_slist_free_full(form->fields, (GDestroyNotify)_free_field); g_hash_table_destroy(form->var_to_tag); g_hash_table_destroy(form->tag_to_var); autocomplete_free(form->tag_ac); free(form); } } static int _field_compare_by_var(FormField *a, FormField *b) { return g_strcmp0(a->var, b->var); } GSList * form_get_non_form_type_fields_sorted(DataForm *form) { GSList *sorted = NULL; GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, "FORM_TYPE") != 0) { sorted = g_slist_insert_sorted(sorted, field, (GCompareFunc)_field_compare_by_var); } curr = g_slist_next(curr); } return sorted; } GSList * form_get_field_values_sorted(FormField *field) { GSList *sorted = NULL; GSList *curr = field->values; while (curr) { char *value = curr->data; if (value) { sorted = g_slist_insert_sorted(sorted, value, (GCompareFunc)g_strcmp0); } curr = g_slist_next(curr); } return sorted; } char * form_get_form_type_field(DataForm *form) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, "FORM_TYPE") == 0) { return field->values->data; } curr = g_slist_next(curr); } return NULL; } gboolean form_tag_exists(DataForm *form, const char * const tag) { GList *tags = g_hash_table_get_keys(form->tag_to_var); GList *curr = tags; while (curr) { if (g_strcmp0(curr->data, tag) == 0) { return TRUE; } curr = g_list_next(curr); } g_list_free(tags); return FALSE; } form_field_type_t form_get_field_type(DataForm *form, const char * const tag) { char *var = g_hash_table_lookup(form->tag_to_var, tag); if (var) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { return field->type_t; } curr = g_slist_next(curr); } } return FIELD_UNKNOWN; } void form_set_value(DataForm *form, const char * const tag, char *value) { char *var = g_hash_table_lookup(form->tag_to_var, tag); if (var) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { if (g_slist_length(field->values) == 0) { field->values = g_slist_append(field->values, strdup(value)); form->modified = TRUE; return; } else if (g_slist_length(field->values) == 1) { free(field->values->data); field->values->data = strdup(value); form->modified = TRUE; return; } } curr = g_slist_next(curr); } } } void form_add_value(DataForm *form, const char * const tag, char *value) { char *var = g_hash_table_lookup(form->tag_to_var, tag); if (var) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { field->values = g_slist_append(field->values, strdup(value)); if (field->type_t == FIELD_TEXT_MULTI) { int total = g_slist_length(field->values); GString *value_index = g_string_new(""); g_string_printf(value_index, "val%d", total); autocomplete_add(field->value_ac, value_index->str); g_string_free(value_index, TRUE); } form->modified = TRUE; return; } curr = g_slist_next(curr); } } } gboolean form_add_unique_value(DataForm *form, const char * const tag, char *value) { char *var = g_hash_table_lookup(form->tag_to_var, tag); if (var) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { GSList *curr_value = field->values; while (curr_value) { if (g_strcmp0(curr_value->data, value) == 0) { return FALSE; } curr_value = g_slist_next(curr_value); } field->values = g_slist_append(field->values, strdup(value)); if (field->type_t == FIELD_JID_MULTI) { autocomplete_add(field->value_ac, value); } form->modified = TRUE; return TRUE; } curr = g_slist_next(curr); } } return FALSE; } gboolean form_remove_value(DataForm *form, const char * const tag, char *value) { char *var = g_hash_table_lookup(form->tag_to_var, tag); if (var) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { GSList *found = g_slist_find_custom(field->values, value, (GCompareFunc)g_strcmp0); if (found) { free(found->data); found->data = NULL; field->values = g_slist_delete_link(field->values, found); if (field->type_t == FIELD_JID_MULTI) { autocomplete_remove(field->value_ac, value); } form->modified = TRUE; return TRUE; } else { return FALSE; } } curr = g_slist_next(curr); } } return FALSE; } gboolean form_remove_text_multi_value(DataForm *form, const char * const tag, int index) { index--; char *var = g_hash_table_lookup(form->tag_to_var, tag); if (var) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { GSList *item = g_slist_nth(field->values, index); if (item) { free(item->data); item->data = NULL; field->values = g_slist_delete_link(field->values, item); GString *value_index = g_string_new(""); g_string_printf(value_index, "val%d", index+1); autocomplete_remove(field->value_ac, value_index->str); g_string_free(value_index, TRUE); form->modified = TRUE; return TRUE; } else { return FALSE; } } curr = g_slist_next(curr); } } return FALSE; } int form_get_value_count(DataForm *form, const char * const tag) { char *var = g_hash_table_lookup(form->tag_to_var, tag); if (var) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { if ((g_slist_length(field->values) == 1) && (field->values->data == NULL)) { return 0; } else { return g_slist_length(field->values); } } curr = g_slist_next(curr); } } return 0; } gboolean form_field_contains_option(DataForm *form, const char * const tag, char *value) { char *var = g_hash_table_lookup(form->tag_to_var, tag); if (var) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { GSList *curr_option = field->options; while (curr_option) { FormOption *option = curr_option->data; if (g_strcmp0(option->value, value) == 0) { return TRUE; } curr_option = g_slist_next(curr_option); } } curr = g_slist_next(curr); } } return FALSE; } FormField * form_get_field_by_tag(DataForm *form, const char * const tag) { char *var = g_hash_table_lookup(form->tag_to_var, tag); if (var) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { return field; } curr = g_slist_next(curr); } } return NULL; } Autocomplete form_get_value_ac(DataForm *form, const char * const tag) { char *var = g_hash_table_lookup(form->tag_to_var, tag); if (var) { GSList *curr = form->fields; while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { return field->value_ac; } curr = g_slist_next(curr); } } return NULL; } void form_reset_autocompleters(DataForm *form) { autocomplete_reset(form->tag_ac); GSList *curr_field = form->fields; while (curr_field) { FormField *field = curr_field->data; autocomplete_reset(field->value_ac); curr_field = g_slist_next(curr_field); } }profanity-0.4.7/src/xmpp/form.h000066400000000000000000000032051257755232500164410ustar00rootroot00000000000000/* * form.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef FORM_H #define FORM_H #include "xmpp/xmpp.h" DataForm* form_create(xmpp_stanza_t * const stanza); xmpp_stanza_t* form_create_submission(DataForm *form); #endif profanity-0.4.7/src/xmpp/iq.c000066400000000000000000001507631257755232500161160ustar00rootroot00000000000000/* * iq.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #ifdef HAVE_GIT_VERSION #include "gitversion.h" #endif #include #include #include #include #include "log.h" #include "muc.h" #include "profanity.h" #include "ui/ui.h" #include "config/preferences.h" #include "event/server_events.h" #include "xmpp/capabilities.h" #include "xmpp/connection.h" #include "xmpp/stanza.h" #include "xmpp/form.h" #include "roster_list.h" #include "xmpp/xmpp.h" #define HANDLE(ns, type, func) xmpp_handler_add(conn, func, ns, STANZA_NAME_IQ, type, ctx) typedef struct p_room_info_data_t { char *room; gboolean display; } ProfRoomInfoData; static int _error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _ping_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _version_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _disco_info_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _room_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _disco_items_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _disco_items_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _destroy_room_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _room_config_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _room_config_submit_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _room_affiliation_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _room_affiliation_set_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _room_role_set_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _room_role_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _room_kick_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _enable_carbons_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _disable_carbons_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _manual_pong_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _ping_timed_handler(xmpp_conn_t * const conn, void * const userdata); static int _caps_response_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _caps_response_handler_for_jid(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _caps_response_handler_legacy(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata); void iq_add_handlers(void) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); HANDLE(NULL, STANZA_TYPE_ERROR, _error_handler); HANDLE(XMPP_NS_DISCO_INFO, STANZA_TYPE_GET, _disco_info_get_handler); HANDLE(XMPP_NS_DISCO_ITEMS, STANZA_TYPE_GET, _disco_items_get_handler); HANDLE(XMPP_NS_DISCO_ITEMS, STANZA_TYPE_RESULT, _disco_items_result_handler); HANDLE(STANZA_NS_VERSION, STANZA_TYPE_GET, _version_get_handler); HANDLE(STANZA_NS_PING, STANZA_TYPE_GET, _ping_get_handler); if (prefs_get_autoping() != 0) { int millis = prefs_get_autoping() * 1000; xmpp_timed_handler_add(conn, _ping_timed_handler, millis, ctx); } } void iq_set_autoping(const int seconds) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); if (jabber_get_connection_status() == JABBER_CONNECTED) { xmpp_timed_handler_delete(conn, _ping_timed_handler); if (seconds != 0) { int millis = seconds * 1000; xmpp_timed_handler_add(conn, _ping_timed_handler, millis, ctx); } } } void iq_room_list_request(gchar *conferencejid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, "confreq", conferencejid); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_enable_carbons() { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_enable_carbons(ctx); char *id = xmpp_stanza_get_id(iq); xmpp_id_handler_add(conn, _enable_carbons_handler, id, NULL); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_disable_carbons() { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_disable_carbons(ctx); char *id = xmpp_stanza_get_id(iq); xmpp_id_handler_add(conn, _disable_carbons_handler, id, NULL); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_disco_info_request(gchar *jid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = create_unique_id("disco_info"); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, jid, NULL); xmpp_id_handler_add(conn, _disco_info_response_handler, id, NULL); free(id); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_room_info_request(const char * const room, gboolean display_result) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = create_unique_id("room_disco_info"); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, room, NULL); ProfRoomInfoData *cb_data = malloc(sizeof(ProfRoomInfoData)); cb_data->room = strdup(room); cb_data->display = display_result; xmpp_id_handler_add(conn, _room_info_response_handler, id, cb_data); free(id); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_send_caps_request_for_jid(const char * const to, const char * const id, const char * const node, const char * const ver) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); if (!node) { log_error("Could not create caps request, no node"); return; } if (!ver) { log_error("Could not create caps request, no ver"); return; } GString *node_str = g_string_new(""); g_string_printf(node_str, "%s#%s", node, ver); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, to, node_str->str); g_string_free(node_str, TRUE); xmpp_id_handler_add(conn, _caps_response_handler_for_jid, id, strdup(to)); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_send_caps_request(const char * const to, const char * const id, const char * const node, const char * const ver) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); if (!node) { log_error("Could not create caps request, no node"); return; } if (!ver) { log_error("Could not create caps request, no ver"); return; } GString *node_str = g_string_new(""); g_string_printf(node_str, "%s#%s", node, ver); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, to, node_str->str); g_string_free(node_str, TRUE); xmpp_id_handler_add(conn, _caps_response_handler, id, NULL); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_send_caps_request_legacy(const char * const to, const char * const id, const char * const node, const char * const ver) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); if (!node) { log_error("Could not create caps request, no node"); return; } if (!ver) { log_error("Could not create caps request, no ver"); return; } GString *node_str = g_string_new(""); g_string_printf(node_str, "%s#%s", node, ver); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, to, node_str->str); xmpp_id_handler_add(conn, _caps_response_handler_legacy, id, node_str->str); g_string_free(node_str, FALSE); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_disco_items_request(gchar *jid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, "discoitemsreq", jid); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_send_software_version(const char * const fulljid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_software_version_iq(ctx, fulljid); char *id = xmpp_stanza_get_id(iq); xmpp_id_handler_add(conn, _version_result_handler, id, strdup(fulljid)); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_confirm_instant_room(const char * const room_jid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_instant_room_request_iq(ctx, room_jid); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_destroy_room(const char * const room_jid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_instant_room_destroy_iq(ctx, room_jid); char *id = xmpp_stanza_get_id(iq); xmpp_id_handler_add(conn, _destroy_room_result_handler, id, NULL); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_request_room_config_form(const char * const room_jid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_room_config_request_iq(ctx, room_jid); char *id = xmpp_stanza_get_id(iq); xmpp_id_handler_add(conn, _room_config_handler, id, NULL); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_submit_room_config(const char * const room, DataForm *form) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_room_config_submit_iq(ctx, room, form); char *id = xmpp_stanza_get_id(iq); xmpp_id_handler_add(conn, _room_config_submit_handler, id, NULL); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_room_config_cancel(const char * const room_jid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_room_config_cancel_iq(ctx, room_jid); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_room_affiliation_list(const char * const room, char *affiliation) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_room_affiliation_list_iq(ctx, room, affiliation); char *id = xmpp_stanza_get_id(iq); xmpp_id_handler_add(conn, _room_affiliation_list_result_handler, id, strdup(affiliation)); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_room_kick_occupant(const char * const room, const char * const nick, const char * const reason) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_room_kick_iq(ctx, room, nick, reason); char *id = xmpp_stanza_get_id(iq); xmpp_id_handler_add(conn, _room_kick_result_handler, id, strdup(nick)); xmpp_send(conn, iq); xmpp_stanza_release(iq); } struct privilege_set_t { char *item; char *privilege; }; void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation, const char * const reason) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_room_affiliation_set_iq(ctx, room, jid, affiliation, reason); char *id = xmpp_stanza_get_id(iq); struct privilege_set_t *affiliation_set = malloc(sizeof(struct privilege_set_t)); affiliation_set->item = strdup(jid); affiliation_set->privilege = strdup(affiliation); xmpp_id_handler_add(conn, _room_affiliation_set_result_handler, id, affiliation_set); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_room_role_set(const char * const room, const char * const nick, char *role, const char * const reason) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_room_role_set_iq(ctx, room, nick, role, reason); char *id = xmpp_stanza_get_id(iq); struct privilege_set_t *role_set = malloc(sizeof(struct privilege_set_t)); role_set->item = strdup(nick); role_set->privilege = strdup(role); xmpp_id_handler_add(conn, _room_role_set_result_handler, id, role_set); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_room_role_list(const char * const room, char *role) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_room_role_list_iq(ctx, room, role); char *id = xmpp_stanza_get_id(iq); xmpp_id_handler_add(conn, _room_role_list_result_handler, id, strdup(role)); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void iq_send_ping(const char * const target) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_ping_iq(ctx, target); char *id = xmpp_stanza_get_id(iq); GDateTime *now = g_date_time_new_now_local(); xmpp_id_handler_add(conn, _manual_pong_handler, id, now); xmpp_send(conn, iq); xmpp_stanza_release(iq); } static int _error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); char *error_msg = stanza_get_error_message(stanza); if (id) { log_debug("IQ error handler fired, id: %s, error: %s", id, error_msg); log_error("IQ error received, id: %s, error: %s", id, error_msg); } else { log_debug("IQ error handler fired, error: %s", error_msg); log_error("IQ error received, error: %s", error_msg); } free(error_msg); return 1; } static int _pong_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *id = xmpp_stanza_get_id(stanza); char *type = xmpp_stanza_get_type(stanza); if (id) { log_debug("IQ pong handler fired, id: %s.", id); } else { log_debug("IQ pong handler fired."); } if (id && type) { // show warning if error if (strcmp(type, STANZA_TYPE_ERROR) == 0) { char *error_msg = stanza_get_error_message(stanza); log_warning("Server ping (id=%s) responded with error: %s", id, error_msg); free(error_msg); // turn off autoping if error type is 'cancel' xmpp_stanza_t *error = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); if (error) { char *errtype = xmpp_stanza_get_type(error); if (errtype) { if (strcmp(errtype, "cancel") == 0) { log_warning("Server ping (id=%s) error type 'cancel', disabling autoping.", id); prefs_set_autoping(0); cons_show_error("Server ping not supported, autoping disabled."); xmpp_timed_handler_delete(conn, _ping_timed_handler); } } } } } // remove this handler return 0; } static int _caps_response_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); char *type = xmpp_stanza_get_type(stanza); // ignore non result if ((g_strcmp0(type, "get") == 0) || (g_strcmp0(type, "set") == 0)) { return 1; } if (id) { log_info("Capabilities response handler fired for id %s", id); } else { log_info("Capabilities response handler fired"); } const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!from) { log_info("No from attribute"); return 0; } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); log_warning("Error received for capabilities response from %s: ", from, error_message); free(error_message); return 0; } if (query == NULL) { log_warning("No query element found."); return 0; } char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE); if (node == NULL) { log_warning("No node attribute found"); return 0; } // validate sha1 gchar **split = g_strsplit(node, "#", -1); char *given_sha1 = split[1]; char *generated_sha1 = caps_create_sha1_str(query); if (g_strcmp0(given_sha1, generated_sha1) != 0) { log_warning("Generated sha-1 does not match given:"); log_warning("Generated : %s", generated_sha1); log_warning("Given : %s", given_sha1); } else { log_info("Valid SHA-1 hash found: %s", given_sha1); if (caps_contains(given_sha1)) { log_info("Capabilties already cached: %s", given_sha1); } else { log_info("Capabilities not cached: %s, storing", given_sha1); Capabilities *capabilities = caps_create(query); caps_add_by_ver(given_sha1, capabilities); caps_destroy(capabilities); } caps_map_jid_to_ver(from, given_sha1); } g_free(generated_sha1); g_strfreev(split); return 0; } static int _caps_response_handler_for_jid(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *jid = (char *)userdata; const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); char *type = xmpp_stanza_get_type(stanza); // ignore non result if ((g_strcmp0(type, "get") == 0) || (g_strcmp0(type, "set") == 0)) { free(jid); return 1; } if (id) { log_info("Capabilities response handler fired for id %s", id); } else { log_info("Capabilities response handler fired"); } const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!from) { log_info("No from attribute"); free(jid); return 0; } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); log_warning("Error received for capabilities response from %s: ", from, error_message); free(error_message); free(jid); return 0; } if (query == NULL) { log_warning("No query element found."); free(jid); return 0; } char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE); if (node == NULL) { log_warning("No node attribute found"); free(jid); return 0; } log_info("Associating capabilities with: %s", jid); Capabilities *capabilities = caps_create(query); caps_add_by_jid(jid, capabilities); free(jid); return 0; } static int _caps_response_handler_legacy(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); char *expected_node = (char *)userdata; char *type = xmpp_stanza_get_type(stanza); // ignore non result if ((g_strcmp0(type, "get") == 0) || (g_strcmp0(type, "set") == 0)) { free(expected_node); return 1; } if (id) { log_info("Capabilities response handler fired for id %s", id); } else { log_info("Capabilities response handler fired"); } const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!from) { log_info("No from attribute"); free(expected_node); return 0; } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); log_warning("Error received for capabilities response from %s: ", from, error_message); free(error_message); free(expected_node); return 0; } if (query == NULL) { log_warning("No query element found."); free(expected_node); return 0; } char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE); if (node == NULL) { log_warning("No node attribute found"); free(expected_node); return 0; } // nodes match if (g_strcmp0(expected_node, node) == 0) { log_info("Legacy capabilities, nodes match %s", node); if (caps_contains(node)) { log_info("Capabilties already cached: %s", node); } else { log_info("Capabilities not cached: %s, storing", node); Capabilities *capabilities = caps_create(query); caps_add_by_ver(node, capabilities); caps_destroy(capabilities); } caps_map_jid_to_ver(from, node); // node match fail } else { log_info("Legacy Capabilities nodes do not match, expeceted %s, given %s.", expected_node, node); } free(expected_node); return 0; } static int _enable_carbons_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *type = xmpp_stanza_get_type(stanza); if (g_strcmp0(type, "error") == 0) { char *error_message = stanza_get_error_message(stanza); cons_show_error("Server error enabling message carbons: %s", error_message); log_debug("Error enabling carbons: %s", error_message); free(error_message); } else { log_debug("Message carbons enabled."); } return 0; } static int _disable_carbons_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *type = xmpp_stanza_get_type(stanza); if (g_strcmp0(type, "error") == 0) { char *error_message = stanza_get_error_message(stanza); cons_show_error("Server error disabling message carbons: %s", error_message); log_debug("Error disabling carbons: %s", error_message); free(error_message); } else { log_debug("Message carbons disabled."); } return 0; } static int _manual_pong_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); char *type = xmpp_stanza_get_type(stanza); GDateTime *sent = (GDateTime *)userdata; // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); if (!error_message) { cons_show_error("Error returned from pinging %s.", from); } else { cons_show_error("Error returned from pinging %s: %s.", from, error_message); } free(error_message); g_date_time_unref(sent); return 0; } GDateTime *now = g_date_time_new_now_local(); GTimeSpan elapsed = g_date_time_difference(now, sent); int elapsed_millis = elapsed / 1000; g_date_time_unref(sent); g_date_time_unref(now); if (from == NULL) { cons_show("Ping response from server: %dms.", elapsed_millis); } else { cons_show("Ping response from %s: %dms.", from, elapsed_millis); } return 0; } static int _ping_timed_handler(xmpp_conn_t * const conn, void * const userdata) { xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; if (jabber_get_connection_status() == JABBER_CONNECTED) { xmpp_stanza_t *iq = stanza_create_ping_iq(ctx, NULL); char *id = xmpp_stanza_get_id(iq); // add pong handler xmpp_id_handler_add(conn, _pong_handler, id, ctx); xmpp_send(conn, iq); xmpp_stanza_release(iq); } return 1; } static int _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *id = xmpp_stanza_get_id(stanza); if (id) { log_debug("IQ version result handler fired, id: %s.", id); } else { log_debug("IQ version result handler fired."); } char *type = xmpp_stanza_get_type(stanza); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (g_strcmp0(type, STANZA_TYPE_RESULT) != 0) { if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); ui_handle_software_version_error(from, error_message); free(error_message); } else { ui_handle_software_version_error(from, "unknown error"); log_error("Software version result with unrecognised type attribute."); } return 0; } const char *jid = xmpp_stanza_get_attribute(stanza, "from"); xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (query == NULL) { log_error("Software version result recieved with no query element."); return 0; } char *ns = xmpp_stanza_get_ns(query); if (g_strcmp0(ns, STANZA_NS_VERSION) != 0) { log_error("Software version result recieved without namespace."); return 0; } char *name_str = NULL; char *version_str = NULL; char *os_str = NULL; xmpp_stanza_t *name = xmpp_stanza_get_child_by_name(query, "name"); xmpp_stanza_t *version = xmpp_stanza_get_child_by_name(query, "version"); xmpp_stanza_t *os = xmpp_stanza_get_child_by_name(query, "os"); if (name) { name_str = xmpp_stanza_get_text(name); } if (version) { version_str = xmpp_stanza_get_text(version); } if (os) { os_str = xmpp_stanza_get_text(os); } if (g_strcmp0(jid, (char*)userdata) != 0) { log_warning("From attribute specified different JID, using original JID."); } xmpp_ctx_t *ctx = xmpp_conn_get_context(conn); Jid *jidp = jid_create((char*)userdata); const char *presence = NULL; if (muc_active(jidp->barejid)) { Occupant *occupant = muc_roster_item(jidp->barejid, jidp->resourcepart); presence = string_from_resource_presence(occupant->presence); } else { PContact contact = roster_get_contact(jidp->barejid); Resource *resource = p_contact_get_resource(contact, jidp->resourcepart); if (!resource) { ui_handle_software_version_error(jidp->fulljid, "Unknown resource"); if (name_str) xmpp_free(ctx, name_str); if (version_str) xmpp_free(ctx, version_str); if (os_str) xmpp_free(ctx, os_str); return 0; } presence = string_from_resource_presence(resource->presence); } ui_show_software_version(jidp->fulljid, presence, name_str, version_str, os_str); jid_destroy(jidp); free(userdata); if (name_str) xmpp_free(ctx, name_str); if (version_str) xmpp_free(ctx, version_str); if (os_str) xmpp_free(ctx, os_str); return 0; } static int _ping_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *to = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TO); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (id) { log_debug("IQ ping get handler fired, id: %s.", id); } else { log_debug("IQ ping get handler fired."); } if ((from == NULL) || (to == NULL)) { return 1; } xmpp_stanza_t *pong = xmpp_stanza_new(ctx); xmpp_stanza_set_name(pong, STANZA_NAME_IQ); xmpp_stanza_set_attribute(pong, STANZA_ATTR_TO, from); xmpp_stanza_set_attribute(pong, STANZA_ATTR_FROM, to); xmpp_stanza_set_attribute(pong, STANZA_ATTR_TYPE, STANZA_TYPE_RESULT); if (id) { xmpp_stanza_set_attribute(pong, STANZA_ATTR_ID, id); } xmpp_send(conn, pong); xmpp_stanza_release(pong); return 1; } static int _version_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (id) { log_debug("IQ version get handler fired, id: %s.", id); } else { log_debug("IQ version get handler fired."); } if (from) { xmpp_stanza_t *response = xmpp_stanza_new(ctx); xmpp_stanza_set_name(response, STANZA_NAME_IQ); if (id) { xmpp_stanza_set_id(response, id); } xmpp_stanza_set_attribute(response, STANZA_ATTR_TO, from); xmpp_stanza_set_type(response, STANZA_TYPE_RESULT); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_VERSION); xmpp_stanza_t *name = xmpp_stanza_new(ctx); xmpp_stanza_set_name(name, "name"); xmpp_stanza_t *name_txt = xmpp_stanza_new(ctx); xmpp_stanza_set_text(name_txt, "Profanity"); xmpp_stanza_add_child(name, name_txt); xmpp_stanza_t *version = xmpp_stanza_new(ctx); xmpp_stanza_set_name(version, "version"); xmpp_stanza_t *version_txt = xmpp_stanza_new(ctx); GString *version_str = g_string_new(PACKAGE_VERSION); if (strcmp(PACKAGE_STATUS, "development") == 0) { #ifdef HAVE_GIT_VERSION g_string_append(version_str, "dev."); g_string_append(version_str, PROF_GIT_BRANCH); g_string_append(version_str, "."); g_string_append(version_str, PROF_GIT_REVISION); #else g_string_append(version_str, "dev"); #endif } xmpp_stanza_set_text(version_txt, version_str->str); xmpp_stanza_add_child(version, version_txt); xmpp_stanza_add_child(query, name); xmpp_stanza_add_child(query, version); xmpp_stanza_add_child(response, query); xmpp_send(conn, response); g_string_free(version_str, TRUE); xmpp_stanza_release(name_txt); xmpp_stanza_release(version_txt); xmpp_stanza_release(name); xmpp_stanza_release(version); xmpp_stanza_release(query); xmpp_stanza_release(response); } return 1; } static int _disco_items_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (id) { log_debug("IQ disco items get handler fired, id: %s.", id); } else { log_debug("IQ disco items get handler fired."); } if (from) { xmpp_stanza_t *response = xmpp_stanza_new(ctx); xmpp_stanza_set_name(response, STANZA_NAME_IQ); xmpp_stanza_set_id(response, xmpp_stanza_get_id(stanza)); xmpp_stanza_set_attribute(response, STANZA_ATTR_TO, from); xmpp_stanza_set_type(response, STANZA_TYPE_RESULT); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, XMPP_NS_DISCO_ITEMS); xmpp_stanza_add_child(response, query); xmpp_send(conn, response); xmpp_stanza_release(response); } return 1; } static int _disco_info_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); xmpp_stanza_t *incoming_query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); const char *node_str = xmpp_stanza_get_attribute(incoming_query, STANZA_ATTR_NODE); const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); if (id) { log_debug("IQ disco info get handler fired, id: %s.", id); } else { log_debug("IQ disco info get handler fired."); } if (from) { xmpp_stanza_t *response = xmpp_stanza_new(ctx); xmpp_stanza_set_name(response, STANZA_NAME_IQ); xmpp_stanza_set_id(response, xmpp_stanza_get_id(stanza)); xmpp_stanza_set_attribute(response, STANZA_ATTR_TO, from); xmpp_stanza_set_type(response, STANZA_TYPE_RESULT); xmpp_stanza_t *query = caps_create_query_response_stanza(ctx); if (node_str) { xmpp_stanza_set_attribute(query, STANZA_ATTR_NODE, node_str); } xmpp_stanza_add_child(response, query); xmpp_send(conn, response); xmpp_stanza_release(query); xmpp_stanza_release(response); } return 1; } static int _destroy_room_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); if (id) { log_debug("IQ destroy room result handler fired, id: %s.", id); } else { log_debug("IQ destroy room result handler fired."); } const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (from == NULL) { log_error("No from attribute for IQ destroy room result"); } else { sv_ev_room_destroy(from); } return 0; } static int _room_config_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (id) { log_debug("IQ room config handler fired, id: %s.", id); } else { log_debug("IQ room config handler fired."); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); ui_handle_room_configuration_form_error(from, error_message); free(error_message); return 0; } if (from == NULL) { log_warning("No from attribute for IQ config request result"); ui_handle_room_configuration_form_error(from, "No from attribute for room cofig response."); return 0; } xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (query == NULL) { log_warning("No query element found parsing room config response"); ui_handle_room_configuration_form_error(from, "No query element found parsing room config response"); return 0; } xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(query, STANZA_NS_DATA); if (x == NULL) { log_warning("No x element found with %s namespace parsing room config response", STANZA_NS_DATA); ui_handle_room_configuration_form_error(from, "No form configuration options available"); return 0; } char *form_type = xmpp_stanza_get_attribute(x, STANZA_ATTR_TYPE); if (g_strcmp0(form_type, "form") != 0) { log_warning("x element not of type 'form' parsing room config response"); ui_handle_room_configuration_form_error(from, "Form not of type 'form' parsing room config response."); return 0; } DataForm *form = form_create(x); ui_handle_room_configuration(from, form); return 0; } static int _room_affiliation_set_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); struct privilege_set_t *affiliation_set = (struct privilege_set_t *)userdata; if (id) { log_debug("IQ affiliation set handler fired, id: %s.", id); } else { log_debug("IQ affiliation set handler fired."); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); log_debug("Error setting affiliation %s list for room %s, user %s: %s", affiliation_set->privilege, from, affiliation_set->item, error_message); ui_handle_room_affiliation_set_error(from, affiliation_set->item, affiliation_set->privilege, error_message); free(error_message); } free(affiliation_set->item); free(affiliation_set->privilege); free(affiliation_set); return 0; } static int _room_role_set_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); struct privilege_set_t *role_set = (struct privilege_set_t *)userdata; if (id) { log_debug("IQ role set handler fired, id: %s.", id); } else { log_debug("IQ role set handler fired."); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); log_debug("Error setting role %s list for room %s, user %s: %s", role_set->privilege, from, role_set->item, error_message); ui_handle_room_role_set_error(from, role_set->item, role_set->privilege, error_message); free(error_message); } free(role_set->item); free(role_set->privilege); free(role_set); return 0; } static int _room_affiliation_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); char *affiliation = (char *)userdata; if (id) { log_debug("IQ affiliation list result handler fired, id: %s.", id); } else { log_debug("IQ affiliation list result handler fired."); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); log_debug("Error retrieving %s list for room %s: %s", affiliation, from, error_message); ui_handle_room_affiliation_list_error(from, affiliation, error_message); free(error_message); free(affiliation); return 0; } GSList *jids = NULL; xmpp_stanza_t *query = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_ADMIN); if (query) { xmpp_stanza_t *child = xmpp_stanza_get_children(query); while (child) { char *name = xmpp_stanza_get_name(child); if (g_strcmp0(name, "item") == 0) { char *jid = xmpp_stanza_get_attribute(child, STANZA_ATTR_JID); if (jid) { jids = g_slist_insert_sorted(jids, jid, (GCompareFunc)g_strcmp0); } } child = xmpp_stanza_get_next(child); } } muc_jid_autocomplete_add_all(from, jids); ui_handle_room_affiliation_list(from, affiliation, jids); free(affiliation); g_slist_free(jids); return 0; } static int _room_role_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); char *role = (char *)userdata; if (id) { log_debug("IQ role list result handler fired, id: %s.", id); } else { log_debug("IQ role list result handler fired."); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); log_debug("Error retrieving %s list for room %s: %s", role, from, error_message); ui_handle_room_role_list_error(from, role, error_message); free(error_message); free(role); return 0; } GSList *nicks = NULL; xmpp_stanza_t *query = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_ADMIN); if (query) { xmpp_stanza_t *child = xmpp_stanza_get_children(query); while (child) { char *name = xmpp_stanza_get_name(child); if (g_strcmp0(name, "item") == 0) { char *nick = xmpp_stanza_get_attribute(child, STANZA_ATTR_NICK); if (nick) { nicks = g_slist_insert_sorted(nicks, nick, (GCompareFunc)g_strcmp0); } } child = xmpp_stanza_get_next(child); } } ui_handle_room_role_list(from, role, nicks); free(role); g_slist_free(nicks); return 0; } static int _room_config_submit_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (id) { log_debug("IQ room config submit handler fired, id: %s.", id); } else { log_debug("IQ room config submit handler fired."); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); ui_handle_room_config_submit_result_error(from, error_message); free(error_message); return 0; } ui_handle_room_config_submit_result(from); return 0; } static int _room_kick_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); char *nick = (char *)userdata; if (id) { log_debug("IQ kick result handler fired, id: %s.", id); } else { log_debug("IQ kick result handler fired."); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); ui_handle_room_kick_error(from, nick, error_message); free(error_message); free(nick); return 0; } free(nick); return 0; } static void _identity_destroy(DiscoIdentity *identity) { if (identity) { free(identity->name); free(identity->type); free(identity->category); free(identity); } } static void _item_destroy(DiscoItem *item) { if (item) { free(item->jid); free(item->name); free(item); } } static int _room_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *type = xmpp_stanza_get_type(stanza); ProfRoomInfoData *cb_data = (ProfRoomInfoData *)userdata; log_info("Received diso#info response for room: %s", cb_data->room); // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { if (cb_data->display) { char *error_message = stanza_get_error_message(stanza); ui_handle_room_info_error(cb_data->room, error_message); free(error_message); } free(cb_data->room); free(cb_data); return 0; } xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (query) { xmpp_stanza_t *child = xmpp_stanza_get_children(query); GSList *identities = NULL; GSList *features = NULL; while (child) { const char *stanza_name = xmpp_stanza_get_name(child); if (g_strcmp0(stanza_name, STANZA_NAME_FEATURE) == 0) { const char *var = xmpp_stanza_get_attribute(child, STANZA_ATTR_VAR); if (var) { features = g_slist_append(features, strdup(var)); } } else if (g_strcmp0(stanza_name, STANZA_NAME_IDENTITY) == 0) { const char *name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME); const char *type = xmpp_stanza_get_attribute(child, STANZA_ATTR_TYPE); const char *category = xmpp_stanza_get_attribute(child, STANZA_ATTR_CATEGORY); if (name || category || type) { DiscoIdentity *identity = malloc(sizeof(struct disco_identity_t)); if (name) { identity->name = strdup(name); } else { identity->name = NULL; } if (category) { identity->category = strdup(category); } else { identity->category = NULL; } if (type) { identity->type = strdup(type); } else { identity->type = NULL; } identities = g_slist_append(identities, identity); } } child = xmpp_stanza_get_next(child); } muc_set_features(cb_data->room, features); if (cb_data->display) { ui_show_room_disco_info(cb_data->room, identities, features); } g_slist_free_full(features, free); g_slist_free_full(identities, (GDestroyNotify)_identity_destroy); } free(cb_data->room); free(cb_data); return 0; } static int _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); const char *type = xmpp_stanza_get_type(stanza); if (from) { log_info("Received diso#info response from: %s", from); } else { log_info("Received diso#info response"); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); if (from) { cons_show_error("Service discovery failed for %s: %s", from, error_message); } else { cons_show_error("Service discovery failed: %s", error_message); } free(error_message); return 0; } xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (query) { xmpp_stanza_t *child = xmpp_stanza_get_children(query); GSList *identities = NULL; GSList *features = NULL; while (child) { const char *stanza_name = xmpp_stanza_get_name(child); if (g_strcmp0(stanza_name, STANZA_NAME_FEATURE) == 0) { const char *var = xmpp_stanza_get_attribute(child, STANZA_ATTR_VAR); if (var) { features = g_slist_append(features, strdup(var)); } } else if (g_strcmp0(stanza_name, STANZA_NAME_IDENTITY) == 0) { const char *name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME); const char *type = xmpp_stanza_get_attribute(child, STANZA_ATTR_TYPE); const char *category = xmpp_stanza_get_attribute(child, STANZA_ATTR_CATEGORY); if (name || category || type) { DiscoIdentity *identity = malloc(sizeof(struct disco_identity_t)); if (name) { identity->name = strdup(name); } else { identity->name = NULL; } if (category) { identity->category = strdup(category); } else { identity->category = NULL; } if (type) { identity->type = strdup(type); } else { identity->type = NULL; } identities = g_slist_append(identities, identity); } } child = xmpp_stanza_get_next(child); } cons_show_disco_info(from, identities, features); g_slist_free_full(features, free); g_slist_free_full(identities, (GDestroyNotify)_identity_destroy); } return 0; } static int _disco_items_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { log_debug("Received diso#items response"); const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); GSList *items = NULL; if ((g_strcmp0(id, "confreq") == 0) || (g_strcmp0(id, "discoitemsreq") == 0)) { log_debug("Response to query: %s", id); xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (query) { xmpp_stanza_t *child = xmpp_stanza_get_children(query); while (child) { const char *stanza_name = xmpp_stanza_get_name(child); if (stanza_name && (g_strcmp0(stanza_name, STANZA_NAME_ITEM) == 0)) { const char *item_jid = xmpp_stanza_get_attribute(child, STANZA_ATTR_JID); if (item_jid) { DiscoItem *item = malloc(sizeof(struct disco_item_t)); item->jid = strdup(item_jid); const char *item_name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME); if (item_name) { item->name = strdup(item_name); } else { item->name = NULL; } items = g_slist_append(items, item); } } child = xmpp_stanza_get_next(child); } } } if (g_strcmp0(id, "confreq") == 0) { cons_show_room_list(items, from); } else if (g_strcmp0(id, "discoitemsreq") == 0) { cons_show_disco_items(items, from); } g_slist_free_full(items, (GDestroyNotify)_item_destroy); return 1; } profanity-0.4.7/src/xmpp/iq.h000066400000000000000000000030771257755232500161160ustar00rootroot00000000000000/* * iq.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef XMPP_IQ_H #define XMPP_IQ_H void iq_add_handlers(void); void iq_roster_request(void); #endif profanity-0.4.7/src/xmpp/message.c000066400000000000000000000615231257755232500171240ustar00rootroot00000000000000/* * message.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include "chat_session.h" #include "config/preferences.h" #include "log.h" #include "muc.h" #include "profanity.h" #include "ui/ui.h" #include "event/server_events.h" #include "xmpp/connection.h" #include "xmpp/message.h" #include "xmpp/roster.h" #include "roster_list.h" #include "xmpp/stanza.h" #include "xmpp/xmpp.h" #include "pgp/gpg.h" #define HANDLE(ns, type, func) xmpp_handler_add(conn, func, ns, STANZA_NAME_MESSAGE, type, ctx) static int _groupchat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _chat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _conference_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _captcha_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _message_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _receipt_received_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); void message_add_handlers(void) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); HANDLE(NULL, STANZA_TYPE_ERROR, _message_error_handler); HANDLE(NULL, STANZA_TYPE_GROUPCHAT, _groupchat_handler); HANDLE(NULL, NULL, _chat_handler); HANDLE(STANZA_NS_MUC_USER, NULL, _muc_user_handler); HANDLE(STANZA_NS_CONFERENCE, NULL, _conference_handler); HANDLE(STANZA_NS_CAPTCHA, NULL, _captcha_handler); HANDLE(STANZA_NS_RECEIPTS, NULL, _receipt_received_handler); } static char* _session_jid(const char * const barejid) { ChatSession *session = chat_session_get(barejid); char *jid = NULL; if (session) { Jid *jidp = jid_create_from_bare_and_resource(session->barejid, session->resource); jid = strdup(jidp->fulljid); jid_destroy(jidp); } else { jid = strdup(barejid); } return jid; } static char* _session_state(const char * const barejid) { ChatSession *session = chat_session_get(barejid); char *state = NULL; if (session) { if (prefs_get_boolean(PREF_STATES) && session->send_states) { state = STANZA_NAME_ACTIVE; } } else { if (prefs_get_boolean(PREF_STATES)) { state = STANZA_NAME_ACTIVE; } } return state; } char * message_send_chat(const char * const barejid, const char * const msg) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *state = _session_state(barejid); char *jid = _session_jid(barejid); char *id = create_unique_id("msg"); xmpp_stanza_t *message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); free(jid); if (state) { stanza_attach_state(ctx, message, state); } if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) { stanza_attach_receipt_request(ctx, message); } xmpp_send(conn, message); xmpp_stanza_release(message); return id; } char * message_send_chat_pgp(const char * const barejid, const char * const msg) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *state = _session_state(barejid); char *jid = _session_jid(barejid); char *id = create_unique_id("msg"); xmpp_stanza_t *message = NULL; #ifdef HAVE_LIBGPGME char *account_name = jabber_get_account_name(); ProfAccount *account = accounts_get_account(account_name); if (account->pgp_keyid) { Jid *jidp = jid_create(jid); char *encrypted = p_gpg_encrypt(jidp->barejid, msg); if (encrypted) { message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, "This message is encrypted."); xmpp_stanza_t *x = xmpp_stanza_new(ctx); xmpp_stanza_set_name(x, STANZA_NAME_X); xmpp_stanza_set_ns(x, STANZA_NS_ENCRYPTED); xmpp_stanza_t *enc_st = xmpp_stanza_new(ctx); xmpp_stanza_set_text(enc_st, encrypted); xmpp_stanza_add_child(x, enc_st); xmpp_stanza_release(enc_st); xmpp_stanza_add_child(message, x); xmpp_stanza_release(x); free(encrypted); } else { message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); } jid_destroy(jidp); } else { message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); } account_free(account); #else message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); #endif free(jid); if (state) { stanza_attach_state(ctx, message, state); } stanza_attach_carbons_private(ctx, message); if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) { stanza_attach_receipt_request(ctx, message); } xmpp_send(conn, message); xmpp_stanza_release(message); return id; } char * message_send_chat_otr(const char * const barejid, const char * const msg) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *state = _session_state(barejid); char *jid = _session_jid(barejid); char *id = create_unique_id("msg"); xmpp_stanza_t *message = stanza_create_message(ctx, id, barejid, STANZA_TYPE_CHAT, msg); free(jid); if (state) { stanza_attach_state(ctx, message, state); } stanza_attach_carbons_private(ctx, message); stanza_attach_hints_no_copy(ctx, message); stanza_attach_hints_no_store(ctx, message); if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) { stanza_attach_receipt_request(ctx, message); } xmpp_send(conn, message); xmpp_stanza_release(message); return id; } void message_send_private(const char * const fulljid, const char * const msg) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = create_unique_id("prv"); xmpp_stanza_t *message = stanza_create_message(ctx, id, fulljid, STANZA_TYPE_CHAT, msg); free(id); xmpp_send(conn, message); xmpp_stanza_release(message); } void message_send_groupchat(const char * const roomjid, const char * const msg) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = create_unique_id("muc"); xmpp_stanza_t *message = stanza_create_message(ctx, id, roomjid, STANZA_TYPE_GROUPCHAT, msg); free(id); xmpp_send(conn, message); xmpp_stanza_release(message); } void message_send_groupchat_subject(const char * const roomjid, const char * const subject) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *message = stanza_create_room_subject_message(ctx, roomjid, subject); xmpp_send(conn, message); xmpp_stanza_release(message); } void message_send_invite(const char * const roomjid, const char * const contact, const char * const reason) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *stanza; muc_member_type_t member_type = muc_member_type(roomjid); if (member_type == MUC_MEMBER_TYPE_PUBLIC) { log_debug("Sending direct invite to %s, for %s", contact, roomjid); char *password = muc_password(roomjid); stanza = stanza_create_invite(ctx, roomjid, contact, reason, password); } else { log_debug("Sending mediated invite to %s, for %s", contact, roomjid); stanza = stanza_create_mediated_invite(ctx, roomjid, contact, reason); } xmpp_send(conn, stanza); xmpp_stanza_release(stanza); } void message_send_composing(const char * const jid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *stanza = stanza_create_chat_state(ctx, jid, STANZA_NAME_COMPOSING); xmpp_send(conn, stanza); xmpp_stanza_release(stanza); } void message_send_paused(const char * const jid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *stanza = stanza_create_chat_state(ctx, jid, STANZA_NAME_PAUSED); xmpp_send(conn, stanza); xmpp_stanza_release(stanza); } void message_send_inactive(const char * const jid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *stanza = stanza_create_chat_state(ctx, jid, STANZA_NAME_INACTIVE); xmpp_send(conn, stanza); xmpp_stanza_release(stanza); } void message_send_gone(const char * const jid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *stanza = stanza_create_chat_state(ctx, jid, STANZA_NAME_GONE); xmpp_send(conn, stanza); xmpp_stanza_release(stanza); } static int _message_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *id = xmpp_stanza_get_id(stanza); char *jid = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); xmpp_stanza_t *error_stanza = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); char *type = NULL; if (error_stanza) { type = xmpp_stanza_get_attribute(error_stanza, STANZA_ATTR_TYPE); } // stanza_get_error never returns NULL char *err_msg = stanza_get_error_message(stanza); GString *log_msg = g_string_new("message stanza error received"); if (id) { g_string_append(log_msg, " id="); g_string_append(log_msg, id); } if (jid) { g_string_append(log_msg, " from="); g_string_append(log_msg, jid); } if (type) { g_string_append(log_msg, " type="); g_string_append(log_msg, type); } g_string_append(log_msg, " error="); g_string_append(log_msg, err_msg); log_info(log_msg->str); g_string_free(log_msg, TRUE); if (!jid) { ui_handle_error(err_msg); } else if (type && (strcmp(type, "cancel") == 0)) { log_info("Recipient %s not found: %s", jid, err_msg); Jid *jidp = jid_create(jid); chat_session_remove(jidp->barejid); jid_destroy(jidp); } else { ui_handle_recipient_error(jid, err_msg); } free(err_msg); return 1; } static int _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *xns_muc_user = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); char *room = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!room) { log_warning("Message received with no from attribute, ignoring"); return 1; } // XEP-0045 xmpp_stanza_t *invite = xmpp_stanza_get_child_by_name(xns_muc_user, STANZA_NAME_INVITE); if (!invite) { return 1; } char *invitor_jid = xmpp_stanza_get_attribute(invite, STANZA_ATTR_FROM); if (!invitor_jid) { log_warning("Chat room invite received with no from attribute"); return 1; } Jid *jidp = jid_create(invitor_jid); if (!jidp) { return 1; } char *invitor = jidp->barejid; char *reason = NULL; xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_name(invite, STANZA_NAME_REASON); if (reason_st) { reason = xmpp_stanza_get_text(reason_st); } char *password = NULL; xmpp_stanza_t *password_st = xmpp_stanza_get_child_by_name(xns_muc_user, STANZA_NAME_PASSWORD); if (password_st) { password = xmpp_stanza_get_text(password_st); } sv_ev_room_invite(INVITE_MEDIATED, invitor, room, reason, password); jid_destroy(jidp); if (reason) { xmpp_free(ctx, reason); } if (password) { xmpp_free(ctx, password); } return 1; } static int _conference_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_stanza_t *xns_conference = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CONFERENCE); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!from) { log_warning("Message received with no from attribute, ignoring"); return 1; } Jid *jidp = jid_create(from); if (!jidp) { return 1; } // XEP-0249 char *room = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_JID); if (!room) { jid_destroy(jidp); return 1; } char *reason = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_REASON); char *password = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_PASSWORD); sv_ev_room_invite(INVITE_DIRECT, jidp->barejid, room, reason, password); jid_destroy(jidp); return 1; } static int _captcha_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!from) { log_warning("Message received with no from attribute, ignoring"); return 1; } // XEP-0158 xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); if (!body) { return 1; } char *message = xmpp_stanza_get_text(body); if (!message) { return 1; } sv_ev_room_broadcast(from, message); xmpp_free(ctx, message); return 1; } static int _groupchat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); char *message = NULL; char *room_jid = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); Jid *jid = jid_create(room_jid); // handle room subject xmpp_stanza_t *subject = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SUBJECT); if (subject) { message = xmpp_stanza_get_text(subject); sv_ev_room_subject(jid->barejid, jid->resourcepart, message); xmpp_free(ctx, message); jid_destroy(jid); return 1; } // handle room broadcasts if (!jid->resourcepart) { xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); if (!body) { jid_destroy(jid); return 1; } message = xmpp_stanza_get_text(body); if (!message) { jid_destroy(jid); return 1; } sv_ev_room_broadcast(room_jid, message); xmpp_free(ctx, message); jid_destroy(jid); return 1; } if (!jid_is_valid_room_form(jid)) { log_error("Invalid room JID: %s", jid->str); jid_destroy(jid); return 1; } // room not active in profanity if (!muc_active(jid->barejid)) { log_error("Message received for inactive chat room: %s", jid->str); jid_destroy(jid); return 1; } xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); // check for and deal with message if (!body) { jid_destroy(jid); return 1; } message = xmpp_stanza_get_text(body); if (!message) { jid_destroy(jid); return 1; } // determine if the notifications happened whilst offline GDateTime *timestamp = stanza_get_delay(stanza); if (timestamp) { sv_ev_room_history(jid->barejid, jid->resourcepart, timestamp, message); g_date_time_unref(timestamp); } else { sv_ev_room_message(jid->barejid, jid->resourcepart, message); } xmpp_free(ctx, message); jid_destroy(jid); return 1; } void _message_send_receipt(const char * const fulljid, const char * const message_id) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *message = xmpp_stanza_new(ctx); xmpp_stanza_set_name(message, STANZA_NAME_MESSAGE); char *id = create_unique_id("receipt"); xmpp_stanza_set_id(message, id); free(id); xmpp_stanza_set_attribute(message, STANZA_ATTR_TO, fulljid); xmpp_stanza_t *receipt = xmpp_stanza_new(ctx); xmpp_stanza_set_name(receipt, "received"); xmpp_stanza_set_ns(receipt, STANZA_NS_RECEIPTS); xmpp_stanza_set_attribute(receipt, STANZA_ATTR_ID, message_id); xmpp_stanza_add_child(message, receipt); xmpp_stanza_release(receipt); xmpp_send(conn, message); xmpp_stanza_release(message); } static int _receipt_received_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_stanza_t *receipt = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_RECEIPTS); char *name = xmpp_stanza_get_name(receipt); if (g_strcmp0(name, "received") != 0) { return 1; } char *id = xmpp_stanza_get_attribute(receipt, STANZA_ATTR_ID); if (!id) { return 1; } char *fulljid = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!fulljid) { return 1; } Jid *jidp = jid_create(fulljid); sv_ev_message_receipt(jidp->barejid, id); jid_destroy(jidp); return 1; } void _receipt_request_handler(xmpp_stanza_t * const stanza) { if (!prefs_get_boolean(PREF_RECEIPTS_SEND)) { return; } char *id = xmpp_stanza_get_id(stanza); if (!id) { return; } xmpp_stanza_t *receipts = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_RECEIPTS); if (!receipts) { return; } char *receipts_name = xmpp_stanza_get_name(receipts); if (g_strcmp0(receipts_name, "request") != 0) { return; } gchar *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); Jid *jid = jid_create(from); _message_send_receipt(jid->fulljid, id); jid_destroy(jid); } void _private_chat_handler(xmpp_stanza_t * const stanza, const char * const fulljid) { xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); if (!body) { return; } char *message = xmpp_stanza_get_text(body); if (!message) { return; } GDateTime *timestamp = stanza_get_delay(stanza); if (timestamp) { sv_ev_delayed_private_message(fulljid, message, timestamp); g_date_time_unref(timestamp); } else { sv_ev_incoming_private_message(fulljid, message); } xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_free(ctx, message); } static gboolean _handle_carbons(xmpp_stanza_t * const stanza) { xmpp_stanza_t *carbons = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CARBONS); if (!carbons) { return FALSE; } char *name = xmpp_stanza_get_name(carbons); if ((g_strcmp0(name, "received") == 0) || (g_strcmp0(name, "sent")) == 0) { xmpp_stanza_t *forwarded = xmpp_stanza_get_child_by_ns(carbons, STANZA_NS_FORWARD); xmpp_stanza_t *message = xmpp_stanza_get_child_by_name(forwarded, STANZA_NAME_MESSAGE); xmpp_ctx_t *ctx = connection_get_ctx(); gchar *to = xmpp_stanza_get_attribute(message, STANZA_ATTR_TO); gchar *from = xmpp_stanza_get_attribute(message, STANZA_ATTR_FROM); // happens when receive a carbon of a self sent message if (!to) to = from; Jid *jid_from = jid_create(from); Jid *jid_to = jid_create(to); Jid *my_jid = jid_create(jabber_get_fulljid()); // check for and deal with message xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(message, STANZA_NAME_BODY); if (body) { char *message = xmpp_stanza_get_text(body); if (message) { // if we are the recipient, treat as standard incoming message if(g_strcmp0(my_jid->barejid, jid_to->barejid) == 0){ sv_ev_incoming_carbon(jid_from->barejid, jid_from->resourcepart, message); } // else treat as a sent message else{ sv_ev_outgoing_carbon(jid_to->barejid, message); } xmpp_free(ctx, message); } } jid_destroy(jid_from); jid_destroy(jid_to); jid_destroy(my_jid); return TRUE; } return FALSE; } static int _chat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { // ignore if type not chat or absent char *type = xmpp_stanza_get_type(stanza); if (!(g_strcmp0(type, "chat") == 0 || type == NULL)) { return 1; } // check if carbon message gboolean res = _handle_carbons(stanza); if (res) { return 1; } // ignore handled namespaces xmpp_stanza_t *conf = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CONFERENCE); xmpp_stanza_t *captcha = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CAPTCHA); if (conf || captcha) { return 1; } // some clients send the mucuser namespace with private messages // if the namespace exists, and the stanza contains a body element, assume its a private message // otherwise exit the handler xmpp_stanza_t *mucuser = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); if (mucuser && body == NULL) { return 1; } gchar *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); Jid *jid = jid_create(from); // private message from chat room use full jid (room/nick) if (muc_active(jid->barejid)) { _private_chat_handler(stanza, jid->fulljid); jid_destroy(jid); return 1; } // standard chat message, use jid without resource xmpp_ctx_t *ctx = connection_get_ctx(); GDateTime *timestamp = stanza_get_delay(stanza); if (body) { char *message = xmpp_stanza_get_text(body); if (message) { char *enc_message = NULL; xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_ENCRYPTED); if (x) { enc_message = xmpp_stanza_get_text(x); } sv_ev_incoming_message(jid->barejid, jid->resourcepart, message, enc_message, timestamp); xmpp_free(ctx, enc_message); _receipt_request_handler(stanza); xmpp_free(ctx, message); } } // handle chat sessions and states if (!timestamp && jid->resourcepart) { gboolean gone = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_GONE) != NULL; gboolean typing = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_COMPOSING) != NULL; gboolean paused = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_PAUSED) != NULL; gboolean inactive = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_INACTIVE) != NULL; if (gone) { sv_ev_gone(jid->barejid, jid->resourcepart); } else if (typing) { sv_ev_typing(jid->barejid, jid->resourcepart); } else if (paused) { sv_ev_paused(jid->barejid, jid->resourcepart); } else if (inactive) { sv_ev_inactive(jid->barejid, jid->resourcepart); } else if (stanza_contains_chat_state(stanza)) { sv_ev_activity(jid->barejid, jid->resourcepart, TRUE); } else { sv_ev_activity(jid->barejid, jid->resourcepart, FALSE); } } if (timestamp) g_date_time_unref(timestamp); jid_destroy(jid); return 1; } profanity-0.4.7/src/xmpp/message.h000066400000000000000000000030651257755232500171260ustar00rootroot00000000000000/* * message.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef XMPP_MESSAGE_H #define XMPP_MESSAGE_H void message_add_handlers(void); #endif profanity-0.4.7/src/xmpp/presence.c000066400000000000000000000643151257755232500173060ustar00rootroot00000000000000/* * presence.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include #include "common.h" #include "config/preferences.h" #include "log.h" #include "muc.h" #include "profanity.h" #include "ui/ui.h" #include "event/server_events.h" #include "xmpp/capabilities.h" #include "xmpp/connection.h" #include "xmpp/stanza.h" #include "xmpp/xmpp.h" static Autocomplete sub_requests_ac; #define HANDLE(ns, type, func) xmpp_handler_add(conn, func, ns, \ STANZA_NAME_PRESENCE, type, ctx) static int _unavailable_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _subscribe_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _subscribed_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _unsubscribed_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _available_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _presence_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); void _send_caps_request(char *node, char *caps_key, char *id, char *from); static void _send_room_presence(xmpp_conn_t *conn, xmpp_stanza_t *presence); void presence_sub_requests_init(void) { sub_requests_ac = autocomplete_new(); } void presence_add_handlers(void) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); HANDLE(NULL, STANZA_TYPE_ERROR, _presence_error_handler); HANDLE(STANZA_NS_MUC_USER, NULL, _muc_user_handler); HANDLE(NULL, STANZA_TYPE_UNAVAILABLE, _unavailable_handler); HANDLE(NULL, STANZA_TYPE_SUBSCRIBE, _subscribe_handler); HANDLE(NULL, STANZA_TYPE_SUBSCRIBED, _subscribed_handler); HANDLE(NULL, STANZA_TYPE_UNSUBSCRIBED, _unsubscribed_handler); HANDLE(NULL, NULL, _available_handler); } void presence_subscription(const char * const jid, const jabber_subscr_t action) { assert(jid != NULL); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_conn_t * const conn = connection_get_conn(); const char *type = NULL; Jid *jidp = jid_create(jid); autocomplete_remove(sub_requests_ac, jidp->barejid); switch (action) { case PRESENCE_SUBSCRIBE: log_debug("Sending presence subscribe: %s", jid); type = STANZA_TYPE_SUBSCRIBE; break; case PRESENCE_SUBSCRIBED: log_debug("Sending presence subscribed: %s", jid); type = STANZA_TYPE_SUBSCRIBED; break; case PRESENCE_UNSUBSCRIBED: log_debug("Sending presence usubscribed: %s", jid); type = STANZA_TYPE_UNSUBSCRIBED; break; default: log_warning("Attempt to send unknown subscription action: %s", jid); break; } xmpp_stanza_t *presence = xmpp_stanza_new(ctx); char *id = create_unique_id("sub"); xmpp_stanza_set_id(presence, id); xmpp_stanza_set_name(presence, STANZA_NAME_PRESENCE); xmpp_stanza_set_type(presence, type); xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, jidp->barejid); xmpp_send(conn, presence); xmpp_stanza_release(presence); jid_destroy(jidp); free(id); } GSList * presence_get_subscription_requests(void) { return autocomplete_create_list(sub_requests_ac); } gint presence_sub_request_count(void) { return autocomplete_length(sub_requests_ac); } void presence_clear_sub_requests(void) { autocomplete_clear(sub_requests_ac); } char * presence_sub_request_find(const char * const search_str) { return autocomplete_complete(sub_requests_ac, search_str, TRUE); } gboolean presence_sub_request_exists(const char * const bare_jid) { gboolean result = FALSE; GSList *requests_p = autocomplete_create_list(sub_requests_ac); GSList *requests = requests_p; while (requests) { if (strcmp(requests->data, bare_jid) == 0) { result = TRUE; break; } requests = g_slist_next(requests); } if (requests_p) { g_slist_free_full(requests_p, free); } return result; } void presence_reset_sub_request_search(void) { autocomplete_reset(sub_requests_ac); } void presence_send(const resource_presence_t presence_type, const char * const msg, const int idle, char *signed_status) { if (jabber_get_connection_status() != JABBER_CONNECTED) { log_warning("Error setting presence, not connected."); return; } if (msg) { log_debug("Updating presence: %s, \"%s\"", string_from_resource_presence(presence_type), msg); } else { log_debug("Updating presence: %s", string_from_resource_presence(presence_type)); } xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_conn_t * const conn = connection_get_conn(); const int pri = accounts_get_priority_for_presence_type(jabber_get_account_name(), presence_type); const char *show = stanza_get_presence_string_from_type(presence_type); connection_set_presence_message(msg); connection_set_priority(pri); xmpp_stanza_t *presence = stanza_create_presence(ctx); char *id = create_unique_id("presence"); xmpp_stanza_set_id(presence, id); stanza_attach_show(ctx, presence, show); stanza_attach_status(ctx, presence, msg); if (signed_status) { xmpp_stanza_t *x = xmpp_stanza_new(ctx); xmpp_stanza_set_name(x, STANZA_NAME_X); xmpp_stanza_set_ns(x, STANZA_NS_SIGNED); xmpp_stanza_t *signed_text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(signed_text, signed_status); xmpp_stanza_add_child(x, signed_text); xmpp_stanza_release(signed_text); xmpp_stanza_add_child(presence, x); xmpp_stanza_release(x); } stanza_attach_priority(ctx, presence, pri); stanza_attach_last_activity(ctx, presence, idle); stanza_attach_caps(ctx, presence); xmpp_send(conn, presence); _send_room_presence(conn, presence); xmpp_stanza_release(presence); // set last presence for account const char *last = show; if (last == NULL) { last = STANZA_TEXT_ONLINE; } accounts_set_last_presence(jabber_get_account_name(), last); free(id); } static void _send_room_presence(xmpp_conn_t *conn, xmpp_stanza_t *presence) { GList *rooms_p = muc_rooms(); GList *rooms = rooms_p; while (rooms) { const char *room = rooms->data; const char *nick = muc_nick(room); if (nick) { char *full_room_jid = create_fulljid(room, nick); xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, full_room_jid); log_debug("Sending presence to room: %s", full_room_jid); xmpp_send(conn, presence); free(full_room_jid); } rooms = g_list_next(rooms); } if (rooms_p) { g_list_free(rooms_p); } } void presence_join_room(char *room, char *nick, char * passwd) { Jid *jid = jid_create_from_bare_and_resource(room, nick); log_debug("Sending room join presence to: %s", jid->fulljid); xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_conn_t *conn = connection_get_conn(); resource_presence_t presence_type = accounts_get_last_presence(jabber_get_account_name()); const char *show = stanza_get_presence_string_from_type(presence_type); char *status = jabber_get_presence_message(); int pri = accounts_get_priority_for_presence_type(jabber_get_account_name(), presence_type); xmpp_stanza_t *presence = stanza_create_room_join_presence(ctx, jid->fulljid, passwd); stanza_attach_show(ctx, presence, show); stanza_attach_status(ctx, presence, status); stanza_attach_priority(ctx, presence, pri); stanza_attach_caps(ctx, presence); xmpp_send(conn, presence); xmpp_stanza_release(presence); jid_destroy(jid); } void presence_change_room_nick(const char * const room, const char * const nick) { assert(room != NULL); assert(nick != NULL); log_debug("Sending room nickname change to: %s, nick: %s", room, nick); xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_conn_t *conn = connection_get_conn(); resource_presence_t presence_type = accounts_get_last_presence(jabber_get_account_name()); const char *show = stanza_get_presence_string_from_type(presence_type); char *status = jabber_get_presence_message(); int pri = accounts_get_priority_for_presence_type(jabber_get_account_name(), presence_type); char *full_room_jid = create_fulljid(room, nick); xmpp_stanza_t *presence = stanza_create_room_newnick_presence(ctx, full_room_jid); stanza_attach_show(ctx, presence, show); stanza_attach_status(ctx, presence, status); stanza_attach_priority(ctx, presence, pri); stanza_attach_caps(ctx, presence); xmpp_send(conn, presence); xmpp_stanza_release(presence); free(full_room_jid); } void presence_leave_chat_room(const char * const room_jid) { assert(room_jid != NULL); log_debug("Sending room leave presence to: %s", room_jid); xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_conn_t *conn = connection_get_conn(); char *nick = muc_nick(room_jid); if (nick) { xmpp_stanza_t *presence = stanza_create_room_leave_presence(ctx, room_jid, nick); xmpp_send(conn, presence); xmpp_stanza_release(presence); } } static int _presence_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *id = xmpp_stanza_get_id(stanza); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); xmpp_stanza_t *error_stanza = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_X); char *xmlns = NULL; if (x) { xmlns = xmpp_stanza_get_ns(x); } char *type = NULL; if (error_stanza) { type = xmpp_stanza_get_attribute(error_stanza, STANZA_ATTR_TYPE); } // handle MUC join errors if (g_strcmp0(xmlns, STANZA_NS_MUC) == 0) { Jid *fulljid = jid_create(from); char *error_cond = NULL; xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_ns(error_stanza, STANZA_NS_STANZAS); if (reason_st) { error_cond = xmpp_stanza_get_name(reason_st); } if (error_cond == NULL) { error_cond = "unknown"; } log_info("Error joining room: %s, reason: %s", fulljid->barejid, error_cond); if (muc_active(fulljid->barejid)) { muc_leave(fulljid->barejid); } ui_handle_room_join_error(fulljid->barejid, error_cond); jid_destroy(fulljid); return 1; } // stanza_get_error never returns NULL char *err_msg = stanza_get_error_message(stanza); GString *log_msg = g_string_new("presence stanza error received"); if (id) { g_string_append(log_msg, " id="); g_string_append(log_msg, id); } if (from) { g_string_append(log_msg, " from="); g_string_append(log_msg, from); } if (type) { g_string_append(log_msg, " type="); g_string_append(log_msg, type); } g_string_append(log_msg, " error="); g_string_append(log_msg, err_msg); log_info(log_msg->str); g_string_free(log_msg, TRUE); if (from) { ui_handle_recipient_error(from, err_msg); } else { ui_handle_error(err_msg); } free(err_msg); return 1; } static int _unsubscribed_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); Jid *from_jid = jid_create(from); log_debug("Unsubscribed presence handler fired for %s", from); sv_ev_subscription(from_jid->barejid, PRESENCE_UNSUBSCRIBED); autocomplete_remove(sub_requests_ac, from_jid->barejid); jid_destroy(from_jid); return 1; } static int _subscribed_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); Jid *from_jid = jid_create(from); log_debug("Subscribed presence handler fired for %s", from); sv_ev_subscription(from_jid->barejid, PRESENCE_SUBSCRIBED); autocomplete_remove(sub_requests_ac, from_jid->barejid); jid_destroy(from_jid); return 1; } static int _subscribe_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); log_debug("Subscribe presence handler fired for %s", from); Jid *from_jid = jid_create(from); if (from_jid == NULL) { return 1; } sv_ev_subscription(from_jid->barejid, PRESENCE_SUBSCRIBE); autocomplete_add(sub_requests_ac, from_jid->barejid); jid_destroy(from_jid); return 1; } static int _unavailable_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { ui_input_nonblocking(TRUE); const char *jid = xmpp_conn_get_jid(conn); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); log_debug("Unavailable presence handler fired for %s", from); Jid *my_jid = jid_create(jid); Jid *from_jid = jid_create(from); if (my_jid == NULL || from_jid == NULL) { jid_destroy(my_jid); jid_destroy(from_jid); return 1; } char *status_str = stanza_get_status(stanza, NULL); if (strcmp(my_jid->barejid, from_jid->barejid) !=0) { if (from_jid->resourcepart) { sv_ev_contact_offline(from_jid->barejid, from_jid->resourcepart, status_str); // hack for servers that do not send full jid with unavailable presence } else { sv_ev_contact_offline(from_jid->barejid, "__prof_default", status_str); } } else { if (from_jid->resourcepart) { connection_remove_available_resource(from_jid->resourcepart); } } free(status_str); jid_destroy(my_jid); jid_destroy(from_jid); return 1; } static void _handle_caps(char *jid, XMPPCaps *caps) { // hash supported, xep-0115, cache against ver if (g_strcmp0(caps->hash, "sha-1") == 0) { log_info("Hash %s supported", caps->hash); if (caps->ver) { if (caps_contains(caps->ver)) { log_info("Capabilities cache hit: %s, for %s.", caps->ver, jid); caps_map_jid_to_ver(jid, caps->ver); } else { log_info("Capabilities cache miss: %s, for %s, sending service discovery request", caps->ver, jid); char *id = create_unique_id("caps"); iq_send_caps_request(jid, id, caps->node, caps->ver); free(id); } } // unsupported hash, xep-0115, associate with JID, no cache } else if (caps->hash) { log_info("Hash %s not supported: %s, sending service discovery request", caps->hash, jid); char *id = create_unique_id("caps"); iq_send_caps_request_for_jid(jid, id, caps->node, caps->ver); free(id); // no hash, legacy caps, cache against node#ver } else if (caps->node && caps->ver) { log_info("No hash specified: %s, legacy request made for %s#%s", jid, caps->node, caps->ver); char *id = create_unique_id("caps"); iq_send_caps_request_legacy(jid, id, caps->node, caps->ver); free(id); } else { log_info("No hash specified: %s, could not create ver string, not sending service disovery request.", jid); } } static int _available_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { ui_input_nonblocking(TRUE); // handler still fires if error if (g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_ERROR) == 0) { return 1; } // handler still fires if other types if ((g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_UNAVAILABLE) == 0) || (g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_SUBSCRIBE) == 0) || (g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_SUBSCRIBED) == 0) || (g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_UNSUBSCRIBED) == 0)) { return 1; } // handler still fires for muc presence if (stanza_is_muc_presence(stanza)) { return 1; } int err = 0; XMPPPresence *xmpp_presence = stanza_parse_presence(stanza, &err); if (!xmpp_presence) { char *from = NULL; switch(err) { case STANZA_PARSE_ERROR_NO_FROM: log_warning("Available presence handler fired with no from attribute."); break; case STANZA_PARSE_ERROR_INVALID_FROM: from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); log_warning("Available presence handler fired with invalid from attribute: %s", from); break; default: log_warning("Available presence handler fired, could not parse stanza."); break; } return 1; } else { char *jid = jid_fulljid_or_barejid(xmpp_presence->jid); log_debug("Presence available handler fired for: %s", jid); } const char *my_jid_str = xmpp_conn_get_jid(conn); Jid *my_jid = jid_create(my_jid_str); XMPPCaps *caps = stanza_parse_caps(stanza); if ((g_strcmp0(my_jid->fulljid, xmpp_presence->jid->fulljid) != 0) && caps) { log_info("Presence contains capabilities."); char *jid = jid_fulljid_or_barejid(xmpp_presence->jid); _handle_caps(jid, caps); } stanza_free_caps(caps); Resource *resource = stanza_resource_from_presence(xmpp_presence); if (g_strcmp0(xmpp_presence->jid->barejid, my_jid->barejid) == 0) { connection_add_available_resource(resource); } else { char *pgpsig = NULL; xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_SIGNED); if (x) { pgpsig = xmpp_stanza_get_text(x); } sv_ev_contact_online(xmpp_presence->jid->barejid, resource, xmpp_presence->last_activity, pgpsig); xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_free(ctx, pgpsig); } jid_destroy(my_jid); stanza_free_presence(xmpp_presence); return 1; } void _send_caps_request(char *node, char *caps_key, char *id, char *from) { xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_conn_t *conn = connection_get_conn(); if (node) { log_debug("Node string: %s.", node); if (!caps_contains(caps_key)) { log_debug("Capabilities not cached for '%s', sending discovery IQ.", from); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, from, node); xmpp_send(conn, iq); xmpp_stanza_release(iq); } else { log_debug("Capabilities already cached, for %s", caps_key); } } else { log_debug("No node string, not sending discovery IQ."); } } static int _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { ui_input_nonblocking(TRUE); char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); // handler still fires if error if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { return 1; } // invalid from attribute Jid *from_jid = jid_create(from); if (from_jid == NULL || from_jid->resourcepart == NULL) { jid_destroy(from_jid); return 1; } char *room = from_jid->barejid; char *nick = from_jid->resourcepart; char *show_str = stanza_get_show(stanza, "online"); char *status_str = stanza_get_status(stanza, NULL); char *jid = NULL; char *role = NULL; char *affiliation = NULL; xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(x, STANZA_NAME_ITEM); if (item) { jid = xmpp_stanza_get_attribute(item, "jid"); role = xmpp_stanza_get_attribute(item, "role"); affiliation = xmpp_stanza_get_attribute(item, "affiliation"); } } // handle self presence if (stanza_is_muc_self_presence(stanza, jabber_get_fulljid())) { log_debug("Room self presence received from %s", from_jid->fulljid); // self unavailable if (g_strcmp0(type, STANZA_TYPE_UNAVAILABLE) == 0) { // handle nickname change char *new_nick = stanza_get_new_nick(stanza); if (new_nick) { muc_nick_change_start(room, new_nick); } else { GSList *status_codes = stanza_get_status_codes_by_ns(stanza, STANZA_NS_MUC_USER); // room destroyed if (stanza_room_destroyed(stanza)) { char *new_jid = stanza_get_muc_destroy_alternative_room(stanza); char *password = stanza_get_muc_destroy_alternative_password(stanza); char *reason = stanza_get_muc_destroy_reason(stanza); sv_ev_room_destroyed(room, new_jid, password, reason); free(password); free(reason); // kicked from room } else if (g_slist_find_custom(status_codes, "307", (GCompareFunc)g_strcmp0)) { char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); sv_ev_room_kicked(room, actor, reason); free(reason); // banned from room } else if (g_slist_find_custom(status_codes, "301", (GCompareFunc)g_strcmp0)) { char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); sv_ev_room_banned(room, actor, reason); free(reason); // normal exit } else { sv_ev_leave_room(room); } g_slist_free_full(status_codes, free); } // self online } else { gboolean config_required = stanza_muc_requires_config(stanza); char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); sv_ev_muc_self_online(room, nick, config_required, role, affiliation, actor, reason, jid, show_str, status_str); } // handle presence from room members } else { log_debug("Room presence received from %s", from_jid->fulljid); if (g_strcmp0(type, STANZA_TYPE_UNAVAILABLE) == 0) { // handle nickname change char *new_nick = stanza_get_new_nick(stanza); if (new_nick) { muc_occupant_nick_change_start(room, new_nick, nick); // handle left room } else { GSList *status_codes = stanza_get_status_codes_by_ns(stanza, STANZA_NS_MUC_USER); // kicked from room if (g_slist_find_custom(status_codes, "307", (GCompareFunc)g_strcmp0)) { char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); sv_ev_room_occupent_kicked(room, nick, actor, reason); free(reason); // banned from room } else if (g_slist_find_custom(status_codes, "301", (GCompareFunc)g_strcmp0)) { char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); sv_ev_room_occupent_banned(room, nick, actor, reason); free(reason); // normal exit } else { sv_ev_room_occupant_offline(room, nick, "offline", status_str); } g_slist_free_full(status_codes, free); } // room occupant online } else { // send disco info for capabilities, if not cached XMPPCaps *caps = stanza_parse_caps(stanza); if (caps) { log_info("Presence contains capabilities."); _handle_caps(from, caps); } stanza_free_caps(caps); char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); sv_ev_muc_occupant_online(room, nick, jid, role, affiliation, actor, reason, show_str, status_str); } } free(show_str); free(status_str); jid_destroy(from_jid); return 1; } profanity-0.4.7/src/xmpp/presence.h000066400000000000000000000032101257755232500172760ustar00rootroot00000000000000/* * presence.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef XMPP_PRESENCE_H #define XMPP_PRESENCE_H void presence_sub_requests_init(void); void presence_add_handlers(void); void presence_clear_sub_requests(void); #endif profanity-0.4.7/src/xmpp/roster.c000066400000000000000000000262151257755232500170150ustar00rootroot00000000000000/* * roster.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include #include "log.h" #include "profanity.h" #include "ui/ui.h" #include "event/server_events.h" #include "event/client_events.h" #include "tools/autocomplete.h" #include "xmpp/connection.h" #include "xmpp/roster.h" #include "roster_list.h" #include "xmpp/stanza.h" #include "xmpp/xmpp.h" #define HANDLE(type, func) xmpp_handler_add(conn, func, XMPP_NS_ROSTER, \ STANZA_NAME_IQ, type, ctx) // callback data for group commands typedef struct _group_data { char *name; char *group; } GroupData; // event handlers static int _roster_set_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _roster_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); // id handlers static int _group_add_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _group_remove_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); // helper functions GSList * _get_groups_from_item(xmpp_stanza_t *item); void roster_add_handlers(void) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); HANDLE(STANZA_TYPE_SET, _roster_set_handler); HANDLE(STANZA_TYPE_RESULT, _roster_result_handler); } void roster_request(void) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_roster_iq(ctx); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void roster_send_add_new(const char * const barejid, const char * const name) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = create_unique_id("roster"); xmpp_stanza_t *iq = stanza_create_roster_set(ctx, id, barejid, name, NULL); free(id); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void roster_send_remove(const char * const barejid) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_stanza_t *iq = stanza_create_roster_remove_set(ctx, barejid); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void roster_send_name_change(const char * const barejid, const char * const new_name, GSList *groups) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = create_unique_id("roster"); xmpp_stanza_t *iq = stanza_create_roster_set(ctx, id, barejid, new_name, groups); free(id); xmpp_send(conn, iq); xmpp_stanza_release(iq); } void roster_send_add_to_group(const char * const group, PContact contact) { GSList *groups = p_contact_groups(contact); GSList *new_groups = NULL; while (groups) { new_groups = g_slist_append(new_groups, strdup(groups->data)); groups = g_slist_next(groups); } new_groups = g_slist_append(new_groups, strdup(group)); // add an id handler to handle the response char *unique_id = create_unique_id(NULL); GroupData *data = malloc(sizeof(GroupData)); data->group = strdup(group); if (p_contact_name(contact)) { data->name = strdup(p_contact_name(contact)); } else { data->name = strdup(p_contact_barejid(contact)); } xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_id_handler_add(conn, _group_add_handler, unique_id, data); xmpp_stanza_t *iq = stanza_create_roster_set(ctx, unique_id, p_contact_barejid(contact), p_contact_name(contact), new_groups); xmpp_send(conn, iq); xmpp_stanza_release(iq); free(unique_id); } static int _group_add_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { if (userdata) { GroupData *data = userdata; ui_group_added(data->name, data->group); free(data->name); free(data->group); free(userdata); } return 0; } void roster_send_remove_from_group(const char * const group, PContact contact) { GSList *groups = p_contact_groups(contact); GSList *new_groups = NULL; while (groups) { if (strcmp(groups->data, group) != 0) { new_groups = g_slist_append(new_groups, strdup(groups->data)); } groups = g_slist_next(groups); } xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); // add an id handler to handle the response char *unique_id = create_unique_id(NULL); GroupData *data = malloc(sizeof(GroupData)); data->group = strdup(group); if (p_contact_name(contact)) { data->name = strdup(p_contact_name(contact)); } else { data->name = strdup(p_contact_barejid(contact)); } xmpp_id_handler_add(conn, _group_remove_handler, unique_id, data); xmpp_stanza_t *iq = stanza_create_roster_set(ctx, unique_id, p_contact_barejid(contact), p_contact_name(contact), new_groups); xmpp_send(conn, iq); xmpp_stanza_release(iq); free(unique_id); } static int _group_remove_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { if (userdata) { GroupData *data = userdata; ui_group_removed(data->name, data->group); free(data->name); free(data->group); free(userdata); } return 0; } static int _roster_set_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(query, STANZA_NAME_ITEM); if (item == NULL) { return 1; } // if from attribute exists and it is not current users barejid, ignore push Jid *my_jid = jid_create(jabber_get_fulljid()); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (from && (strcmp(from, my_jid->barejid) != 0)) { jid_destroy(my_jid); return 1; } jid_destroy(my_jid); const char *barejid = xmpp_stanza_get_attribute(item, STANZA_ATTR_JID); gchar *barejid_lower = g_utf8_strdown(barejid, -1); const char *name = xmpp_stanza_get_attribute(item, STANZA_ATTR_NAME); const char *sub = xmpp_stanza_get_attribute(item, STANZA_ATTR_SUBSCRIPTION); const char *ask = xmpp_stanza_get_attribute(item, STANZA_ATTR_ASK); // do not set nickname to empty string, set to NULL instead if (name && (strlen(name) == 0)) { name = NULL; } // remove from roster if (g_strcmp0(sub, "remove") == 0) { // remove barejid and name if (name == NULL) { name = barejid_lower; } roster_remove(name, barejid_lower); ui_roster_remove(barejid_lower); // otherwise update local roster } else { // check for pending out subscriptions gboolean pending_out = FALSE; if (ask && (strcmp(ask, "subscribe") == 0)) { pending_out = TRUE; } GSList *groups = _get_groups_from_item(item); // update the local roster PContact contact = roster_get_contact(barejid_lower); if (contact == NULL) { gboolean added = roster_add(barejid_lower, name, groups, sub, pending_out); if (added) { ui_roster_add(barejid_lower, name); } } else { sv_ev_roster_update(barejid_lower, name, groups, sub, pending_out); } } g_free(barejid_lower); return 1; } static int _roster_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); if (g_strcmp0(id, "roster") != 0) { return 1; } // handle initial roster response xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); xmpp_stanza_t *item = xmpp_stanza_get_children(query); while (item) { const char *barejid = xmpp_stanza_get_attribute(item, STANZA_ATTR_JID); gchar *barejid_lower = g_utf8_strdown(barejid, -1); const char *name = xmpp_stanza_get_attribute(item, STANZA_ATTR_NAME); const char *sub = xmpp_stanza_get_attribute(item, STANZA_ATTR_SUBSCRIPTION); // do not set nickname to empty string, set to NULL instead if (name && (strlen(name) == 0)) name = NULL; gboolean pending_out = FALSE; const char *ask = xmpp_stanza_get_attribute(item, STANZA_ATTR_ASK); if (g_strcmp0(ask, "subscribe") == 0) { pending_out = TRUE; } GSList *groups = _get_groups_from_item(item); gboolean added = roster_add(barejid_lower, name, groups, sub, pending_out); if (!added) { log_warning("Attempt to add contact twice: %s", barejid_lower); } g_free(barejid_lower); item = xmpp_stanza_get_next(item); } sv_ev_roster_received(); resource_presence_t conn_presence = accounts_get_login_presence(jabber_get_account_name()); cl_ev_presence_send(conn_presence, NULL, 0); return 1; } GSList * _get_groups_from_item(xmpp_stanza_t *item) { GSList *groups = NULL; xmpp_stanza_t *group_element = xmpp_stanza_get_children(item); while (group_element) { if (strcmp(xmpp_stanza_get_name(group_element), STANZA_NAME_GROUP) == 0) { char *groupname = xmpp_stanza_get_text(group_element); if (groupname) { groups = g_slist_append(groups, groupname); } } group_element = xmpp_stanza_get_next(group_element); } return groups; } profanity-0.4.7/src/xmpp/roster.h000066400000000000000000000031141257755232500170130ustar00rootroot00000000000000/* * roster.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef XMPP_ROSTER_H #define XMPP_ROSTER_H void roster_add_handlers(void); void roster_request(void); #endif profanity-0.4.7/src/xmpp/stanza.c000066400000000000000000001562671257755232500170120ustar00rootroot00000000000000/* * stanza.c * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include #include #include #include #include "common.h" #include "log.h" #include "xmpp/connection.h" #include "xmpp/stanza.h" #include "xmpp/capabilities.h" #include "xmpp/form.h" #include "muc.h" #if 0 xmpp_stanza_t * stanza_create_bookmarks_pubsub_request(xmpp_ctx_t *ctx) { xmpp_stanza_t *iq, *pubsub, *items; /* TODO: check pointers for NULL */ iq = xmpp_stanza_new(ctx); pubsub = xmpp_stanza_new(ctx); items = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); xmpp_stanza_set_name(pubsub, STANZA_NAME_PUBSUB); xmpp_stanza_set_ns(pubsub, STANZA_NS_PUBSUB); xmpp_stanza_set_name(items, STANZA_NAME_ITEMS); xmpp_stanza_set_attribute(items, "node", "storage:bookmarks"); xmpp_stanza_add_child(pubsub, items); xmpp_stanza_add_child(iq, pubsub); xmpp_stanza_release(items); xmpp_stanza_release(pubsub); return iq; } #endif xmpp_stanza_t * stanza_create_bookmarks_storage_request(xmpp_ctx_t *ctx) { xmpp_stanza_t *iq, *query, *storage; /* TODO: check pointers for NULL */ iq = xmpp_stanza_new(ctx); query = xmpp_stanza_new(ctx); storage = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); xmpp_stanza_set_ns(iq, "jabber:client"); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, "jabber:iq:private"); xmpp_stanza_set_name(storage, STANZA_NAME_STORAGE); xmpp_stanza_set_ns(storage, "storage:bookmarks"); xmpp_stanza_add_child(query, storage); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(storage); xmpp_stanza_release(query); return iq; } #if 0 xmpp_stanza_t * stanza_create_bookmarks_pubsub_add(xmpp_ctx_t *ctx, const char * const jid, const gboolean autojoin, const char * const nick) { xmpp_stanza_t *stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_name(stanza, STANZA_NAME_IQ); char *id = create_unique_id("bookmark_add"); xmpp_stanza_set_id(stanza, id); free(id); xmpp_stanza_set_type(stanza, STANZA_TYPE_SET); xmpp_stanza_t *pubsub = xmpp_stanza_new(ctx); xmpp_stanza_set_name(pubsub, STANZA_NAME_PUBSUB); xmpp_stanza_set_ns(pubsub, STANZA_NS_PUBSUB); xmpp_stanza_add_child(stanza, pubsub); xmpp_stanza_t *publish = xmpp_stanza_new(ctx); xmpp_stanza_set_name(publish, STANZA_NAME_PUBLISH); xmpp_stanza_set_attribute(publish, STANZA_ATTR_NODE, "storage:bookmarks"); xmpp_stanza_add_child(pubsub, publish); xmpp_stanza_t *item = xmpp_stanza_new(ctx); xmpp_stanza_set_name(item, STANZA_NAME_ITEM); xmpp_stanza_add_child(publish, item); xmpp_stanza_t *conference = xmpp_stanza_new(ctx); xmpp_stanza_set_name(conference, STANZA_NAME_CONFERENCE); xmpp_stanza_set_ns(conference, "storage:bookmarks"); xmpp_stanza_set_attribute(conference, STANZA_ATTR_JID, jid); if (autojoin) { xmpp_stanza_set_attribute(conference, STANZA_ATTR_AUTOJOIN, "true"); } else { xmpp_stanza_set_attribute(conference, STANZA_ATTR_AUTOJOIN, "false"); } if (nick) { xmpp_stanza_t *nick_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(nick_st, STANZA_NAME_NICK); xmpp_stanza_set_text(nick_st, nick); xmpp_stanza_add_child(conference, nick_st); } xmpp_stanza_add_child(item, conference); xmpp_stanza_t *publish_options = xmpp_stanza_new(ctx); xmpp_stanza_set_name(publish_options, STANZA_NAME_PUBLISH_OPTIONS); xmpp_stanza_add_child(pubsub, publish_options); xmpp_stanza_t *x = xmpp_stanza_new(ctx); xmpp_stanza_set_name(x, STANZA_NAME_X); xmpp_stanza_set_ns(x, STANZA_NS_DATA); xmpp_stanza_set_attribute(x, STANZA_ATTR_TYPE, "submit"); xmpp_stanza_add_child(publish_options, x); xmpp_stanza_t *form_type = xmpp_stanza_new(ctx); xmpp_stanza_set_name(form_type, STANZA_NAME_FIELD); xmpp_stanza_set_attribute(form_type, STANZA_ATTR_VAR, "FORM_TYPE"); xmpp_stanza_set_attribute(form_type, STANZA_ATTR_TYPE, "hidden"); xmpp_stanza_t *form_type_value = xmpp_stanza_new(ctx); xmpp_stanza_set_name(form_type_value, STANZA_NAME_VALUE); xmpp_stanza_t *form_type_value_text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(form_type_value_text, "http://jabber.org/protocol/pubsub#publish-options"); xmpp_stanza_add_child(form_type_value, form_type_value_text); xmpp_stanza_add_child(form_type, form_type_value); xmpp_stanza_add_child(x, form_type); xmpp_stanza_t *persist_items = xmpp_stanza_new(ctx); xmpp_stanza_set_name(persist_items, STANZA_NAME_FIELD); xmpp_stanza_set_attribute(persist_items, STANZA_ATTR_VAR, "pubsub#persist_items"); xmpp_stanza_t *persist_items_value = xmpp_stanza_new(ctx); xmpp_stanza_set_name(persist_items_value, STANZA_NAME_VALUE); xmpp_stanza_t *persist_items_value_text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(persist_items_value_text, "true"); xmpp_stanza_add_child(persist_items_value, persist_items_value_text); xmpp_stanza_add_child(persist_items, persist_items_value); xmpp_stanza_add_child(x, persist_items); xmpp_stanza_t *access_model = xmpp_stanza_new(ctx); xmpp_stanza_set_name(access_model, STANZA_NAME_FIELD); xmpp_stanza_set_attribute(access_model, STANZA_ATTR_VAR, "pubsub#access_model"); xmpp_stanza_t *access_model_value = xmpp_stanza_new(ctx); xmpp_stanza_set_name(access_model_value, STANZA_NAME_VALUE); xmpp_stanza_t *access_model_value_text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(access_model_value_text, "whitelist"); xmpp_stanza_add_child(access_model_value, access_model_value_text); xmpp_stanza_add_child(access_model, access_model_value); xmpp_stanza_add_child(x, access_model); return stanza; } #endif xmpp_stanza_t * stanza_enable_carbons(xmpp_ctx_t *ctx){ xmpp_stanza_t *iq = xmpp_stanza_new(ctx); char *id = create_unique_id("carbons"); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *carbons_enable = xmpp_stanza_new(ctx); xmpp_stanza_set_name(carbons_enable, STANZA_NAME_ENABLE); xmpp_stanza_set_ns(carbons_enable, STANZA_NS_CARBONS); xmpp_stanza_add_child(iq, carbons_enable); xmpp_stanza_release(carbons_enable); return iq; } xmpp_stanza_t * stanza_disable_carbons(xmpp_ctx_t *ctx){ xmpp_stanza_t *iq = xmpp_stanza_new(ctx); char *id = create_unique_id("carbons"); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *carbons_disable = xmpp_stanza_new(ctx); xmpp_stanza_set_name(carbons_disable, STANZA_NAME_DISABLE); xmpp_stanza_set_ns(carbons_disable, STANZA_NS_CARBONS); xmpp_stanza_add_child(iq, carbons_disable); xmpp_stanza_release(carbons_disable); return iq; } xmpp_stanza_t * stanza_create_chat_state(xmpp_ctx_t *ctx, const char * const fulljid, const char * const state) { xmpp_stanza_t *msg, *chat_state; msg = xmpp_stanza_new(ctx); xmpp_stanza_set_name(msg, STANZA_NAME_MESSAGE); xmpp_stanza_set_type(msg, STANZA_TYPE_CHAT); xmpp_stanza_set_attribute(msg, STANZA_ATTR_TO, fulljid); char *id = create_unique_id(NULL); xmpp_stanza_set_id(msg, id); free(id); chat_state = xmpp_stanza_new(ctx); xmpp_stanza_set_name(chat_state, state); xmpp_stanza_set_ns(chat_state, STANZA_NS_CHATSTATES); xmpp_stanza_add_child(msg, chat_state); xmpp_stanza_release(chat_state); return msg; } xmpp_stanza_t * stanza_create_room_subject_message(xmpp_ctx_t *ctx, const char * const room, const char * const subject) { xmpp_stanza_t *msg = xmpp_stanza_new(ctx); xmpp_stanza_set_name(msg, STANZA_NAME_MESSAGE); xmpp_stanza_set_type(msg, STANZA_TYPE_GROUPCHAT); xmpp_stanza_set_attribute(msg, STANZA_ATTR_TO, room); xmpp_stanza_t *subject_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(subject_st, STANZA_NAME_SUBJECT); if (subject) { xmpp_stanza_t *subject_text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(subject_text, subject); xmpp_stanza_add_child(subject_st, subject_text); xmpp_stanza_release(subject_text); } xmpp_stanza_add_child(msg, subject_st); xmpp_stanza_release(subject_st); return msg; } xmpp_stanza_t * stanza_attach_state(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char * const state) { xmpp_stanza_t *chat_state = xmpp_stanza_new(ctx); xmpp_stanza_set_name(chat_state, state); xmpp_stanza_set_ns(chat_state, STANZA_NS_CHATSTATES); xmpp_stanza_add_child(stanza, chat_state); xmpp_stanza_release(chat_state); return stanza; } xmpp_stanza_t * stanza_attach_carbons_private(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza) { xmpp_stanza_t *private_carbon = xmpp_stanza_new(ctx); xmpp_stanza_set_name(private_carbon, "private"); xmpp_stanza_set_ns(private_carbon, STANZA_NS_CARBONS); xmpp_stanza_add_child(stanza, private_carbon); xmpp_stanza_release(private_carbon); return stanza; } xmpp_stanza_t * stanza_attach_hints_no_copy(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza) { xmpp_stanza_t *no_copy = xmpp_stanza_new(ctx); xmpp_stanza_set_name(no_copy, "no-copy"); xmpp_stanza_set_ns(no_copy, STANZA_NS_HINTS); xmpp_stanza_add_child(stanza, no_copy); xmpp_stanza_release(no_copy); return stanza; } xmpp_stanza_t * stanza_attach_hints_no_store(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza) { xmpp_stanza_t *no_store = xmpp_stanza_new(ctx); xmpp_stanza_set_name(no_store, "no-store"); xmpp_stanza_set_ns(no_store, STANZA_NS_HINTS); xmpp_stanza_add_child(stanza, no_store); xmpp_stanza_release(no_store); return stanza; } xmpp_stanza_t * stanza_attach_receipt_request(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza) { xmpp_stanza_t *receipet_request = xmpp_stanza_new(ctx); xmpp_stanza_set_name(receipet_request, "request"); xmpp_stanza_set_ns(receipet_request, STANZA_NS_RECEIPTS); xmpp_stanza_add_child(stanza, receipet_request); xmpp_stanza_release(receipet_request); return stanza; } xmpp_stanza_t * stanza_create_message(xmpp_ctx_t *ctx, char *id, const char * const recipient, const char * const type, const char * const message) { xmpp_stanza_t *msg, *body, *text; msg = xmpp_stanza_new(ctx); xmpp_stanza_set_name(msg, STANZA_NAME_MESSAGE); xmpp_stanza_set_type(msg, type); xmpp_stanza_set_attribute(msg, STANZA_ATTR_TO, recipient); xmpp_stanza_set_id(msg, id); body = xmpp_stanza_new(ctx); xmpp_stanza_set_name(body, STANZA_NAME_BODY); text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(text, message); xmpp_stanza_add_child(body, text); xmpp_stanza_release(text); xmpp_stanza_add_child(msg, body); xmpp_stanza_release(body); return msg; } xmpp_stanza_t * stanza_create_roster_remove_set(xmpp_ctx_t *ctx, const char * const barejid) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); char *id = create_unique_id("roster"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, XMPP_NS_ROSTER); xmpp_stanza_t *item = xmpp_stanza_new(ctx); xmpp_stanza_set_name(item, STANZA_NAME_ITEM); xmpp_stanza_set_attribute(item, STANZA_ATTR_JID, barejid); xmpp_stanza_set_attribute(item, STANZA_ATTR_SUBSCRIPTION, "remove"); xmpp_stanza_add_child(query, item); xmpp_stanza_release(item); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const id, const char * const jid, const char * const handle, GSList *groups) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); if (id) { xmpp_stanza_set_id(iq, id); } xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, XMPP_NS_ROSTER); xmpp_stanza_t *item = xmpp_stanza_new(ctx); xmpp_stanza_set_name(item, STANZA_NAME_ITEM); xmpp_stanza_set_attribute(item, STANZA_ATTR_JID, jid); if (handle) { xmpp_stanza_set_attribute(item, STANZA_ATTR_NAME, handle); } else { xmpp_stanza_set_attribute(item, STANZA_ATTR_NAME, ""); } while (groups) { xmpp_stanza_t *group = xmpp_stanza_new(ctx); xmpp_stanza_t *groupname = xmpp_stanza_new(ctx); xmpp_stanza_set_name(group, STANZA_NAME_GROUP); xmpp_stanza_set_text(groupname, groups->data); xmpp_stanza_add_child(group, groupname); xmpp_stanza_release(groupname); xmpp_stanza_add_child(item, group); xmpp_stanza_release(group); groups = g_slist_next(groups); } xmpp_stanza_add_child(query, item); xmpp_stanza_release(item); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_invite(xmpp_ctx_t *ctx, const char * const room, const char * const contact, const char * const reason, const char * const password) { xmpp_stanza_t *message, *x; message = xmpp_stanza_new(ctx); xmpp_stanza_set_name(message, STANZA_NAME_MESSAGE); xmpp_stanza_set_attribute(message, STANZA_ATTR_TO, contact); char *id = create_unique_id(NULL); xmpp_stanza_set_id(message, id); free(id); x = xmpp_stanza_new(ctx); xmpp_stanza_set_name(x, STANZA_NAME_X); xmpp_stanza_set_ns(x, STANZA_NS_CONFERENCE); xmpp_stanza_set_attribute(x, STANZA_ATTR_JID, room); if (reason) { xmpp_stanza_set_attribute(x, STANZA_ATTR_REASON, reason); } if (password) { xmpp_stanza_set_attribute(x, STANZA_ATTR_PASSWORD, password); } xmpp_stanza_add_child(message, x); xmpp_stanza_release(x); return message; } xmpp_stanza_t * stanza_create_mediated_invite(xmpp_ctx_t *ctx, const char * const room, const char * const contact, const char * const reason) { xmpp_stanza_t *message, *x, *invite; message = xmpp_stanza_new(ctx); xmpp_stanza_set_name(message, STANZA_NAME_MESSAGE); xmpp_stanza_set_attribute(message, STANZA_ATTR_TO, room); char *id = create_unique_id(NULL); xmpp_stanza_set_id(message, id); free(id); x = xmpp_stanza_new(ctx); xmpp_stanza_set_name(x, STANZA_NAME_X); xmpp_stanza_set_ns(x, STANZA_NS_MUC_USER); invite = xmpp_stanza_new(ctx); xmpp_stanza_set_name(invite, STANZA_NAME_INVITE); xmpp_stanza_set_attribute(invite, STANZA_ATTR_TO, contact); if (reason) { xmpp_stanza_t *reason_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(reason_st, STANZA_NAME_REASON); xmpp_stanza_t *reason_txt = xmpp_stanza_new(ctx); xmpp_stanza_set_text(reason_txt, reason); xmpp_stanza_add_child(reason_st, reason_txt); xmpp_stanza_release(reason_txt); xmpp_stanza_add_child(invite, reason_st); xmpp_stanza_release(reason_st); } xmpp_stanza_add_child(x, invite); xmpp_stanza_release(invite); xmpp_stanza_add_child(message, x); xmpp_stanza_release(x); return message; } xmpp_stanza_t * stanza_create_room_join_presence(xmpp_ctx_t * const ctx, const char * const full_room_jid, const char * const passwd) { xmpp_stanza_t *presence = xmpp_stanza_new(ctx); xmpp_stanza_set_name(presence, STANZA_NAME_PRESENCE); xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, full_room_jid); char *id = create_unique_id("join"); xmpp_stanza_set_id(presence, id); free(id); xmpp_stanza_t *x = xmpp_stanza_new(ctx); xmpp_stanza_set_name(x, STANZA_NAME_X); xmpp_stanza_set_ns(x, STANZA_NS_MUC); // if a password was given if (passwd) { xmpp_stanza_t *pass = xmpp_stanza_new(ctx); xmpp_stanza_set_name(pass, "password"); xmpp_stanza_t *text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(text, passwd); xmpp_stanza_add_child(pass, text); xmpp_stanza_add_child(x, pass); xmpp_stanza_release(text); xmpp_stanza_release(pass); } xmpp_stanza_add_child(presence, x); xmpp_stanza_release(x); return presence; } xmpp_stanza_t * stanza_create_room_newnick_presence(xmpp_ctx_t *ctx, const char * const full_room_jid) { xmpp_stanza_t *presence = xmpp_stanza_new(ctx); char *id = create_unique_id("sub"); xmpp_stanza_set_id(presence, id); free(id); xmpp_stanza_set_name(presence, STANZA_NAME_PRESENCE); xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, full_room_jid); return presence; } xmpp_stanza_t * stanza_create_room_leave_presence(xmpp_ctx_t *ctx, const char * const room, const char * const nick) { GString *full_jid = g_string_new(room); g_string_append(full_jid, "/"); g_string_append(full_jid, nick); xmpp_stanza_t *presence = xmpp_stanza_new(ctx); xmpp_stanza_set_name(presence, STANZA_NAME_PRESENCE); xmpp_stanza_set_type(presence, STANZA_TYPE_UNAVAILABLE); xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, full_jid->str); char *id = create_unique_id("leave"); xmpp_stanza_set_id(presence, id); free(id); g_string_free(full_jid, TRUE); return presence; } xmpp_stanza_t * stanza_create_instant_room_request_iq(xmpp_ctx_t *ctx, const char * const room_jid) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room_jid); char *id = create_unique_id("room"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_MUC_OWNER); xmpp_stanza_t *x = xmpp_stanza_new(ctx); xmpp_stanza_set_name(x, STANZA_NAME_X); xmpp_stanza_set_type(x, "submit"); xmpp_stanza_set_ns(x, STANZA_NS_DATA); xmpp_stanza_add_child(query, x); xmpp_stanza_release(x); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_instant_room_destroy_iq(xmpp_ctx_t *ctx, const char * const room_jid) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room_jid); char *id = create_unique_id("room"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_MUC_OWNER); xmpp_stanza_t *destroy = xmpp_stanza_new(ctx); xmpp_stanza_set_name(destroy, STANZA_NAME_DESTROY); xmpp_stanza_add_child(query, destroy); xmpp_stanza_release(destroy); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_room_config_request_iq(xmpp_ctx_t *ctx, const char * const room_jid) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room_jid); char *id = create_unique_id("room"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_MUC_OWNER); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_room_config_cancel_iq(xmpp_ctx_t *ctx, const char * const room_jid) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room_jid); char *id = create_unique_id("room"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_MUC_OWNER); xmpp_stanza_t *x = xmpp_stanza_new(ctx); xmpp_stanza_set_name(x, STANZA_NAME_X); xmpp_stanza_set_type(x, "cancel"); xmpp_stanza_set_ns(x, STANZA_NS_DATA); xmpp_stanza_add_child(query, x); xmpp_stanza_release(x); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_room_affiliation_list_iq(xmpp_ctx_t *ctx, const char * const room, const char * const affiliation) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room); char *id = create_unique_id("affiliation_get"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_MUC_ADMIN); xmpp_stanza_t *item = xmpp_stanza_new(ctx); xmpp_stanza_set_name(item, STANZA_NAME_ITEM); xmpp_stanza_set_attribute(item, "affiliation", affiliation); xmpp_stanza_add_child(query, item); xmpp_stanza_release(item); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_room_role_list_iq(xmpp_ctx_t *ctx, const char * const room, const char * const role) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room); char *id = create_unique_id("role_get"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_MUC_ADMIN); xmpp_stanza_t *item = xmpp_stanza_new(ctx); xmpp_stanza_set_name(item, STANZA_NAME_ITEM); xmpp_stanza_set_attribute(item, "role", role); xmpp_stanza_add_child(query, item); xmpp_stanza_release(item); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_room_affiliation_set_iq(xmpp_ctx_t *ctx, const char * const room, const char * const jid, const char * const affiliation, const char * const reason) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room); char *id = create_unique_id("affiliation_set"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_MUC_ADMIN); xmpp_stanza_t *item = xmpp_stanza_new(ctx); xmpp_stanza_set_name(item, STANZA_NAME_ITEM); xmpp_stanza_set_attribute(item, "affiliation", affiliation); xmpp_stanza_set_attribute(item, STANZA_ATTR_JID, jid); if (reason) { xmpp_stanza_t *reason_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(reason_st, STANZA_NAME_REASON); xmpp_stanza_t *reason_text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(reason_text, reason); xmpp_stanza_add_child(reason_st, reason_text); xmpp_stanza_release(reason_text); xmpp_stanza_add_child(item, reason_st); xmpp_stanza_release(reason_st); } xmpp_stanza_add_child(query, item); xmpp_stanza_release(item); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_room_role_set_iq(xmpp_ctx_t * const ctx, const char * const room, const char * const nick, const char * const role, const char * const reason) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room); char *id = create_unique_id("role_set"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_MUC_ADMIN); xmpp_stanza_t *item = xmpp_stanza_new(ctx); xmpp_stanza_set_name(item, STANZA_NAME_ITEM); xmpp_stanza_set_attribute(item, "role", role); xmpp_stanza_set_attribute(item, STANZA_ATTR_NICK, nick); if (reason) { xmpp_stanza_t *reason_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(reason_st, STANZA_NAME_REASON); xmpp_stanza_t *reason_text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(reason_text, reason); xmpp_stanza_add_child(reason_st, reason_text); xmpp_stanza_release(reason_text); xmpp_stanza_add_child(item, reason_st); xmpp_stanza_release(reason_st); } xmpp_stanza_add_child(query, item); xmpp_stanza_release(item); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_room_kick_iq(xmpp_ctx_t * const ctx, const char * const room, const char * const nick, const char * const reason) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room); char *id = create_unique_id("room_kick"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_MUC_ADMIN); xmpp_stanza_t *item = xmpp_stanza_new(ctx); xmpp_stanza_set_name(item, STANZA_NAME_ITEM); xmpp_stanza_set_attribute(item, STANZA_ATTR_NICK, nick); xmpp_stanza_set_attribute(item, "role", "none"); if (reason) { xmpp_stanza_t *reason_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(reason_st, STANZA_NAME_REASON); xmpp_stanza_t *reason_text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(reason_text, reason); xmpp_stanza_add_child(reason_st, reason_text); xmpp_stanza_release(reason_text); xmpp_stanza_add_child(item, reason_st); xmpp_stanza_release(reason_st); } xmpp_stanza_add_child(query, item); xmpp_stanza_release(item); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_presence(xmpp_ctx_t * const ctx) { xmpp_stanza_t *presence = xmpp_stanza_new(ctx); xmpp_stanza_set_name(presence, STANZA_NAME_PRESENCE); return presence; } xmpp_stanza_t * stanza_create_software_version_iq(xmpp_ctx_t *ctx, const char * const fulljid) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); char *id = create_unique_id("sv"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_set_attribute(iq, "to", fulljid); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_VERSION); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_roster_iq(xmpp_ctx_t *ctx) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); xmpp_stanza_set_id(iq, "roster"); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, XMPP_NS_ROSTER); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_disco_info_iq(xmpp_ctx_t *ctx, const char * const id, const char * const to, const char * const node) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, to); xmpp_stanza_set_id(iq, id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, XMPP_NS_DISCO_INFO); if (node) { xmpp_stanza_set_attribute(query, STANZA_ATTR_NODE, node); } xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char * const id, const char * const jid) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, jid); xmpp_stanza_set_id(iq, id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, XMPP_NS_DISCO_ITEMS); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } xmpp_stanza_t * stanza_create_room_config_submit_iq(xmpp_ctx_t *ctx, const char * const room, DataForm *form) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, room); char *id = create_unique_id("roomconf_submit"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_MUC_OWNER); xmpp_stanza_t *x = form_create_submission(form); xmpp_stanza_add_child(query, x); xmpp_stanza_release(x); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); return iq; } gboolean stanza_contains_chat_state(xmpp_stanza_t *stanza) { return ((xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ACTIVE) != NULL) || (xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_COMPOSING) != NULL) || (xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_PAUSED) != NULL) || (xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_GONE) != NULL) || (xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_INACTIVE) != NULL)); } xmpp_stanza_t * stanza_create_ping_iq(xmpp_ctx_t *ctx, const char * const target) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); if (target) { xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, target); } char *id = create_unique_id("ping"); xmpp_stanza_set_id(iq, id); free(id); xmpp_stanza_t *ping = xmpp_stanza_new(ctx); xmpp_stanza_set_name(ping, STANZA_NAME_PING); xmpp_stanza_set_ns(ping, STANZA_NS_PING); xmpp_stanza_add_child(iq, ping); xmpp_stanza_release(ping); return iq; } GDateTime* stanza_get_delay(xmpp_stanza_t * const stanza) { GTimeVal utc_stamp; // first check for XEP-0203 delayed delivery xmpp_stanza_t *delay = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_DELAY); if (delay) { char *xmlns = xmpp_stanza_get_attribute(delay, STANZA_ATTR_XMLNS); if (xmlns && (strcmp(xmlns, "urn:xmpp:delay") == 0)) { char *stamp = xmpp_stanza_get_attribute(delay, STANZA_ATTR_STAMP); if (stamp && (g_time_val_from_iso8601(stamp, &utc_stamp))) { GDateTime *utc_datetime = g_date_time_new_from_timeval_utc(&utc_stamp); GDateTime *local_datetime = g_date_time_to_local(utc_datetime); g_date_time_unref(utc_datetime); return local_datetime; } } } // otherwise check for XEP-0091 legacy delayed delivery // stanp format : CCYYMMDDThh:mm:ss xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_X); if (x) { char *xmlns = xmpp_stanza_get_attribute(x, STANZA_ATTR_XMLNS); if (xmlns && (strcmp(xmlns, "jabber:x:delay") == 0)) { char *stamp = xmpp_stanza_get_attribute(x, STANZA_ATTR_STAMP); if (stamp && (g_time_val_from_iso8601(stamp, &utc_stamp))) { GDateTime *utc_datetime = g_date_time_new_from_timeval_utc(&utc_stamp); GDateTime *local_datetime = g_date_time_to_local(utc_datetime); g_date_time_unref(utc_datetime); return local_datetime; } } } return NULL; } char * stanza_get_status(xmpp_stanza_t *stanza, char *def) { xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *status = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_STATUS); if (status) { // xmpp_free and free may be different functions so convert all to // libc malloc char *s1, *s2 = NULL; s1 = xmpp_stanza_get_text(status); if (s1) { s2 = strdup(s1); xmpp_free(ctx, s1); } return s2; } else if (def) { return strdup(def); } else { return NULL; } } char * stanza_get_show(xmpp_stanza_t *stanza, char *def) { xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *show = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SHOW); if (show) { // xmpp_free and free may be different functions so convert all to // libc malloc char *s1, *s2 = NULL; s1 = xmpp_stanza_get_text(show); if (s1) { s2 = strdup(s1); xmpp_free(ctx, s1); } return s2; } else if (def) { return strdup(def); } else { return NULL; } } gboolean stanza_is_muc_presence(xmpp_stanza_t * const stanza) { if (stanza == NULL) { return FALSE; } if (strcmp(xmpp_stanza_get_name(stanza), STANZA_NAME_PRESENCE) != 0) { return FALSE; } xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { return TRUE; } else { return FALSE; } } gboolean stanza_muc_requires_config(xmpp_stanza_t * const stanza) { // no stanza, or not presence stanza if ((stanza == NULL) || (g_strcmp0(xmpp_stanza_get_name(stanza), STANZA_NAME_PRESENCE) != 0)) { return FALSE; } // muc user namespaced x element xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { // check for item element with owner affiliation xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(x, "item"); if (item == NULL) { return FALSE; } char *affiliation = xmpp_stanza_get_attribute(item, "affiliation"); if (g_strcmp0(affiliation, "owner") != 0) { return FALSE; } // check for status code 201 xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); while (x_children) { if (g_strcmp0(xmpp_stanza_get_name(x_children), STANZA_NAME_STATUS) == 0) { char *code = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_CODE); if (g_strcmp0(code, "201") == 0) { return TRUE; } } x_children = xmpp_stanza_get_next(x_children); } } return FALSE; } gboolean stanza_is_muc_self_presence(xmpp_stanza_t * const stanza, const char * const self_jid) { // no stanza, or not presence stanza if ((stanza == NULL) || (g_strcmp0(xmpp_stanza_get_name(stanza), STANZA_NAME_PRESENCE) != 0)) { return FALSE; } // muc user namespaced x element xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { // check for status child element with 110 code xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); while (x_children) { if (g_strcmp0(xmpp_stanza_get_name(x_children), STANZA_NAME_STATUS) == 0) { char *code = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_CODE); if (g_strcmp0(code, "110") == 0) { return TRUE; } } x_children = xmpp_stanza_get_next(x_children); } // check for item child element with jid property xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(x, STANZA_NAME_ITEM); if (item) { char *jid = xmpp_stanza_get_attribute(item, STANZA_ATTR_JID); if (jid) { if (g_str_has_prefix(self_jid, jid)) { return TRUE; } } } // check if 'from' attribute identifies this user char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (from) { Jid *from_jid = jid_create(from); if (muc_active(from_jid->barejid)) { char *nick = muc_nick(from_jid->barejid); if (g_strcmp0(from_jid->resourcepart, nick) == 0) { jid_destroy(from_jid); return TRUE; } } // check if a new nickname maps to a pending nick change for this user if (muc_nick_change_pending(from_jid->barejid)) { char *new_nick = from_jid->resourcepart; if (new_nick) { char *nick = muc_nick(from_jid->barejid); char *old_nick = muc_old_nick(from_jid->barejid, new_nick); if (g_strcmp0(old_nick, nick) == 0) { jid_destroy(from_jid); return TRUE; } } } jid_destroy(from_jid); } } // self presence not found return FALSE; } GSList * stanza_get_status_codes_by_ns(xmpp_stanza_t * const stanza, char *ns) { GSList *codes = NULL; xmpp_stanza_t *ns_child = xmpp_stanza_get_child_by_ns(stanza, ns); if (ns_child) { xmpp_stanza_t *child = xmpp_stanza_get_children(ns_child); while (child) { char *name = xmpp_stanza_get_name(child); if (g_strcmp0(name, STANZA_NAME_STATUS) == 0) { char *code = xmpp_stanza_get_attribute(child, STANZA_ATTR_CODE); if (code) { codes = g_slist_append(codes, strdup(code)); } } child = xmpp_stanza_get_next(child); } } return codes; } gboolean stanza_room_destroyed(xmpp_stanza_t *stanza) { char *stanza_name = xmpp_stanza_get_name(stanza); if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) { xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { xmpp_stanza_t *destroy = xmpp_stanza_get_child_by_name(x, STANZA_NAME_DESTROY); if (destroy) { return TRUE; } } } return FALSE; } char * stanza_get_muc_destroy_alternative_room(xmpp_stanza_t *stanza) { char *stanza_name = xmpp_stanza_get_name(stanza); if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) { xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { xmpp_stanza_t *destroy = xmpp_stanza_get_child_by_name(x, STANZA_NAME_DESTROY); if (destroy) { char *jid = xmpp_stanza_get_attribute(destroy, STANZA_ATTR_JID); if (jid) { return jid; } } } } return NULL; } char * stanza_get_muc_destroy_alternative_password(xmpp_stanza_t *stanza) { char *stanza_name = xmpp_stanza_get_name(stanza); if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) { xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { xmpp_stanza_t *destroy = xmpp_stanza_get_child_by_name(x, STANZA_NAME_DESTROY); if (destroy) { xmpp_stanza_t *password_st = xmpp_stanza_get_child_by_name(destroy, STANZA_NAME_PASSWORD); if (password_st) { char *password = xmpp_stanza_get_text(password_st); if (password) { return password; } } } } } return NULL; } char * stanza_get_muc_destroy_reason(xmpp_stanza_t *stanza) { char *stanza_name = xmpp_stanza_get_name(stanza); if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) { xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { xmpp_stanza_t *destroy = xmpp_stanza_get_child_by_name(x, STANZA_NAME_DESTROY); if (destroy) { xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_name(destroy, STANZA_NAME_REASON); if (reason_st) { char *reason = xmpp_stanza_get_text(reason_st); if (reason) { return reason; } } } } } return NULL; } char * stanza_get_actor(xmpp_stanza_t *stanza) { char *stanza_name = xmpp_stanza_get_name(stanza); if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) { xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(x, STANZA_NAME_ITEM); if (item) { xmpp_stanza_t *actor = xmpp_stanza_get_child_by_name(item, STANZA_NAME_ACTOR); if (actor) { char *nick = xmpp_stanza_get_attribute(actor, STANZA_ATTR_NICK); if (nick) { return nick; } char *jid = xmpp_stanza_get_attribute(actor, STANZA_ATTR_JID); if (jid) { return jid; } } } } } return NULL; } char * stanza_get_reason(xmpp_stanza_t *stanza) { char *stanza_name = xmpp_stanza_get_name(stanza); if (g_strcmp0(stanza_name, STANZA_NAME_PRESENCE) == 0) { xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(x, STANZA_NAME_ITEM); if (item) { xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_name(item, STANZA_NAME_REASON); if (reason_st) { char *reason = xmpp_stanza_get_text(reason_st); if (reason) { return reason; } } } } } return NULL; } gboolean stanza_is_room_nick_change(xmpp_stanza_t * const stanza) { // no stanza, or not presence stanza if ((stanza == NULL) || (g_strcmp0(xmpp_stanza_get_name(stanza), STANZA_NAME_PRESENCE) != 0)) { return FALSE; } // muc user namespaced x element xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); if (x) { // check for status child element with 303 code xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); while (x_children) { if (g_strcmp0(xmpp_stanza_get_name(x_children), STANZA_NAME_STATUS) == 0) { char *code = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_CODE); if (g_strcmp0(code, "303") == 0) { return TRUE; } } x_children = xmpp_stanza_get_next(x_children); } } return FALSE; } char * stanza_get_new_nick(xmpp_stanza_t * const stanza) { if (!stanza_is_room_nick_change(stanza)) { return NULL; } xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_X); xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); while (x_children) { if (strcmp(xmpp_stanza_get_name(x_children), STANZA_NAME_ITEM) == 0) { char *nick = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_NICK); if (nick) { return nick; } } x_children = xmpp_stanza_get_next(x_children); } return NULL; } int stanza_get_idle_time(xmpp_stanza_t * const stanza) { xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (query == NULL) { return 0; } char *ns = xmpp_stanza_get_ns(query); if (ns == NULL) { return 0; } if (strcmp(ns, STANZA_NS_LASTACTIVITY) != 0) { return 0; } char *seconds_str = xmpp_stanza_get_attribute(query, STANZA_ATTR_SECONDS); if (seconds_str == NULL) { return 0; } int result = atoi(seconds_str); if (result < 1) { return 0; } else { return result; } } XMPPCaps* stanza_parse_caps(xmpp_stanza_t * const stanza) { xmpp_stanza_t *caps_st = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_C); if (!caps_st) { return NULL; } char *ns = xmpp_stanza_get_ns(caps_st); if (g_strcmp0(ns, STANZA_NS_CAPS) != 0) { return NULL; } char *hash = xmpp_stanza_get_attribute(caps_st, STANZA_ATTR_HASH); char *node = xmpp_stanza_get_attribute(caps_st, STANZA_ATTR_NODE); char *ver = xmpp_stanza_get_attribute(caps_st, STANZA_ATTR_VER); XMPPCaps *caps = (XMPPCaps *)malloc(sizeof(XMPPCaps)); caps->hash = hash ? strdup(hash) : NULL; caps->node = node ? strdup(node) : NULL; caps->ver = ver ? strdup(ver) : NULL; return caps; } char * stanza_get_caps_str(xmpp_stanza_t * const stanza) { xmpp_stanza_t *caps = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_C); if (caps == NULL) { return NULL; } if (strcmp(xmpp_stanza_get_ns(caps), STANZA_NS_CAPS) != 0) { return NULL; } char *node = xmpp_stanza_get_attribute(caps, STANZA_ATTR_NODE); char *ver = xmpp_stanza_get_attribute(caps, STANZA_ATTR_VER); if ((node == NULL) || (ver == NULL)) { return NULL; } GString *caps_gstr = g_string_new(node); g_string_append(caps_gstr, "#"); g_string_append(caps_gstr, ver); char *caps_str = caps_gstr->str; g_string_free(caps_gstr, FALSE); return caps_str; } char * stanza_get_error_message(xmpp_stanza_t *stanza) { xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *error_stanza = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); // return nothing if no error stanza if (error_stanza == NULL) { return strdup("unknown"); } else { // check for text child xmpp_stanza_t *text_stanza = xmpp_stanza_get_child_by_name(error_stanza, STANZA_NAME_TEXT); // check for text if (text_stanza) { gchar *err_msg = xmpp_stanza_get_text(text_stanza); if (err_msg) { char *result = strdup(err_msg); xmpp_free(ctx, err_msg); return result; } // otherwise check each defined-condition RFC-6120 8.3.3 } else { gchar *defined_conditions[] = { STANZA_NAME_BAD_REQUEST, STANZA_NAME_CONFLICT, STANZA_NAME_FEATURE_NOT_IMPLEMENTED, STANZA_NAME_FORBIDDEN, STANZA_NAME_GONE, STANZA_NAME_INTERNAL_SERVER_ERROR, STANZA_NAME_ITEM_NOT_FOUND, STANZA_NAME_JID_MALFORMED, STANZA_NAME_NOT_ACCEPTABLE, STANZA_NAME_NOT_ALLOWED, STANZA_NAME_NOT_AUTHORISED, STANZA_NAME_POLICY_VIOLATION, STANZA_NAME_RECIPIENT_UNAVAILABLE, STANZA_NAME_REDIRECT, STANZA_NAME_REGISTRATION_REQUIRED, STANZA_NAME_REMOTE_SERVER_NOT_FOUND, STANZA_NAME_REMOTE_SERVER_TIMEOUT, STANZA_NAME_RESOURCE_CONSTRAINT, STANZA_NAME_SERVICE_UNAVAILABLE, STANZA_NAME_SUBSCRIPTION_REQUIRED, STANZA_NAME_UNEXPECTED_REQUEST }; int i; for (i = 0; i < ARRAY_SIZE(defined_conditions); i++) { xmpp_stanza_t *cond_stanza = xmpp_stanza_get_child_by_name(error_stanza, defined_conditions[i]); if (cond_stanza) { char *result = strdup(xmpp_stanza_get_name(cond_stanza)); return result; } } } } // if undefined-condition or no condition, return nothing return strdup("unknown"); } void stanza_attach_priority(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence, const int pri) { if (pri != 0) { xmpp_stanza_t *priority, *value; char pri_str[10]; snprintf(pri_str, sizeof(pri_str), "%d", pri); priority = xmpp_stanza_new(ctx); value = xmpp_stanza_new(ctx); xmpp_stanza_set_name(priority, STANZA_NAME_PRIORITY); xmpp_stanza_set_text(value, pri_str); xmpp_stanza_add_child(priority, value); xmpp_stanza_release(value); xmpp_stanza_add_child(presence, priority); xmpp_stanza_release(priority); } } void stanza_attach_show(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence, const char * const show) { if (show) { xmpp_stanza_t *show_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_name(show_stanza, STANZA_NAME_SHOW); xmpp_stanza_t *text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(text, show); xmpp_stanza_add_child(show_stanza, text); xmpp_stanza_add_child(presence, show_stanza); xmpp_stanza_release(text); xmpp_stanza_release(show_stanza); } } void stanza_attach_status(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence, const char * const status) { if (status) { xmpp_stanza_t *status_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_name(status_stanza, STANZA_NAME_STATUS); xmpp_stanza_t *text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(text, status); xmpp_stanza_add_child(status_stanza, text); xmpp_stanza_add_child(presence, status_stanza); xmpp_stanza_release(text); xmpp_stanza_release(status_stanza); } } void stanza_attach_last_activity(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence, const int idle) { if (idle > 0) { xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, STANZA_NS_LASTACTIVITY); char idle_str[10]; snprintf(idle_str, sizeof(idle_str), "%d", idle); xmpp_stanza_set_attribute(query, STANZA_ATTR_SECONDS, idle_str); xmpp_stanza_add_child(presence, query); xmpp_stanza_release(query); } } void stanza_attach_caps(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence) { xmpp_stanza_t *caps = xmpp_stanza_new(ctx); xmpp_stanza_set_name(caps, STANZA_NAME_C); xmpp_stanza_set_ns(caps, STANZA_NS_CAPS); xmpp_stanza_t *query = caps_create_query_response_stanza(ctx); char *sha1 = caps_get_my_sha1(ctx); xmpp_stanza_set_attribute(caps, STANZA_ATTR_HASH, "sha-1"); xmpp_stanza_set_attribute(caps, STANZA_ATTR_NODE, "http://www.profanity.im"); xmpp_stanza_set_attribute(caps, STANZA_ATTR_VER, sha1); xmpp_stanza_add_child(presence, caps); xmpp_stanza_release(caps); xmpp_stanza_release(query); } const char * stanza_get_presence_string_from_type(resource_presence_t presence_type) { switch(presence_type) { case RESOURCE_AWAY: return STANZA_TEXT_AWAY; case RESOURCE_DND: return STANZA_TEXT_DND; case RESOURCE_CHAT: return STANZA_TEXT_CHAT; case RESOURCE_XA: return STANZA_TEXT_XA; default: return NULL; } } Resource* stanza_resource_from_presence(XMPPPresence *presence) { // create Resource Resource *resource = NULL; resource_presence_t resource_presence = resource_presence_from_string(presence->show); if (presence->jid->resourcepart == NULL) { // hack for servers that do not send full jid resource = resource_new("__prof_default", resource_presence, presence->status, presence->priority); } else { resource = resource_new(presence->jid->resourcepart, resource_presence, presence->status, presence->priority); } return resource; } void stanza_free_caps(XMPPCaps *caps) { if (caps) { if (caps->hash) { free(caps->hash); } if (caps->node) { free(caps->node); } if (caps->ver) { free(caps->ver); } FREE_SET_NULL(caps); } } void stanza_free_presence(XMPPPresence *presence) { if (presence) { if (presence->jid) { jid_destroy(presence->jid); } if (presence->last_activity) { g_date_time_unref(presence->last_activity); } if (presence->show) { free(presence->show); } if (presence->status) { free(presence->status); } FREE_SET_NULL(presence); } } XMPPPresence * stanza_parse_presence(xmpp_stanza_t *stanza, int *err) { char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!from) { *err = STANZA_PARSE_ERROR_NO_FROM; return NULL; } Jid *from_jid = jid_create(from); if (!from_jid) { *err = STANZA_PARSE_ERROR_INVALID_FROM; return NULL; } XMPPPresence *result = (XMPPPresence *)malloc(sizeof(XMPPPresence)); result->jid = from_jid; result->show = stanza_get_show(stanza, "online"); result->status = stanza_get_status(stanza, NULL); int idle_seconds = stanza_get_idle_time(stanza); if (idle_seconds > 0) { GDateTime *now = g_date_time_new_now_local(); result->last_activity = g_date_time_add_seconds(now, 0 - idle_seconds); g_date_time_unref(now); } else { result->last_activity = NULL; } result->priority = 0; xmpp_stanza_t *priority_stanza = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_PRIORITY); if (priority_stanza) { char *priority_str = xmpp_stanza_get_text(priority_stanza); if (priority_str) { result->priority = atoi(priority_str); } free(priority_str); } return result; } profanity-0.4.7/src/xmpp/stanza.h000066400000000000000000000313121257755232500167760ustar00rootroot00000000000000/* * stanza.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef XMPP_STANZA_H #define XMPP_STANZA_H #include #include #define STANZA_NAME_ACTIVE "active" #define STANZA_NAME_INACTIVE "inactive" #define STANZA_NAME_COMPOSING "composing" #define STANZA_NAME_PAUSED "paused" #define STANZA_NAME_GONE "gone" #define STANZA_NAME_MESSAGE "message" #define STANZA_NAME_BODY "body" #define STANZA_NAME_PRESENCE "presence" #define STANZA_NAME_PRIORITY "priority" #define STANZA_NAME_X "x" #define STANZA_NAME_SHOW "show" #define STANZA_NAME_STATUS "status" #define STANZA_NAME_IQ "iq" #define STANZA_NAME_QUERY "query" #define STANZA_NAME_DELAY "delay" #define STANZA_NAME_ERROR "error" #define STANZA_NAME_PING "ping" #define STANZA_NAME_TEXT "text" #define STANZA_NAME_SUBJECT "subject" #define STANZA_NAME_ITEM "item" #define STANZA_NAME_ITEMS "items" #define STANZA_NAME_C "c" #define STANZA_NAME_IDENTITY "identity" #define STANZA_NAME_FEATURE "feature" #define STANZA_NAME_INVITE "invite" #define STANZA_NAME_REASON "reason" #define STANZA_NAME_GROUP "group" #define STANZA_NAME_PUBSUB "pubsub" #define STANZA_NAME_PUBLISH "publish" #define STANZA_NAME_PUBLISH_OPTIONS "publish-options" #define STANZA_NAME_FIELD "field" #define STANZA_NAME_STORAGE "storage" #define STANZA_NAME_NICK "nick" #define STANZA_NAME_PASSWORD "password" #define STANZA_NAME_CONFERENCE "conference" #define STANZA_NAME_VALUE "value" #define STANZA_NAME_DESTROY "destroy" #define STANZA_NAME_ACTOR "actor" #define STANZA_NAME_ENABLE "enable" #define STANZA_NAME_DISABLE "disable" // error conditions #define STANZA_NAME_BAD_REQUEST "bad-request" #define STANZA_NAME_CONFLICT "conflict" #define STANZA_NAME_FEATURE_NOT_IMPLEMENTED "feature-not-implemented" #define STANZA_NAME_FORBIDDEN "forbidden" #define STANZA_NAME_GONE "gone" #define STANZA_NAME_INTERNAL_SERVER_ERROR "internal-server-error" #define STANZA_NAME_ITEM_NOT_FOUND "item-not-found" #define STANZA_NAME_JID_MALFORMED "jid-malformed" #define STANZA_NAME_NOT_ACCEPTABLE "not-acceptable" #define STANZA_NAME_NOT_ALLOWED "not-allowed" #define STANZA_NAME_NOT_AUTHORISED "not-authorised" #define STANZA_NAME_POLICY_VIOLATION "policy-violation" #define STANZA_NAME_RECIPIENT_UNAVAILABLE "recipient-unavailable" #define STANZA_NAME_REDIRECT "redirect" #define STANZA_NAME_REGISTRATION_REQUIRED "registration-required" #define STANZA_NAME_REMOTE_SERVER_NOT_FOUND "remote-server-not-found" #define STANZA_NAME_REMOTE_SERVER_TIMEOUT "remote-server-timeout" #define STANZA_NAME_RESOURCE_CONSTRAINT "resource-constraint" #define STANZA_NAME_SERVICE_UNAVAILABLE "service-unavailable" #define STANZA_NAME_SUBSCRIPTION_REQUIRED "subscription-required" #define STANZA_NAME_UNDEFINED_CONDITION "undefined-condition" #define STANZA_NAME_UNEXPECTED_REQUEST "unexpected-request" #define STANZA_TYPE_CHAT "chat" #define STANZA_TYPE_GROUPCHAT "groupchat" #define STANZA_TYPE_UNAVAILABLE "unavailable" #define STANZA_TYPE_SUBSCRIBE "subscribe" #define STANZA_TYPE_SUBSCRIBED "subscribed" #define STANZA_TYPE_UNSUBSCRIBED "unsubscribed" #define STANZA_TYPE_GET "get" #define STANZA_TYPE_SET "set" #define STANZA_TYPE_ERROR "error" #define STANZA_TYPE_RESULT "result" #define STANZA_ATTR_TO "to" #define STANZA_ATTR_FROM "from" #define STANZA_ATTR_STAMP "stamp" #define STANZA_ATTR_TYPE "type" #define STANZA_ATTR_CODE "code" #define STANZA_ATTR_JID "jid" #define STANZA_ATTR_NAME "name" #define STANZA_ATTR_SUBSCRIPTION "subscription" #define STANZA_ATTR_XMLNS "xmlns" #define STANZA_ATTR_NICK "nick" #define STANZA_ATTR_ASK "ask" #define STANZA_ATTR_ID "id" #define STANZA_ATTR_SECONDS "seconds" #define STANZA_ATTR_NODE "node" #define STANZA_ATTR_VER "ver" #define STANZA_ATTR_VAR "var" #define STANZA_ATTR_HASH "hash" #define STANZA_ATTR_CATEGORY "category" #define STANZA_ATTR_REASON "reason" #define STANZA_ATTR_AUTOJOIN "autojoin" #define STANZA_ATTR_PASSWORD "password" #define STANZA_TEXT_AWAY "away" #define STANZA_TEXT_DND "dnd" #define STANZA_TEXT_CHAT "chat" #define STANZA_TEXT_XA "xa" #define STANZA_TEXT_ONLINE "online" #define STANZA_NS_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas" #define STANZA_NS_CHATSTATES "http://jabber.org/protocol/chatstates" #define STANZA_NS_MUC "http://jabber.org/protocol/muc" #define STANZA_NS_MUC_USER "http://jabber.org/protocol/muc#user" #define STANZA_NS_MUC_OWNER "http://jabber.org/protocol/muc#owner" #define STANZA_NS_MUC_ADMIN "http://jabber.org/protocol/muc#admin" #define STANZA_NS_CAPS "http://jabber.org/protocol/caps" #define STANZA_NS_PING "urn:xmpp:ping" #define STANZA_NS_LASTACTIVITY "jabber:iq:last" #define STANZA_NS_DATA "jabber:x:data" #define STANZA_NS_VERSION "jabber:iq:version" #define STANZA_NS_CONFERENCE "jabber:x:conference" #define STANZA_NS_CAPTCHA "urn:xmpp:captcha" #define STANZA_NS_PUBSUB "http://jabber.org/protocol/pubsub" #define STANZA_NS_CARBONS "urn:xmpp:carbons:2" #define STANZA_NS_HINTS "urn:xmpp:hints" #define STANZA_NS_FORWARD "urn:xmpp:forward:0" #define STANZA_NS_RECEIPTS "urn:xmpp:receipts" #define STANZA_NS_SIGNED "jabber:x:signed" #define STANZA_NS_ENCRYPTED "jabber:x:encrypted" #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo" typedef struct caps_stanza_t { char *hash; char *node; char *ver; } XMPPCaps; typedef struct presence_stanza_t { Jid *jid; char *show; char *status; int priority; GDateTime *last_activity; } XMPPPresence; typedef enum { STANZA_PARSE_ERROR_NO_FROM, STANZA_PARSE_ERROR_INVALID_FROM } stanza_parse_error_t; xmpp_stanza_t* stanza_create_bookmarks_storage_request(xmpp_ctx_t *ctx); xmpp_stanza_t * stanza_enable_carbons(xmpp_ctx_t *ctx); xmpp_stanza_t * stanza_disable_carbons(xmpp_ctx_t *ctx); xmpp_stanza_t* stanza_create_chat_state(xmpp_ctx_t *ctx, const char * const fulljid, const char * const state); xmpp_stanza_t * stanza_attach_state(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char * const state); xmpp_stanza_t * stanza_attach_carbons_private(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza); xmpp_stanza_t * stanza_attach_hints_no_copy(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza); xmpp_stanza_t * stanza_attach_hints_no_store(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza); xmpp_stanza_t * stanza_attach_receipt_request(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza); xmpp_stanza_t* stanza_create_message(xmpp_ctx_t *ctx, char *id, const char * const recipient, const char * const type, const char * const message); xmpp_stanza_t* stanza_create_room_join_presence(xmpp_ctx_t * const ctx, const char * const full_room_jid, const char * const passwd); xmpp_stanza_t* stanza_create_room_newnick_presence(xmpp_ctx_t *ctx, const char * const full_room_jid); xmpp_stanza_t* stanza_create_room_leave_presence(xmpp_ctx_t *ctx, const char * const room, const char * const nick); xmpp_stanza_t* stanza_create_presence(xmpp_ctx_t * const ctx); xmpp_stanza_t* stanza_create_roster_iq(xmpp_ctx_t *ctx); xmpp_stanza_t* stanza_create_ping_iq(xmpp_ctx_t *ctx, const char * const target); xmpp_stanza_t* stanza_create_disco_info_iq(xmpp_ctx_t *ctx, const char * const id, const char * const to, const char * const node); xmpp_stanza_t* stanza_create_invite(xmpp_ctx_t *ctx, const char * const room, const char * const contact, const char * const reason, const char * const password); xmpp_stanza_t* stanza_create_mediated_invite(xmpp_ctx_t *ctx, const char * const room, const char * const contact, const char * const reason); gboolean stanza_contains_chat_state(xmpp_stanza_t *stanza); GDateTime* stanza_get_delay(xmpp_stanza_t * const stanza); gboolean stanza_is_muc_presence(xmpp_stanza_t * const stanza); gboolean stanza_is_muc_self_presence(xmpp_stanza_t * const stanza, const char * const self_jid); gboolean stanza_is_room_nick_change(xmpp_stanza_t * const stanza); gboolean stanza_muc_requires_config(xmpp_stanza_t * const stanza); char * stanza_get_new_nick(xmpp_stanza_t * const stanza); xmpp_stanza_t* stanza_create_instant_room_request_iq(xmpp_ctx_t *ctx, const char * const room_jid); xmpp_stanza_t* stanza_create_instant_room_destroy_iq(xmpp_ctx_t *ctx, const char * const room_jid); xmpp_stanza_t* stanza_create_room_config_request_iq(xmpp_ctx_t *ctx, const char * const room_jid); xmpp_stanza_t* stanza_create_room_config_cancel_iq(xmpp_ctx_t *ctx, const char * const room_jid); xmpp_stanza_t* stanza_create_room_config_submit_iq(xmpp_ctx_t *ctx, const char * const room, DataForm *form); xmpp_stanza_t* stanza_create_room_affiliation_list_iq(xmpp_ctx_t *ctx, const char * const room, const char * const affiliation); xmpp_stanza_t* stanza_create_room_affiliation_set_iq(xmpp_ctx_t *ctx, const char * const room, const char * const jid, const char * const affiliation, const char * const reason); xmpp_stanza_t* stanza_create_room_role_set_iq(xmpp_ctx_t * const ctx, const char * const room, const char * const jid, const char * const role, const char * const reason); xmpp_stanza_t* stanza_create_room_role_list_iq(xmpp_ctx_t *ctx, const char * const room, const char * const role); xmpp_stanza_t* stanza_create_room_subject_message(xmpp_ctx_t *ctx, const char * const room, const char * const subject); xmpp_stanza_t* stanza_create_room_kick_iq(xmpp_ctx_t * const ctx, const char * const room, const char * const nick, const char * const reason); int stanza_get_idle_time(xmpp_stanza_t * const stanza); char * stanza_get_caps_str(xmpp_stanza_t * const stanza); DataForm * stanza_create_form(xmpp_stanza_t * const stanza); void stanza_destroy_form(DataForm *form); void stanza_attach_priority(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence, const int pri); void stanza_attach_last_activity(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence, const int idle); void stanza_attach_caps(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence); void stanza_attach_show(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence, const char * const show); void stanza_attach_status(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence, const char * const status); const char * stanza_get_presence_string_from_type(resource_presence_t presence_type); xmpp_stanza_t * stanza_create_software_version_iq(xmpp_ctx_t *ctx, const char * const fulljid); xmpp_stanza_t * stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char * const id, const char * const jid); char * stanza_get_status(xmpp_stanza_t *stanza, char *def); char * stanza_get_show(xmpp_stanza_t *stanza, char *def); xmpp_stanza_t * stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const id, const char * const jid, const char * const handle, GSList *groups); xmpp_stanza_t * stanza_create_roster_remove_set(xmpp_ctx_t *ctx, const char * const barejid); char * stanza_get_error_message(xmpp_stanza_t * const stanza); GSList* stanza_get_status_codes_by_ns(xmpp_stanza_t * const stanza, char *ns); gboolean stanza_room_destroyed(xmpp_stanza_t *stanza); char* stanza_get_muc_destroy_alternative_room(xmpp_stanza_t *stanza); char* stanza_get_muc_destroy_alternative_password(xmpp_stanza_t *stanza); char* stanza_get_muc_destroy_reason(xmpp_stanza_t *stanza); char* stanza_get_actor(xmpp_stanza_t *stanza); char* stanza_get_reason(xmpp_stanza_t *stanza); Resource* stanza_resource_from_presence(XMPPPresence *presence); XMPPPresence* stanza_parse_presence(xmpp_stanza_t *stanza, int *err); void stanza_free_presence(XMPPPresence *presence); XMPPCaps* stanza_parse_caps(xmpp_stanza_t * const stanza); void stanza_free_caps(XMPPCaps *caps); #endif profanity-0.4.7/src/xmpp/xmpp.h000066400000000000000000000216261257755232500164710ustar00rootroot00000000000000/* * xmpp.h * * Copyright (C) 2012 - 2015 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #ifndef XMPP_XMPP_H #define XMPP_XMPP_H #include #include "config/accounts.h" #include "contact.h" #include "jid.h" #include "tools/autocomplete.h" #define JABBER_PRIORITY_MIN -128 #define JABBER_PRIORITY_MAX 127 typedef enum { JABBER_UNDEFINED, JABBER_STARTED, JABBER_CONNECTING, JABBER_CONNECTED, JABBER_DISCONNECTING, JABBER_DISCONNECTED } jabber_conn_status_t; typedef enum { PRESENCE_SUBSCRIBE, PRESENCE_SUBSCRIBED, PRESENCE_UNSUBSCRIBED } jabber_subscr_t; typedef enum { INVITE_DIRECT, INVITE_MEDIATED } jabber_invite_t; typedef struct capabilities_t { char *category; char *type; char *name; char *software; char *software_version; char *os; char *os_version; GSList *features; } Capabilities; typedef struct disco_item_t { char *jid; char *name; } DiscoItem; typedef struct disco_identity_t { char *name; char *type; char *category; } DiscoIdentity; typedef enum { FIELD_HIDDEN, FIELD_TEXT_SINGLE, FIELD_TEXT_PRIVATE, FIELD_TEXT_MULTI, FIELD_BOOLEAN, FIELD_LIST_SINGLE, FIELD_LIST_MULTI, FIELD_JID_SINGLE, FIELD_JID_MULTI, FIELD_FIXED, FIELD_UNKNOWN } form_field_type_t; typedef struct form_option_t { char *label; char *value; } FormOption; typedef struct form_field_t { char *label; char *type; form_field_type_t type_t; char *var; char *description; gboolean required; GSList *values; GSList *options; Autocomplete value_ac; } FormField; typedef struct data_form_t { char *type; char *title; char *instructions; GSList *fields; GHashTable *var_to_tag; GHashTable *tag_to_var; Autocomplete tag_ac; gboolean modified; } DataForm; // connection functions void jabber_init(const int disable_tls); jabber_conn_status_t jabber_connect_with_details(const char * const jid, const char * const passwd, const char * const altdomain, const int port); jabber_conn_status_t jabber_connect_with_account(const ProfAccount * const account); void jabber_disconnect(void); void jabber_shutdown(void); void jabber_process_events(int millis); const char * jabber_get_fulljid(void); const char * jabber_get_domain(void); jabber_conn_status_t jabber_get_connection_status(void); char * jabber_get_presence_message(void); char* jabber_get_account_name(void); GList * jabber_get_available_resources(void); // message functions char* message_send_chat(const char * const barejid, const char * const msg); char* message_send_chat_otr(const char * const barejid, const char * const msg); char* message_send_chat_pgp(const char * const barejid, const char * const msg); void message_send_private(const char * const fulljid, const char * const msg); void message_send_groupchat(const char * const roomjid, const char * const msg); void message_send_groupchat_subject(const char * const roomjid, const char * const subject); void message_send_inactive(const char * const jid); void message_send_composing(const char * const jid); void message_send_paused(const char * const jid); void message_send_gone(const char * const jid); void message_send_invite(const char * const room, const char * const contact, const char * const reason); // presence functions void presence_subscription(const char * const jid, const jabber_subscr_t action); GSList* presence_get_subscription_requests(void); gint presence_sub_request_count(void); void presence_reset_sub_request_search(void); char * presence_sub_request_find(const char * const search_str); void presence_join_room(char *room, char *nick, char * passwd); void presence_change_room_nick(const char * const room, const char * const nick); void presence_leave_chat_room(const char * const room_jid); void presence_send(resource_presence_t status, const char * const msg, int idle, char *signed_status); gboolean presence_sub_request_exists(const char * const bare_jid); // iq functions void iq_enable_carbons(); void iq_disable_carbons(); void iq_send_software_version(const char * const fulljid); void iq_room_list_request(gchar *conferencejid); void iq_disco_info_request(gchar *jid); void iq_disco_items_request(gchar *jid); void iq_set_autoping(int seconds); void iq_confirm_instant_room(const char * const room_jid); void iq_destroy_room(const char * const room_jid); void iq_request_room_config_form(const char * const room_jid); void iq_submit_room_config(const char * const room, DataForm *form); void iq_room_config_cancel(const char * const room_jid); void iq_send_ping(const char * const target); void iq_send_caps_request(const char * const to, const char * const id, const char * const node, const char * const ver); void iq_send_caps_request_for_jid(const char * const to, const char * const id, const char * const node, const char * const ver); void iq_send_caps_request_legacy(const char * const to, const char * const id, const char * const node, const char * const ver); void iq_room_info_request(const char * const room, gboolean display_result); void iq_room_affiliation_list(const char * const room, char *affiliation); void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation, const char * const reason); void iq_room_kick_occupant(const char * const room, const char * const nick, const char * const reason); void iq_room_role_set(const char * const room, const char * const nick, char *role, const char * const reason); void iq_room_role_list(const char * const room, char *role); // caps functions Capabilities* caps_lookup(const char * const jid); void caps_close(void); void caps_destroy(Capabilities *caps); gboolean bookmark_add(const char *jid, const char *nick, const char *password, const char *autojoin_str); gboolean bookmark_update(const char *jid, const char *nick, const char *password, const char *autojoin_str); gboolean bookmark_remove(const char *jid); gboolean bookmark_join(const char *jid); const GList * bookmark_get_list(void); char * bookmark_find(const char * const search_str); void bookmark_autocomplete_reset(void); void roster_send_name_change(const char * const barejid, const char * const new_name, GSList *groups); void roster_send_add_to_group(const char * const group, PContact contact); void roster_send_remove_from_group(const char * const group, PContact contact); void roster_send_add_new(const char * const barejid, const char * const name); void roster_send_remove(const char * const barejid); void form_destroy(DataForm *form); char * form_get_form_type_field(DataForm *form); void form_set_value(DataForm *form, const char * const tag, char *value); gboolean form_add_unique_value(DataForm *form, const char * const tag, char *value); void form_add_value(DataForm *form, const char * const tag, char *value); gboolean form_remove_value(DataForm *form, const char * const tag, char *value); gboolean form_remove_text_multi_value(DataForm *form, const char * const tag, int index); gboolean form_tag_exists(DataForm *form, const char * const tag); form_field_type_t form_get_field_type(DataForm *form, const char * const tag); gboolean form_field_contains_option(DataForm *form, const char * const tag, char *value); int form_get_value_count(DataForm *form, const char * const tag); FormField* form_get_field_by_tag(DataForm *form, const char * const tag); Autocomplete form_get_value_ac(DataForm *form, const char * const tag); void form_reset_autocompleters(DataForm *form); GSList * form_get_non_form_type_fields_sorted(DataForm *form); GSList * form_get_field_values_sorted(FormField *field); #endif profanity-0.4.7/tests/000077500000000000000000000000001257755232500147145ustar00rootroot00000000000000profanity-0.4.7/tests/functionaltests/000077500000000000000000000000001257755232500201415ustar00rootroot00000000000000profanity-0.4.7/tests/functionaltests/functionaltests.c000066400000000000000000000061001257755232500235270ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "config.h" #include "proftest.h" #include "test_connect.h" #include "test_ping.h" #include "test_rooms.h" #include "test_presence.h" #include "test_message.h" #include "test_carbons.h" #include "test_chat_session.h" #include "test_receipts.h" #include "test_roster.h" #include "test_software.h" #define PROF_FUNC_TEST(test) unit_test_setup_teardown(test, init_prof_test, close_prof_test) int main(int argc, char* argv[]) { const UnitTest all_tests[] = { PROF_FUNC_TEST(connect_jid_requests_roster), PROF_FUNC_TEST(connect_jid_sends_presence_after_receiving_roster), PROF_FUNC_TEST(connect_jid_requests_bookmarks), PROF_FUNC_TEST(connect_bad_password), PROF_FUNC_TEST(connect_shows_presence_updates), PROF_FUNC_TEST(ping_multiple), PROF_FUNC_TEST(ping_responds), PROF_FUNC_TEST(rooms_query), PROF_FUNC_TEST(presence_away), PROF_FUNC_TEST(presence_away_with_message), PROF_FUNC_TEST(presence_online), PROF_FUNC_TEST(presence_online_with_message), PROF_FUNC_TEST(presence_xa), PROF_FUNC_TEST(presence_xa_with_message), PROF_FUNC_TEST(presence_dnd), PROF_FUNC_TEST(presence_dnd_with_message), PROF_FUNC_TEST(presence_chat), PROF_FUNC_TEST(presence_chat_with_message), PROF_FUNC_TEST(presence_set_priority), PROF_FUNC_TEST(presence_includes_priority), PROF_FUNC_TEST(presence_received), PROF_FUNC_TEST(presence_missing_resource_defaults), PROF_FUNC_TEST(message_send), PROF_FUNC_TEST(message_receive), PROF_FUNC_TEST(sends_message_to_barejid_when_contact_offline), PROF_FUNC_TEST(sends_message_to_barejid_when_contact_online), PROF_FUNC_TEST(sends_message_to_fulljid_when_received_from_fulljid), PROF_FUNC_TEST(sends_subsequent_messages_to_fulljid), PROF_FUNC_TEST(resets_to_barejid_after_presence_received), PROF_FUNC_TEST(new_session_when_message_received_from_different_fulljid), PROF_FUNC_TEST(send_enable_carbons), PROF_FUNC_TEST(connect_with_carbons_enabled), PROF_FUNC_TEST(send_disable_carbons), PROF_FUNC_TEST(receive_carbon), PROF_FUNC_TEST(receive_self_carbon), PROF_FUNC_TEST(send_receipt_request), PROF_FUNC_TEST(send_receipt_on_request), PROF_FUNC_TEST(sends_new_item), PROF_FUNC_TEST(sends_new_item_nick), PROF_FUNC_TEST(sends_remove_item), PROF_FUNC_TEST(sends_nick_change), PROF_FUNC_TEST(send_software_version_request), PROF_FUNC_TEST(display_software_version_result), PROF_FUNC_TEST(shows_message_when_software_version_error), PROF_FUNC_TEST(display_software_version_result_when_from_domainpart), PROF_FUNC_TEST(show_message_in_chat_window_when_no_resource), PROF_FUNC_TEST(display_software_version_result_in_chat), }; return run_tests(all_tests); } profanity-0.4.7/tests/functionaltests/proftest.c000066400000000000000000000133121257755232500221530ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include "proftest.h" char *config_orig; char *data_orig; int fd = 0; gboolean _create_dir(char *name) { struct stat sb; if (stat(name, &sb) != 0) { if (errno != ENOENT || mkdir(name, S_IRWXU) != 0) { return FALSE; } } else { if ((sb.st_mode & S_IFDIR) != S_IFDIR) { return FALSE; } } return TRUE; } gboolean _mkdir_recursive(const char *dir) { int i; gboolean result = TRUE; for (i = 1; i <= strlen(dir); i++) { if (dir[i] == '/' || dir[i] == '\0') { gchar *next_dir = g_strndup(dir, i); result = _create_dir(next_dir); g_free(next_dir); if (!result) { break; } } } return result; } void _create_config_dir(void) { GString *profanity_dir = g_string_new(XDG_CONFIG_HOME); g_string_append(profanity_dir, "/profanity"); if (!_mkdir_recursive(profanity_dir->str)) { assert_true(FALSE); } g_string_free(profanity_dir, TRUE); } void _create_data_dir(void) { GString *profanity_dir = g_string_new(XDG_DATA_HOME); g_string_append(profanity_dir, "/profanity"); if (!_mkdir_recursive(profanity_dir->str)) { assert_true(FALSE); } g_string_free(profanity_dir, TRUE); } void _create_chatlogs_dir(void) { GString *chatlogs_dir = g_string_new(XDG_DATA_HOME); g_string_append(chatlogs_dir, "/profanity/chatlogs"); if (!_mkdir_recursive(chatlogs_dir->str)) { assert_true(FALSE); } g_string_free(chatlogs_dir, TRUE); } void _create_logs_dir(void) { GString *logs_dir = g_string_new(XDG_DATA_HOME); g_string_append(logs_dir, "/profanity/logs"); if (!_mkdir_recursive(logs_dir->str)) { assert_true(FALSE); } g_string_free(logs_dir, TRUE); } void _cleanup_dirs(void) { int res = system("rm -rf ./tests/functionaltests/files"); if (res == -1) { assert_true(FALSE); } } void prof_start(void) { // helper script sets terminal columns, avoids assertions failing // based on the test runner terminal size fd = exp_spawnl("sh", "sh", "-c", "./tests/functionaltests/start_profanity.sh", NULL); FILE *fp = fdopen(fd, "r+"); assert_true(fp != NULL); setbuf(fp, (char *)0); } void init_prof_test(void **state) { if (stbbr_start(STBBR_LOGDEBUG ,5230, 0) != 0) { assert_true(FALSE); return; } config_orig = getenv("XDG_CONFIG_HOME"); data_orig = getenv("XDG_DATA_HOME"); setenv("XDG_CONFIG_HOME", XDG_CONFIG_HOME, 1); setenv("XDG_DATA_HOME", XDG_DATA_HOME, 1); _cleanup_dirs(); _create_config_dir(); _create_data_dir(); _create_chatlogs_dir(); _create_logs_dir(); prof_start(); assert_true(prof_output_exact("Profanity")); // set UI options to make expect assertions faster and more reliable prof_input("/inpblock timeout 5"); assert_true(prof_output_exact("Input blocking set to 5 milliseconds")); prof_input("/inpblock dynamic off"); assert_true(prof_output_exact("Dynamic input blocking disabled")); prof_input("/notify message off"); assert_true(prof_output_exact("Message notifications disabled")); prof_input("/wrap off"); assert_true(prof_output_exact("Word wrap disabled")); prof_input("/roster hide"); assert_true(prof_output_exact("Roster disabled")); prof_input("/time main off"); prof_input("/time main off"); assert_true(prof_output_exact("Time display disabled")); } void close_prof_test(void **state) { prof_input("/quit"); waitpid(exp_pid, NULL, 0); _cleanup_dirs(); setenv("XDG_CONFIG_HOME", config_orig, 1); setenv("XDG_DATA_HOME", data_orig, 1); stbbr_stop(); } void prof_input(char *input) { GString *inp_str = g_string_new(input); g_string_append(inp_str, "\r"); write(fd, inp_str->str, inp_str->len); g_string_free(inp_str, TRUE); } int prof_output_exact(char *text) { return (1 == exp_expectl(fd, exp_exact, text, 1, exp_end)); } int prof_output_regex(char *text) { return (1 == exp_expectl(fd, exp_regexp, text, 1, exp_end)); } void prof_connect_with_roster(char *roster) { GString *roster_str = g_string_new( "" "" ); g_string_append(roster_str, roster); g_string_append(roster_str, "" "" ); stbbr_for_query("jabber:iq:roster", roster_str->str); g_string_free(roster_str, TRUE); stbbr_for_id("prof_presence_1", "" "0" "" "" ); prof_input("/connect stabber@localhost port 5230"); prof_input("password"); // Allow time for profanity to connect exp_timeout = 30; assert_true(prof_output_regex("stabber@localhost logged in successfully, .+online.+ \\(priority 0\\)\\.")); exp_timeout = 10; stbbr_wait_for("prof_presence_*"); } void prof_connect(void) { prof_connect_with_roster( "" "" ); } profanity-0.4.7/tests/functionaltests/proftest.h000066400000000000000000000007141257755232500221620ustar00rootroot00000000000000#ifndef __H_PROFTEST #define __H_PROFTEST #define XDG_CONFIG_HOME "./tests/functionaltests/files/xdg_config_home" #define XDG_DATA_HOME "./tests/functionaltests/files/xdg_data_home" void init_prof_test(void **state); void close_prof_test(void **state); void prof_start(void); void prof_connect(void); void prof_connect_with_roster(char *roster); void prof_input(char *input); int prof_output_exact(char *text); int prof_output_regex(char *text); #endif profanity-0.4.7/tests/functionaltests/start_profanity.sh000077500000000000000000000000501257755232500237230ustar00rootroot00000000000000export COLUMNS=300 ./profanity -l DEBUG profanity-0.4.7/tests/functionaltests/test_carbons.c000066400000000000000000000063671257755232500230070ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "proftest.h" void send_enable_carbons(void **state) { prof_connect(); prof_input("/carbons on"); assert_true(stbbr_received( "" )); } void connect_with_carbons_enabled(void **state) { prof_input("/carbons on"); prof_connect(); assert_true(stbbr_received( "" )); } void send_disable_carbons(void **state) { prof_input("/carbons on"); prof_connect(); prof_input("/carbons off"); assert_true(stbbr_received( "" )); } void receive_carbon(void **state) { prof_input("/carbons on"); prof_connect(); assert_true(stbbr_received( "" )); stbbr_send( "" "10" "On my mobile" "" ); assert_true(prof_output_exact("Buddy1 (mobile) is online, \"On my mobile\"")); prof_input("/msg Buddy1"); prof_output_exact("unencrypted"); stbbr_send( "" "" "" "" "test carbon from recipient" "" "" "" "" ); assert_true(prof_output_regex("Buddy1/mobile: .+test carbon from recipient")); } void receive_self_carbon(void **state) { prof_input("/carbons on"); prof_connect(); assert_true(stbbr_received( "" )); stbbr_send( "" "10" "On my mobile" "" ); assert_true(prof_output_exact("Buddy1 (mobile) is online, \"On my mobile\"")); prof_input("/msg Buddy1"); prof_output_exact("unencrypted"); stbbr_send( "" "" "" "" "self sent carbon" "" "" "" "" ); assert_true(prof_output_regex("me: .+self sent carbon")); } profanity-0.4.7/tests/functionaltests/test_carbons.h000066400000000000000000000003161257755232500230000ustar00rootroot00000000000000void send_enable_carbons(void **state); void connect_with_carbons_enabled(void **state); void send_disable_carbons(void **state); void receive_carbon(void **state); void receive_self_carbon(void **state); profanity-0.4.7/tests/functionaltests/test_chat_session.c000066400000000000000000000135511257755232500240330ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "proftest.h" void sends_message_to_barejid_when_contact_offline(void **state) { prof_connect(); prof_input("/msg buddy1@localhost Hi there"); assert_true(stbbr_received( "" "Hi there" "" )); } void sends_message_to_barejid_when_contact_online(void **state) { prof_connect(); stbbr_send( "" "10" "" ); assert_true(prof_output_exact("Buddy1 (mobile) is online")); prof_input("/msg buddy1@localhost Hi there"); assert_true(stbbr_received( "" "Hi there" "" )); } void sends_message_to_fulljid_when_received_from_fulljid(void **state) { prof_connect(); stbbr_send( "" "10" "" ); assert_true(prof_output_exact("Buddy1 (mobile) is online")); stbbr_send( "" "First message" "" ); assert_true(prof_output_exact("<< incoming from Buddy1/mobile (2)")); prof_input("/msg buddy1@localhost Hi there"); assert_true(stbbr_received( "" "Hi there" "" )); } void sends_subsequent_messages_to_fulljid(void **state) { prof_connect(); stbbr_send( "" "10" "" ); assert_true(prof_output_exact("Buddy1 (mobile) is online")); stbbr_send( "" "First message" "" ); assert_true(prof_output_exact("<< incoming from Buddy1/mobile (2)")); prof_input("/msg buddy1@localhost Outgoing 1"); assert_true(stbbr_received( "" "Outgoing 1" "" )); prof_input("/msg buddy1@localhost Outgoing 2"); assert_true(stbbr_received( "" "Outgoing 2" "" )); prof_input("/msg buddy1@localhost Outgoing 3"); assert_true(stbbr_received( "" "Outgoing 3" "" )); } void resets_to_barejid_after_presence_received(void **state) { prof_connect(); stbbr_send( "" "10" "" ); assert_true(prof_output_exact("Buddy1 (mobile) is online")); stbbr_send( "" "First message" "" ); assert_true(prof_output_exact("<< incoming from Buddy1/mobile (2)")); prof_input("/msg buddy1@localhost Outgoing 1"); assert_true(stbbr_received( "" "Outgoing 1" "" )); stbbr_send( "" "5" "dnd" "" ); assert_true(prof_output_exact("Buddy1 (laptop) is dnd")); prof_input("/msg buddy1@localhost Outgoing 2"); assert_true(stbbr_received( "" "Outgoing 2" "" )); } void new_session_when_message_received_from_different_fulljid(void **state) { prof_connect(); stbbr_send( "" "10" "" ); assert_true(prof_output_exact("Buddy1 (mobile) is online")); stbbr_send( "" "8" "away" "" ); assert_true(prof_output_exact("Buddy1 (laptop) is away")); stbbr_send( "" "From first resource" "" ); assert_true(prof_output_exact("<< incoming from Buddy1/mobile (2)")); prof_input("/msg buddy1@localhost Outgoing 1"); assert_true(stbbr_received( "" "Outgoing 1" "" )); stbbr_send( "" "From second resource" "" ); assert_true(prof_output_regex("Buddy1/laptop:.+From second resource")); prof_input("/msg buddy1@localhost Outgoing 2"); assert_true(stbbr_received( "" "Outgoing 2" "" )); } profanity-0.4.7/tests/functionaltests/test_chat_session.h000066400000000000000000000006201257755232500240310ustar00rootroot00000000000000void sends_message_to_barejid_when_contact_offline(void **state); void sends_message_to_barejid_when_contact_online(void **state); void sends_message_to_fulljid_when_received_from_fulljid(void **state); void sends_subsequent_messages_to_fulljid(void **state); void resets_to_barejid_after_presence_received(void **state); void new_session_when_message_received_from_different_fulljid(void **state); profanity-0.4.7/tests/functionaltests/test_connect.c000066400000000000000000000044611257755232500230020ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "proftest.h" void connect_jid_requests_roster(void **state) { prof_connect(); assert_true(stbbr_received( "" )); } void connect_jid_sends_presence_after_receiving_roster(void **state) { prof_connect(); assert_true(stbbr_received( "" "" "" )); } void connect_jid_requests_bookmarks(void **state) { prof_connect(); assert_true(stbbr_received( "" "" "" "" "" )); } void connect_bad_password(void **state) { prof_input("/connect stabber@localhost port 5230"); prof_input("badpassword"); assert_true(prof_output_exact("Login failed.")); } void connect_shows_presence_updates(void **state) { prof_connect(); stbbr_send( "" "dnd" "busy!" "" ); assert_true(prof_output_exact("Buddy1 (mobile) is dnd, \"busy!\"")); stbbr_send( "" "chat" "Talk to me!" "" ); assert_true(prof_output_exact("Buddy1 (laptop) is chat, \"Talk to me!\"")); stbbr_send( "" "away" "Out of office" "" ); assert_true(prof_output_exact("Buddy2 (work) is away, \"Out of office\"")); stbbr_send( "" "xa" "Gone :(" "" ); assert_true(prof_output_exact("Buddy1 (mobile) is xa, \"Gone :(\"")); } profanity-0.4.7/tests/functionaltests/test_connect.h000066400000000000000000000004061257755232500230020ustar00rootroot00000000000000void connect_jid_requests_roster(void **state); void connect_jid_sends_presence_after_receiving_roster(void **state); void connect_jid_requests_bookmarks(void **state); void connect_bad_password(void **state); void connect_shows_presence_updates(void **state); profanity-0.4.7/tests/functionaltests/test_message.c000066400000000000000000000015731257755232500227760ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "proftest.h" void message_send(void **state) { prof_connect(); prof_input("/msg somejid@someserver.com Hi there"); assert_true(stbbr_received( "" "Hi there" "" )); assert_true(prof_output_regex("me: .+Hi there")); } void message_receive(void **state) { prof_connect(); stbbr_send( "" "How are you?" "" ); assert_true(prof_output_exact("<< incoming from someuser@chatserv.org/laptop (2)")); } profanity-0.4.7/tests/functionaltests/test_message.h000066400000000000000000000001051257755232500227710ustar00rootroot00000000000000void message_send(void **state); void message_receive(void **state); profanity-0.4.7/tests/functionaltests/test_ping.c000066400000000000000000000025431257755232500223050ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "proftest.h" void ping_multiple(void **state) { stbbr_for_id("prof_ping_2", "" ); stbbr_for_id("prof_ping_3", "" ); prof_connect(); prof_input("/ping"); assert_true(stbbr_received( "" "" "" )); assert_true(prof_output_exact("Ping response from server")); prof_input("/ping"); assert_true(stbbr_received( "" "" "" )); assert_true(prof_output_exact("Ping response from server")); } void ping_responds(void **state) { prof_connect(); stbbr_send( "" "" "" ); assert_true(stbbr_received( "" )); } profanity-0.4.7/tests/functionaltests/test_ping.h000066400000000000000000000001041257755232500223010ustar00rootroot00000000000000void ping_multiple(void **state); void ping_responds(void **state); profanity-0.4.7/tests/functionaltests/test_presence.c000066400000000000000000000154201257755232500231520ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "proftest.h" void presence_online(void **state) { prof_connect(); prof_input("/online"); assert_true(stbbr_received( "" "" "" )); assert_true(prof_output_exact("Status set to online (priority 0)")); } void presence_online_with_message(void **state) { prof_connect(); prof_input("/online \"Hi there\""); assert_true(stbbr_received( "" "Hi there" "" "" )); assert_true(prof_output_exact("Status set to online (priority 0), \"Hi there\".")); } void presence_away(void **state) { prof_connect(); prof_input("/away"); assert_true(stbbr_received( "" "away" "" "" )); assert_true(prof_output_exact("Status set to away (priority 0)")); } void presence_away_with_message(void **state) { prof_connect(); prof_input("/away \"I'm not here for a bit\""); assert_true(stbbr_received( "" "away" "I'm not here for a bit" "" "" )); assert_true(prof_output_exact("Status set to away (priority 0), \"I'm not here for a bit\".")); } void presence_xa(void **state) { prof_connect(); prof_input("/xa"); assert_true(stbbr_received( "" "xa" "" "" )); assert_true(prof_output_exact("Status set to xa (priority 0)")); } void presence_xa_with_message(void **state) { prof_connect(); prof_input("/xa \"Gone to the shops\""); assert_true(stbbr_received( "" "xa" "Gone to the shops" "" "" )); assert_true(prof_output_exact("Status set to xa (priority 0), \"Gone to the shops\".")); } void presence_dnd(void **state) { prof_connect(); prof_input("/dnd"); assert_true(stbbr_received( "" "dnd" "" "" )); assert_true(prof_output_exact("Status set to dnd (priority 0)")); } void presence_dnd_with_message(void **state) { prof_connect(); prof_input("/dnd \"Working\""); assert_true(stbbr_received( "" "dnd" "Working" "" "" )); assert_true(prof_output_exact("Status set to dnd (priority 0), \"Working\".")); } void presence_chat(void **state) { prof_connect(); prof_input("/chat"); assert_true(stbbr_received( "" "chat" "" "" )); assert_true(prof_output_exact("Status set to chat (priority 0)")); } void presence_chat_with_message(void **state) { prof_connect(); prof_input("/chat \"Free to talk\""); assert_true(stbbr_received( "" "chat" "Free to talk" "" "" )); assert_true(prof_output_exact("Status set to chat (priority 0), \"Free to talk\".")); } void presence_set_priority(void **state) { prof_connect(); prof_input("/priority 25"); assert_true(stbbr_received( "" "25" "" "" )); assert_true(prof_output_exact("Priority set to 25.")); } void presence_includes_priority(void **state) { prof_connect(); prof_input("/priority 25"); assert_true(stbbr_received( "" "25" "" "" )); assert_true(prof_output_exact("Priority set to 25.")); prof_input("/chat \"Free to talk\""); assert_true(stbbr_received( "" "25" "chat" "Free to talk" "" "" )); assert_true(prof_output_exact("Status set to chat (priority 25), \"Free to talk\".")); } void presence_received(void **state) { prof_connect(); stbbr_send( "" "10" "I'm here" "" ); assert_true(prof_output_exact("Buddy1 (mobile) is online, \"I'm here\"")); } // Typical use case for gateways that don't support resources void presence_missing_resource_defaults(void **state) { prof_connect(); stbbr_send( "" "15" "My status" "" ); assert_true(prof_output_exact("Buddy1 is online, \"My status\"")); prof_input("/info Buddy1"); assert_true(prof_output_exact("__prof_default (15), online")); } profanity-0.4.7/tests/functionaltests/test_presence.h000066400000000000000000000011111257755232500231470ustar00rootroot00000000000000void presence_away(void **state); void presence_away_with_message(void **state); void presence_online(void **state); void presence_online_with_message(void **state); void presence_xa(void **state); void presence_xa_with_message(void **state); void presence_dnd(void **state); void presence_dnd_with_message(void **state); void presence_chat(void **state); void presence_chat_with_message(void **state); void presence_set_priority(void **state); void presence_includes_priority(void **state); void presence_received(void **state); void presence_missing_resource_defaults(void **state); profanity-0.4.7/tests/functionaltests/test_receipts.c000066400000000000000000000022071257755232500231630ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "proftest.h" void send_receipt_request(void **state) { prof_input("/receipts request on"); prof_connect(); prof_input("/msg somejid@someserver.com Hi there"); assert_true(stbbr_received( "" "Hi there" "" "" )); } void send_receipt_on_request(void **state) { prof_input("/receipts send on"); prof_connect(); stbbr_send( "" "Wants a receipt" "" "" ); assert_true(stbbr_received( "" "" "" )); } profanity-0.4.7/tests/functionaltests/test_receipts.h000066400000000000000000000001261257755232500231660ustar00rootroot00000000000000void send_receipt_request(void **state); void send_receipt_on_request(void **state); profanity-0.4.7/tests/functionaltests/test_rooms.c000066400000000000000000000021111257755232500224760ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "proftest.h" void rooms_query(void **state) { stbbr_for_id("confreq", "" "" "" "" "" "" ); prof_connect(); prof_input("/rooms"); assert_true(prof_output_exact("chatroom@conference.localhost, (A chat room)")); assert_true(prof_output_exact("hangout@conference.localhost, (Another chat room)")); assert_true(stbbr_last_received( "" "" "" )); } profanity-0.4.7/tests/functionaltests/test_rooms.h000066400000000000000000000000411257755232500225030ustar00rootroot00000000000000void rooms_query(void **state); profanity-0.4.7/tests/functionaltests/test_roster.c000066400000000000000000000055561257755232500226750ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "proftest.h" void sends_new_item(void **state) { prof_connect(); stbbr_for_query("jabber:iq:roster", "" "" "" "" "" ); prof_input("/roster add bob@localhost"); assert_true(stbbr_received( "" "" "" "" "" )); assert_true(prof_output_exact("Roster item added: bob@localhost")); } void sends_new_item_nick(void **state) { prof_connect(); stbbr_for_query("jabber:iq:roster", "" "" "" "" "" ); prof_input("/roster add bob@localhost Bobby"); assert_true(stbbr_received( "" "" "" "" "" )); assert_true(prof_output_exact("Roster item added: bob@localhost (Bobby)")); } void sends_remove_item(void **state) { prof_connect_with_roster( "" "" ); stbbr_for_query("jabber:iq:roster", "" "" "" "" "" ); prof_input("/roster remove buddy1@localhost"); assert_true(stbbr_received( "" "" "" "" "" )); assert_true(prof_output_exact("Roster item removed: buddy1@localhost")); } void sends_nick_change(void **state) { prof_connect_with_roster( "" ); prof_input("/roster nick buddy1@localhost Buddy1"); assert_true(prof_output_exact("Nickname for buddy1@localhost set to: Buddy1.")); assert_true(stbbr_received( "" "" "" "" "" )); } profanity-0.4.7/tests/functionaltests/test_roster.h000066400000000000000000000002271257755232500226700ustar00rootroot00000000000000void sends_new_item(void **state); void sends_new_item_nick(void **state); void sends_remove_item(void **state); void sends_nick_change(void **state); profanity-0.4.7/tests/functionaltests/test_software.c000066400000000000000000000123071257755232500232010ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "proftest.h" void send_software_version_request(void **state) { prof_connect(); stbbr_send( "" "10" "I'm here" "" ); prof_output_exact("Buddy1 (mobile) is online, \"I'm here\""); prof_input("/software buddy1@localhost/mobile"); stbbr_received( "" "" "" ); } void display_software_version_result(void **state) { prof_connect(); stbbr_send( "" "10" "I'm here" "" ); prof_output_exact("Buddy1 (mobile) is online, \"I'm here\""); stbbr_for_query("jabber:iq:version", "" "" "Profanity" "0.4.7dev.master.2cb2f83" "" "" ); prof_input("/software buddy1@localhost/mobile"); // assert_true(prof_output_exact("buddy1@localhost/mobile:")); // assert_true(prof_output_exact("Name : Profanity")); assert_true(prof_output_exact("Version : 0.4.7dev.master.2cb2f83")); } void shows_message_when_software_version_error(void **state) { prof_connect(); stbbr_send( "" "10" "I'm here" "" ); prof_output_exact("Buddy1 (mobile) is online, \"I'm here\""); stbbr_for_query("jabber:iq:version", "" "" "" "" "" "" ); prof_input("/software buddy1@localhost/laptop"); assert_true(prof_output_exact("Could not get software version: service-unavailable")); } // Typical use case for gateways that don't support resources void display_software_version_result_when_from_domainpart(void **state) { prof_connect(); stbbr_send( "" "10" "I'm here" "" ); prof_output_exact("Buddy1 is online, \"I'm here\""); stbbr_for_query("jabber:iq:version", "" "" "Some Gateway" "1.0" "" "" ); prof_input("/software buddy1@localhost/__prof_default"); // assert_true(prof_output_exact("buddy1@localhost/__prof_default:")); // assert_true(prof_output_exact("Name : Some Gateway")); assert_true(prof_output_exact("Version : 1.0")); } void show_message_in_chat_window_when_no_resource(void **state) { prof_connect(); stbbr_send( "" "10" "I'm here" "" ); prof_output_exact("Buddy1 (mobile) is online, \"I'm here\""); prof_input("/msg Buddy1"); prof_input("/software"); assert_true(prof_output_exact("Unknown resource for /software command.")); } void display_software_version_result_in_chat(void **state) { prof_connect(); stbbr_send( "" "10" "I'm here" "" ); prof_output_exact("Buddy1 (mobile) is online, \"I'm here\""); prof_input("/msg Buddy1"); stbbr_send( "" "Here's a message" "" ); prof_output_exact("Here's a message"); stbbr_for_query("jabber:iq:version", "" "" "Profanity" "0.4.7dev.master.2cb2f83" "" "" ); prof_input("/software"); // assert_true(prof_output_exact("buddy1@localhost/mobile:")); // assert_true(prof_output_exact("Name : Profanity")); assert_true(prof_output_exact("Version : 0.4.7dev.master.2cb2f83")); } profanity-0.4.7/tests/functionaltests/test_software.h000066400000000000000000000005531257755232500232060ustar00rootroot00000000000000void send_software_version_request(void **state); void display_software_version_result(void **state); void shows_message_when_software_version_error(void **state); void display_software_version_result_when_from_domainpart(void **state); void show_message_in_chat_window_when_no_resource(void **state); void display_software_version_result_in_chat(void **state); profanity-0.4.7/tests/unittests/000077500000000000000000000000001257755232500167565ustar00rootroot00000000000000profanity-0.4.7/tests/unittests/config/000077500000000000000000000000001257755232500202235ustar00rootroot00000000000000profanity-0.4.7/tests/unittests/config/stub_accounts.c000066400000000000000000000112001257755232500232350ustar00rootroot00000000000000#include #include #include #include #include "common.h" #include "config/account.h" void accounts_load(void) {} void accounts_close(void) {} char * accounts_find_all(char *prefix) { return NULL; } char * accounts_find_enabled(char *prefix) { return NULL; } void accounts_reset_all_search(void) {} void accounts_reset_enabled_search(void) {} void accounts_add(const char *jid, const char *altdomain, const int port) { check_expected(jid); check_expected(altdomain); check_expected(port); } int accounts_remove(const char *jid) { return 0; } gchar** accounts_get_list(void) { return (gchar **)mock(); } ProfAccount* accounts_get_account(const char * const name) { check_expected(name); return (ProfAccount*)mock(); } gboolean accounts_enable(const char * const name) { check_expected(name); return (gboolean)mock(); } gboolean accounts_disable(const char * const name) { check_expected(name); return (gboolean)mock(); } gboolean accounts_rename(const char * const account_name, const char * const new_name) { check_expected(account_name); check_expected(new_name); return (gboolean)mock(); } gboolean accounts_account_exists(const char * const account_name) { check_expected(account_name); return (gboolean)mock(); } void accounts_set_jid(const char * const account_name, const char * const value) { check_expected(account_name); check_expected(value); } void accounts_set_server(const char * const account_name, const char * const value) { check_expected(account_name); check_expected(value); } void accounts_set_port(const char * const account_name, const int value) {} void accounts_set_resource(const char * const account_name, const char * const value) { check_expected(account_name); check_expected(value); } void accounts_set_password(const char * const account_name, const char * const value) { check_expected(account_name); check_expected(value); } void accounts_set_eval_password(const char * const account_name, const char * const value) { check_expected(account_name); check_expected(value); } void accounts_set_muc_service(const char * const account_name, const char * const value) { check_expected(account_name); check_expected(value); } void accounts_set_muc_nick(const char * const account_name, const char * const value) { check_expected(account_name); check_expected(value); } void accounts_set_otr_policy(const char * const account_name, const char * const value) { check_expected(account_name); check_expected(value); } void accounts_set_last_presence(const char * const account_name, const char * const value) {} void accounts_set_pgp_keyid(const char * const account_name, const char * const value) {} void accounts_set_login_presence(const char * const account_name, const char * const value) { check_expected(account_name); check_expected(value); } resource_presence_t accounts_get_login_presence(const char * const account_name) { return RESOURCE_ONLINE; } resource_presence_t accounts_get_last_presence(const char * const account_name) { check_expected(account_name); return (resource_presence_t)mock(); } void accounts_set_priority_online(const char * const account_name, const gint value) { check_expected(account_name); check_expected(value); } void accounts_set_priority_chat(const char * const account_name, const gint value) { check_expected(account_name); check_expected(value); } void accounts_set_priority_away(const char * const account_name, const gint value) { check_expected(account_name); check_expected(value); } void accounts_set_priority_xa(const char * const account_name, const gint value) { check_expected(account_name); check_expected(value); } void accounts_set_priority_dnd(const char * const account_name, const gint value) { check_expected(account_name); check_expected(value); } void accounts_set_priority_all(const char * const account_name, const gint value) {} gint accounts_get_priority_for_presence_type(const char * const account_name, resource_presence_t presence_type) { return 0; } void accounts_clear_password(const char * const account_name) {} void accounts_clear_eval_password(const char * const account_name) {} void accounts_clear_server(const char * const account_name) {} void accounts_clear_port(const char * const account_name) {} void accounts_clear_otr(const char * const account_name) {} void accounts_clear_pgp_keyid(const char * const account_name) {} void accounts_add_otr_policy(const char * const account_name, const char * const contact_jid, const char * const policy) {} profanity-0.4.7/tests/unittests/helpers.c000066400000000000000000000060021257755232500205620ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "common.h" #include "helpers.h" #include "config/preferences.h" #include "chat_session.h" void create_config_dir(void **state) { setenv("XDG_CONFIG_HOME", "./tests/files/xdg_config_home", 1); gchar *xdg_config = xdg_get_config_home(); GString *profanity_dir = g_string_new(xdg_config); g_string_append(profanity_dir, "/profanity"); if (!mkdir_recursive(profanity_dir->str)) { assert_true(FALSE); } g_free(xdg_config); g_string_free(profanity_dir, TRUE); } void remove_config_dir(void **state) { rmdir("./tests/files/xdg_config_home/profanity"); rmdir("./tests/files/xdg_config_home"); } void create_data_dir(void **state) { setenv("XDG_DATA_HOME", "./tests/files/xdg_data_home", 1); gchar *xdg_data = xdg_get_data_home(); GString *profanity_dir = g_string_new(xdg_data); g_string_append(profanity_dir, "/profanity"); if (!mkdir_recursive(profanity_dir->str)) { assert_true(FALSE); } g_free(xdg_data); g_string_free(profanity_dir, TRUE); } void remove_data_dir(void **state) { rmdir("./tests/files/xdg_data_home/profanity"); rmdir("./tests/files/xdg_data_home"); } void load_preferences(void **state) { create_config_dir(state); FILE *f = fopen("./tests/files/xdg_config_home/profanity/profrc", "ab+"); if (f) { prefs_load(); } } void close_preferences(void **state) { prefs_close(); remove("./tests/files/xdg_config_home/profanity/profrc"); remove_config_dir(state); rmdir("./tests/files"); } void init_chat_sessions(void **state) { load_preferences(NULL); chat_sessions_init(); } void close_chat_sessions(void **state) { chat_sessions_clear(); close_preferences(NULL); } int utf8_pos_to_col(char *str, int utf8_pos) { int col = 0; int i = 0; for (i = 0; idata); ex = g_list_next(ex); } printf("\n\n"); p = ac; printf("\nActual\n"); while(ac) { printf("\n\n%s\n", (char *)p->data); ac = g_list_next(ac); } printf("\n\n"); if (g_list_length(ex) != g_list_length(ac)) { return 0; } GList *ex_curr = ex; while (ex_curr != NULL) { if (g_list_find_custom(ac, ex_curr->data, cmp_func) == NULL) { return 0; } ex_curr = g_list_next(ex_curr); } return 1; } profanity-0.4.7/tests/unittests/helpers.h000066400000000000000000000005101257755232500205650ustar00rootroot00000000000000#include "glib.h" void load_preferences(void **state); void close_preferences(void **state); void init_chat_sessions(void **state); void close_chat_sessions(void **state); int utf8_pos_to_col(char *str, int utf8_pos); void glist_set_cmp(GCompareFunc func); int glist_contents_equal(const void *actual, const void *expected);profanity-0.4.7/tests/unittests/log/000077500000000000000000000000001257755232500175375ustar00rootroot00000000000000profanity-0.4.7/tests/unittests/log/stub_log.c000066400000000000000000000046501257755232500215260ustar00rootroot00000000000000/* * mock_log.c * * Copyright (C) 2012, 2013 James Booth * * This file is part of Profanity. * * Profanity 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. * * Profanity 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 Profanity. If not, see . * */ #include #include #include #include "log.h" void log_init(log_level_t filter) {} log_level_t log_get_filter(void) { return (log_level_t)mock(); } void log_reinit(void) {} void log_close(void) {} void log_debug(const char * const msg, ...) {} void log_info(const char * const msg, ...) {} void log_warning(const char * const msg, ...) {} void log_error(const char * const msg, ...) {} void log_msg(log_level_t level, const char * const area, const char * const msg) {} char * get_log_file_location(void) { return mock_ptr_type(char *); } log_level_t log_level_from_string(char *log_level) { return (log_level_t)mock(); } void log_stderr_init(log_level_t level) {} void log_stderr_close(void) {} void log_stderr_handler(void) {} void chat_log_init(void) {} void chat_log_msg_out(const char * const barejid, const char * const msg) {} void chat_log_otr_msg_out(const char * const barejid, const char * const msg) {} void chat_log_pgp_msg_out(const char * const barejid, const char * const msg) {} void chat_log_msg_in(const char * const barejid, const char * const msg, GDateTime *timestamp) {} void chat_log_otr_msg_in(const char * const barejid, const char * const msg, gboolean was_decrypted, GDateTime *timestamp) {} void chat_log_pgp_msg_in(const char * const barejid, const char * const msg, GDateTime *timestamp) {} void chat_log_close(void) {} GSList * chat_log_get_previous(const gchar * const login, const gchar * const recipient) { return mock_ptr_type(GSList *); } void groupchat_log_init(void) {} void groupchat_log_chat(const gchar * const login, const gchar * const room, const gchar * const nick, const gchar * const msg) {} profanity-0.4.7/tests/unittests/otr/000077500000000000000000000000001257755232500175625ustar00rootroot00000000000000profanity-0.4.7/tests/unittests/otr/stub_otr.c000066400000000000000000000042301257755232500215660ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "config/account.h" #include "otr/otr.h" OtrlUserState otr_userstate(void) { return NULL; } OtrlMessageAppOps* otr_messageops(void) { return NULL; } GHashTable* otr_smpinitators(void) { return NULL; } void otr_init(void) {} void otr_shutdown(void) {} char* otr_libotr_version(void) { return (char*)mock(); } char* otr_start_query(void) { return (char*)mock(); } void otr_poll(void) {} void otr_on_connect(ProfAccount *account) {} char* otr_on_message_recv(const char * const barejid, const char * const resource, const char * const message, gboolean *was_decrypted) { return NULL; } gboolean otr_on_message_send(ProfChatWin *chatwin, const char * const message) { return FALSE; } void otr_keygen(ProfAccount *account) { check_expected(account); } gboolean otr_key_loaded(void) { return (gboolean)mock(); } char* otr_tag_message(const char * const msg) { return NULL; } gboolean otr_is_secure(const char * const recipient) { return FALSE; } gboolean otr_is_trusted(const char * const recipient) { return FALSE; } void otr_trust(const char * const recipient) {} void otr_untrust(const char * const recipient) {} void otr_smp_secret(const char * const recipient, const char *secret) {} void otr_smp_question(const char * const recipient, const char *question, const char *answer) {} void otr_smp_answer(const char * const recipient, const char *answer) {} void otr_end_session(const char * const recipient) {} char * otr_get_my_fingerprint(void) { return (char *)mock(); } char * otr_get_their_fingerprint(const char * const recipient) { check_expected(recipient); return (char *)mock(); } char * otr_encrypt_message(const char * const to, const char * const message) { return NULL; } char * otr_decrypt_message(const char * const from, const char * const message, gboolean *was_decrypted) { return NULL; } void otr_free_message(char *message) {} prof_otrpolicy_t otr_get_policy(const char * const recipient) { return PROF_OTRPOLICY_MANUAL; } profanity-0.4.7/tests/unittests/pgp/000077500000000000000000000000001257755232500175445ustar00rootroot00000000000000profanity-0.4.7/tests/unittests/pgp/stub_gpg.c000066400000000000000000000021051257755232500215200ustar00rootroot00000000000000#include #include "pgp/gpg.h" void p_gpg_init(void) {} void p_gpg_close(void) {} GHashTable* p_gpg_list_keys(void) { return NULL; } GHashTable* p_gpg_pubkeys(void) { return NULL; } const char* p_gpg_libver(void) { return NULL; } void p_gpg_verify(const char * const barejid, const char *const sign) {} char* p_gpg_sign(const char * const str, const char * const fp) { return NULL; } gboolean p_gpg_valid_key(const char * const keyid) { return FALSE; } gboolean p_gpg_available(const char * const barejid) { return FALSE; } char * p_gpg_decrypt(const char * const cipher) { return NULL; } void p_gpg_on_connect(const char * const barejid) {} void p_gpg_on_disconnect(void) {} gboolean p_gpg_addkey(const char * const jid, const char * const keyid) { return TRUE; } void p_gpg_free_decrypted(char *decrypted) {} void p_gpg_free_keys(GHashTable *keys) {} void p_gpg_autocomplete_key_reset(void) {} char * p_gpg_autocomplete_key(const char * const search_str) { return NULL; } char * p_gpg_format_fp_str(char *fp) { return NULL; } profanity-0.4.7/tests/unittests/test_autocomplete.c000066400000000000000000000053301257755232500226630ustar00rootroot00000000000000#include #include #include #include #include #include #include "contact.h" #include "tools/autocomplete.h" void clear_empty(void **state) { Autocomplete ac = autocomplete_new(); autocomplete_clear(ac); } void reset_after_create(void **state) { Autocomplete ac = autocomplete_new(); autocomplete_reset(ac); autocomplete_clear(ac); } void find_after_create(void **state) { Autocomplete ac = autocomplete_new(); autocomplete_complete(ac, "hello", TRUE); autocomplete_clear(ac); } void get_after_create_returns_null(void **state) { Autocomplete ac = autocomplete_new(); GSList *result = autocomplete_create_list(ac); assert_null(result); autocomplete_clear(ac); g_slist_free_full(result, g_free); } void add_one_and_complete(void **state) { Autocomplete ac = autocomplete_new(); autocomplete_add(ac, "Hello"); char *result = autocomplete_complete(ac, "Hel", TRUE); assert_string_equal("Hello", result); autocomplete_clear(ac); } void add_two_and_complete_returns_first(void **state) { Autocomplete ac = autocomplete_new(); autocomplete_add(ac, "Hello"); autocomplete_add(ac, "Help"); char *result = autocomplete_complete(ac, "Hel", TRUE); assert_string_equal("Hello", result); autocomplete_clear(ac); } void add_two_and_complete_returns_second(void **state) { Autocomplete ac = autocomplete_new(); autocomplete_add(ac, "Hello"); autocomplete_add(ac, "Help"); char *result1 = autocomplete_complete(ac, "Hel", TRUE); char *result2 = autocomplete_complete(ac, result1, TRUE); assert_string_equal("Help", result2); autocomplete_clear(ac); } void add_two_adds_two(void **state) { Autocomplete ac = autocomplete_new(); autocomplete_add(ac, "Hello"); autocomplete_add(ac, "Help"); GSList *result = autocomplete_create_list(ac); assert_int_equal(2, g_slist_length(result)); autocomplete_clear(ac); g_slist_free_full(result, g_free); } void add_two_same_adds_one(void **state) { Autocomplete ac = autocomplete_new(); autocomplete_add(ac, "Hello"); autocomplete_add(ac, "Hello"); GSList *result = autocomplete_create_list(ac); assert_int_equal(1, g_slist_length(result)); autocomplete_clear(ac); g_slist_free_full(result, g_free); } void add_two_same_updates(void **state) { Autocomplete ac = autocomplete_new(); autocomplete_add(ac, "Hello"); autocomplete_add(ac, "Hello"); GSList *result = autocomplete_create_list(ac); GSList *first = g_slist_nth(result, 0); char *str = first->data; assert_string_equal("Hello", str); autocomplete_clear(ac); g_slist_free_full(result, g_free); } profanity-0.4.7/tests/unittests/test_autocomplete.h000066400000000000000000000006571257755232500226770ustar00rootroot00000000000000void clear_empty(void **state); void reset_after_create(void **state); void find_after_create(void **state); void get_after_create_returns_null(void **state); void add_one_and_complete(void **state); void add_two_and_complete_returns_first(void **state); void add_two_and_complete_returns_second(void **state); void add_two_adds_two(void **state); void add_two_same_adds_one(void **state); void add_two_same_updates(void **state); profanity-0.4.7/tests/unittests/test_chat_session.c000066400000000000000000000025371257755232500226520ustar00rootroot00000000000000#include #include #include #include #include #include #include "chat_session.h" void returns_false_when_chat_session_does_not_exist(void **state) { ChatSession *session = chat_session_get("somejid@server.org"); assert_null(session); } void creates_chat_session_on_recipient_activity(void **state) { char *barejid = "myjid@server.org"; char *resource = "tablet"; chat_session_recipient_active(barejid, resource, FALSE); ChatSession *session = chat_session_get(barejid); assert_non_null(session); assert_string_equal(session->resource, resource); } void replaces_chat_session_on_recipient_activity_with_different_resource(void **state) { char *barejid = "myjid@server.org"; char *resource1 = "tablet"; char *resource2 = "mobile"; chat_session_recipient_active(barejid, resource1, FALSE); chat_session_recipient_active(barejid, resource2, FALSE); ChatSession *session = chat_session_get(barejid); assert_string_equal(session->resource, resource2); } void removes_chat_session(void **state) { char *barejid = "myjid@server.org"; char *resource1 = "laptop"; chat_session_recipient_active(barejid, resource1, FALSE); chat_session_remove(barejid); ChatSession *session = chat_session_get(barejid); assert_null(session); }profanity-0.4.7/tests/unittests/test_chat_session.h000066400000000000000000000004021257755232500226440ustar00rootroot00000000000000void returns_false_when_chat_session_does_not_exist(void **state); void creates_chat_session_on_recipient_activity(void **state); void replaces_chat_session_on_recipient_activity_with_different_resource(void **state); void removes_chat_session(void **state);profanity-0.4.7/tests/unittests/test_cmd_account.c000066400000000000000000000652171257755232500224530ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "xmpp/xmpp.h" #include "ui/ui.h" #include "ui/stub_ui.h" #include "config/accounts.h" #include "command/commands.h" #define CMD_ACCOUNT "/account" void cmd_account_shows_usage_when_not_connected_and_no_args(void **state) { gchar *args[] = { NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_shows_account_when_connected_and_no_args(void **state) { ProfAccount *account = account_new("jabber_org", "me@jabber.org", NULL, NULL, TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); gchar *args[] = { NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(jabber_get_account_name, "account_name"); expect_any(accounts_get_account, name); will_return(accounts_get_account, account); expect_memory(cons_show_account, account, account, sizeof(ProfAccount)); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_list_shows_accounts(void **state) { gchar *args[] = { "list", NULL }; gchar **accounts = malloc(sizeof(gchar *) * 4); accounts[0] = strdup("account1"); accounts[1] = strdup("account2"); accounts[2] = strdup("account3"); accounts[3] = NULL; will_return(accounts_get_list, accounts); expect_memory(cons_show_account_list, accounts, accounts, sizeof(accounts)); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_show_shows_usage_when_no_arg(void **state) { gchar *args[] = { "show", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_show_shows_message_when_account_does_not_exist(void **state) { gchar *args[] = { "show", "account_name", NULL }; expect_any(accounts_get_account, name); will_return(accounts_get_account, NULL); expect_cons_show("No such account."); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_show_shows_account_when_exists(void **state) { gchar *args[] = { "show", "account_name", NULL }; ProfAccount *account = account_new("jabber_org", "me@jabber.org", NULL, NULL, TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); expect_any(accounts_get_account, name); will_return(accounts_get_account, account); expect_memory(cons_show_account, account, account, sizeof(account)); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_add_shows_usage_when_no_arg(void **state) { gchar *args[] = { "add", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_add_adds_account(void **state) { gchar *args[] = { "add", "new_account", NULL }; expect_string(accounts_add, jid, "new_account"); expect_value(accounts_add, altdomain, NULL); expect_value(accounts_add, port, 0); expect_cons_show("Account created."); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_enable_shows_usage_when_no_arg(void **state) { gchar *args[] = { "enable", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_enable_enables_account(void **state) { gchar *args[] = { "enable", "account_name", NULL }; expect_string(accounts_enable, name, "account_name"); will_return(accounts_enable, TRUE); expect_cons_show("Account enabled."); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_enable_shows_message_when_account_doesnt_exist(void **state) { gchar *args[] = { "enable", "account_name", NULL }; expect_any(accounts_enable, name); will_return(accounts_enable, FALSE); expect_cons_show("No such account: account_name"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_disable_shows_usage_when_no_arg(void **state) { gchar *args[] = { "disable", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_disable_disables_account(void **state) { gchar *args[] = { "disable", "account_name", NULL }; expect_string(accounts_disable, name, "account_name"); will_return(accounts_disable, TRUE); expect_cons_show("Account disabled."); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_disable_shows_message_when_account_doesnt_exist(void **state) { gchar *args[] = { "disable", "account_name", NULL }; expect_any(accounts_disable, name); will_return(accounts_disable, FALSE); expect_cons_show("No such account: account_name"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_rename_shows_usage_when_no_args(void **state) { gchar *args[] = { "rename", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_rename_shows_usage_when_one_arg(void **state) { gchar *args[] = { "rename", "original_name", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_rename_renames_account(void **state) { gchar *args[] = { "rename", "original_name", "new_name", NULL }; expect_string(accounts_rename, account_name, "original_name"); expect_string(accounts_rename, new_name, "new_name"); will_return(accounts_rename, TRUE); expect_cons_show("Account renamed."); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_rename_shows_message_when_not_renamed(void **state) { gchar *args[] = { "rename", "original_name", "new_name", NULL }; expect_any(accounts_rename, account_name); expect_any(accounts_rename, new_name); will_return(accounts_rename, FALSE); expect_cons_show("Either account original_name doesn't exist, or account new_name already exists."); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_shows_usage_when_no_args(void **state) { gchar *args[] = { "set", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_shows_usage_when_one_arg(void **state) { gchar *args[] = { "set", "a_account", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_shows_usage_when_two_args(void **state) { gchar *args[] = { "set", "a_account", "a_property", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_shows_message_when_account_doesnt_exist(void **state) { gchar *args[] = { "set", "a_account", "a_property", "a_value", NULL }; expect_string(accounts_account_exists, account_name, "a_account"); will_return(accounts_account_exists, FALSE); expect_cons_show("Account a_account doesn't exist"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_jid_shows_message_for_malformed_jid(void **state) { gchar *args[] = { "set", "a_account", "jid", "@malformed", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_cons_show("Malformed jid: @malformed"); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_jid_sets_barejid(void **state) { gchar *args[] = { "set", "a_account", "jid", "a_local@a_domain", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_jid, account_name, "a_account"); expect_string(accounts_set_jid, value, "a_local@a_domain"); expect_cons_show("Updated jid for account a_account: a_local@a_domain"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_jid_sets_resource(void **state) { gchar *args[] = { "set", "a_account", "jid", "a_local@a_domain/a_resource", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_jid, account_name, "a_account"); expect_string(accounts_set_jid, value, "a_local@a_domain"); expect_cons_show("Updated jid for account a_account: a_local@a_domain"); expect_string(accounts_set_resource, account_name, "a_account"); expect_string(accounts_set_resource, value, "a_resource"); expect_cons_show("Updated resource for account a_account: a_resource"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_server_sets_server(void **state) { gchar *args[] = { "set", "a_account", "server", "a_server", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_server, account_name, "a_account"); expect_string(accounts_set_server, value, "a_server"); expect_cons_show("Updated server for account a_account: a_server"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_resource_sets_resource(void **state) { gchar *args[] = { "set", "a_account", "resource", "a_resource", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_resource, account_name, "a_account"); expect_string(accounts_set_resource, value, "a_resource"); expect_cons_show("Updated resource for account a_account: a_resource"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_resource_sets_resource_with_online_message(void **state) { gchar *args[] = { "set", "a_account", "resource", "a_resource", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_resource, account_name, "a_account"); expect_string(accounts_set_resource, value, "a_resource"); expect_cons_show("Updated resource for account a_account: a_resource, you will need to reconnect to pick up the change."); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_password_sets_password(void **state) { gchar *args[] = { "set", "a_account", "password", "a_password", NULL }; ProfAccount *account = account_new("a_account", NULL, NULL, NULL, TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_get_account, name, "a_account"); will_return(accounts_get_account, account); expect_string(accounts_set_password, account_name, "a_account"); expect_string(accounts_set_password, value, "a_password"); expect_cons_show("Updated password for account a_account"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_eval_password_sets_eval_password(void **state) { gchar *args[] = { "set", "a_account", "eval_password", "a_password", NULL }; ProfAccount *account = account_new("a_account", NULL, NULL, NULL, TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_get_account, name, "a_account"); will_return(accounts_get_account, account); expect_string(accounts_set_eval_password, account_name, "a_account"); expect_string(accounts_set_eval_password, value, "a_password"); expect_cons_show("Updated eval_password for account a_account"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_password_when_eval_password_set(void **state) { gchar *args[] = { "set", "a_account", "password", "a_password", NULL }; ProfAccount *account = account_new("a_account", NULL, NULL, "a_password", TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_get_account, name, "a_account"); will_return(accounts_get_account, account); expect_cons_show("Cannot set password when eval_password is set."); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_eval_password_when_password_set(void **state) { gchar *args[] = { "set", "a_account", "eval_password", "a_password", NULL }; ProfAccount *account = account_new("a_account", NULL, "a_password", NULL, TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_get_account, name, "a_account"); will_return(accounts_get_account, account); expect_cons_show("Cannot set eval_password when password is set."); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_muc_sets_muc(void **state) { gchar *args[] = { "set", "a_account", "muc", "a_muc", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_muc_service, account_name, "a_account"); expect_string(accounts_set_muc_service, value, "a_muc"); expect_cons_show("Updated muc service for account a_account: a_muc"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_nick_sets_nick(void **state) { gchar *args[] = { "set", "a_account", "nick", "a_nick", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_muc_nick, account_name, "a_account"); expect_string(accounts_set_muc_nick, value, "a_nick"); expect_cons_show("Updated muc nick for account a_account: a_nick"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_show_message_for_missing_otr_policy(void **state) { gchar *args[] = { "set", "a_account", "otr", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_show_message_for_invalid_otr_policy(void **state) { gchar *args[] = { "set", "a_account", "otr", "bad_otr_policy", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_cons_show("OTR policy must be one of: manual, opportunistic or always."); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_otr_sets_otr(void **state) { gchar *args[] = { "set", "a_account", "otr", "opportunistic", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_otr_policy, account_name, "a_account"); expect_string(accounts_set_otr_policy, value, "opportunistic"); expect_cons_show("Updated OTR policy for account a_account: opportunistic"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_status_shows_message_when_invalid_status(void **state) { gchar *args[] = { "set", "a_account", "status", "bad_status", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_cons_show("Invalid status: bad_status"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_status_sets_status_when_valid(void **state) { gchar *args[] = { "set", "a_account", "status", "away", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_login_presence, account_name, "a_account"); expect_string(accounts_set_login_presence, value, "away"); expect_cons_show("Updated login status for account a_account: away"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_status_sets_status_when_last(void **state) { gchar *args[] = { "set", "a_account", "status", "last", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_login_presence, account_name, "a_account"); expect_string(accounts_set_login_presence, value, "last"); expect_cons_show("Updated login status for account a_account: last"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_invalid_presence_string_priority_shows_message(void **state) { gchar *args[] = { "set", "a_account", "blah", "10", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_cons_show("Invalid property: blah"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_last_priority_shows_message(void **state) { gchar *args[] = { "set", "a_account", "last", "10", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_cons_show("Invalid property: last"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_online_priority_sets_preference(void **state) { gchar *args[] = { "set", "a_account", "online", "10", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_priority_online, account_name, "a_account"); expect_value(accounts_set_priority_online, value, 10); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("Updated online priority for account a_account: 10"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_chat_priority_sets_preference(void **state) { gchar *args[] = { "set", "a_account", "chat", "10", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_priority_chat, account_name, "a_account"); expect_value(accounts_set_priority_chat, value, 10); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("Updated chat priority for account a_account: 10"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_away_priority_sets_preference(void **state) { gchar *args[] = { "set", "a_account", "away", "10", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_priority_away, account_name, "a_account"); expect_value(accounts_set_priority_away, value, 10); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("Updated away priority for account a_account: 10"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_xa_priority_sets_preference(void **state) { gchar *args[] = { "set", "a_account", "xa", "10", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_priority_xa, account_name, "a_account"); expect_value(accounts_set_priority_xa, value, 10); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("Updated xa priority for account a_account: 10"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_dnd_priority_sets_preference(void **state) { gchar *args[] = { "set", "a_account", "dnd", "10", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_string(accounts_set_priority_dnd, account_name, "a_account"); expect_value(accounts_set_priority_dnd, value, 10); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("Updated dnd priority for account a_account: 10"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_priority_too_low_shows_message(void **state) { gchar *args[] = { "set", "a_account", "online", "-150", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_cons_show("Value -150 out of range. Must be in -128..127."); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_priority_too_high_shows_message(void **state) { gchar *args[] = { "set", "a_account", "online", "150", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_cons_show("Value 150 out of range. Must be in -128..127."); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_priority_when_not_number_shows_message(void **state) { gchar *args[] = { "set", "a_account", "online", "abc", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_cons_show("Could not convert \"abc\" to a number."); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_priority_when_empty_shows_message(void **state) { gchar *args[] = { "set", "a_account", "online", "", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_cons_show("Could not convert \"\" to a number."); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_set_priority_updates_presence_when_account_connected_with_presence(void **state) { gchar *args[] = { "set", "a_account", "online", "10", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_any(accounts_set_priority_online, account_name); expect_any(accounts_set_priority_online, value); will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_any(accounts_get_last_presence, account_name); will_return(accounts_get_last_presence, RESOURCE_ONLINE); will_return(jabber_get_account_name, "a_account"); #ifdef HAVE_LIBGPGME ProfAccount *account = account_new("a_account", "a_jid", NULL, NULL, TRUE, NULL, 5222, "a_resource", NULL, NULL, 10, 10, 10, 10, 10, NULL, NULL, NULL, NULL, NULL, NULL, NULL); will_return(jabber_get_account_name, "a_account"); expect_any(accounts_get_account, name); will_return(accounts_get_account, account); #endif will_return(jabber_get_presence_message, "Free to chat"); expect_value(presence_send, status, RESOURCE_ONLINE); expect_string(presence_send, msg, "Free to chat"); expect_value(presence_send, idle, 0); expect_value(presence_send, signed_status, NULL); expect_cons_show("Updated online priority for account a_account: 10"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_clear_shows_usage_when_no_args(void **state) { gchar *args[] = { "clear", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_clear_shows_usage_when_one_arg(void **state) { gchar *args[] = { "clear", "a_account", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ACCOUNT); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_clear_shows_message_when_account_doesnt_exist(void **state) { gchar *args[] = { "clear", "a_account", "a_property", NULL }; expect_string(accounts_account_exists, account_name, "a_account"); will_return(accounts_account_exists, FALSE); expect_cons_show("Account a_account doesn't exist"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } void cmd_account_clear_shows_message_when_invalid_property(void **state) { gchar *args[] = { "clear", "a_account", "badproperty", NULL }; expect_any(accounts_account_exists, account_name); will_return(accounts_account_exists, TRUE); expect_cons_show("Invalid property: badproperty"); expect_cons_show(""); gboolean result = cmd_account(NULL, CMD_ACCOUNT, args); assert_true(result); } profanity-0.4.7/tests/unittests/test_cmd_account.h000066400000000000000000000071451257755232500224540ustar00rootroot00000000000000void cmd_account_shows_usage_when_not_connected_and_no_args(void **state); void cmd_account_shows_account_when_connected_and_no_args(void **state); void cmd_account_list_shows_accounts(void **state); void cmd_account_show_shows_usage_when_no_arg(void **state); void cmd_account_show_shows_message_when_account_does_not_exist(void **state); void cmd_account_show_shows_account_when_exists(void **state); void cmd_account_add_shows_usage_when_no_arg(void **state); void cmd_account_add_adds_account(void **state); void cmd_account_enable_shows_usage_when_no_arg(void **state); void cmd_account_enable_enables_account(void **state); void cmd_account_enable_shows_message_when_account_doesnt_exist(void **state); void cmd_account_disable_shows_usage_when_no_arg(void **state); void cmd_account_disable_disables_account(void **state); void cmd_account_disable_shows_message_when_account_doesnt_exist(void **state); void cmd_account_rename_shows_usage_when_no_args(void **state); void cmd_account_rename_shows_usage_when_one_arg(void **state); void cmd_account_rename_renames_account(void **state); void cmd_account_rename_shows_message_when_not_renamed(void **state); void cmd_account_set_shows_usage_when_no_args(void **state); void cmd_account_set_shows_usage_when_one_arg(void **state); void cmd_account_set_shows_usage_when_two_args(void **state); void cmd_account_set_shows_message_when_account_doesnt_exist(void **state); void cmd_account_set_jid_shows_message_for_malformed_jid(void **state); void cmd_account_set_jid_sets_barejid(void **state); void cmd_account_set_jid_sets_resource(void **state); void cmd_account_set_server_sets_server(void **state); void cmd_account_set_resource_sets_resource(void **state); void cmd_account_set_resource_sets_resource_with_online_message(void **state); void cmd_account_set_password_sets_password(void **state); void cmd_account_set_eval_password_sets_eval_password(void **state); void cmd_account_set_password_when_eval_password_set(void **state); void cmd_account_set_eval_password_when_password_set(void **state); void cmd_account_set_muc_sets_muc(void **state); void cmd_account_set_nick_sets_nick(void **state); void cmd_account_show_message_for_missing_otr_policy(void **state); void cmd_account_show_message_for_invalid_otr_policy(void **state); void cmd_account_set_otr_sets_otr(void **state); void cmd_account_set_status_shows_message_when_invalid_status(void **state); void cmd_account_set_status_sets_status_when_valid(void **state); void cmd_account_set_status_sets_status_when_last(void **state); void cmd_account_set_invalid_presence_string_priority_shows_message(void **state); void cmd_account_set_last_priority_shows_message(void **state); void cmd_account_set_online_priority_sets_preference(void **state); void cmd_account_set_chat_priority_sets_preference(void **state); void cmd_account_set_away_priority_sets_preference(void **state); void cmd_account_set_xa_priority_sets_preference(void **state); void cmd_account_set_dnd_priority_sets_preference(void **state); void cmd_account_set_priority_too_low_shows_message(void **state); void cmd_account_set_priority_too_high_shows_message(void **state); void cmd_account_set_priority_when_not_number_shows_message(void **state); void cmd_account_set_priority_when_empty_shows_message(void **state); void cmd_account_set_priority_updates_presence_when_account_connected_with_presence(void **state); void cmd_account_clear_shows_usage_when_no_args(void **state); void cmd_account_clear_shows_usage_when_one_arg(void **state); void cmd_account_clear_shows_message_when_account_doesnt_exist(void **state); void cmd_account_clear_shows_message_when_invalid_property(void **state); profanity-0.4.7/tests/unittests/test_cmd_alias.c000066400000000000000000000061151257755232500221000ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "xmpp/xmpp.h" #include "ui/ui.h" #include "ui/stub_ui.h" #include "config/preferences.h" #include "command/command.h" #include "command/commands.h" #define CMD_ALIAS "/alias" void cmd_alias_add_shows_usage_when_no_args(void **state) { gchar *args[] = { "add", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ALIAS); gboolean result = cmd_alias(NULL, CMD_ALIAS, args); assert_true(result); } void cmd_alias_add_shows_usage_when_no_value(void **state) { gchar *args[] = { "add", "alias", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ALIAS); gboolean result = cmd_alias(NULL, CMD_ALIAS, args); assert_true(result); } void cmd_alias_remove_shows_usage_when_no_args(void **state) { gchar *args[] = { "remove", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ALIAS); gboolean result = cmd_alias(NULL, CMD_ALIAS, args); assert_true(result); } void cmd_alias_show_usage_when_invalid_subcmd(void **state) { gchar *args[] = { "blah", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_ALIAS); gboolean result = cmd_alias(NULL, CMD_ALIAS, args); assert_true(result); } void cmd_alias_add_adds_alias(void **state) { gchar *args[] = { "add", "hc", "/help commands", NULL }; expect_cons_show("Command alias added /hc -> /help commands"); gboolean result = cmd_alias(NULL, CMD_ALIAS, args); assert_true(result); char *returned_val = prefs_get_alias("hc"); assert_string_equal("/help commands", returned_val); } void cmd_alias_add_shows_message_when_exists(void **state) { gchar *args[] = { "add", "hc", "/help commands", NULL }; cmd_init(); prefs_add_alias("hc", "/help commands"); cmd_autocomplete_add("/hc"); expect_cons_show("Command or alias '/hc' already exists."); gboolean result = cmd_alias(NULL, CMD_ALIAS, args); assert_true(result); } void cmd_alias_remove_removes_alias(void **state) { gchar *args[] = { "remove", "hn", NULL }; prefs_add_alias("hn", "/help navigation"); expect_cons_show("Command alias removed -> /hn"); gboolean result = cmd_alias(NULL, CMD_ALIAS, args); assert_true(result); char *returned_val = prefs_get_alias("hn"); assert_null(returned_val); } void cmd_alias_remove_shows_message_when_no_alias(void **state) { gchar *args[] = { "remove", "hn", NULL }; expect_cons_show("No such command alias /hn"); gboolean result = cmd_alias(NULL, CMD_ALIAS, args); assert_true(result); } void cmd_alias_list_shows_all_aliases(void **state) { gchar *args[] = { "list", NULL }; prefs_add_alias("vy", "/vercheck on"); prefs_add_alias("q", "/quit"); prefs_add_alias("hn", "/help navigation"); prefs_add_alias("hc", "/help commands"); prefs_add_alias("vn", "/vercheck off"); // write a custom checker to check the correct list is passed expect_any(cons_show_aliases, aliases); gboolean result = cmd_alias(NULL, CMD_ALIAS, args); assert_true(result); } profanity-0.4.7/tests/unittests/test_cmd_alias.h000066400000000000000000000010041257755232500220750ustar00rootroot00000000000000void cmd_alias_add_shows_usage_when_no_args(void **state); void cmd_alias_add_shows_usage_when_no_value(void **state); void cmd_alias_remove_shows_usage_when_no_args(void **state); void cmd_alias_show_usage_when_invalid_subcmd(void **state); void cmd_alias_add_adds_alias(void **state); void cmd_alias_add_shows_message_when_exists(void **state); void cmd_alias_remove_removes_alias(void **state); void cmd_alias_remove_shows_message_when_no_alias(void **state); void cmd_alias_list_shows_all_aliases(void **state); profanity-0.4.7/tests/unittests/test_cmd_bookmark.c000066400000000000000000000167151257755232500226230ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "xmpp/xmpp.h" #include "ui/ui.h" #include "ui/stub_ui.h" #include "muc.h" #include "common.h" #include "command/commands.h" #include "xmpp/bookmark.h" #include "helpers.h" #define CMD_BOOKMARK "/bookmark" static void test_with_connection_status(jabber_conn_status_t status) { will_return(jabber_get_connection_status, status); expect_cons_show("You are not currently connected."); gboolean result = cmd_bookmark(NULL, CMD_BOOKMARK, NULL); assert_true(result); } void cmd_bookmark_shows_message_when_disconnected(void **state) { test_with_connection_status(JABBER_DISCONNECTED); } void cmd_bookmark_shows_message_when_disconnecting(void **state) { test_with_connection_status(JABBER_DISCONNECTING); } void cmd_bookmark_shows_message_when_connecting(void **state) { test_with_connection_status(JABBER_CONNECTING); } void cmd_bookmark_shows_message_when_started(void **state) { test_with_connection_status(JABBER_STARTED); } void cmd_bookmark_shows_message_when_undefined(void **state) { test_with_connection_status(JABBER_UNDEFINED); } void cmd_bookmark_shows_usage_when_no_args(void **state) { gchar *args[] = { NULL }; ProfWin window; window.type = WIN_CONSOLE; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_BOOKMARK); gboolean result = cmd_bookmark(&window, CMD_BOOKMARK, args); assert_true(result); } static void _free_bookmark(Bookmark *bookmark) { free(bookmark->jid); free(bookmark->nick); free(bookmark); } static gboolean _cmp_bookmark(Bookmark *bm1, Bookmark *bm2) { if (strcmp(bm1->jid, bm2->jid) != 0) { return FALSE; } if (strcmp(bm1->nick, bm2->nick) != 0) { return FALSE; } if (bm1->autojoin != bm2->autojoin) { return FALSE; } return TRUE; } void cmd_bookmark_list_shows_bookmarks(void **state) { gchar *args[] = { "list", NULL }; GList *bookmarks = NULL; ProfWin window; window.type = WIN_CONSOLE; Bookmark *bm1 = malloc(sizeof(Bookmark)); bm1->jid = strdup("room1@conf.org"); bm1->nick = strdup("bob"); bm1->autojoin = FALSE; Bookmark *bm2 = malloc(sizeof(Bookmark)); bm2->jid = strdup("room2@conf.org"); bm2->nick = strdup("steve"); bm2->autojoin = TRUE; Bookmark *bm3 = malloc(sizeof(Bookmark)); bm3->jid = strdup("room3@conf.org"); bm3->nick = strdup("dave"); bm3->autojoin = TRUE; Bookmark *bm4 = malloc(sizeof(Bookmark)); bm4->jid = strdup("room4@conf.org"); bm4->nick = strdup("james"); bm4->autojoin = FALSE; Bookmark *bm5 = malloc(sizeof(Bookmark)); bm5->jid = strdup("room5@conf.org"); bm5->nick = strdup("mike"); bm5->autojoin = FALSE; bookmarks = g_list_append(bookmarks, bm1); bookmarks = g_list_append(bookmarks, bm2); bookmarks = g_list_append(bookmarks, bm3); bookmarks = g_list_append(bookmarks, bm4); bookmarks = g_list_append(bookmarks, bm5); will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(bookmark_get_list, bookmarks); // TODO - Custom list compare glist_set_cmp((GCompareFunc)_cmp_bookmark); expect_any(cons_show_bookmarks, list); gboolean result = cmd_bookmark(&window, CMD_BOOKMARK, args); assert_true(result); g_list_free_full(bookmarks, (GDestroyNotify)_free_bookmark); } void cmd_bookmark_add_shows_message_when_invalid_jid(void **state) { char *jid = "room"; gchar *args[] = { "add", jid, NULL }; ProfWin window; window.type = WIN_CONSOLE; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_cons_show("Can't add bookmark with JID 'room'; should be 'room@domain.tld'"); gboolean result = cmd_bookmark(&window, CMD_BOOKMARK, args); assert_true(result); } void cmd_bookmark_add_adds_bookmark_with_jid(void **state) { char *jid = "room@conf.server"; gchar *args[] = { "add", jid, NULL }; ProfWin window; window.type = WIN_CONSOLE; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(bookmark_add, jid, jid); expect_any(bookmark_add, nick); expect_any(bookmark_add, password); expect_any(bookmark_add, autojoin_str); will_return(bookmark_add, TRUE); expect_cons_show("Bookmark added for room@conf.server."); gboolean result = cmd_bookmark(&window, CMD_BOOKMARK, args); assert_true(result); } void cmd_bookmark_add_adds_bookmark_with_jid_nick(void **state) { char *jid = "room@conf.server"; char *nick = "bob"; gchar *args[] = { "add", jid, "nick", nick, NULL }; ProfWin window; window.type = WIN_CONSOLE; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(bookmark_add, jid, jid); expect_string(bookmark_add, nick, nick); expect_any(bookmark_add, password); expect_any(bookmark_add, autojoin_str); will_return(bookmark_add, TRUE); expect_cons_show("Bookmark added for room@conf.server."); gboolean result = cmd_bookmark(&window, CMD_BOOKMARK, args); assert_true(result); } void cmd_bookmark_add_adds_bookmark_with_jid_autojoin(void **state) { char *jid = "room@conf.server"; gchar *args[] = { "add", jid, "autojoin", "on", NULL }; ProfWin window; window.type = WIN_CONSOLE; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(bookmark_add, jid, jid); expect_any(bookmark_add, nick); expect_any(bookmark_add, password); expect_string(bookmark_add, autojoin_str, "on"); will_return(bookmark_add, TRUE); expect_cons_show("Bookmark added for room@conf.server."); gboolean result = cmd_bookmark(&window, CMD_BOOKMARK, args); assert_true(result); } void cmd_bookmark_add_adds_bookmark_with_jid_nick_autojoin(void **state) { char *jid = "room@conf.server"; char *nick = "bob"; gchar *args[] = { "add", jid, "nick", nick, "autojoin", "on", NULL }; ProfWin window; window.type = WIN_CONSOLE; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(bookmark_add, jid, jid); expect_string(bookmark_add, nick, nick); expect_any(bookmark_add, password); expect_string(bookmark_add, autojoin_str, "on"); will_return(bookmark_add, TRUE); expect_cons_show("Bookmark added for room@conf.server."); gboolean result = cmd_bookmark(&window, CMD_BOOKMARK, args); assert_true(result); } void cmd_bookmark_remove_removes_bookmark(void **state) { char *jid = "room@conf.server"; gchar *args[] = { "remove", jid, NULL }; ProfWin window; window.type = WIN_CONSOLE; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(bookmark_remove, jid, jid); will_return(bookmark_remove, TRUE); expect_cons_show("Bookmark removed for room@conf.server."); gboolean result = cmd_bookmark(&window, CMD_BOOKMARK, args); assert_true(result); } void cmd_bookmark_remove_shows_message_when_no_bookmark(void **state) { char *jid = "room@conf.server"; gchar *args[] = { "remove", jid, NULL }; ProfWin window; window.type = WIN_CONSOLE; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_any(bookmark_remove, jid); will_return(bookmark_remove, FALSE); expect_cons_show("No bookmark exists for room@conf.server."); gboolean result = cmd_bookmark(&window, CMD_BOOKMARK, args); assert_true(result); } profanity-0.4.7/tests/unittests/test_cmd_bookmark.h000066400000000000000000000015741257755232500226250ustar00rootroot00000000000000void cmd_bookmark_shows_message_when_disconnected(void **state); void cmd_bookmark_shows_message_when_disconnecting(void **state); void cmd_bookmark_shows_message_when_connecting(void **state); void cmd_bookmark_shows_message_when_started(void **state); void cmd_bookmark_shows_message_when_undefined(void **state); void cmd_bookmark_shows_usage_when_no_args(void **state); void cmd_bookmark_list_shows_bookmarks(void **state); void cmd_bookmark_add_shows_message_when_invalid_jid(void **state); void cmd_bookmark_add_adds_bookmark_with_jid(void **state); void cmd_bookmark_add_adds_bookmark_with_jid_nick(void **state); void cmd_bookmark_add_adds_bookmark_with_jid_autojoin(void **state); void cmd_bookmark_add_adds_bookmark_with_jid_nick_autojoin(void **state); void cmd_bookmark_remove_removes_bookmark(void **state); void cmd_bookmark_remove_shows_message_when_no_bookmark(void **state); profanity-0.4.7/tests/unittests/test_cmd_connect.c000066400000000000000000000312221257755232500224350ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "xmpp/xmpp.h" #include "ui/ui.h" #include "ui/stub_ui.h" #include "command/commands.h" #include "config/accounts.h" #define CMD_CONNECT "/connect" static void test_with_connection_status(jabber_conn_status_t status) { will_return(jabber_get_connection_status, status); expect_cons_show("You are either connected already, or a login is in process."); gboolean result = cmd_connect(NULL, CMD_CONNECT, NULL); assert_true(result); } void cmd_connect_shows_message_when_disconnecting(void **state) { test_with_connection_status(JABBER_DISCONNECTING); } void cmd_connect_shows_message_when_connecting(void **state) { test_with_connection_status(JABBER_CONNECTING); } void cmd_connect_shows_message_when_connected(void **state) { test_with_connection_status(JABBER_CONNECTED); } void cmd_connect_shows_message_when_undefined(void **state) { test_with_connection_status(JABBER_UNDEFINED); } void cmd_connect_when_no_account(void **state) { gchar *args[] = { "user@server.org", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(accounts_get_account, name, "user@server.org"); will_return(accounts_get_account, NULL); will_return(ui_ask_password, strdup("password")); expect_cons_show("Connecting as user@server.org"); expect_string(jabber_connect_with_details, jid, "user@server.org"); expect_string(jabber_connect_with_details, passwd, "password"); expect_value(jabber_connect_with_details, altdomain, NULL); expect_value(jabber_connect_with_details, port, 0); will_return(jabber_connect_with_details, JABBER_CONNECTING); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_fail_message(void **state) { gchar *args[] = { "user@server.org", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_any(accounts_get_account, name); will_return(accounts_get_account, NULL); will_return(ui_ask_password, strdup("password")); expect_cons_show("Connecting as user@server.org"); expect_any(jabber_connect_with_details, jid); expect_any(jabber_connect_with_details, passwd); expect_any(jabber_connect_with_details, altdomain); expect_any(jabber_connect_with_details, port); will_return(jabber_connect_with_details, JABBER_DISCONNECTED); expect_cons_show_error("Connection attempt for user@server.org failed."); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_lowercases_argument(void **state) { gchar *args[] = { "USER@server.ORG", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(accounts_get_account, name, "user@server.org"); will_return(accounts_get_account, NULL); will_return(ui_ask_password, strdup("password")); expect_cons_show("Connecting as user@server.org"); expect_any(jabber_connect_with_details, jid); expect_any(jabber_connect_with_details, passwd); expect_any(jabber_connect_with_details, altdomain); expect_any(jabber_connect_with_details, port); will_return(jabber_connect_with_details, JABBER_CONNECTING); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_asks_password_when_not_in_account(void **state) { gchar *args[] = { "jabber_org", NULL }; ProfAccount *account = account_new("jabber_org", "me@jabber.org", NULL, NULL, TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_any(accounts_get_account, name); will_return(accounts_get_account, account); will_return(ui_ask_password, strdup("password")); expect_cons_show("Connecting with account jabber_org as me@jabber.org"); expect_any(jabber_connect_with_account, account); will_return(jabber_connect_with_account, JABBER_CONNECTING); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_usage_when_no_server_value(void **state) { gchar *args[] = { "user@server.org", "server", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_CONNECT); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_usage_when_server_no_port_value(void **state) { gchar *args[] = { "user@server.org", "server", "aserver", "port", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_CONNECT); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_usage_when_no_port_value(void **state) { gchar *args[] = { "user@server.org", "port", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_CONNECT); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_usage_when_port_no_server_value(void **state) { gchar *args[] = { "user@server.org", "port", "5678", "server", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_CONNECT); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_message_when_port_0(void **state) { gchar *args[] = { "user@server.org", "port", "0", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("Value 0 out of range. Must be in 1..65535."); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_message_when_port_minus1(void **state) { gchar *args[] = { "user@server.org", "port", "-1", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("Value -1 out of range. Must be in 1..65535."); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_message_when_port_65536(void **state) { gchar *args[] = { "user@server.org", "port", "65536", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("Value 65536 out of range. Must be in 1..65535."); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_message_when_port_contains_chars(void **state) { gchar *args[] = { "user@server.org", "port", "52f66", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("Could not convert \"52f66\" to a number."); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_usage_when_server_provided_twice(void **state) { gchar *args[] = { "user@server.org", "server", "server1", "server", "server2", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_CONNECT); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_usage_when_port_provided_twice(void **state) { gchar *args[] = { "user@server.org", "port", "1111", "port", "1111", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_CONNECT); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_usage_when_invalid_first_property(void **state) { gchar *args[] = { "user@server.org", "wrong", "server", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_CONNECT); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_usage_when_invalid_second_property(void **state) { gchar *args[] = { "user@server.org", "server", "aserver", "wrong", "1234", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_CONNECT); expect_cons_show(""); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_with_server_when_provided(void **state) { gchar *args[] = { "user@server.org", "server", "aserver", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(accounts_get_account, name, "user@server.org"); will_return(accounts_get_account, NULL); will_return(ui_ask_password, strdup("password")); expect_cons_show("Connecting as user@server.org"); expect_string(jabber_connect_with_details, jid, "user@server.org"); expect_string(jabber_connect_with_details, passwd, "password"); expect_string(jabber_connect_with_details, altdomain, "aserver"); expect_value(jabber_connect_with_details, port, 0); will_return(jabber_connect_with_details, JABBER_CONNECTING); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_with_port_when_provided(void **state) { gchar *args[] = { "user@server.org", "port", "5432", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(accounts_get_account, name, "user@server.org"); will_return(accounts_get_account, NULL); will_return(ui_ask_password, strdup("password")); expect_cons_show("Connecting as user@server.org"); expect_string(jabber_connect_with_details, jid, "user@server.org"); expect_string(jabber_connect_with_details, passwd, "password"); expect_value(jabber_connect_with_details, altdomain, NULL); expect_value(jabber_connect_with_details, port, 5432); will_return(jabber_connect_with_details, JABBER_CONNECTING); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_with_server_and_port_when_provided(void **state) { gchar *args[] = { "user@server.org", "port", "5432", "server", "aserver", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_string(accounts_get_account, name, "user@server.org"); will_return(accounts_get_account, NULL); will_return(ui_ask_password, strdup("password")); expect_cons_show("Connecting as user@server.org"); expect_string(jabber_connect_with_details, jid, "user@server.org"); expect_string(jabber_connect_with_details, passwd, "password"); expect_string(jabber_connect_with_details, altdomain, "aserver"); expect_value(jabber_connect_with_details, port, 5432); will_return(jabber_connect_with_details, JABBER_CONNECTING); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_shows_message_when_connecting_with_account(void **state) { gchar *args[] = { "jabber_org", NULL }; ProfAccount *account = account_new("jabber_org", "user@jabber.org", "password", NULL, TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_any(accounts_get_account, name); will_return(accounts_get_account, account); expect_cons_show("Connecting with account jabber_org as user@jabber.org/laptop"); expect_any(jabber_connect_with_account, account); will_return(jabber_connect_with_account, JABBER_CONNECTING); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } void cmd_connect_connects_with_account(void **state) { gchar *args[] = { "jabber_org", NULL }; ProfAccount *account = account_new("jabber_org", "me@jabber.org", "password", NULL, TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_any(accounts_get_account, name); will_return(accounts_get_account, account); expect_cons_show("Connecting with account jabber_org as me@jabber.org"); expect_memory(jabber_connect_with_account, account, account, sizeof(account)); will_return(jabber_connect_with_account, JABBER_CONNECTING); gboolean result = cmd_connect(NULL, CMD_CONNECT, args); assert_true(result); } profanity-0.4.7/tests/unittests/test_cmd_connect.h000066400000000000000000000031461257755232500224460ustar00rootroot00000000000000void cmd_connect_shows_message_when_disconnecting(void **state); void cmd_connect_shows_message_when_connecting(void **state); void cmd_connect_shows_message_when_connected(void **state); void cmd_connect_shows_message_when_undefined(void **state); void cmd_connect_when_no_account(void **state); void cmd_connect_with_altdomain_when_provided(void **state); void cmd_connect_fail_message(void **state); void cmd_connect_lowercases_argument(void **state); void cmd_connect_asks_password_when_not_in_account(void **state); void cmd_connect_shows_message_when_connecting_with_account(void **state); void cmd_connect_connects_with_account(void **state); void cmd_connect_shows_usage_when_no_server_value(void **state); void cmd_connect_shows_usage_when_server_no_port_value(void **state); void cmd_connect_shows_usage_when_no_port_value(void **state); void cmd_connect_shows_usage_when_port_no_server_value(void **state); void cmd_connect_shows_message_when_port_0(void **state); void cmd_connect_shows_message_when_port_minus1(void **state); void cmd_connect_shows_message_when_port_65536(void **state); void cmd_connect_shows_message_when_port_contains_chars(void **state); void cmd_connect_with_server_when_provided(void **state); void cmd_connect_with_port_when_provided(void **state); void cmd_connect_with_server_and_port_when_provided(void **state); void cmd_connect_shows_usage_when_server_provided_twice(void **state); void cmd_connect_shows_usage_when_port_provided_twice(void **state); void cmd_connect_shows_usage_when_invalid_first_property(void **state); void cmd_connect_shows_usage_when_invalid_second_property(void **state); profanity-0.4.7/tests/unittests/test_cmd_disconnect.c000066400000000000000000000016631257755232500231430ustar00rootroot00000000000000#include #include #include #include #include #include #include "chat_session.h" #include "command/commands.h" #include "xmpp/xmpp.h" #include "roster_list.h" #include "ui/stub_ui.h" #define CMD_DISCONNECT "/disconnect" void clears_chat_sessions(void **state) { chat_sessions_init(); roster_init(); chat_session_recipient_active("bob@server.org", "laptop", FALSE); chat_session_recipient_active("mike@server.org", "work", FALSE); will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(jabber_get_fulljid, "myjid@myserver.com"); expect_any_cons_show(); gboolean result = cmd_disconnect(NULL, CMD_DISCONNECT, NULL); assert_true(result); ChatSession *session1 = chat_session_get("bob@server.org"); ChatSession *session2 = chat_session_get("mike@server.org"); assert_null(session1); assert_null(session2); } profanity-0.4.7/tests/unittests/test_cmd_disconnect.h000066400000000000000000000000511257755232500231360ustar00rootroot00000000000000void clears_chat_sessions(void **state); profanity-0.4.7/tests/unittests/test_cmd_join.c000066400000000000000000000122101257755232500217370ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "xmpp/xmpp.h" #include "ui/ui.h" #include "ui/stub_ui.h" #include "config/accounts.h" #include "command/commands.h" #include "muc.h" #define CMD_JOIN "/join" static void test_with_connection_status(jabber_conn_status_t status) { will_return(jabber_get_connection_status, status); expect_cons_show("You are not currently connected."); gboolean result = cmd_join(NULL, CMD_JOIN, NULL); assert_true(result); } void cmd_join_shows_message_when_disconnecting(void **state) { test_with_connection_status(JABBER_DISCONNECTING); } void cmd_join_shows_message_when_connecting(void **state) { test_with_connection_status(JABBER_CONNECTING); } void cmd_join_shows_message_when_disconnected(void **state) { test_with_connection_status(JABBER_DISCONNECTED); } void cmd_join_shows_message_when_undefined(void **state) { test_with_connection_status(JABBER_UNDEFINED); } void cmd_join_shows_error_message_when_invalid_room_jid(void **state) { gchar *args[] = { "//@@/", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_cons_show_error("Specified room has incorrect format."); expect_cons_show(""); gboolean result = cmd_join(NULL, CMD_JOIN, args); assert_true(result); } void cmd_join_uses_account_mucservice_when_no_service_specified(void **state) { char *account_name = "an_account"; char *room = "room"; char *nick = "bob"; char *account_service = "conference.server.org"; char *expected_room = "room@conference.server.org"; gchar *args[] = { room, "nick", nick, NULL }; ProfAccount *account = account_new(account_name, "user@server.org", NULL, NULL, TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, account_service, NULL, NULL, NULL, NULL, NULL, NULL); muc_init(); will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(jabber_get_account_name, account_name); expect_string(accounts_get_account, name, account_name); will_return(accounts_get_account, account); expect_string(presence_join_room, room, expected_room); expect_string(presence_join_room, nick, nick); expect_value(presence_join_room, passwd, NULL); gboolean result = cmd_join(NULL, CMD_JOIN, args); assert_true(result); } void cmd_join_uses_supplied_nick(void **state) { char *account_name = "an_account"; char *room = "room@conf.server.org"; char *nick = "bob"; gchar *args[] = { room, "nick", nick, NULL }; ProfAccount *account = account_new(account_name, "user@server.org", NULL, NULL, TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); muc_init(); will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(jabber_get_account_name, account_name); expect_string(accounts_get_account, name, account_name); will_return(accounts_get_account, account); expect_string(presence_join_room, room, room); expect_string(presence_join_room, nick, nick); expect_value(presence_join_room, passwd, NULL); gboolean result = cmd_join(NULL, CMD_JOIN, args); assert_true(result); } void cmd_join_uses_account_nick_when_not_supplied(void **state) { char *account_name = "an_account"; char *room = "room2@conf.server.org"; char *account_nick = "a_nick"; gchar *args[] = { room, NULL }; ProfAccount *account = account_new(account_name, "user@server.org", NULL, NULL, TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, account_nick, NULL, NULL, NULL, NULL, NULL); muc_init(); will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(jabber_get_account_name, account_name); expect_string(accounts_get_account, name, account_name); will_return(accounts_get_account, account); expect_string(presence_join_room, room, room); expect_string(presence_join_room, nick, account_nick); expect_value(presence_join_room, passwd, NULL); gboolean result = cmd_join(NULL, CMD_JOIN, args); assert_true(result); } void cmd_join_uses_password_when_supplied(void **state) { char *account_name = "an_account"; char *room = "room"; char *password = "a_password"; char *account_nick = "a_nick"; char *account_service = "a_service"; char *expected_room = "room@a_service"; gchar *args[] = { room, "password", password, NULL }; ProfAccount *account = account_new(account_name, "user@server.org", NULL, NULL, TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, account_service, account_nick, NULL, NULL, NULL, NULL, NULL); muc_init(); will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(jabber_get_account_name, account_name); expect_string(accounts_get_account, name, account_name); will_return(accounts_get_account, account); expect_string(presence_join_room, room, expected_room); expect_string(presence_join_room, nick, account_nick); expect_value(presence_join_room, passwd, password); gboolean result = cmd_join(NULL, CMD_JOIN, args); assert_true(result); } profanity-0.4.7/tests/unittests/test_cmd_join.h000066400000000000000000000010601257755232500217450ustar00rootroot00000000000000void cmd_join_shows_message_when_disconnecting(void **state); void cmd_join_shows_message_when_connecting(void **state); void cmd_join_shows_message_when_disconnected(void **state); void cmd_join_shows_message_when_undefined(void **state); void cmd_join_shows_error_message_when_invalid_room_jid(void **state); void cmd_join_uses_account_mucservice_when_no_service_specified(void **state); void cmd_join_uses_supplied_nick(void **state); void cmd_join_uses_account_nick_when_not_supplied(void **state); void cmd_join_uses_password_when_supplied(void **state); profanity-0.4.7/tests/unittests/test_cmd_otr.c000066400000000000000000000321411257755232500216110ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "config.h" #ifdef HAVE_LIBOTR #include #include "otr/otr.h" #endif #include "config/preferences.h" #include "command/command.h" #include "command/commands.h" #include "window_list.h" #include "ui/ui.h" #include "ui/stub_ui.h" #define CMD_OTR "/otr" #ifdef HAVE_LIBOTR void cmd_otr_shows_usage_when_no_args(void **state) { gchar *args[] = { NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_OTR); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } void cmd_otr_shows_usage_when_invalid_subcommand(void **state) { gchar *args[] = { "unknown", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_OTR); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } void cmd_otr_log_shows_usage_when_no_args(void **state) { gchar *args[] = { "log", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_OTR); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } void cmd_otr_log_shows_usage_when_invalid_subcommand(void **state) { gchar *args[] = { "log", "wrong", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_OTR); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } void cmd_otr_log_on_enables_logging(void **state) { gchar *args[] = { "log", "on", NULL }; prefs_set_string(PREF_OTR_LOG, "off"); prefs_set_boolean(PREF_CHLOG, TRUE); expect_cons_show("OTR messages will be logged as plaintext."); gboolean result = cmd_otr(NULL, CMD_OTR, args); char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); assert_true(result); assert_string_equal("on", pref_otr_log); } void cmd_otr_log_on_shows_warning_when_chlog_disabled(void **state) { gchar *args[] = { "log", "on", NULL }; prefs_set_string(PREF_OTR_LOG, "off"); prefs_set_boolean(PREF_CHLOG, FALSE); expect_cons_show("OTR messages will be logged as plaintext."); expect_cons_show("Chat logging is currently disabled, use '/chlog on' to enable."); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } void cmd_otr_log_off_disables_logging(void **state) { gchar *args[] = { "log", "off", NULL }; prefs_set_string(PREF_OTR_LOG, "on"); prefs_set_boolean(PREF_CHLOG, TRUE); expect_cons_show("OTR message logging disabled."); gboolean result = cmd_otr(NULL, CMD_OTR, args); char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); assert_true(result); assert_string_equal("off", pref_otr_log); } void cmd_otr_redact_redacts_logging(void **state) { gchar *args[] = { "log", "redact", NULL }; prefs_set_string(PREF_OTR_LOG, "on"); prefs_set_boolean(PREF_CHLOG, TRUE); expect_cons_show("OTR messages will be logged as '[redacted]'."); gboolean result = cmd_otr(NULL, CMD_OTR, args); char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); assert_true(result); assert_string_equal("redact", pref_otr_log); } void cmd_otr_log_redact_shows_warning_when_chlog_disabled(void **state) { gchar *args[] = { "log", "redact", NULL }; prefs_set_string(PREF_OTR_LOG, "off"); prefs_set_boolean(PREF_CHLOG, FALSE); expect_cons_show("OTR messages will be logged as '[redacted]'."); expect_cons_show("Chat logging is currently disabled, use '/chlog on' to enable."); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } void cmd_otr_libver_shows_libotr_version(void **state) { gchar *args[] = { "libver", NULL }; char *version = "9.9.9"; GString *message = g_string_new("Using libotr version "); g_string_append(message, version); will_return(otr_libotr_version, version); expect_cons_show(message->str); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); g_string_free(message, TRUE); } void cmd_otr_gen_shows_message_when_not_connected(void **state) { gchar *args[] = { "gen", NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("You must be connected with an account to load OTR information."); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } static void test_with_command_and_connection_status(char *command, jabber_conn_status_t status) { gchar *args[] = { command, NULL }; will_return(jabber_get_connection_status, status); expect_cons_show("You must be connected with an account to load OTR information."); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } void cmd_otr_gen_shows_message_when_disconnected(void **state) { test_with_command_and_connection_status("gen", JABBER_DISCONNECTED); } void cmd_otr_gen_shows_message_when_undefined(void **state) { test_with_command_and_connection_status("gen", JABBER_UNDEFINED); } void cmd_otr_gen_shows_message_when_started(void **state) { test_with_command_and_connection_status("gen", JABBER_STARTED); } void cmd_otr_gen_shows_message_when_connecting(void **state) { test_with_command_and_connection_status("gen", JABBER_CONNECTING); } void cmd_otr_gen_shows_message_when_disconnecting(void **state) { test_with_command_and_connection_status("gen", JABBER_DISCONNECTING); } void cmd_otr_gen_generates_key_for_connected_account(void **state) { gchar *args[] = { "gen", NULL }; char *account_name = "myaccount"; ProfAccount *account = account_new(account_name, "me@jabber.org", NULL, NULL, TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(jabber_get_account_name, account_name); expect_string(accounts_get_account, name, account_name); will_return(accounts_get_account, account); expect_memory(otr_keygen, account, account, sizeof(ProfAccount)); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } void cmd_otr_myfp_shows_message_when_disconnected(void **state) { test_with_command_and_connection_status("myfp", JABBER_DISCONNECTED); } void cmd_otr_myfp_shows_message_when_undefined(void **state) { test_with_command_and_connection_status("myfp", JABBER_UNDEFINED); } void cmd_otr_myfp_shows_message_when_started(void **state) { test_with_command_and_connection_status("myfp", JABBER_STARTED); } void cmd_otr_myfp_shows_message_when_connecting(void **state) { test_with_command_and_connection_status("myfp", JABBER_CONNECTING); } void cmd_otr_myfp_shows_message_when_disconnecting(void **state) { test_with_command_and_connection_status("myfp", JABBER_DISCONNECTING); } void cmd_otr_myfp_shows_message_when_no_key(void **state) { gchar *args[] = { "myfp", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(otr_key_loaded, FALSE); expect_ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'"); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } void cmd_otr_myfp_shows_my_fingerprint(void **state) { char *fingerprint = "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE"; gchar *args[] = { "myfp", NULL }; GString *message = g_string_new("Your OTR fingerprint: "); g_string_append(message, fingerprint); will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(otr_key_loaded, TRUE); will_return(otr_get_my_fingerprint, strdup(fingerprint)); expect_ui_current_print_formatted_line('!', 0, message->str); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); g_string_free(message, TRUE); } static void test_cmd_otr_theirfp_from_wintype(win_type_t wintype) { gchar *args[] = { "theirfp", NULL }; ProfWin window; window.type = wintype; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_ui_current_print_line("You must be in a regular chat window to view a recipient's fingerprint."); gboolean result = cmd_otr(&window, CMD_OTR, args); assert_true(result); } void cmd_otr_theirfp_shows_message_when_in_console(void **state) { test_cmd_otr_theirfp_from_wintype(WIN_CONSOLE); } void cmd_otr_theirfp_shows_message_when_in_muc(void **state) { test_cmd_otr_theirfp_from_wintype(WIN_MUC); } void cmd_otr_theirfp_shows_message_when_in_private(void **state) { test_cmd_otr_theirfp_from_wintype(WIN_PRIVATE); } void cmd_otr_theirfp_shows_message_when_non_otr_chat_window(void **state) { gchar *args[] = { "theirfp", NULL }; ProfWin window; window.type = WIN_CHAT; ProfChatWin chatwin; chatwin.window = window; chatwin.memcheck = PROFCHATWIN_MEMCHECK; chatwin.pgp_send = FALSE; chatwin.is_otr = FALSE; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session."); gboolean result = cmd_otr((ProfWin*)&chatwin, CMD_OTR, args); assert_true(result); } void cmd_otr_theirfp_shows_fingerprint(void **state) { char *recipient = "someone@chat.com"; char *fingerprint = "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE"; gchar *args[] = { "theirfp", NULL }; GString *message = g_string_new(recipient); g_string_append(message, "'s OTR fingerprint: "); g_string_append(message, fingerprint); ProfWin window; window.type = WIN_CHAT; ProfChatWin chatwin; chatwin.window = window; chatwin.barejid = recipient; chatwin.memcheck = PROFCHATWIN_MEMCHECK; chatwin.pgp_send = FALSE; chatwin.is_otr = TRUE; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(otr_get_their_fingerprint, recipient, recipient); will_return(otr_get_their_fingerprint, strdup(fingerprint)); expect_ui_current_print_formatted_line('!', 0, message->str); gboolean result = cmd_otr((ProfWin*)&chatwin, CMD_OTR, args); assert_true(result); g_string_free(message, TRUE); } static void test_cmd_otr_start_from_wintype(win_type_t wintype) { gchar *args[] = { "start", NULL }; ProfWin window; window.type = wintype; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_ui_current_print_line("You must be in a regular chat window to start an OTR session."); gboolean result = cmd_otr(&window, CMD_OTR, args); assert_true(result); } void cmd_otr_start_shows_message_when_in_console(void **state) { test_cmd_otr_start_from_wintype(WIN_CONSOLE); } void cmd_otr_start_shows_message_when_in_muc(void **state) { test_cmd_otr_start_from_wintype(WIN_MUC); } void cmd_otr_start_shows_message_when_in_private(void **state) { test_cmd_otr_start_from_wintype(WIN_PRIVATE); } void cmd_otr_start_shows_message_when_already_started(void **state) { char *recipient = "someone@server.org"; gchar *args[] = { "start", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); ProfWin window; window.type = WIN_CHAT; ProfChatWin chatwin; chatwin.window = window; chatwin.barejid = recipient; chatwin.memcheck = PROFCHATWIN_MEMCHECK; chatwin.pgp_send = FALSE; chatwin.is_otr = TRUE; expect_ui_current_print_formatted_line('!', 0, "You are already in an OTR session."); gboolean result = cmd_otr((ProfWin*)&chatwin, CMD_OTR, args); assert_true(result); } void cmd_otr_start_shows_message_when_no_key(void **state) { char *recipient = "someone@server.org"; gchar *args[] = { "start", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(otr_key_loaded, FALSE); ProfWin window; window.type = WIN_CHAT; ProfChatWin chatwin; chatwin.window = window; chatwin.barejid = recipient; chatwin.memcheck = PROFCHATWIN_MEMCHECK; chatwin.pgp_send = FALSE; chatwin.is_otr = FALSE; expect_ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'"); gboolean result = cmd_otr((ProfWin*)&chatwin, CMD_OTR, args); assert_true(result); } void cmd_otr_start_sends_otr_query_message_to_current_recipeint(void **state) { char *recipient = "buddy@chat.com"; char *query_message = "?OTR?"; gchar *args[] = { "start", NULL }; ProfWin window; window.type = WIN_CHAT; ProfChatWin chatwin; chatwin.window = window; chatwin.barejid = recipient; chatwin.memcheck = PROFCHATWIN_MEMCHECK; chatwin.pgp_send = FALSE; chatwin.is_otr = FALSE; will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(otr_key_loaded, TRUE); will_return(otr_start_query, query_message); expect_string(message_send_chat_otr, barejid, recipient); expect_string(message_send_chat_otr, msg, query_message); gboolean result = cmd_otr((ProfWin*)&chatwin, CMD_OTR, args); assert_true(result); } #else void cmd_otr_shows_message_when_otr_unsupported(void **state) { gchar *args[] = { "gen", NULL }; expect_cons_show("This version of Profanity has not been built with OTR support enabled"); gboolean result = cmd_otr(NULL, CMD_OTR, args); assert_true(result); } #endif profanity-0.4.7/tests/unittests/test_cmd_otr.h000066400000000000000000000043771257755232500216300ustar00rootroot00000000000000#include "config.h" #ifdef HAVE_LIBOTR void cmd_otr_shows_usage_when_no_args(void **state); void cmd_otr_shows_usage_when_invalid_subcommand(void **state); void cmd_otr_log_shows_usage_when_no_args(void **state); void cmd_otr_log_shows_usage_when_invalid_subcommand(void **state); void cmd_otr_log_on_enables_logging(void **state); void cmd_otr_log_off_disables_logging(void **state); void cmd_otr_redact_redacts_logging(void **state); void cmd_otr_log_on_shows_warning_when_chlog_disabled(void **state); void cmd_otr_log_redact_shows_warning_when_chlog_disabled(void **state); void cmd_otr_libver_shows_libotr_version(void **state); void cmd_otr_gen_shows_message_when_not_connected(void **state); void cmd_otr_gen_generates_key_for_connected_account(void **state); void cmd_otr_gen_shows_message_when_disconnected(void **state); void cmd_otr_gen_shows_message_when_undefined(void **state); void cmd_otr_gen_shows_message_when_started(void **state); void cmd_otr_gen_shows_message_when_connecting(void **state); void cmd_otr_gen_shows_message_when_disconnecting(void **state); void cmd_otr_myfp_shows_message_when_disconnected(void **state); void cmd_otr_myfp_shows_message_when_undefined(void **state); void cmd_otr_myfp_shows_message_when_started(void **state); void cmd_otr_myfp_shows_message_when_connecting(void **state); void cmd_otr_myfp_shows_message_when_disconnecting(void **state); void cmd_otr_myfp_shows_message_when_no_key(void **state); void cmd_otr_myfp_shows_my_fingerprint(void **state); void cmd_otr_theirfp_shows_message_when_in_console(void **state); void cmd_otr_theirfp_shows_message_when_in_muc(void **state); void cmd_otr_theirfp_shows_message_when_in_private(void **state); void cmd_otr_theirfp_shows_message_when_non_otr_chat_window(void **state); void cmd_otr_theirfp_shows_fingerprint(void **state); void cmd_otr_start_shows_message_when_in_console(void **state); void cmd_otr_start_shows_message_when_in_muc(void **state); void cmd_otr_start_shows_message_when_in_private(void **state); void cmd_otr_start_shows_message_when_already_started(void **state); void cmd_otr_start_shows_message_when_no_key(void **state); void cmd_otr_start_sends_otr_query_message_to_current_recipeint(void **state); #else void cmd_otr_shows_message_when_otr_unsupported(void **state); #endif profanity-0.4.7/tests/unittests/test_cmd_pgp.c000066400000000000000000000056161257755232500216020ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "config.h" #include "command/commands.h" #include "ui/stub_ui.h" #define CMD_PGP "/pgp" #ifdef HAVE_LIBGPGME void cmd_pgp_shows_usage_when_no_args(void **state) { gchar *args[] = { NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_PGP); gboolean result = cmd_pgp(NULL, CMD_PGP, args); assert_true(result); } void cmd_pgp_start_shows_message_when_connection(jabber_conn_status_t conn_status) { gchar *args[] = { "start", NULL }; ProfWin window; window.type = WIN_CHAT; will_return(jabber_get_connection_status, conn_status); expect_cons_show("You must be connected to start PGP encrpytion."); gboolean result = cmd_pgp(&window, CMD_PGP, args); assert_true(result); } void cmd_pgp_start_shows_message_when_disconnected(void **state) { cmd_pgp_start_shows_message_when_connection(JABBER_DISCONNECTED); } void cmd_pgp_start_shows_message_when_disconnecting(void **state) { cmd_pgp_start_shows_message_when_connection(JABBER_DISCONNECTING); } void cmd_pgp_start_shows_message_when_connecting(void **state) { cmd_pgp_start_shows_message_when_connection(JABBER_CONNECTING); } void cmd_pgp_start_shows_message_when_undefined(void **state) { cmd_pgp_start_shows_message_when_connection(JABBER_UNDEFINED); } void cmd_pgp_start_shows_message_when_started(void **state) { cmd_pgp_start_shows_message_when_connection(JABBER_STARTED); } void cmd_pgp_start_shows_message_when_no_arg_in_wintype(win_type_t wintype) { gchar *args[] = { "start", NULL }; ProfWin window; window.type = wintype; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_cons_show("You must be in a regular chat window to start PGP encrpytion."); gboolean result = cmd_pgp(&window, CMD_PGP, args); assert_true(result); } void cmd_pgp_start_shows_message_when_no_arg_in_console(void **state) { cmd_pgp_start_shows_message_when_no_arg_in_wintype(WIN_CONSOLE); } void cmd_pgp_start_shows_message_when_no_arg_in_muc(void **state) { cmd_pgp_start_shows_message_when_no_arg_in_wintype(WIN_MUC); } void cmd_pgp_start_shows_message_when_no_arg_in_mucconf(void **state) { cmd_pgp_start_shows_message_when_no_arg_in_wintype(WIN_MUC_CONFIG); } void cmd_pgp_start_shows_message_when_no_arg_in_private(void **state) { cmd_pgp_start_shows_message_when_no_arg_in_wintype(WIN_PRIVATE); } void cmd_pgp_start_shows_message_when_no_arg_in_xmlconsole(void **state) { cmd_pgp_start_shows_message_when_no_arg_in_wintype(WIN_XML); } #else void cmd_pgp_shows_message_when_pgp_unsupported(void **state) { gchar *args[] = { "gen", NULL }; expect_cons_show("This version of Profanity has not been built with PGP support enabled"); gboolean result = cmd_pgp(NULL, CMD_PGP, args); assert_true(result); } #endif profanity-0.4.7/tests/unittests/test_cmd_pgp.h000066400000000000000000000015161257755232500216020ustar00rootroot00000000000000#include "config.h" #ifdef HAVE_LIBGPGME void cmd_pgp_shows_usage_when_no_args(void **state); void cmd_pgp_start_shows_message_when_disconnected(void **state); void cmd_pgp_start_shows_message_when_disconnecting(void **state); void cmd_pgp_start_shows_message_when_connecting(void **state); void cmd_pgp_start_shows_message_when_undefined(void **state); void cmd_pgp_start_shows_message_when_started(void **state); void cmd_pgp_start_shows_message_when_no_arg_in_console(void **state); void cmd_pgp_start_shows_message_when_no_arg_in_muc(void **state); void cmd_pgp_start_shows_message_when_no_arg_in_mucconf(void **state); void cmd_pgp_start_shows_message_when_no_arg_in_private(void **state); void cmd_pgp_start_shows_message_when_no_arg_in_xmlconsole(void **state); #else void cmd_pgp_shows_message_when_pgp_unsupported(void **state); #endif profanity-0.4.7/tests/unittests/test_cmd_rooms.c000066400000000000000000000047021257755232500221460ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "xmpp/xmpp.h" #include "ui/ui.h" #include "ui/stub_ui.h" #include "config/accounts.h" #include "command/commands.h" #define CMD_ROOMS "/rooms" static void test_with_connection_status(jabber_conn_status_t status) { will_return(jabber_get_connection_status, status); expect_cons_show("You are not currently connected."); gboolean result = cmd_rooms(NULL, CMD_ROOMS, NULL); assert_true(result); } void cmd_rooms_shows_message_when_disconnected(void **state) { test_with_connection_status(JABBER_DISCONNECTED); } void cmd_rooms_shows_message_when_disconnecting(void **state) { test_with_connection_status(JABBER_DISCONNECTING); } void cmd_rooms_shows_message_when_connecting(void **state) { test_with_connection_status(JABBER_CONNECTING); } void cmd_rooms_shows_message_when_started(void **state) { test_with_connection_status(JABBER_STARTED); } void cmd_rooms_shows_message_when_undefined(void **state) { test_with_connection_status(JABBER_UNDEFINED); } void cmd_rooms_uses_account_default_when_no_arg(void **state) { gchar *args[] = { NULL }; ProfAccount *account = malloc(sizeof(ProfAccount)); account->name = NULL; account->jid = NULL; account->password = NULL; account->eval_password = NULL; account->resource = NULL; account->server = NULL; account->last_presence = NULL; account->login_presence = NULL; account->muc_nick = NULL; account->otr_policy = NULL; account->otr_manual = NULL; account->otr_opportunistic = NULL; account->otr_always = NULL; account->pgp_keyid = NULL; account->muc_service = strdup("default_conf_server"); will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(jabber_get_account_name, "account_name"); expect_any(accounts_get_account, name); will_return(accounts_get_account, account); expect_string(iq_room_list_request, conferencejid, "default_conf_server"); gboolean result = cmd_rooms(NULL, CMD_ROOMS, args); assert_true(result); } void cmd_rooms_arg_used_when_passed(void **state) { gchar *args[] = { "conf_server_arg" }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(iq_room_list_request, conferencejid, "conf_server_arg"); gboolean result = cmd_rooms(NULL, CMD_ROOMS, args); assert_true(result); } profanity-0.4.7/tests/unittests/test_cmd_rooms.h000066400000000000000000000006371257755232500221560ustar00rootroot00000000000000void cmd_rooms_shows_message_when_disconnected(void **state); void cmd_rooms_shows_message_when_disconnecting(void **state); void cmd_rooms_shows_message_when_connecting(void **state); void cmd_rooms_shows_message_when_started(void **state); void cmd_rooms_shows_message_when_undefined(void **state); void cmd_rooms_uses_account_default_when_no_arg(void **state); void cmd_rooms_arg_used_when_passed(void **state); profanity-0.4.7/tests/unittests/test_cmd_roster.c000066400000000000000000000143701257755232500223270ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "ui/ui.h" #include "ui/stub_ui.h" #include "xmpp/xmpp.h" #include "roster_list.h" #include "command/commands.h" #define CMD_ROSTER "/roster" static void test_with_connection_status(jabber_conn_status_t status) { gchar *args[] = { NULL }; will_return(jabber_get_connection_status, status); expect_cons_show("You are not currently connected."); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); } void cmd_roster_shows_message_when_disconnecting(void **state) { test_with_connection_status(JABBER_DISCONNECTING); } void cmd_roster_shows_message_when_connecting(void **state) { test_with_connection_status(JABBER_CONNECTING); } void cmd_roster_shows_message_when_disconnected(void **state) { test_with_connection_status(JABBER_DISCONNECTED); } void cmd_roster_shows_message_when_undefined(void **state) { test_with_connection_status(JABBER_UNDEFINED); } void cmd_roster_shows_roster_when_no_args(void **state) { gchar *args[] = { NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); roster_init(); roster_add("bob@server.org", "bob", NULL, "both", FALSE); GSList *roster = roster_get_contacts(); expect_memory(cons_show_roster, list, roster, sizeof(roster)); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); roster_free(); } void cmd_roster_add_shows_message_when_no_jid(void **state) { gchar *args[] = { "add", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_ROSTER); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); } void cmd_roster_add_sends_roster_add_request(void **state) { char *jid = "bob@server.org"; char *nick = "bob"; gchar *args[] = { "add", jid, nick, NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(roster_send_add_new, barejid, jid); expect_string(roster_send_add_new, name, nick); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); } void cmd_roster_remove_shows_message_when_no_jid(void **state) { gchar *args[] = { "remove", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_ROSTER); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); } void cmd_roster_remove_sends_roster_remove_request(void **state) { char *jid = "bob@server.org"; gchar *args[] = { "remove", jid, NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(roster_send_remove, barejid, jid); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); } void cmd_roster_nick_shows_message_when_no_jid(void **state) { gchar *args[] = { "nick", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_ROSTER); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); } void cmd_roster_nick_shows_message_when_no_nick(void **state) { gchar *args[] = { "nick", "bob@server.org", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_ROSTER); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); } void cmd_roster_nick_shows_message_when_no_contact_exists(void **state) { gchar *args[] = { "nick", "bob@server.org", "bobster", NULL }; roster_init(); will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_cons_show("Contact not found in roster: bob@server.org"); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); roster_free(); } void cmd_roster_nick_sends_name_change_request(void **state) { char *jid = "bob@server.org"; char *nick = "bobster"; gchar *args[] = { "nick", jid, nick, NULL }; roster_init(); GSList *groups = NULL; groups = g_slist_append(groups, "group1"); roster_add(jid, "bob", groups, "both", FALSE); will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(roster_send_name_change, barejid, jid); expect_string(roster_send_name_change, new_name, nick); expect_memory(roster_send_name_change, groups, groups, sizeof(groups)); expect_cons_show("Nickname for bob@server.org set to: bobster."); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); PContact contact = roster_get_contact(jid); assert_string_equal(p_contact_name(contact), nick); roster_free(); } void cmd_roster_clearnick_shows_message_when_no_jid(void **state) { gchar *args[] = { "clearnick", NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_ROSTER); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); } void cmd_roster_clearnick_shows_message_when_no_contact_exists(void **state) { gchar *args[] = { "clearnick", "bob@server.org", NULL }; roster_init(); will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_cons_show("Contact not found in roster: bob@server.org"); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); roster_free(); } void cmd_roster_clearnick_sends_name_change_request_with_empty_nick(void **state) { char *jid = "bob@server.org"; gchar *args[] = { "clearnick", jid, NULL }; roster_init(); GSList *groups = NULL; groups = g_slist_append(groups, "group1"); roster_add(jid, "bob", groups, "both", FALSE); will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(roster_send_name_change, barejid, jid); expect_value(roster_send_name_change, new_name, NULL); expect_memory(roster_send_name_change, groups, groups, sizeof(groups)); expect_cons_show("Nickname for bob@server.org removed."); gboolean result = cmd_roster(NULL, CMD_ROSTER, args); assert_true(result); PContact contact = roster_get_contact(jid); assert_null(p_contact_name(contact)); roster_free(); } profanity-0.4.7/tests/unittests/test_cmd_roster.h000066400000000000000000000020241257755232500223250ustar00rootroot00000000000000void cmd_roster_shows_message_when_disconnecting(void **state); void cmd_roster_shows_message_when_connecting(void **state); void cmd_roster_shows_message_when_disconnected(void **state); void cmd_roster_shows_message_when_undefined(void **state); void cmd_roster_shows_roster_when_no_args(void **state); void cmd_roster_add_shows_message_when_no_jid(void **state); void cmd_roster_add_sends_roster_add_request(void **state); void cmd_roster_remove_shows_message_when_no_jid(void **state); void cmd_roster_remove_sends_roster_remove_request(void **state); void cmd_roster_nick_shows_message_when_no_jid(void **state); void cmd_roster_nick_shows_message_when_no_nick(void **state); void cmd_roster_nick_shows_message_when_no_contact_exists(void **state); void cmd_roster_nick_sends_name_change_request(void **state); void cmd_roster_clearnick_shows_message_when_no_jid(void **state); void cmd_roster_clearnick_shows_message_when_no_contact_exists(void **state); void cmd_roster_clearnick_sends_name_change_request_with_empty_nick(void **state); profanity-0.4.7/tests/unittests/test_cmd_statuses.c000066400000000000000000000115461257755232500226660ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "config/preferences.h" #include "ui/ui.h" #include "ui/stub_ui.h" #include "command/commands.h" #define CMD_STATUSES "/statuses" void cmd_statuses_shows_usage_when_bad_subcmd(void **state) { gchar *args[] = { "badcmd", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_STATUSES); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); assert_true(result); } void cmd_statuses_shows_usage_when_bad_console_setting(void **state) { gchar *args[] = { "console", "badsetting", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_STATUSES); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); assert_true(result); } void cmd_statuses_shows_usage_when_bad_chat_setting(void **state) { gchar *args[] = { "chat", "badsetting", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_STATUSES); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); assert_true(result); } void cmd_statuses_shows_usage_when_bad_muc_setting(void **state) { gchar *args[] = { "muc", "badsetting", NULL }; expect_string(cons_bad_cmd_usage, cmd, CMD_STATUSES); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); assert_true(result); } void cmd_statuses_console_sets_all(void **state) { gchar *args[] = { "console", "all", NULL }; expect_cons_show("All presence updates will appear in the console."); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); char *setting = prefs_get_string(PREF_STATUSES_CONSOLE); assert_non_null(setting); assert_string_equal("all", setting); assert_true(result); } void cmd_statuses_console_sets_online(void **state) { gchar *args[] = { "console", "online", NULL }; expect_cons_show("Only online/offline presence updates will appear in the console."); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); char *setting = prefs_get_string(PREF_STATUSES_CONSOLE); assert_non_null(setting); assert_string_equal("online", setting); assert_true(result); } void cmd_statuses_console_sets_none(void **state) { gchar *args[] = { "console", "none", NULL }; expect_cons_show("Presence updates will not appear in the console."); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); char *setting = prefs_get_string(PREF_STATUSES_CONSOLE); assert_non_null(setting); assert_string_equal("none", setting); assert_true(result); } void cmd_statuses_chat_sets_all(void **state) { gchar *args[] = { "chat", "all", NULL }; expect_cons_show("All presence updates will appear in chat windows."); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); char *setting = prefs_get_string(PREF_STATUSES_CHAT); assert_non_null(setting); assert_string_equal("all", setting); assert_true(result); } void cmd_statuses_chat_sets_online(void **state) { gchar *args[] = { "chat", "online", NULL }; expect_cons_show("Only online/offline presence updates will appear in chat windows."); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); char *setting = prefs_get_string(PREF_STATUSES_CHAT); assert_non_null(setting); assert_string_equal("online", setting); assert_true(result); } void cmd_statuses_chat_sets_none(void **state) { gchar *args[] = { "chat", "none", NULL }; expect_cons_show("Presence updates will not appear in chat windows."); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); char *setting = prefs_get_string(PREF_STATUSES_CHAT); assert_non_null(setting); assert_string_equal("none", setting); assert_true(result); } void cmd_statuses_muc_sets_all(void **state) { gchar *args[] = { "muc", "all", NULL }; expect_cons_show("All presence updates will appear in chat room windows."); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); char *setting = prefs_get_string(PREF_STATUSES_MUC); assert_non_null(setting); assert_string_equal("all", setting); assert_true(result); } void cmd_statuses_muc_sets_online(void **state) { gchar *args[] = { "muc", "online", NULL }; expect_cons_show("Only join/leave presence updates will appear in chat room windows."); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); char *setting = prefs_get_string(PREF_STATUSES_MUC); assert_non_null(setting); assert_string_equal("online", setting); assert_true(result); } void cmd_statuses_muc_sets_none(void **state) { gchar *args[] = { "muc", "none", NULL }; expect_cons_show("Presence updates will not appear in chat room windows."); gboolean result = cmd_statuses(NULL, CMD_STATUSES, args); char *setting = prefs_get_string(PREF_STATUSES_MUC); assert_non_null(setting); assert_string_equal("none", setting); assert_true(result); } profanity-0.4.7/tests/unittests/test_cmd_statuses.h000066400000000000000000000013011257755232500226570ustar00rootroot00000000000000void cmd_statuses_shows_usage_when_bad_subcmd(void **state); void cmd_statuses_shows_usage_when_bad_console_setting(void **state); void cmd_statuses_shows_usage_when_bad_chat_setting(void **state); void cmd_statuses_shows_usage_when_bad_muc_setting(void **state); void cmd_statuses_console_sets_all(void **state); void cmd_statuses_console_sets_online(void **state); void cmd_statuses_console_sets_none(void **state); void cmd_statuses_chat_sets_all(void **state); void cmd_statuses_chat_sets_online(void **state); void cmd_statuses_chat_sets_none(void **state); void cmd_statuses_muc_sets_all(void **state); void cmd_statuses_muc_sets_online(void **state); void cmd_statuses_muc_sets_none(void **state); profanity-0.4.7/tests/unittests/test_cmd_sub.c000066400000000000000000000015161257755232500216000ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "xmpp/xmpp.h" #include "ui/ui.h" #include "ui/stub_ui.h" #include "command/commands.h" #define CMD_SUB "/sub" void cmd_sub_shows_message_when_not_connected(void **state) { gchar *args[] = { NULL }; will_return(jabber_get_connection_status, JABBER_DISCONNECTED); expect_cons_show("You are currently not connected."); gboolean result = cmd_sub(NULL, CMD_SUB, args); assert_true(result); } void cmd_sub_shows_usage_when_no_arg(void **state) { gchar *args[] = { NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); expect_string(cons_bad_cmd_usage, cmd, CMD_SUB); gboolean result = cmd_sub(NULL, CMD_SUB, args); assert_true(result); } profanity-0.4.7/tests/unittests/test_cmd_sub.h000066400000000000000000000001611257755232500216000ustar00rootroot00000000000000void cmd_sub_shows_message_when_not_connected(void **state); void cmd_sub_shows_usage_when_no_arg(void **state); profanity-0.4.7/tests/unittests/test_common.c000066400000000000000000000561751257755232500214670ustar00rootroot00000000000000#include "common.h" #include #include #include #include #include void replace_one_substr(void **state) { char *string = "it is a string"; char *sub = "is"; char *new = "was"; char *result = str_replace(string, sub, new); assert_string_equal("it was a string", result); free(result); } void replace_one_substr_beginning(void **state) { char *string = "it is a string"; char *sub = "it"; char *new = "that"; char *result = str_replace(string, sub, new); assert_string_equal("that is a string", result); free(result); } void replace_one_substr_end(void **state) { char *string = "it is a string"; char *sub = "string"; char *new = "thing"; char *result = str_replace(string, sub, new); assert_string_equal("it is a thing", result); free(result); } void replace_two_substr(void **state) { char *string = "it is a is string"; char *sub = "is"; char *new = "was"; char *result = str_replace(string, sub, new); assert_string_equal("it was a was string", result); free(result); } void replace_char(void **state) { char *string = "some & a thing & something else"; char *sub = "&"; char *new = "&"; char *result = str_replace(string, sub, new); assert_string_equal("some & a thing & something else", result); free(result); } void replace_when_none(void **state) { char *string = "its another string"; char *sub = "haha"; char *new = "replaced"; char *result = str_replace(string, sub, new); assert_string_equal("its another string", result); free(result); } void replace_when_match(void **state) { char *string = "hello"; char *sub = "hello"; char *new = "goodbye"; char *result = str_replace(string, sub, new); assert_string_equal("goodbye", result); free(result); } void replace_when_string_empty(void **state) { char *string = ""; char *sub = "hello"; char *new = "goodbye"; char *result = str_replace(string, sub, new); assert_string_equal("", result); free(result); } void replace_when_string_null(void **state) { char *string = NULL; char *sub = "hello"; char *new = "goodbye"; char *result = str_replace(string, sub, new); assert_null(result); } void replace_when_sub_empty(void **state) { char *string = "hello"; char *sub = ""; char *new = "goodbye"; char *result = str_replace(string, sub, new); assert_string_equal("hello", result); free(result); } void replace_when_sub_null(void **state) { char *string = "hello"; char *sub = NULL; char *new = "goodbye"; char *result = str_replace(string, sub, new); assert_string_equal("hello", result); free(result); } void replace_when_new_empty(void **state) { char *string = "hello"; char *sub = "hello"; char *new = ""; char *result = str_replace(string, sub, new); assert_string_equal("", result); free(result); } void replace_when_new_null(void **state) { char *string = "hello"; char *sub = "hello"; char *new = NULL; char *result = str_replace(string, sub, new); assert_string_equal("hello", result); free(result); } void compare_win_nums_less(void **state) { gconstpointer a = GINT_TO_POINTER(2); gconstpointer b = GINT_TO_POINTER(3); int result = cmp_win_num(a, b); assert_true(result < 0); } void compare_win_nums_equal(void **state) { gconstpointer a = GINT_TO_POINTER(5); gconstpointer b = GINT_TO_POINTER(5); int result = cmp_win_num(a, b); assert_true(result == 0); } void compare_win_nums_greater(void **state) { gconstpointer a = GINT_TO_POINTER(7); gconstpointer b = GINT_TO_POINTER(6); int result = cmp_win_num(a, b); assert_true(result > 0); } void compare_0s_equal(void **state) { gconstpointer a = GINT_TO_POINTER(0); gconstpointer b = GINT_TO_POINTER(0); int result = cmp_win_num(a, b); assert_true(result == 0); } void compare_0_greater_than_1(void **state) { gconstpointer a = GINT_TO_POINTER(0); gconstpointer b = GINT_TO_POINTER(1); int result = cmp_win_num(a, b); assert_true(result > 0); } void compare_1_less_than_0(void **state) { gconstpointer a = GINT_TO_POINTER(1); gconstpointer b = GINT_TO_POINTER(0); int result = cmp_win_num(a, b); assert_true(result < 0); } void compare_0_less_than_11(void **state) { gconstpointer a = GINT_TO_POINTER(0); gconstpointer b = GINT_TO_POINTER(11); int result = cmp_win_num(a, b); assert_true(result < 0); } void compare_11_greater_than_0(void **state) { gconstpointer a = GINT_TO_POINTER(11); gconstpointer b = GINT_TO_POINTER(0); int result = cmp_win_num(a, b); assert_true(result > 0); } void compare_0_greater_than_9(void **state) { gconstpointer a = GINT_TO_POINTER(0); gconstpointer b = GINT_TO_POINTER(9); int result = cmp_win_num(a, b); assert_true(result > 0); } void compare_9_less_than_0(void **state) { gconstpointer a = GINT_TO_POINTER(9); gconstpointer b = GINT_TO_POINTER(0); int result = cmp_win_num(a, b); assert_true(result < 0); } void next_available_when_only_console(void **state) { GList *used = NULL; used = g_list_append(used, GINT_TO_POINTER(1)); int result = get_next_available_win_num(used); assert_int_equal(2, result); } void next_available_3_at_end(void **state) { GList *used = NULL; used = g_list_append(used, GINT_TO_POINTER(1)); used = g_list_append(used, GINT_TO_POINTER(2)); int result = get_next_available_win_num(used); assert_int_equal(3, result); } void next_available_9_at_end(void **state) { GList *used = NULL; used = g_list_append(used, GINT_TO_POINTER(1)); used = g_list_append(used, GINT_TO_POINTER(2)); used = g_list_append(used, GINT_TO_POINTER(3)); used = g_list_append(used, GINT_TO_POINTER(4)); used = g_list_append(used, GINT_TO_POINTER(5)); used = g_list_append(used, GINT_TO_POINTER(6)); used = g_list_append(used, GINT_TO_POINTER(7)); used = g_list_append(used, GINT_TO_POINTER(8)); int result = get_next_available_win_num(used); assert_int_equal(9, result); } void next_available_0_at_end(void **state) { GList *used = NULL; used = g_list_append(used, GINT_TO_POINTER(1)); used = g_list_append(used, GINT_TO_POINTER(2)); used = g_list_append(used, GINT_TO_POINTER(3)); used = g_list_append(used, GINT_TO_POINTER(4)); used = g_list_append(used, GINT_TO_POINTER(5)); used = g_list_append(used, GINT_TO_POINTER(6)); used = g_list_append(used, GINT_TO_POINTER(7)); used = g_list_append(used, GINT_TO_POINTER(8)); used = g_list_append(used, GINT_TO_POINTER(9)); int result = get_next_available_win_num(used); assert_int_equal(0, result); } void next_available_2_in_first_gap(void **state) { GList *used = NULL; used = g_list_append(used, GINT_TO_POINTER(1)); used = g_list_append(used, GINT_TO_POINTER(3)); used = g_list_append(used, GINT_TO_POINTER(4)); used = g_list_append(used, GINT_TO_POINTER(5)); used = g_list_append(used, GINT_TO_POINTER(9)); used = g_list_append(used, GINT_TO_POINTER(0)); int result = get_next_available_win_num(used); assert_int_equal(2, result); } void next_available_9_in_first_gap(void **state) { GList *used = NULL; used = g_list_append(used, GINT_TO_POINTER(1)); used = g_list_append(used, GINT_TO_POINTER(2)); used = g_list_append(used, GINT_TO_POINTER(3)); used = g_list_append(used, GINT_TO_POINTER(4)); used = g_list_append(used, GINT_TO_POINTER(5)); used = g_list_append(used, GINT_TO_POINTER(6)); used = g_list_append(used, GINT_TO_POINTER(7)); used = g_list_append(used, GINT_TO_POINTER(8)); used = g_list_append(used, GINT_TO_POINTER(0)); used = g_list_append(used, GINT_TO_POINTER(11)); used = g_list_append(used, GINT_TO_POINTER(12)); used = g_list_append(used, GINT_TO_POINTER(13)); used = g_list_append(used, GINT_TO_POINTER(20)); int result = get_next_available_win_num(used); assert_int_equal(9, result); } void next_available_0_in_first_gap(void **state) { GList *used = NULL; used = g_list_append(used, GINT_TO_POINTER(1)); used = g_list_append(used, GINT_TO_POINTER(2)); used = g_list_append(used, GINT_TO_POINTER(3)); used = g_list_append(used, GINT_TO_POINTER(4)); used = g_list_append(used, GINT_TO_POINTER(5)); used = g_list_append(used, GINT_TO_POINTER(6)); used = g_list_append(used, GINT_TO_POINTER(7)); used = g_list_append(used, GINT_TO_POINTER(8)); used = g_list_append(used, GINT_TO_POINTER(9)); used = g_list_append(used, GINT_TO_POINTER(11)); used = g_list_append(used, GINT_TO_POINTER(12)); used = g_list_append(used, GINT_TO_POINTER(13)); used = g_list_append(used, GINT_TO_POINTER(20)); int result = get_next_available_win_num(used); assert_int_equal(0, result); } void next_available_11_in_first_gap(void **state) { GList *used = NULL; used = g_list_append(used, GINT_TO_POINTER(1)); used = g_list_append(used, GINT_TO_POINTER(2)); used = g_list_append(used, GINT_TO_POINTER(3)); used = g_list_append(used, GINT_TO_POINTER(4)); used = g_list_append(used, GINT_TO_POINTER(5)); used = g_list_append(used, GINT_TO_POINTER(6)); used = g_list_append(used, GINT_TO_POINTER(7)); used = g_list_append(used, GINT_TO_POINTER(8)); used = g_list_append(used, GINT_TO_POINTER(9)); used = g_list_append(used, GINT_TO_POINTER(0)); used = g_list_append(used, GINT_TO_POINTER(12)); used = g_list_append(used, GINT_TO_POINTER(13)); used = g_list_append(used, GINT_TO_POINTER(20)); int result = get_next_available_win_num(used); assert_int_equal(11, result); } void next_available_24_first_big_gap(void **state) { GList *used = NULL; used = g_list_append(used, GINT_TO_POINTER(1)); used = g_list_append(used, GINT_TO_POINTER(2)); used = g_list_append(used, GINT_TO_POINTER(3)); used = g_list_append(used, GINT_TO_POINTER(4)); used = g_list_append(used, GINT_TO_POINTER(5)); used = g_list_append(used, GINT_TO_POINTER(6)); used = g_list_append(used, GINT_TO_POINTER(7)); used = g_list_append(used, GINT_TO_POINTER(8)); used = g_list_append(used, GINT_TO_POINTER(9)); used = g_list_append(used, GINT_TO_POINTER(0)); used = g_list_append(used, GINT_TO_POINTER(11)); used = g_list_append(used, GINT_TO_POINTER(12)); used = g_list_append(used, GINT_TO_POINTER(13)); used = g_list_append(used, GINT_TO_POINTER(14)); used = g_list_append(used, GINT_TO_POINTER(15)); used = g_list_append(used, GINT_TO_POINTER(16)); used = g_list_append(used, GINT_TO_POINTER(17)); used = g_list_append(used, GINT_TO_POINTER(18)); used = g_list_append(used, GINT_TO_POINTER(19)); used = g_list_append(used, GINT_TO_POINTER(20)); used = g_list_append(used, GINT_TO_POINTER(21)); used = g_list_append(used, GINT_TO_POINTER(22)); used = g_list_append(used, GINT_TO_POINTER(23)); used = g_list_append(used, GINT_TO_POINTER(51)); used = g_list_append(used, GINT_TO_POINTER(52)); used = g_list_append(used, GINT_TO_POINTER(53)); used = g_list_append(used, GINT_TO_POINTER(89)); used = g_list_append(used, GINT_TO_POINTER(90)); used = g_list_append(used, GINT_TO_POINTER(100)); used = g_list_append(used, GINT_TO_POINTER(101)); used = g_list_append(used, GINT_TO_POINTER(102)); int result = get_next_available_win_num(used); assert_int_equal(24, result); } void test_online_is_valid_resource_presence_string(void **state) { assert_true(valid_resource_presence_string("online")); } void test_chat_is_valid_resource_presence_string(void **state) { assert_true(valid_resource_presence_string("chat")); } void test_away_is_valid_resource_presence_string(void **state) { assert_true(valid_resource_presence_string("away")); } void test_xa_is_valid_resource_presence_string(void **state) { assert_true(valid_resource_presence_string("xa")); } void test_dnd_is_valid_resource_presence_string(void **state) { assert_true(valid_resource_presence_string("dnd")); } void test_available_is_not_valid_resource_presence_string(void **state) { assert_false(valid_resource_presence_string("available")); } void test_unavailable_is_not_valid_resource_presence_string(void **state) { assert_false(valid_resource_presence_string("unavailable")); } void test_blah_is_not_valid_resource_presence_string(void **state) { assert_false(valid_resource_presence_string("blah")); } void test_p_sha1_hash1(void **state) { char *inp = "some message\nanother element\n"; char *result = p_sha1_hash(inp); assert_string_equal(result, "ZJLLzkYc51Lug3fZ7MJJzK95Ikg="); } void test_p_sha1_hash2(void **state) { char *inp = ""; char *result = p_sha1_hash(inp); assert_string_equal(result, "2jmj7l5rSw0yVb/vlWAYkK/YBwk="); } void test_p_sha1_hash3(void **state) { char *inp = "m"; char *result = p_sha1_hash(inp); assert_string_equal(result, "aw0xwNVjIjAk2kVpFYRkOseMlug="); } void test_p_sha1_hash4(void **state) { char *inp = "\n"; char *result = p_sha1_hash(inp); assert_string_equal(result, "xcgld4ZfXvU0P7+cW3WFLUuE3C8="); } void test_p_sha1_hash5(void **state) { char *inp = " "; char *result = p_sha1_hash(inp); assert_string_equal(result, "CZYAoQqUQRSqxAbRNrYl+0Ft13k="); } void test_p_sha1_hash6(void **state) { char *inp = " sdf \n "; char *result = p_sha1_hash(inp); assert_string_equal(result, "zjtm8dKlTj1KhYDlM2z8FsmAhSQ="); } void test_p_sha1_hash7(void **state) { char *inp = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. Quisque volutpat condimentum velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices. Suspendisse in justo eu magna luctus suscipit. Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor. Sed non quam. In vel mi sit amet augue congue elementum. Morbi in ipsum sit amet pede facilisis laoreet. Donec lacus nunc, viverra nec, blandit vel, egestas et, augue. Vestibulum tincidunt malesuada tellus. Ut ultrices ultrices enim. Curabitur sit amet mauris. Morbi in dui quis est pulvinar ullamcorper. Nulla facilisi. Integer lacinia sollicitudin massa. Cras metus. Sed aliquet risus a tortor. Integer id quam. Morbi mi. Quisque nisl felis, venenatis tristique, dignissim in, ultrices sit amet, augue. Proin sodales libero eget ante. Nulla quam. Aenean laoreet. Vestibulum nisi lectus, commodo ac, facilisis ac, ultricies eu, pede. Ut orci risus, accumsan porttitor, cursus quis, aliquet eget, justo. Sed pretium blandit orci. Ut eu diam at pede suscipit sodales. Aenean lectus elit, fermentum non, convallis id, sagittis at, neque. Nullam mauris orci, aliquet et, iaculis et, viverra vitae, ligula. Nulla ut felis in purus aliquam imperdiet. Maecenas aliquet mollis lectus. Vivamus consectetuer risus et tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. Quisque volutpat condimentum velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices. Suspendisse in justo eu magna luctus suscipit. Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor. Sed non quam. In vel mi sit amet augue congue elementum. Morbi in ipsum sit amet pede facilisis laoreet. Donec lacus nunc, viverra nec, blandit vel, egestas et, augue. Vestibulum tincidunt malesuada tellus. Ut ultrices ultrices enim. Curabitur sit amet mauris. Morbi in dui quis est pulvinar ullamcorper. Nulla facilisi. Integer lacinia sollicitudin massa. Cras metus. Sed aliquet risus a tortor. Integer id quam. Morbi mi. Quisque nisl felis, venenatis tristique, dignissim in, ultrices sit amet, augue. Proin sodales libero eget ante. Nulla quam. Aenean laoreet. Vestibulum nisi lectus, commodo ac, facilisis ac, ultricies eu, pede. Ut orci risus, accumsan porttitor, cursus quis, aliquet eget, justo. Sed pretium blandit orci. Ut eu diam at pede suscipit sodales. Aenean lectus elit, fermentum non, convallis id, sagittis at, neque. Nullam mauris orci, aliquet et, iaculis et, viverra vitae, ligula. Nulla ut felis in purus aliquam imperdiet. Maecenas aliquet mollis lectus. Vivamus consectetuer risus et tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. Quisque volutpat condimentum velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices. Suspendisse in justo eu magna luctus suscipit. Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor. Sed non quam. In vel mi sit amet augue congue elementum. Morbi in ipsum si."; char *result = p_sha1_hash(inp); assert_string_equal(result, "bNfKVfqEOGmzlH8M+e8FYTB46SU="); } void utf8_display_len_null_str(void **state) { int result = utf8_display_len(NULL); assert_int_equal(0, result); } void utf8_display_len_1_non_wide(void **state) { int result = utf8_display_len("1"); assert_int_equal(1, result); } void utf8_display_len_1_wide(void **state) { int result = utf8_display_len("四"); assert_int_equal(2, result); } void utf8_display_len_non_wide(void **state) { int result = utf8_display_len("123456789abcdef"); assert_int_equal(15, result); } void utf8_display_len_wide(void **state) { int result = utf8_display_len("12三四56"); assert_int_equal(8, result); } void utf8_display_len_all_wide(void **state) { int result = utf8_display_len("ひらがな"); assert_int_equal(8, result); } void strip_quotes_does_nothing_when_no_quoted(void **state) { char *input = "/cmd test string"; char *result = strip_arg_quotes(input); assert_string_equal("/cmd test string", result); free(result); } void strip_quotes_strips_first(void **state) { char *input = "/cmd \"test string"; char *result = strip_arg_quotes(input); assert_string_equal("/cmd test string", result); free(result); } void strip_quotes_strips_last(void **state) { char *input = "/cmd test string\""; char *result = strip_arg_quotes(input); assert_string_equal("/cmd test string", result); free(result); } void strip_quotes_strips_both(void **state) { char *input = "/cmd \"test string\""; char *result = strip_arg_quotes(input); assert_string_equal("/cmd test string", result); free(result); } void str_not_contains_str(void **state) { char *main = "somestring"; char *occur = "not"; assert_false(str_contains_str(main, occur)); } void str_contains_str_at_start(void **state) { char *main = "somestring"; char *occur = "some"; assert_true(str_contains_str(main, occur)); } void str_contains_str_at_end(void **state) { char *main = "somestring"; char *occur = "string"; assert_true(str_contains_str(main, occur)); } void str_contains_str_in_middle(void **state) { char *main = "somestring"; char *occur = "str"; assert_true(str_contains_str(main, occur)); } void str_contains_str_whole(void **state) { char *main = "somestring"; char *occur = "somestring"; assert_true(str_contains_str(main, occur)); } void str_empty_not_contains_str(void **state) { char *main = NULL; char *occur = "str"; assert_false(str_contains_str(main, occur)); } void str_not_contains_str_empty(void **state) { char *main = "somestring"; char *occur = NULL; assert_false(str_contains_str(main, occur)); } void str_empty_not_contains_str_empty(void **state) { char *main = NULL; char *occur = NULL; assert_false(str_contains_str(main, occur)); } profanity-0.4.7/tests/unittests/test_common.h000066400000000000000000000060151257755232500214600ustar00rootroot00000000000000void replace_one_substr(void **state); void replace_one_substr_beginning(void **state); void replace_one_substr_end(void **state); void replace_two_substr(void **state); void replace_char(void **state); void replace_when_none(void **state); void replace_when_match(void **state); void replace_when_string_empty(void **state); void replace_when_string_null(void **state); void replace_when_sub_empty(void **state); void replace_when_sub_null(void **state); void replace_when_new_empty(void **state); void replace_when_new_null(void **state); void compare_win_nums_less(void **state); void compare_win_nums_equal(void **state); void compare_win_nums_greater(void **state); void compare_0s_equal(void **state); void compare_0_greater_than_1(void **state); void compare_1_less_than_0(void **state); void compare_0_less_than_11(void **state); void compare_11_greater_than_0(void **state); void compare_0_greater_than_9(void **state); void compare_9_less_than_0(void **state); void next_available_when_only_console(void **state); void next_available_3_at_end(void **state); void next_available_9_at_end(void **state); void next_available_0_at_end(void **state); void next_available_2_in_first_gap(void **state); void next_available_9_in_first_gap(void **state); void next_available_0_in_first_gap(void **state); void next_available_11_in_first_gap(void **state); void next_available_24_first_big_gap(void **state); void test_online_is_valid_resource_presence_string(void **state); void test_chat_is_valid_resource_presence_string(void **state); void test_away_is_valid_resource_presence_string(void **state); void test_xa_is_valid_resource_presence_string(void **state); void test_dnd_is_valid_resource_presence_string(void **state); void test_available_is_not_valid_resource_presence_string(void **state); void test_unavailable_is_not_valid_resource_presence_string(void **state); void test_blah_is_not_valid_resource_presence_string(void **state); void test_p_sha1_hash1(void **state); void test_p_sha1_hash2(void **state); void test_p_sha1_hash3(void **state); void test_p_sha1_hash4(void **state); void test_p_sha1_hash5(void **state); void test_p_sha1_hash6(void **state); void test_p_sha1_hash6(void **state); void test_p_sha1_hash7(void **state); void utf8_display_len_null_str(void **state); void utf8_display_len_1_non_wide(void **state); void utf8_display_len_1_wide(void **state); void utf8_display_len_non_wide(void **state); void utf8_display_len_wide(void **state); void utf8_display_len_all_wide(void **state); void strip_quotes_does_nothing_when_no_quoted(void **state); void strip_quotes_strips_first(void **state); void strip_quotes_strips_last(void **state); void strip_quotes_strips_both(void **state); void str_not_contains_str(void **state); void str_contains_str_at_start(void **state); void str_contains_str_at_end(void **state); void str_contains_str_in_middle(void **state); void str_contains_str_whole(void **state); void str_empty_not_contains_str(void **state); void str_not_contains_str_empty(void **state); void str_empty_not_contains_str_empty(void **state); profanity-0.4.7/tests/unittests/test_contact.c000066400000000000000000000322601257755232500216170ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "contact.h" void contact_in_group(void **state) { GSList *groups = NULL; groups = g_slist_append(groups, strdup("somegroup")); PContact contact = p_contact_new("bob@server.com", "bob", groups, "both", "is offline", FALSE); gboolean result = p_contact_in_group(contact, "somegroup"); assert_true(result); p_contact_free(contact); // g_slist_free(groups); } void contact_not_in_group(void **state) { GSList *groups = NULL; groups = g_slist_append(groups, strdup("somegroup")); PContact contact = p_contact_new("bob@server.com", "bob", groups, "both", "is offline", FALSE); gboolean result = p_contact_in_group(contact, "othergroup"); assert_false(result); p_contact_free(contact); // g_slist_free(groups); } void contact_name_when_name_exists(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); const char *name = p_contact_name_or_jid(contact); assert_string_equal("bob", name); p_contact_free(contact); } void contact_jid_when_name_not_exists(void **state) { PContact contact = p_contact_new("bob@server.com", NULL, NULL, "both", "is offline", FALSE); const char *jid = p_contact_name_or_jid(contact); assert_string_equal("bob@server.com", jid); p_contact_free(contact); } void contact_string_when_name_exists(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); char *str = p_contact_create_display_string(contact, "laptop"); assert_string_equal("bob (laptop)", str); p_contact_free(contact); free(str); } void contact_string_when_name_not_exists(void **state) { PContact contact = p_contact_new("bob@server.com", NULL, NULL, "both", "is offline", FALSE); char *str = p_contact_create_display_string(contact, "laptop"); assert_string_equal("bob@server.com (laptop)", str); p_contact_free(contact); free(str); } void contact_string_when_default_resource(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); char *str = p_contact_create_display_string(contact, "__prof_default"); assert_string_equal("bob", str); p_contact_free(contact); free(str); } void contact_presence_offline(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); const char *presence = p_contact_presence(contact); assert_string_equal("offline", presence); p_contact_free(contact); } void contact_presence_uses_highest_priority(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); Resource *resource10 = resource_new("resource10", RESOURCE_ONLINE, NULL, 10); Resource *resource20 = resource_new("resource20", RESOURCE_CHAT, NULL, 20); Resource *resource30 = resource_new("resource30", RESOURCE_AWAY, NULL, 30); Resource *resource1 = resource_new("resource1", RESOURCE_XA, NULL, 1); Resource *resource2 = resource_new("resource2", RESOURCE_DND, NULL, 2); p_contact_set_presence(contact, resource10); p_contact_set_presence(contact, resource20); p_contact_set_presence(contact, resource30); p_contact_set_presence(contact, resource1); p_contact_set_presence(contact, resource2); const char *presence = p_contact_presence(contact); assert_string_equal("away", presence); p_contact_free(contact); } void contact_presence_chat_when_same_prioroty(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); Resource *resource_online = resource_new("resource_online", RESOURCE_ONLINE, NULL, 10); Resource *resource_chat = resource_new("resource_chat", RESOURCE_CHAT, NULL, 10); Resource *resource_away = resource_new("resource_away", RESOURCE_AWAY, NULL, 10); Resource *resource_xa = resource_new("resource_xa", RESOURCE_XA, NULL, 10); Resource *resource_dnd = resource_new("resource_dnd", RESOURCE_DND, NULL, 10); p_contact_set_presence(contact, resource_online); p_contact_set_presence(contact, resource_chat); p_contact_set_presence(contact, resource_away); p_contact_set_presence(contact, resource_xa); p_contact_set_presence(contact, resource_dnd); const char *presence = p_contact_presence(contact); assert_string_equal("chat", presence); p_contact_free(contact); } void contact_presence_online_when_same_prioroty(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); Resource *resource_online = resource_new("resource_online", RESOURCE_ONLINE, NULL, 10); Resource *resource_away = resource_new("resource_away", RESOURCE_AWAY, NULL, 10); Resource *resource_xa = resource_new("resource_xa", RESOURCE_XA, NULL, 10); Resource *resource_dnd = resource_new("resource_dnd", RESOURCE_DND, NULL, 10); p_contact_set_presence(contact, resource_online); p_contact_set_presence(contact, resource_away); p_contact_set_presence(contact, resource_xa); p_contact_set_presence(contact, resource_dnd); const char *presence = p_contact_presence(contact); assert_string_equal("online", presence); p_contact_free(contact); } void contact_presence_away_when_same_prioroty(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); Resource *resource_away = resource_new("resource_away", RESOURCE_AWAY, NULL, 10); Resource *resource_xa = resource_new("resource_xa", RESOURCE_XA, NULL, 10); Resource *resource_dnd = resource_new("resource_dnd", RESOURCE_DND, NULL, 10); p_contact_set_presence(contact, resource_away); p_contact_set_presence(contact, resource_xa); p_contact_set_presence(contact, resource_dnd); const char *presence = p_contact_presence(contact); assert_string_equal("away", presence); p_contact_free(contact); } void contact_presence_xa_when_same_prioroty(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); Resource *resource_xa = resource_new("resource_xa", RESOURCE_XA, NULL, 10); Resource *resource_dnd = resource_new("resource_dnd", RESOURCE_DND, NULL, 10); p_contact_set_presence(contact, resource_xa); p_contact_set_presence(contact, resource_dnd); const char *presence = p_contact_presence(contact); assert_string_equal("xa", presence); p_contact_free(contact); } void contact_presence_dnd(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); Resource *resource_dnd = resource_new("resource_dnd", RESOURCE_DND, NULL, 10); p_contact_set_presence(contact, resource_dnd); const char *presence = p_contact_presence(contact); assert_string_equal("dnd", presence); p_contact_free(contact); } void contact_subscribed_when_to(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "to", "is offline", FALSE); gboolean result = p_contact_subscribed(contact); assert_true(result); p_contact_free(contact); } void contact_subscribed_when_both(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "both", "is offline", FALSE); gboolean result = p_contact_subscribed(contact); assert_true(result); p_contact_free(contact); } void contact_not_subscribed_when_from(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, "from", "is offline", FALSE); gboolean result = p_contact_subscribed(contact); assert_false(result); p_contact_free(contact); } void contact_not_subscribed_when_no_subscription_value(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, NULL, "is offline", FALSE); gboolean result = p_contact_subscribed(contact); assert_false(result); p_contact_free(contact); } void contact_not_available(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, NULL, "is offline", FALSE); gboolean result = p_contact_is_available(contact); assert_false(result); p_contact_free(contact); } void contact_not_available_when_highest_priority_away(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, NULL, "is offline", FALSE); Resource *resource_online = resource_new("resource_online", RESOURCE_ONLINE, NULL, 10); Resource *resource_chat = resource_new("resource_chat", RESOURCE_CHAT, NULL, 10); Resource *resource_away = resource_new("resource_away", RESOURCE_AWAY, NULL, 20); Resource *resource_xa = resource_new("resource_xa", RESOURCE_XA, NULL, 10); Resource *resource_dnd = resource_new("resource_dnd", RESOURCE_DND, NULL, 10); p_contact_set_presence(contact, resource_online); p_contact_set_presence(contact, resource_chat); p_contact_set_presence(contact, resource_away); p_contact_set_presence(contact, resource_xa); p_contact_set_presence(contact, resource_dnd); gboolean result = p_contact_is_available(contact); assert_false(result); p_contact_free(contact); } void contact_not_available_when_highest_priority_xa(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, NULL, "is offline", FALSE); Resource *resource_online = resource_new("resource_online", RESOURCE_ONLINE, NULL, 10); Resource *resource_chat = resource_new("resource_chat", RESOURCE_CHAT, NULL, 10); Resource *resource_away = resource_new("resource_away", RESOURCE_AWAY, NULL, 10); Resource *resource_xa = resource_new("resource_xa", RESOURCE_XA, NULL, 20); Resource *resource_dnd = resource_new("resource_dnd", RESOURCE_DND, NULL, 10); p_contact_set_presence(contact, resource_online); p_contact_set_presence(contact, resource_chat); p_contact_set_presence(contact, resource_away); p_contact_set_presence(contact, resource_xa); p_contact_set_presence(contact, resource_dnd); gboolean result = p_contact_is_available(contact); assert_false(result); p_contact_free(contact); } void contact_not_available_when_highest_priority_dnd(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, NULL, "is offline", FALSE); Resource *resource_online = resource_new("resource_online", RESOURCE_ONLINE, NULL, 10); Resource *resource_chat = resource_new("resource_chat", RESOURCE_CHAT, NULL, 10); Resource *resource_away = resource_new("resource_away", RESOURCE_AWAY, NULL, 10); Resource *resource_xa = resource_new("resource_xa", RESOURCE_XA, NULL, 10); Resource *resource_dnd = resource_new("resource_dnd", RESOURCE_DND, NULL, 20); p_contact_set_presence(contact, resource_online); p_contact_set_presence(contact, resource_chat); p_contact_set_presence(contact, resource_away); p_contact_set_presence(contact, resource_xa); p_contact_set_presence(contact, resource_dnd); gboolean result = p_contact_is_available(contact); assert_false(result); p_contact_free(contact); } void contact_available_when_highest_priority_online(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, NULL, "is offline", FALSE); Resource *resource_online = resource_new("resource_online", RESOURCE_ONLINE, NULL, 20); Resource *resource_chat = resource_new("resource_chat", RESOURCE_CHAT, NULL, 10); Resource *resource_away = resource_new("resource_away", RESOURCE_AWAY, NULL, 10); Resource *resource_xa = resource_new("resource_xa", RESOURCE_XA, NULL, 10); Resource *resource_dnd = resource_new("resource_dnd", RESOURCE_DND, NULL, 10); p_contact_set_presence(contact, resource_online); p_contact_set_presence(contact, resource_chat); p_contact_set_presence(contact, resource_away); p_contact_set_presence(contact, resource_xa); p_contact_set_presence(contact, resource_dnd); gboolean result = p_contact_is_available(contact); assert_true(result); p_contact_free(contact); } void contact_available_when_highest_priority_chat(void **state) { PContact contact = p_contact_new("bob@server.com", "bob", NULL, NULL, "is offline", FALSE); Resource *resource_online = resource_new("resource_online", RESOURCE_ONLINE, NULL, 10); Resource *resource_chat = resource_new("resource_chat", RESOURCE_CHAT, NULL, 20); Resource *resource_away = resource_new("resource_away", RESOURCE_AWAY, NULL, 10); Resource *resource_xa = resource_new("resource_xa", RESOURCE_XA, NULL, 10); Resource *resource_dnd = resource_new("resource_dnd", RESOURCE_DND, NULL, 10); p_contact_set_presence(contact, resource_online); p_contact_set_presence(contact, resource_chat); p_contact_set_presence(contact, resource_away); p_contact_set_presence(contact, resource_xa); p_contact_set_presence(contact, resource_dnd); gboolean result = p_contact_is_available(contact); assert_true(result); p_contact_free(contact); } profanity-0.4.7/tests/unittests/test_contact.h000066400000000000000000000024641257755232500216270ustar00rootroot00000000000000void contact_in_group(void **state); void contact_not_in_group(void **state); void contact_name_when_name_exists(void **state); void contact_jid_when_name_not_exists(void **state); void contact_string_when_name_exists(void **state); void contact_string_when_name_not_exists(void **state); void contact_string_when_default_resource(void **state); void contact_presence_offline(void **state); void contact_presence_uses_highest_priority(void **state); void contact_presence_chat_when_same_prioroty(void **state); void contact_presence_online_when_same_prioroty(void **state); void contact_presence_away_when_same_prioroty(void **state); void contact_presence_xa_when_same_prioroty(void **state); void contact_presence_dnd(void **state); void contact_subscribed_when_to(void **state); void contact_subscribed_when_both(void **state); void contact_not_subscribed_when_from(void **state); void contact_not_subscribed_when_no_subscription_value(void **state); void contact_not_available(void **state); void contact_not_available_when_highest_priority_away(void **state); void contact_not_available_when_highest_priority_xa(void **state); void contact_not_available_when_highest_priority_dnd(void **state); void contact_available_when_highest_priority_online(void **state); void contact_available_when_highest_priority_chat(void **state); profanity-0.4.7/tests/unittests/test_form.c000066400000000000000000000543011257755232500211270ustar00rootroot00000000000000#include #include #include #include #include #include #include "xmpp/form.h" xmpp_ctx_t* connection_get_ctx(void) { return NULL; } static DataForm* _new_form(void) { DataForm *form = malloc(sizeof(DataForm)); form->type = NULL; form->title = NULL; form->instructions = NULL; form->fields = NULL; form->var_to_tag = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); form->tag_to_var = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); form->tag_ac = NULL; return form; } static FormField* _new_field(void) { FormField *field = malloc(sizeof(FormField)); field->label = NULL; field->type = NULL; field->description = NULL; field->required = FALSE; field->options = NULL; field->var = NULL; field->values = NULL; field->value_ac = NULL; return field; } void get_form_type_field_returns_null_no_fields(void **state) { DataForm *form = _new_form(); char *result = form_get_form_type_field(form); assert_null(result); form_destroy(form); } void get_form_type_field_returns_null_when_not_present(void **state) { DataForm *form = _new_form(); FormField *field = _new_field(); field->var = strdup("var1"); field->values = g_slist_append(field->values, strdup("value1")); form->fields = g_slist_append(form->fields, field); char *result = form_get_form_type_field(form); assert_null(result); form_destroy(form); } void get_form_type_field_returns_value_when_present(void **state) { DataForm *form = _new_form(); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->values = g_slist_append(field1->values, strdup("value1")); form->fields = g_slist_append(form->fields, field1); FormField *field2 = _new_field(); field2->var = strdup("FORM_TYPE"); field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); FormField *field3 = _new_field(); field3->var = strdup("var3"); field3->values = g_slist_append(field3->values, strdup("value3")); form->fields = g_slist_append(form->fields, field3); char *result = form_get_form_type_field(form); assert_string_equal(result, "value2"); form_destroy(form); } void get_field_type_returns_unknown_when_no_fields(void **state) { DataForm *form = _new_form(); form_field_type_t result = form_get_field_type(form, "tag"); assert_int_equal(result, FIELD_UNKNOWN); form_destroy(form); } void get_field_type_returns_correct_type(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_TEXT_SINGLE; field1->values = g_slist_append(field1->values, strdup("value1")); form->fields = g_slist_append(form->fields, field1); FormField *field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_TEXT_MULTI; field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); form_field_type_t result = form_get_field_type(form, "tag2"); assert_int_equal(result, FIELD_TEXT_MULTI); form_destroy(form); } void set_value_adds_when_none(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_TEXT_SINGLE; field1->values = g_slist_append(field1->values, strdup("value1")); form->fields = g_slist_append(form->fields, field1); FormField *field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_LIST_SINGLE; form->fields = g_slist_append(form->fields, field2); form_set_value(form, "tag2", "a new value"); int length = 0; char *value = NULL; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var2") == 0) { length = g_slist_length(field->values); value = field->values->data; break; } curr_field = g_slist_next(curr_field); } assert_int_equal(length, 1); assert_string_equal(value, "a new value"); form_destroy(form); } void set_value_updates_when_one(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_TEXT_SINGLE; form->fields = g_slist_append(form->fields, field1); FormField *field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_LIST_SINGLE; field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); form_set_value(form, "tag2", "a new value"); int length = 0; char *value = NULL; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var2") == 0) { length = g_slist_length(field->values); value = field->values->data; break; } curr_field = g_slist_next(curr_field); } assert_int_equal(length, 1); assert_string_equal(value, "a new value"); form_destroy(form); } void add_unique_value_adds_when_none(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_JID_MULTI; form->fields = g_slist_append(form->fields, field1); FormField *field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_LIST_SINGLE; field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); gboolean ret = form_add_unique_value(form, "tag1", "me@server.com"); int length = 0; char *value = NULL; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); value = field->values->data; break; } curr_field = g_slist_next(curr_field); } assert_true(ret); assert_int_equal(length, 1); assert_string_equal(value, "me@server.com"); form_destroy(form); } void add_unique_value_does_nothing_when_exists(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_JID_MULTI; field1->values = g_slist_append(field1->values, strdup("me@server.com")); form->fields = g_slist_append(form->fields, field1); FormField *field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_LIST_SINGLE; field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); gboolean ret = form_add_unique_value(form, "tag1", "me@server.com"); int length = 0; char *value = NULL; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); value = field->values->data; break; } curr_field = g_slist_next(curr_field); } assert_false(ret); assert_int_equal(length, 1); assert_string_equal(value, "me@server.com"); form_destroy(form); } void add_unique_value_adds_when_doesnt_exist(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); g_hash_table_insert(form->tag_to_var, strdup("tag2"), strdup("var2")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_JID_MULTI; field1->values = g_slist_append(field1->values, strdup("dolan@server.com")); field1->values = g_slist_append(field1->values, strdup("kieran@server.com")); field1->values = g_slist_append(field1->values, strdup("chi@server.com")); form->fields = g_slist_append(form->fields, field1); FormField *field2 = _new_field(); field2->var = strdup("var2"); field2->type_t = FIELD_LIST_SINGLE; field2->values = g_slist_append(field2->values, strdup("value2")); form->fields = g_slist_append(form->fields, field2); gboolean ret = form_add_unique_value(form, "tag1", "me@server.com"); int length = 0; int count = 0; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); GSList *curr_value = field->values; while (curr_value != NULL) { if (g_strcmp0(curr_value->data, "me@server.com") == 0) { count++; } curr_value = g_slist_next(curr_value); } break; } curr_field = g_slist_next(curr_field); } assert_true(ret); assert_int_equal(length, 4); assert_int_equal(count, 1); form_destroy(form); } void add_value_adds_when_none(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; form->fields = g_slist_append(form->fields, field1); form_add_value(form, "tag1", "somevalue"); int length = 0; char *value = NULL; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); value = field->values->data; break; } curr_field = g_slist_next(curr_field); } assert_int_equal(length, 1); assert_string_equal(value, "somevalue"); form_destroy(form); } void add_value_adds_when_some(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("some text")); field1->values = g_slist_append(field1->values, strdup("some more text")); field1->values = g_slist_append(field1->values, strdup("yet some more text")); form->fields = g_slist_append(form->fields, field1); form_add_value(form, "tag1", "new value"); int num_values = 0; int new_value_count = 0; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { GSList *curr_value = field->values; while (curr_value != NULL) { num_values++; if (g_strcmp0(curr_value->data, "new value") == 0) { new_value_count++; } curr_value = g_slist_next(curr_value); } break; } curr_field = g_slist_next(curr_field); } assert_int_equal(num_values, 4); assert_int_equal(new_value_count, 1); form_destroy(form); } void add_value_adds_when_exists(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("some text")); field1->values = g_slist_append(field1->values, strdup("some more text")); field1->values = g_slist_append(field1->values, strdup("yet some more text")); field1->values = g_slist_append(field1->values, strdup("new value")); form->fields = g_slist_append(form->fields, field1); form_add_value(form, "tag1", "new value"); int num_values = 0; int new_value_count = 0; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { GSList *curr_value = field->values; while (curr_value != NULL) { num_values++; if (g_strcmp0(curr_value->data, "new value") == 0) { new_value_count++; } curr_value = g_slist_next(curr_value); } break; } curr_field = g_slist_next(curr_field); } assert_int_equal(num_values, 5); assert_int_equal(new_value_count, 2); form_destroy(form); } void remove_value_does_nothing_when_none(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_value(form, "tag1", "some value"); int length = -1; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); } curr_field = g_slist_next(curr_field); } assert_false(res); assert_int_equal(length, 0); form_destroy(form); } void remove_value_does_nothing_when_doesnt_exist(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value1")); field1->values = g_slist_append(field1->values, strdup("value2")); field1->values = g_slist_append(field1->values, strdup("value3")); field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_value(form, "tag1", "value5"); int length = -1; int value_count = 0; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); GSList *curr_value = field->values; while (curr_value != NULL) { if (g_strcmp0(curr_value->data, "value5") == 0) { value_count++; } curr_value = g_slist_next(curr_value); } } curr_field = g_slist_next(curr_field); } assert_false(res); assert_int_equal(length, 4); assert_int_equal(value_count, 0); form_destroy(form); } void remove_value_removes_when_one(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_value(form, "tag1", "value4"); int length = -1; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); } curr_field = g_slist_next(curr_field); } assert_true(res); assert_int_equal(length, 0); form_destroy(form); } void remove_value_removes_when_many(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value1")); field1->values = g_slist_append(field1->values, strdup("value2")); field1->values = g_slist_append(field1->values, strdup("value3")); field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_value(form, "tag1", "value2"); int length = -1; int value_count = 0; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); GSList *curr_value = field->values; while (curr_value != NULL) { if (g_strcmp0(curr_value->data, "value2") == 0) { value_count++; } curr_value = g_slist_next(curr_value); } } curr_field = g_slist_next(curr_field); } assert_true(res); assert_int_equal(length, 3); assert_int_equal(value_count, 0); form_destroy(form); } void remove_text_multi_value_does_nothing_when_none(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_text_multi_value(form, "tag1", 3); int length = -1; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); } curr_field = g_slist_next(curr_field); } assert_false(res); assert_int_equal(length, 0); form_destroy(form); } void remove_text_multi_value_does_nothing_when_doesnt_exist(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value1")); field1->values = g_slist_append(field1->values, strdup("value2")); field1->values = g_slist_append(field1->values, strdup("value3")); field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_text_multi_value(form, "tag1", 5); int length = -1; int value_count = 0; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); GSList *curr_value = field->values; while (curr_value != NULL) { if (g_strcmp0(curr_value->data, "value5") == 0) { value_count++; } curr_value = g_slist_next(curr_value); } } curr_field = g_slist_next(curr_field); } assert_false(res); assert_int_equal(length, 4); assert_int_equal(value_count, 0); form_destroy(form); } void remove_text_multi_value_removes_when_one(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_text_multi_value(form, "tag1", 1); int length = -1; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); } curr_field = g_slist_next(curr_field); } assert_true(res); assert_int_equal(length, 0); form_destroy(form); } void remove_text_multi_value_removes_when_many(void **state) { DataForm *form = _new_form(); g_hash_table_insert(form->tag_to_var, strdup("tag1"), strdup("var1")); FormField *field1 = _new_field(); field1->var = strdup("var1"); field1->type_t = FIELD_LIST_MULTI; field1->values = g_slist_append(field1->values, strdup("value1")); field1->values = g_slist_append(field1->values, strdup("value2")); field1->values = g_slist_append(field1->values, strdup("value3")); field1->values = g_slist_append(field1->values, strdup("value4")); form->fields = g_slist_append(form->fields, field1); gboolean res = form_remove_text_multi_value(form, "tag1", 2); int length = -1; int value_count = 0; GSList *curr_field = form->fields; while (curr_field != NULL) { FormField *field = curr_field->data; if (g_strcmp0(field->var, "var1") == 0) { length = g_slist_length(field->values); GSList *curr_value = field->values; while (curr_value != NULL) { if (g_strcmp0(curr_value->data, "value2") == 0) { value_count++; } curr_value = g_slist_next(curr_value); } } curr_field = g_slist_next(curr_field); } assert_true(res); assert_int_equal(length, 3); assert_int_equal(value_count, 0); form_destroy(form); } profanity-0.4.7/tests/unittests/test_form.h000066400000000000000000000022731257755232500211350ustar00rootroot00000000000000void get_form_type_field_returns_null_no_fields(void **state); void get_form_type_field_returns_null_when_not_present(void **state); void get_form_type_field_returns_value_when_present(void **state); void get_field_type_returns_unknown_when_no_fields(void **state); void get_field_type_returns_correct_type(void **state); void set_value_adds_when_none(void **state); void set_value_updates_when_one(void **state); void add_unique_value_adds_when_none(void **state); void add_unique_value_does_nothing_when_exists(void **state); void add_unique_value_adds_when_doesnt_exist(void **state); void add_value_adds_when_none(void **state); void add_value_adds_when_some(void **state); void add_value_adds_when_exists(void **state); void remove_value_does_nothing_when_none(void **state); void remove_value_does_nothing_when_doesnt_exist(void **state); void remove_value_removes_when_one(void **state); void remove_value_removes_when_many(void **state); void remove_text_multi_value_does_nothing_when_none(void **state); void remove_text_multi_value_does_nothing_when_doesnt_exist(void **state); void remove_text_multi_value_removes_when_one(void **state); void remove_text_multi_value_removes_when_many(void **state); profanity-0.4.7/tests/unittests/test_jid.c000066400000000000000000000130171257755232500207310ustar00rootroot00000000000000#include #include #include #include #include #include "jid.h" void create_jid_from_null_returns_null(void **state) { Jid *result = jid_create(NULL); assert_null(result); } void create_jid_from_empty_string_returns_null(void **state) { Jid *result = jid_create(""); assert_null(result); } void create_jid_from_full_returns_full(void **state) { Jid *result = jid_create("myuser@mydomain/laptop"); assert_string_equal("myuser@mydomain/laptop", result->fulljid); } void create_jid_from_full_returns_bare(void **state) { Jid *result = jid_create("myuser@mydomain/laptop"); assert_string_equal("myuser@mydomain", result->barejid); } void create_jid_from_full_returns_resourcepart(void **state) { Jid *result = jid_create("myuser@mydomain/laptop"); assert_string_equal("laptop", result->resourcepart); } void create_jid_from_full_returns_localpart(void **state) { Jid *result = jid_create("myuser@mydomain/laptop"); assert_string_equal("myuser", result->localpart); } void create_jid_from_full_returns_domainpart(void **state) { Jid *result = jid_create("myuser@mydomain/laptop"); assert_string_equal("mydomain", result->domainpart); } void create_jid_from_full_nolocal_returns_full(void **state) { Jid *result = jid_create("mydomain/laptop"); assert_string_equal("mydomain/laptop", result->fulljid); } void create_jid_from_full_nolocal_returns_bare(void **state) { Jid *result = jid_create("mydomain/laptop"); assert_string_equal("mydomain", result->barejid); } void create_jid_from_full_nolocal_returns_resourcepart(void **state) { Jid *result = jid_create("mydomain/laptop"); assert_string_equal("laptop", result->resourcepart); } void create_jid_from_full_nolocal_returns_domainpart(void **state) { Jid *result = jid_create("mydomain/laptop"); assert_string_equal("mydomain", result->domainpart); } void create_jid_from_full_nolocal_returns_null_localpart(void **state) { Jid *result = jid_create("mydomain/laptop"); assert_null(result->localpart); } void create_jid_from_bare_returns_null_full(void **state) { Jid *result = jid_create("myuser@mydomain"); assert_null(result->fulljid); } void create_jid_from_bare_returns_null_resource(void **state) { Jid *result = jid_create("myuser@mydomain"); assert_null(result->resourcepart); } void create_jid_from_bare_returns_bare(void **state) { Jid *result = jid_create("myuser@mydomain"); assert_string_equal("myuser@mydomain", result->barejid); } void create_jid_from_bare_returns_localpart(void **state) { Jid *result = jid_create("myuser@mydomain"); assert_string_equal("myuser", result->localpart); } void create_jid_from_bare_returns_domainpart(void **state) { Jid *result = jid_create("myuser@mydomain"); assert_string_equal("mydomain", result->domainpart); } void create_room_jid_returns_room(void **state) { Jid *result = jid_create_from_bare_and_resource("room@conference.domain.org", "myname"); assert_string_equal("room@conference.domain.org", result->barejid); } void create_room_jid_returns_nick(void **state) { Jid *result = jid_create_from_bare_and_resource("room@conference.domain.org", "myname"); assert_string_equal("myname", result->resourcepart); } void create_with_slash_in_resource(void **state) { Jid *result = jid_create("room@conference.domain.org/my/nick"); assert_string_equal("room", result->localpart); assert_string_equal("conference.domain.org", result->domainpart); assert_string_equal("my/nick", result->resourcepart); assert_string_equal("room@conference.domain.org", result->barejid); assert_string_equal("room@conference.domain.org/my/nick", result->fulljid); } void create_with_at_in_resource(void **state) { Jid *result = jid_create("room@conference.domain.org/my@nick"); assert_string_equal("room", result->localpart); assert_string_equal("conference.domain.org", result->domainpart); assert_string_equal("my@nick", result->resourcepart); assert_string_equal("room@conference.domain.org", result->barejid); assert_string_equal("room@conference.domain.org/my@nick", result->fulljid); } void create_with_at_and_slash_in_resource(void **state) { Jid *result = jid_create("room@conference.domain.org/my@nick/something"); assert_string_equal("room", result->localpart); assert_string_equal("conference.domain.org", result->domainpart); assert_string_equal("my@nick/something", result->resourcepart); assert_string_equal("room@conference.domain.org", result->barejid); assert_string_equal("room@conference.domain.org/my@nick/something", result->fulljid); } void create_full_with_trailing_slash(void **state) { Jid *result = jid_create("room@conference.domain.org/nick/"); assert_string_equal("room", result->localpart); assert_string_equal("conference.domain.org", result->domainpart); assert_string_equal("nick/", result->resourcepart); assert_string_equal("room@conference.domain.org", result->barejid); assert_string_equal("room@conference.domain.org/nick/", result->fulljid); } void returns_fulljid_when_exists(void **state) { Jid *jid = jid_create("localpart@domainpart/resourcepart"); char *result = jid_fulljid_or_barejid(jid); assert_string_equal("localpart@domainpart/resourcepart", result); } void returns_barejid_when_fulljid_not_exists(void **state) { Jid *jid = jid_create("localpart@domainpart"); char *result = jid_fulljid_or_barejid(jid); assert_string_equal("localpart@domainpart", result); }profanity-0.4.7/tests/unittests/test_jid.h000066400000000000000000000026461257755232500207440ustar00rootroot00000000000000void create_jid_from_null_returns_null(void **state); void create_jid_from_empty_string_returns_null(void **state); void create_jid_from_full_returns_full(void **state); void create_jid_from_full_returns_bare(void **state); void create_jid_from_full_returns_resourcepart(void **state); void create_jid_from_full_returns_localpart(void **state); void create_jid_from_full_returns_domainpart(void **state); void create_jid_from_full_nolocal_returns_full(void **state); void create_jid_from_full_nolocal_returns_bare(void **state); void create_jid_from_full_nolocal_returns_resourcepart(void **state); void create_jid_from_full_nolocal_returns_domainpart(void **state); void create_jid_from_full_nolocal_returns_null_localpart(void **state); void create_jid_from_bare_returns_null_full(void **state); void create_jid_from_bare_returns_null_resource(void **state); void create_jid_from_bare_returns_bare(void **state); void create_jid_from_bare_returns_localpart(void **state); void create_jid_from_bare_returns_domainpart(void **state); void create_room_jid_returns_room(void **state); void create_room_jid_returns_nick(void **state); void create_with_slash_in_resource(void **state); void create_with_at_in_resource(void **state); void create_with_at_and_slash_in_resource(void **state); void create_full_with_trailing_slash(void **state); void returns_fulljid_when_exists(void **state); void returns_barejid_when_fulljid_not_exists(void **state); profanity-0.4.7/tests/unittests/test_keyhandlers.c000066400000000000000000000523571257755232500225060ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "ui/keyhandlers.h" #include "ui/inputwin.h" #include "tests/helpers.h" static char line[INP_WIN_MAX]; // append void append_to_empty(void **state) { setlocale(LC_ALL, ""); line[0] = '\0'; int line_utf8_pos = 0; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_printable(line, &line_utf8_pos, &col, &pad_start, 'a', 80); assert_string_equal("a", line); assert_int_equal(line_utf8_pos, 1); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void append_wide_to_empty(void **state) { setlocale(LC_ALL, ""); line[0] = '\0'; int line_utf8_pos = 0; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_printable(line, &line_utf8_pos, &col, &pad_start, 0x56DB, 80); assert_string_equal("四", line); assert_int_equal(line_utf8_pos, 1); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void append_to_single(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "a", 1); line[1] = '\0'; int line_utf8_pos = 1; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_printable(line, &line_utf8_pos, &col, &pad_start, 'b', 80); assert_string_equal("ab", line); assert_int_equal(line_utf8_pos, 2); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void append_wide_to_single_non_wide(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "a", 1); line[1] = '\0'; int line_utf8_pos = 1; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_printable(line, &line_utf8_pos, &col, &pad_start, 0x56DB, 80); assert_string_equal("a四", line); assert_int_equal(line_utf8_pos, 2); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void append_non_wide_to_single_wide(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "四", 1); line[strlen(line)] = '\0'; int line_utf8_pos = 1; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_printable(line, &line_utf8_pos, &col, &pad_start, 'b', 80); assert_string_equal("四b", line); assert_int_equal(line_utf8_pos, 2); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void append_wide_to_single_wide(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "四", 1); line[strlen(line)] = '\0'; int line_utf8_pos = 1; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_printable(line, &line_utf8_pos, &col, &pad_start, 0x4E09, 80); assert_string_equal("四三", line); assert_int_equal(line_utf8_pos, 2); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void append_non_wide_when_overrun(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "0123456789四1234567", 18); line[strlen(line)] = '\0'; int line_utf8_pos = 18; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_printable(line, &line_utf8_pos, &col, &pad_start, 'z', 20); key_printable(line, &line_utf8_pos, &col, &pad_start, 'z', 20); key_printable(line, &line_utf8_pos, &col, &pad_start, 'z', 20); assert_string_equal("0123456789四1234567zzz", line); assert_int_equal(line_utf8_pos, 21); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 3); } void insert_non_wide_to_non_wide(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd", 4); line[strlen(line)] = '\0'; int line_utf8_pos = 2; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_printable(line, &line_utf8_pos, &col, &pad_start, '0', 80); assert_string_equal("ab0cd", line); assert_int_equal(line_utf8_pos, 3); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void insert_single_non_wide_when_pad_scrolled(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "AAAAAAAAAAAAAAA", 15); line[strlen(line)] = '\0'; int line_utf8_pos = 2; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 2; key_printable(line, &line_utf8_pos, &col, &pad_start, 'B', 12); assert_string_equal("AABAAAAAAAAAAAAA", line); assert_int_equal(line_utf8_pos, 3); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 2); } void insert_many_non_wide_when_pad_scrolled(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "AAAAAAAAAAAAAAA", 15); line[strlen(line)] = '\0'; int line_utf8_pos = 2; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 2; key_printable(line, &line_utf8_pos, &col, &pad_start, 'B', 12); key_printable(line, &line_utf8_pos, &col, &pad_start, 'C', 12); key_printable(line, &line_utf8_pos, &col, &pad_start, 'D', 12); assert_string_equal("AABCDAAAAAAAAAAAAA", line); assert_int_equal(line_utf8_pos, 5); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 2); } void insert_single_non_wide_last_column(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcdefghijklmno", 15); line[strlen(line)] = '\0'; int line_utf8_pos = 7; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 2; key_printable(line, &line_utf8_pos, &col, &pad_start, '1', 5); assert_string_equal("abcdefg1hijklmno", line); assert_int_equal(line_utf8_pos, 8); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 3); } void insert_many_non_wide_last_column(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcdefghijklmno", 15); line[strlen(line)] = '\0'; int line_utf8_pos = 7; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 2; key_printable(line, &line_utf8_pos, &col, &pad_start, '1', 5); key_printable(line, &line_utf8_pos, &col, &pad_start, '2', 5); assert_string_equal("abcdefg12hijklmno", line); assert_int_equal(line_utf8_pos, 9); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 4); } void ctrl_left_when_no_input(void **state) { setlocale(LC_ALL, ""); line[0] = '\0'; int line_utf8_pos = 0; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 0); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_at_start(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 0; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 0); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_in_first_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 2; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 0); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_in_first_space(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 4; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 0); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_at_start_of_second_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 5; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 0); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_in_second_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 8; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 5); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_at_end_of_second_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 10; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 5); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_in_second_space(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 11; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 5); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_at_start_of_third_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 12; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 5); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_in_third_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 14; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 12); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_at_end_of_third_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 15; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 12); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_in_third_space(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 16; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 12); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_at_end(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); line[strlen(line)] = '\0'; int line_utf8_pos = 20; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 17); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_in_only_whitespace(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, " ", 7); line[strlen(line)] = '\0'; int line_utf8_pos = 5; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 0); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_start_whitespace_start_of_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, " hello", 9); line[strlen(line)] = '\0'; int line_utf8_pos = 4; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 0); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_start_whitespace_middle_of_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, " hello", 9); line[strlen(line)] = '\0'; int line_utf8_pos = 7; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 4); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_in_whitespace_between_words(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "hey hello", 12); line[strlen(line)] = '\0'; int line_utf8_pos = 5; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 0); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_in_whitespace_between_words_start_of_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "hey hello", 12); line[strlen(line)] = '\0'; int line_utf8_pos = 7; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 0); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_in_whitespace_between_words_middle_of_word(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "hey hello", 12); line[strlen(line)] = '\0'; int line_utf8_pos = 9; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 7); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_left_when_word_overrun_to_left(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "someword anotherword", 20); line[strlen(line)] = '\0'; int line_utf8_pos = 18; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 14; key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 9); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 9); } void ctrl_right_when_no_input(void **state) { setlocale(LC_ALL, ""); line[0] = '\0'; int line_utf8_pos = 0; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 0); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_when_at_end(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "someword anotherword", 20); line[strlen(line)] = '\0'; int line_utf8_pos = 20; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 20); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_one_word_at_start(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "someword", 8); line[strlen(line)] = '\0'; int line_utf8_pos = 0; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 8); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_one_word_in_middle(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "someword", 8); line[strlen(line)] = '\0'; int line_utf8_pos = 3; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 8); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_one_word_at_end(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "someword", 8); line[strlen(line)] = '\0'; int line_utf8_pos = 7; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 8); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_two_words_from_middle_first(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "someword anotherword", 20); line[strlen(line)] = '\0'; int line_utf8_pos = 4; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 8); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_two_words_from_end_first(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "someword anotherword", 20); line[strlen(line)] = '\0'; int line_utf8_pos = 7; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 8); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_two_words_from_space(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "someword anotherword", 20); line[strlen(line)] = '\0'; int line_utf8_pos = 8; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 20); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_two_words_from_start_second(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "someword anotherword", 20); line[strlen(line)] = '\0'; int line_utf8_pos = 9; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 20); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_one_word_leading_whitespace(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, " someword", 15); line[strlen(line)] = '\0'; int line_utf8_pos = 3; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 15); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_two_words_in_whitespace(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, " someword adfasdf", 30); line[strlen(line)] = '\0'; int line_utf8_pos = 19; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 30); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); } void ctrl_right_trailing_whitespace_from_middle(void **state) { setlocale(LC_ALL, ""); g_utf8_strncpy(line, "someword ", 16); line[strlen(line)] = '\0'; int line_utf8_pos = 3; int col = utf8_pos_to_col(line, line_utf8_pos); int pad_start = 0; key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); assert_int_equal(line_utf8_pos, 8); assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); assert_int_equal(pad_start, 0); }profanity-0.4.7/tests/unittests/test_keyhandlers.h000066400000000000000000000044341257755232500225040ustar00rootroot00000000000000void append_to_empty(void **state); void append_wide_to_empty(void **state); void append_to_single(void **state); void append_wide_to_single_non_wide(void **state); void append_non_wide_to_single_wide(void **state); void append_wide_to_single_wide(void **state); void append_non_wide_when_overrun(void **state); void insert_non_wide_to_non_wide(void **state); void insert_single_non_wide_when_pad_scrolled(void **state); void insert_many_non_wide_when_pad_scrolled(void **state); void insert_single_non_wide_last_column(void **state); void insert_many_non_wide_last_column(void **state); void ctrl_left_when_no_input(void **state); void ctrl_left_when_at_start(void **state); void ctrl_left_when_in_first_word(void **state); void ctrl_left_when_in_first_space(void **state); void ctrl_left_when_at_start_of_second_word(void **state); void ctrl_left_when_in_second_word(void **state); void ctrl_left_when_at_end_of_second_word(void **state); void ctrl_left_when_in_second_space(void **state); void ctrl_left_when_at_start_of_third_word(void **state); void ctrl_left_when_in_third_word(void **state); void ctrl_left_when_at_end_of_third_word(void **state); void ctrl_left_when_in_third_space(void **state); void ctrl_left_when_at_end(void **state); void ctrl_left_when_in_only_whitespace(void **state); void ctrl_left_when_start_whitespace_start_of_word(void **state); void ctrl_left_when_start_whitespace_middle_of_word(void **state); void ctrl_left_in_whitespace_between_words(void **state); void ctrl_left_in_whitespace_between_words_start_of_word(void **state); void ctrl_left_in_whitespace_between_words_middle_of_word(void **state); void ctrl_left_when_word_overrun_to_left(void **state); void ctrl_right_when_no_input(void **state); void ctrl_right_when_at_end(void **state); void ctrl_right_one_word_at_start(void **state); void ctrl_right_one_word_in_middle(void **state); void ctrl_right_one_word_at_end(void **state); void ctrl_right_two_words_from_middle_first(void **state); void ctrl_right_two_words_from_end_first(void **state); void ctrl_right_two_words_from_space(void **state); void ctrl_right_two_words_from_start_second(void **state); void ctrl_right_one_word_leading_whitespace(void **state); void ctrl_right_two_words_in_whitespace(void **state); void ctrl_right_trailing_whitespace_from_middle(void **state);profanity-0.4.7/tests/unittests/test_muc.c000066400000000000000000000030401257755232500207420ustar00rootroot00000000000000#include #include #include #include #include #include "muc.h" void muc_before_test(void **state) { muc_init(); } void muc_after_test(void **state) { muc_close(); } void test_muc_invites_add(void **state) { char *room = "room@conf.server"; muc_invites_add(room, NULL); gboolean invite_exists = muc_invites_contain(room); assert_true(invite_exists); } void test_muc_remove_invite(void **state) { char *room = "room@conf.server"; muc_invites_add(room, NULL); muc_invites_remove(room); gboolean invite_exists = muc_invites_contain(room); assert_false(invite_exists); } void test_muc_invites_count_0(void **state) { int invite_count = muc_invites_count(); assert_true(invite_count == 0); } void test_muc_invites_count_5(void **state) { muc_invites_add("room1@conf.server", NULL); muc_invites_add("room2@conf.server", NULL); muc_invites_add("room3@conf.server", NULL); muc_invites_add("room4@conf.server", NULL); muc_invites_add("room5@conf.server", NULL); int invite_count = muc_invites_count(); assert_true(invite_count == 5); } void test_muc_room_is_not_active(void **state) { char *room = "room@server.org"; gboolean room_is_active = muc_active(room); assert_false(room_is_active); } void test_muc_active(void **state) { char *room = "room@server.org"; char *nick = "bob"; muc_join(room, nick, NULL, FALSE); gboolean room_is_active = muc_active(room); assert_true(room_is_active); } profanity-0.4.7/tests/unittests/test_muc.h000066400000000000000000000005121257755232500207500ustar00rootroot00000000000000void muc_before_test(void **state); void muc_after_test(void **state); void test_muc_invites_add(void **state); void test_muc_remove_invite(void **state); void test_muc_invites_count_0(void **state); void test_muc_invites_count_5(void **state); void test_muc_room_is_not_active(void **state); void test_muc_active(void **state); profanity-0.4.7/tests/unittests/test_parser.c000066400000000000000000000376361257755232500214740ustar00rootroot00000000000000#include #include #include #include #include #include "tools/parser.h" void parse_null_returns_null(void **state) { char *inp = NULL; gboolean result = TRUE; gchar **args = parse_args(inp, 1, 2, &result); assert_false(result); assert_null(args); g_strfreev(args); } void parse_empty_returns_null(void **state) { char *inp = ""; gboolean result = TRUE; gchar **args = parse_args(inp, 1, 2, &result); assert_false(result); assert_null(args); g_strfreev(args); } void parse_space_returns_null(void **state) { char *inp = " "; gboolean result = TRUE; gchar **args = parse_args(inp, 1, 2, &result); assert_false(result); assert_null(args); g_strfreev(args); } void parse_cmd_no_args_returns_null(void **state) { char *inp = "/cmd"; gboolean result = TRUE; gchar **args = parse_args(inp, 1, 2, &result); assert_false(result); assert_null(args); g_strfreev(args); } void parse_cmd_with_space_returns_null(void **state) { char *inp = "/cmd "; gboolean result = TRUE; gchar **args = parse_args(inp, 1, 2, &result); assert_false(result); assert_null(args); g_strfreev(args); } void parse_cmd_with_too_few_returns_null(void **state) { char *inp = "/cmd arg1"; gboolean result = TRUE; gchar **args = parse_args(inp, 2, 3, &result); assert_false(result); assert_null(args); g_strfreev(args); } void parse_cmd_with_too_many_returns_null(void **state) { char *inp = "/cmd arg1 arg2 arg3 arg4"; gboolean result = TRUE; gchar **args = parse_args(inp, 1, 3, &result); assert_false(result); assert_null(args); g_strfreev(args); } void parse_cmd_one_arg(void **state) { char *inp = "/cmd arg1"; gboolean result = FALSE; gchar **args = parse_args(inp, 1, 2, &result); assert_true(result); assert_int_equal(1, g_strv_length(args)); assert_string_equal("arg1", args[0]); g_strfreev(args); } void parse_cmd_two_args(void **state) { char *inp = "/cmd arg1 arg2"; gboolean result = FALSE; gchar **args = parse_args(inp, 1, 2, &result); assert_true(result); assert_int_equal(2, g_strv_length(args)); assert_string_equal("arg1", args[0]); assert_string_equal("arg2", args[1]); g_strfreev(args); } void parse_cmd_three_args(void **state) { char *inp = "/cmd arg1 arg2 arg3"; gboolean result = FALSE; gchar **args = parse_args(inp, 3, 3, &result); assert_true(result); assert_int_equal(3, g_strv_length(args)); assert_string_equal("arg1", args[0]); assert_string_equal("arg2", args[1]); assert_string_equal("arg3", args[2]); g_strfreev(args); } void parse_cmd_three_args_with_spaces(void **state) { char *inp = " /cmd arg1 arg2 arg3 "; gboolean result = FALSE; gchar **args = parse_args(inp, 3, 3, &result); assert_true(result); assert_int_equal(3, g_strv_length(args)); assert_string_equal("arg1", args[0]); assert_string_equal("arg2", args[1]); assert_string_equal("arg3", args[2]); g_strfreev(args); } void parse_cmd_with_freetext(void **state) { char *inp = "/cmd this is some free text"; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 1, 1, &result); assert_true(result); assert_int_equal(1, g_strv_length(args)); assert_string_equal("this is some free text", args[0]); g_strfreev(args); } void parse_cmd_one_arg_with_freetext(void **state) { char *inp = "/cmd arg1 this is some free text"; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 1, 2, &result); assert_true(result); assert_int_equal(2, g_strv_length(args)); assert_string_equal("arg1", args[0]); assert_string_equal("this is some free text", args[1]); g_strfreev(args); } void parse_cmd_two_args_with_freetext(void **state) { char *inp = "/cmd arg1 arg2 this is some free text"; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 1, 3, &result); assert_true(result); assert_int_equal(3, g_strv_length(args)); assert_string_equal("arg1", args[0]); assert_string_equal("arg2", args[1]); assert_string_equal("this is some free text", args[2]); g_strfreev(args); } void parse_cmd_min_zero(void **state) { char *inp = "/cmd"; gboolean result = FALSE; gchar **args = parse_args(inp, 0, 2, &result); assert_true(result); assert_int_equal(0, g_strv_length(args)); assert_null(args[0]); g_strfreev(args); } void parse_cmd_min_zero_with_freetext(void **state) { char *inp = "/cmd"; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 0, 2, &result); assert_true(result); assert_int_equal(0, g_strv_length(args)); assert_null(args[0]); g_strfreev(args); } void parse_cmd_with_quoted(void **state) { char *inp = "/cmd \"arg1\" arg2"; gboolean result = FALSE; gchar **args = parse_args(inp, 2, 2, &result); assert_true(result); assert_int_equal(2, g_strv_length(args)); assert_string_equal("arg1", args[0]); assert_string_equal("arg2", args[1]); g_strfreev(args); } void parse_cmd_with_quoted_and_space(void **state) { char *inp = "/cmd \"the arg1\" arg2"; gboolean result = FALSE; gchar **args = parse_args(inp, 2, 2, &result); assert_true(result); assert_int_equal(2, g_strv_length(args)); assert_string_equal("the arg1", args[0]); assert_string_equal("arg2", args[1]); g_strfreev(args); } void parse_cmd_with_quoted_and_many_spaces(void **state) { char *inp = "/cmd \"the arg1 is here\" arg2"; gboolean result = FALSE; gchar **args = parse_args(inp, 2, 2, &result); assert_true(result); assert_int_equal(2, g_strv_length(args)); assert_string_equal("the arg1 is here", args[0]); assert_string_equal("arg2", args[1]); g_strfreev(args); } void parse_cmd_with_many_quoted_and_many_spaces(void **state) { char *inp = "/cmd \"the arg1 is here\" \"and arg2 is right here\""; gboolean result = FALSE; gchar **args = parse_args(inp, 2, 2, &result); assert_true(result); assert_int_equal(2, g_strv_length(args)); assert_string_equal("the arg1 is here", args[0]); assert_string_equal("and arg2 is right here", args[1]); g_strfreev(args); } void parse_cmd_freetext_with_quoted(void **state) { char *inp = "/cmd \"arg1\" arg2 hello there whats up"; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 3, 3, &result); assert_true(result); assert_int_equal(3, g_strv_length(args)); assert_string_equal("arg1", args[0]); assert_string_equal("arg2", args[1]); assert_string_equal("hello there whats up", args[2]); g_strfreev(args); } void parse_cmd_freetext_with_quoted_and_space(void **state) { char *inp = "/cmd \"the arg1\" arg2 another bit of freetext"; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 3, 3, &result); assert_true(result); assert_int_equal(3, g_strv_length(args)); assert_string_equal("the arg1", args[0]); assert_string_equal("arg2", args[1]); assert_string_equal("another bit of freetext", args[2]); g_strfreev(args); } void parse_cmd_freetext_with_quoted_and_many_spaces(void **state) { char *inp = "/cmd \"the arg1 is here\" arg2 some more freetext"; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 3, 3, &result); assert_true(result); assert_int_equal(3, g_strv_length(args)); assert_string_equal("the arg1 is here", args[0]); assert_string_equal("arg2", args[1]); assert_string_equal("some more freetext", args[2]); g_strfreev(args); } void parse_cmd_freetext_with_many_quoted_and_many_spaces(void **state) { char *inp = "/cmd \"the arg1 is here\" \"and arg2 is right here\" and heres the free text"; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 3, 3, &result); assert_true(result); assert_int_equal(3, g_strv_length(args)); assert_string_equal("the arg1 is here", args[0]); assert_string_equal("and arg2 is right here", args[1]); assert_string_equal("and heres the free text", args[2]); g_strfreev(args); } void parse_cmd_with_quoted_freetext(void **state) { char *inp = "/cmd arg1 here is \"some\" quoted freetext"; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 1, 2, &result); assert_true(result); assert_int_equal(2, g_strv_length(args)); assert_string_equal("arg1", args[0]); assert_string_equal("here is \"some\" quoted freetext", args[1]); g_strfreev(args); } void parse_cmd_with_third_arg_quoted_0_min_3_max(void **state) { char *inp = "/group add friends \"The User\""; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 0, 3, &result); assert_true(result); assert_int_equal(3, g_strv_length(args)); assert_string_equal("add", args[0]); assert_string_equal("friends", args[1]); assert_string_equal("The User", args[2]); } void parse_cmd_with_second_arg_quoted_0_min_3_max(void **state) { char *inp = "/group add \"The Group\" friend"; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 0, 3, &result); assert_true(result); assert_int_equal(3, g_strv_length(args)); assert_string_equal("add", args[0]); assert_string_equal("The Group", args[1]); assert_string_equal("friend", args[2]); } void parse_cmd_with_second_and_third_arg_quoted_0_min_3_max(void **state) { char *inp = "/group add \"The Group\" \"The User\""; gboolean result = FALSE; gchar **args = parse_args_with_freetext(inp, 0, 3, &result); assert_true(result); assert_int_equal(3, g_strv_length(args)); assert_string_equal("add", args[0]); assert_string_equal("The Group", args[1]); assert_string_equal("The User", args[2]); } void count_one_token(void **state) { char *inp = "one"; int result = count_tokens(inp); assert_int_equal(1, result); } void count_one_token_quoted_no_whitespace(void **state) { char *inp = "\"one\""; int result = count_tokens(inp); assert_int_equal(1, result); } void count_one_token_quoted_with_whitespace(void **state) { char *inp = "\"one two\""; int result = count_tokens(inp); assert_int_equal(1, result); } void count_two_tokens(void **state) { char *inp = "one two"; int result = count_tokens(inp); assert_int_equal(2, result); } void count_two_tokens_first_quoted(void **state) { char *inp = "\"one and\" two"; int result = count_tokens(inp); assert_int_equal(2, result); } void count_two_tokens_second_quoted(void **state) { char *inp = "one \"two and\""; int result = count_tokens(inp); assert_int_equal(2, result); } void count_two_tokens_both_quoted(void **state) { char *inp = "\"one and then\" \"two and\""; int result = count_tokens(inp); assert_int_equal(2, result); } void get_first_of_one(void **state) { char *inp = "one"; char *result = get_start(inp, 2); assert_string_equal("one", result); } void get_first_of_two(void **state) { char *inp = "one two"; char *result = get_start(inp, 2); assert_string_equal("one ", result); } void get_first_two_of_three(void **state) { char *inp = "one two three"; char *result = get_start(inp, 3); assert_string_equal("one two ", result); } void get_first_two_of_three_first_quoted(void **state) { char *inp = "\"one\" two three"; char *result = get_start(inp, 3); assert_string_equal("\"one\" two ", result); } void get_first_two_of_three_second_quoted(void **state) { char *inp = "one \"two\" three"; char *result = get_start(inp, 3); assert_string_equal("one \"two\" ", result); } void get_first_two_of_three_first_and_second_quoted(void **state) { char *inp = "\"one\" \"two\" three"; char *result = get_start(inp, 3); assert_string_equal("\"one\" \"two\" ", result); } void parse_options_when_none_returns_empty_hasmap(void **state) { gchar *args[] = { "cmd1", "cmd2", NULL }; gchar *keys[] = { "opt1", NULL }; gboolean res = FALSE; GHashTable *options = parse_options(&args[2], keys, &res); assert_true(options != NULL); assert_int_equal(0, g_hash_table_size(options)); assert_true(res); options_destroy(options); } void parse_options_when_opt1_no_val_sets_error(void **state) { gchar *args[] = { "cmd1", "cmd2", "opt1", NULL }; gchar *keys[] = { "opt1", NULL }; gboolean res = TRUE; GHashTable *options = parse_options(&args[2], keys, &res); assert_null(options); assert_false(res); options_destroy(options); } void parse_options_when_one_returns_map(void **state) { gchar *args[] = { "cmd1", "cmd2", "opt1", "val1", NULL }; gchar *keys[] = { "opt1", NULL }; gboolean res = FALSE; GHashTable *options = parse_options(&args[2], keys, &res); assert_int_equal(1, g_hash_table_size(options)); assert_true(g_hash_table_contains(options, "opt1")); assert_string_equal("val1", g_hash_table_lookup(options, "opt1")); assert_true(res); options_destroy(options); } void parse_options_when_opt2_no_val_sets_error(void **state) { gchar *args[] = { "cmd1", "cmd2", "opt1", "val1", "opt2", NULL }; gchar *keys[] = { "opt1", "opt2", NULL }; gboolean res = TRUE; GHashTable *options = parse_options(&args[2], keys, &res); assert_null(options); assert_false(res); options_destroy(options); } void parse_options_when_two_returns_map(void **state) { gchar *args[] = { "cmd1", "cmd2", "opt1", "val1", "opt2", "val2", NULL }; gchar *keys[] = { "opt1", "opt2", NULL }; gboolean res = FALSE; GHashTable *options = parse_options(&args[2], keys, &res); assert_int_equal(2, g_hash_table_size(options)); assert_true(g_hash_table_contains(options, "opt1")); assert_true(g_hash_table_contains(options, "opt2")); assert_string_equal("val1", g_hash_table_lookup(options, "opt1")); assert_string_equal("val2", g_hash_table_lookup(options, "opt2")); assert_true(res); options_destroy(options); } void parse_options_when_opt3_no_val_sets_error(void **state) { gchar *args[] = { "cmd1", "cmd2", "opt1", "val1", "opt2", "val2", "opt3", NULL }; gchar *keys[] = { "opt1", "opt2", "opt3", NULL }; gboolean res = TRUE; GHashTable *options = parse_options(&args[2], keys, &res); assert_null(options); assert_false(res); options_destroy(options); } void parse_options_when_three_returns_map(void **state) { gchar *args[] = { "cmd1", "cmd2", "opt1", "val1", "opt2", "val2", "opt3", "val3", NULL }; gchar *keys[] = { "opt1", "opt2", "opt3", NULL }; gboolean res = FALSE; GHashTable *options = parse_options(&args[2], keys, &res); assert_int_equal(3, g_hash_table_size(options)); assert_true(g_hash_table_contains(options, "opt1")); assert_true(g_hash_table_contains(options, "opt2")); assert_true(g_hash_table_contains(options, "opt3")); assert_string_equal("val1", g_hash_table_lookup(options, "opt1")); assert_string_equal("val2", g_hash_table_lookup(options, "opt2")); assert_string_equal("val3", g_hash_table_lookup(options, "opt3")); assert_true(res); options_destroy(options); } void parse_options_when_unknown_opt_sets_error(void **state) { gchar *args[] = { "cmd1", "cmd2", "opt1", "val1", "oops", "val2", "opt3", "val3", NULL }; gchar *keys[] = { "opt1", "opt2", "opt3", NULL }; gboolean res = TRUE; GHashTable *options = parse_options(&args[2], keys, &res); assert_null(options); assert_false(res); options_destroy(options); } void parse_options_with_duplicated_option_sets_error(void **state) { gchar *args[] = { "cmd1", "cmd2", "opt1", "val1", "opt2", "val2", "opt1", "val3", NULL }; gchar *keys[] = { "opt1", "opt2", "opt3", NULL }; gboolean res = TRUE; GHashTable *options = parse_options(&args[2], keys, &res); assert_null(options); assert_false(res); options_destroy(options); }profanity-0.4.7/tests/unittests/test_parser.h000066400000000000000000000051551257755232500214700ustar00rootroot00000000000000void parse_null_returns_null(void **state); void parse_empty_returns_null(void **state); void parse_space_returns_null(void **state); void parse_cmd_no_args_returns_null(void **state); void parse_cmd_with_space_returns_null(void **state); void parse_cmd_with_too_few_returns_null(void **state); void parse_cmd_with_too_many_returns_null(void **state); void parse_cmd_one_arg(void **state); void parse_cmd_two_args(void **state); void parse_cmd_three_args(void **state); void parse_cmd_three_args_with_spaces(void **state); void parse_cmd_with_freetext(void **state); void parse_cmd_one_arg_with_freetext(void **state); void parse_cmd_two_args_with_freetext(void **state); void parse_cmd_min_zero(void **state); void parse_cmd_min_zero_with_freetext(void **state); void parse_cmd_with_quoted(void **state); void parse_cmd_with_quoted_and_space(void **state); void parse_cmd_with_quoted_and_many_spaces(void **state); void parse_cmd_with_many_quoted_and_many_spaces(void **state); void parse_cmd_freetext_with_quoted(void **state); void parse_cmd_freetext_with_quoted_and_space(void **state); void parse_cmd_freetext_with_quoted_and_many_spaces(void **state); void parse_cmd_freetext_with_many_quoted_and_many_spaces(void **state); void parse_cmd_with_quoted_freetext(void **state); void parse_cmd_with_third_arg_quoted_0_min_3_max(void **state); void parse_cmd_with_second_arg_quoted_0_min_3_max(void **state); void parse_cmd_with_second_and_third_arg_quoted_0_min_3_max(void **state); void count_one_token(void **state); void count_one_token_quoted_no_whitespace(void **state); void count_one_token_quoted_with_whitespace(void **state); void count_two_tokens(void **state); void count_two_tokens_first_quoted(void **state); void count_two_tokens_second_quoted(void **state); void count_two_tokens_both_quoted(void **state); void get_first_of_one(void **state); void get_first_of_two(void **state); void get_first_two_of_three(void **state); void get_first_two_of_three_first_quoted(void **state); void get_first_two_of_three_second_quoted(void **state); void get_first_two_of_three_first_and_second_quoted(void **state); void parse_options_when_none_returns_empty_hasmap(void **state); void parse_options_when_opt1_no_val_sets_error(void **state); void parse_options_when_one_returns_map(void **state); void parse_options_when_opt2_no_val_sets_error(void **state); void parse_options_when_two_returns_map(void **state); void parse_options_when_opt3_no_val_sets_error(void **state); void parse_options_when_three_returns_map(void **state); void parse_options_when_unknown_opt_sets_error(void **state); void parse_options_with_duplicated_option_sets_error(void **state); profanity-0.4.7/tests/unittests/test_preferences.c000066400000000000000000000013271257755232500224650ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "config/preferences.h" void statuses_console_defaults_to_all(void **state) { char *setting = prefs_get_string(PREF_STATUSES_CONSOLE); assert_non_null(setting); assert_string_equal("all", setting); } void statuses_chat_defaults_to_all(void **state) { char *setting = prefs_get_string(PREF_STATUSES_CHAT); assert_non_null(setting); assert_string_equal("all", setting); } void statuses_muc_defaults_to_all(void **state) { char *setting = prefs_get_string(PREF_STATUSES_MUC); assert_non_null(setting); assert_string_equal("all", setting); } profanity-0.4.7/tests/unittests/test_preferences.h000066400000000000000000000002301257755232500224620ustar00rootroot00000000000000void statuses_console_defaults_to_all(void **state); void statuses_chat_defaults_to_all(void **state); void statuses_muc_defaults_to_all(void **state); profanity-0.4.7/tests/unittests/test_roster_list.c000066400000000000000000000176161257755232500225450ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "contact.h" #include "roster_list.h" void empty_list_when_none_added(void **state) { roster_init(); GSList *list = roster_get_contacts(); assert_null(list); roster_free(); } void contains_one_element(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); GSList *list = roster_get_contacts(); assert_int_equal(1, g_slist_length(list)); roster_free(); } void first_element_correct(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); GSList *list = roster_get_contacts(); PContact james = list->data; assert_string_equal("James", p_contact_barejid(james)); roster_free(); } void contains_two_elements(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); GSList *list = roster_get_contacts(); assert_int_equal(2, g_slist_length(list)); roster_free(); } void first_and_second_elements_correct(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); GSList *list = roster_get_contacts(); PContact first = list->data; PContact second = (g_slist_next(list))->data; assert_string_equal("Dave", p_contact_barejid(first)); assert_string_equal("James", p_contact_barejid(second)); roster_free(); } void contains_three_elements(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Bob", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); GSList *list = roster_get_contacts(); assert_int_equal(3, g_slist_length(list)); roster_free(); } void first_three_elements_correct(void **state) { roster_init(); roster_add("Bob", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); roster_add("James", NULL, NULL, NULL, FALSE); GSList *list = roster_get_contacts(); PContact bob = list->data; PContact dave = (g_slist_next(list))->data; PContact james = (g_slist_next(g_slist_next(list)))->data; assert_string_equal("James", p_contact_barejid(james)); assert_string_equal("Dave", p_contact_barejid(dave)); assert_string_equal("Bob", p_contact_barejid(bob)); roster_free(); } void add_twice_at_beginning_adds_once(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); roster_add("Bob", NULL, NULL, NULL, FALSE); GSList *list = roster_get_contacts(); PContact first = list->data; PContact second = (g_slist_next(list))->data; PContact third = (g_slist_next(g_slist_next(list)))->data; assert_int_equal(3, g_slist_length(list)); assert_string_equal("Bob", p_contact_barejid(first)); assert_string_equal("Dave", p_contact_barejid(second)); assert_string_equal("James", p_contact_barejid(third)); roster_free(); } void add_twice_in_middle_adds_once(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Bob", NULL, NULL, NULL, FALSE); GSList *list = roster_get_contacts(); PContact first = list->data; PContact second = (g_slist_next(list))->data; PContact third = (g_slist_next(g_slist_next(list)))->data; assert_int_equal(3, g_slist_length(list)); assert_string_equal("Bob", p_contact_barejid(first)); assert_string_equal("Dave", p_contact_barejid(second)); assert_string_equal("James", p_contact_barejid(third)); roster_free(); } void add_twice_at_end_adds_once(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); roster_add("Bob", NULL, NULL, NULL, FALSE); roster_add("James", NULL, NULL, NULL, FALSE); GSList *list = roster_get_contacts(); PContact first = list->data; PContact second = (g_slist_next(list))->data; PContact third = (g_slist_next(g_slist_next(list)))->data; assert_int_equal(3, g_slist_length(list)); assert_string_equal("Bob", p_contact_barejid(first)); assert_string_equal("Dave", p_contact_barejid(second)); assert_string_equal("James", p_contact_barejid(third)); roster_free(); } void find_first_exists(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); roster_add("Bob", NULL, NULL, NULL, FALSE); char *search = strdup("B"); char *result = roster_contact_autocomplete(search); assert_string_equal("Bob", result); free(result); free(search); roster_free(); } void find_second_exists(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); roster_add("Bob", NULL, NULL, NULL, FALSE); char *result = roster_contact_autocomplete("Dav"); assert_string_equal("Dave", result); free(result); roster_free(); } void find_third_exists(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); roster_add("Bob", NULL, NULL, NULL, FALSE); char *result = roster_contact_autocomplete("Ja"); assert_string_equal("James", result); free(result); roster_free(); } void find_returns_null(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); roster_add("Bob", NULL, NULL, NULL, FALSE); char *result = roster_contact_autocomplete("Mike"); assert_null(result); roster_free(); } void find_on_empty_returns_null(void **state) { roster_init(); char *result = roster_contact_autocomplete("James"); assert_null(result); roster_free(); } void find_twice_returns_second_when_two_match(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Jamie", NULL, NULL, NULL, FALSE); roster_add("Bob", NULL, NULL, NULL, FALSE); char *result1 = roster_contact_autocomplete("Jam"); char *result2 = roster_contact_autocomplete(result1); assert_string_equal("Jamie", result2); free(result1); free(result2); roster_free(); } void find_five_times_finds_fifth(void **state) { roster_init(); roster_add("Jama", NULL, NULL, NULL, FALSE); roster_add("Jamb", NULL, NULL, NULL, FALSE); roster_add("Mike", NULL, NULL, NULL, FALSE); roster_add("Dave", NULL, NULL, NULL, FALSE); roster_add("Jamm", NULL, NULL, NULL, FALSE); roster_add("Jamn", NULL, NULL, NULL, FALSE); roster_add("Matt", NULL, NULL, NULL, FALSE); roster_add("Jamo", NULL, NULL, NULL, FALSE); roster_add("Jamy", NULL, NULL, NULL, FALSE); roster_add("Jamz", NULL, NULL, NULL, FALSE); char *result1 = roster_contact_autocomplete("Jam"); char *result2 = roster_contact_autocomplete(result1); char *result3 = roster_contact_autocomplete(result2); char *result4 = roster_contact_autocomplete(result3); char *result5 = roster_contact_autocomplete(result4); assert_string_equal("Jamo", result5); free(result1); free(result2); free(result3); free(result4); free(result5); roster_free(); } void find_twice_returns_first_when_two_match_and_reset(void **state) { roster_init(); roster_add("James", NULL, NULL, NULL, FALSE); roster_add("Jamie", NULL, NULL, NULL, FALSE); roster_add("Bob", NULL, NULL, NULL, FALSE); char *result1 = roster_contact_autocomplete("Jam"); roster_reset_search_attempts(); char *result2 = roster_contact_autocomplete(result1); assert_string_equal("James", result2); free(result1); free(result2); roster_free(); } profanity-0.4.7/tests/unittests/test_roster_list.h000066400000000000000000000015201257755232500225350ustar00rootroot00000000000000void empty_list_when_none_added(void **state); void contains_one_element(void **state); void first_element_correct(void **state); void contains_two_elements(void **state); void first_and_second_elements_correct(void **state); void contains_three_elements(void **state); void first_three_elements_correct(void **state); void add_twice_at_beginning_adds_once(void **state); void add_twice_in_middle_adds_once(void **state); void add_twice_at_end_adds_once(void **state); void find_first_exists(void **state); void find_second_exists(void **state); void find_third_exists(void **state); void find_returns_null(void **state); void find_on_empty_returns_null(void **state); void find_twice_returns_second_when_two_match(void **state); void find_five_times_finds_fifth(void **state); void find_twice_returns_first_when_two_match_and_reset(void **state); profanity-0.4.7/tests/unittests/test_server_events.c000066400000000000000000000061521257755232500230570ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "event/server_events.h" #include "roster_list.h" #include "chat_session.h" #include "config/preferences.h" #include "ui/ui.h" #include "ui/stub_ui.h" #include "muc.h" void console_shows_online_presence_when_set_online(void **state) { prefs_set_string(PREF_STATUSES_CONSOLE, "online"); roster_init(); char *barejid = "test1@server"; roster_add(barejid, "bob", NULL, "both", FALSE); Resource *resource = resource_new("resource", RESOURCE_ONLINE, NULL, 10); expect_memory(ui_contact_online, barejid, barejid, sizeof(barejid)); expect_memory(ui_contact_online, resource, resource, sizeof(resource)); expect_value(ui_contact_online, last_activity, NULL); sv_ev_contact_online(barejid, resource, NULL, NULL); roster_clear(); } void console_shows_online_presence_when_set_all(void **state) { prefs_set_string(PREF_STATUSES_CONSOLE, "all"); roster_init(); char *barejid = "test1@server"; roster_add(barejid, "bob", NULL, "both", FALSE); Resource *resource = resource_new("resource", RESOURCE_ONLINE, NULL, 10); expect_memory(ui_contact_online, barejid, barejid, sizeof(barejid)); expect_memory(ui_contact_online, resource, resource, sizeof(resource)); expect_value(ui_contact_online, last_activity, NULL); sv_ev_contact_online(barejid, resource, NULL, NULL); roster_clear(); } void console_shows_dnd_presence_when_set_all(void **state) { prefs_set_string(PREF_STATUSES_CONSOLE, "all"); roster_init(); char *barejid = "test1@server"; roster_add(barejid, "bob", NULL, "both", FALSE); Resource *resource = resource_new("resource", RESOURCE_ONLINE, NULL, 10); expect_memory(ui_contact_online, barejid, barejid, sizeof(barejid)); expect_memory(ui_contact_online, resource, resource, sizeof(resource)); expect_value(ui_contact_online, last_activity, NULL); sv_ev_contact_online(barejid, resource, NULL, NULL); roster_clear(); } void handle_offline_removes_chat_session(void **state) { chat_sessions_init(); char *barejid = "friend@server.chat.com"; char *resource = "home"; roster_init(); roster_add(barejid, "bob", NULL, "both", FALSE); Resource *resourcep = resource_new(resource, RESOURCE_ONLINE, NULL, 10); roster_update_presence(barejid, resourcep, NULL); chat_session_recipient_active(barejid, resource, FALSE); sv_ev_contact_offline(barejid, resource, NULL); ChatSession *session = chat_session_get(barejid); assert_null(session); roster_clear(); chat_sessions_clear(); } void lost_connection_clears_chat_sessions(void **state) { chat_sessions_init(); chat_session_recipient_active("bob@server.org", "laptop", FALSE); chat_session_recipient_active("steve@server.org", "mobile", FALSE); expect_any_cons_show_error(); sv_ev_lost_connection(); ChatSession *session1 = chat_session_get("bob@server.org"); ChatSession *session2 = chat_session_get("steve@server.org"); assert_null(session1); assert_null(session2); } profanity-0.4.7/tests/unittests/test_server_events.h000066400000000000000000000016111257755232500230570ustar00rootroot00000000000000void console_doesnt_show_online_presence_when_set_none(void **state); void console_shows_online_presence_when_set_online(void **state); void console_shows_online_presence_when_set_all(void **state); void console_doesnt_show_dnd_presence_when_set_none(void **state); void console_doesnt_show_dnd_presence_when_set_online(void **state); void console_shows_dnd_presence_when_set_all(void **state); void handle_message_error_when_no_recipient(void **state); void handle_message_error_when_recipient_cancel(void **state); void handle_message_error_when_recipient_cancel_disables_chat_session(void **state); void handle_message_error_when_recipient_and_no_type(void **state); void handle_presence_error_when_no_recipient(void **state); void handle_presence_error_when_from_recipient(void **state); void handle_offline_removes_chat_session(void **state); void lost_connection_clears_chat_sessions(void **state); profanity-0.4.7/tests/unittests/ui/000077500000000000000000000000001257755232500173735ustar00rootroot00000000000000profanity-0.4.7/tests/unittests/ui/stub_ui.c000066400000000000000000000453621257755232500212230ustar00rootroot00000000000000#include #include #include #include #include "ui/window.h" #include "ui/ui.h" #include "tests/unittests/ui/stub_ui.h" // mock state static char output[256]; void expect_cons_show(char *expected) { expect_string(cons_show, output, expected); } void expect_any_cons_show(void) { expect_any(cons_show, output); } void expect_cons_show_error(char *expected) { expect_string(cons_show_error, output, expected); } void expect_any_cons_show_error(void) { expect_any(cons_show_error, output); } void expect_ui_current_print_line(char *message) { expect_string(ui_current_print_line, output, message); } void expect_ui_current_print_formatted_line(char show_char, int attrs, char *message) { expect_value(ui_current_print_formatted_line, show_char, show_char); expect_value(ui_current_print_formatted_line, attrs, attrs); expect_string(ui_current_print_formatted_line, output, message); } // stubs void ui_init(void) {} void ui_load_colours(void) {} void ui_update(void) {} void ui_close(void) {} void ui_redraw(void) {} void ui_resize(void) {} GSList* ui_get_chat_recipients(void) { return NULL; } void ui_switch_win(ProfWin *win) {} void ui_gone_secure(const char * const barejid, gboolean trusted) {} void ui_gone_insecure(const char * const barejid) {} void ui_trust(const char * const barejid) {} void ui_untrust(const char * const barejid) {} void ui_smp_recipient_initiated(const char * const barejid) {} void ui_smp_recipient_initiated_q(const char * const barejid, const char *question) {} void ui_smp_successful(const char * const barejid) {} void ui_smp_unsuccessful_sender(const char * const barejid) {} void ui_smp_unsuccessful_receiver(const char * const barejid) {} void ui_smp_aborted(const char * const barejid) {} void ui_smp_answer_success(const char * const barejid) {} void ui_smp_answer_failure(const char * const barejid) {} void ui_otr_authenticating(const char * const barejid) {} void ui_otr_authetication_waiting(const char * const recipient) {} void ui_sigwinch_handler(int sig) {} unsigned long ui_get_idle_time(void) { return 0; } void ui_reset_idle_time(void) {} ProfPrivateWin* ui_new_private_win(const char * const fulljid) { return NULL; } ProfChatWin* ui_new_chat_win(const char * const barejid) { return NULL; } void ui_print_system_msg_from_recipient(const char * const barejid, const char *message) {} gint ui_unread(void) { return 0; } void ui_close_connected_win(int index) {} int ui_close_all_wins(void) { return 0; } int ui_close_read_wins(void) { return 0; } // current window actions void ui_clear_current(void) {} void ui_current_print_line(const char * const msg, ...) { va_list args; va_start(args, msg); vsnprintf(output, sizeof(output), msg, args); check_expected(output); va_end(args); } void ui_current_print_formatted_line(const char show_char, int attrs, const char * const msg, ...) { check_expected(show_char); check_expected(attrs); va_list args; va_start(args, msg); vsnprintf(output, sizeof(output), msg, args); check_expected(output); va_end(args); } void ui_current_error_line(const char * const msg) {} void ui_win_error_line(ProfWin *window, const char * const msg) {} win_type_t ui_win_type(int index) { return WIN_CONSOLE; } void ui_close_win(int index) {} int ui_win_unread(int index) { return 0; } void ui_page_up(void) {} void ui_page_down(void) {} void ui_subwin_page_up(void) {} void ui_subwin_page_down(void) {} void ui_clear_win(ProfWin *window) {} char * ui_ask_password(void) { return mock_ptr_type(char *); } void ui_handle_stanza(const char * const msg) {} // ui events void ui_contact_online(char *barejid, Resource *resource, GDateTime *last_activity) { check_expected(barejid); check_expected(resource); check_expected(last_activity); } void ui_contact_typing(const char * const barejid, const char * const resource) {} void ui_incoming_msg(ProfChatWin *chatwin, const char * const resource, const char * const message, GDateTime *timestamp, gboolean win_created, prof_enc_t enc_mode) {} void ui_message_receipt(const char * const barejid, const char * const id) {} void ui_incoming_private_msg(const char * const fulljid, const char * const message, GDateTime *timestamp) {} void ui_disconnected(void) {} void ui_recipient_gone(const char * const barejid, const char * const resource) {} void ui_outgoing_chat_msg(ProfChatWin *chatwin, const char * const message, char *id, prof_enc_t enc_mode) {} void ui_outgoing_chat_msg_carbon(const char * const barejid, const char * const message) {} void ui_outgoing_private_msg(ProfPrivateWin *privwin, const char * const message) {} void ui_room_join(const char * const roomjid, gboolean focus) {} void ui_switch_to_room(const char * const roomjid) {} void ui_room_role_change(const char * const roomjid, const char * const role, const char * const actor, const char * const reason) {} void ui_room_affiliation_change(const char * const roomjid, const char * const affiliation, const char * const actor, const char * const reason) {} void ui_room_role_and_affiliation_change(const char * const roomjid, const char * const role, const char * const affiliation, const char * const actor, const char * const reason) {} void ui_room_occupant_role_change(const char * const roomjid, const char * const nick, const char * const role, const char * const actor, const char * const reason) {} void ui_room_occupant_affiliation_change(const char * const roomjid, const char * const nick, const char * const affiliation, const char * const actor, const char * const reason) {} void ui_room_occupant_role_and_affiliation_change(const char * const roomjid, const char * const nick, const char * const role, const char * const affiliation, const char * const actor, const char * const reason) {} void ui_room_roster(const char * const roomjid, GList *occupants, const char * const presence) {} void ui_room_history(const char * const roomjid, const char * const nick, GDateTime *timestamp, const char * const message) {} void ui_room_message(const char * const roomjid, const char * const nick, const char * const message) {} void ui_room_subject(const char * const roomjid, const char * const nick, const char * const subject) {} void ui_room_requires_config(const char * const roomjid) {} void ui_room_destroy(const char * const roomjid) {} void ui_show_room_info(ProfMucWin *mucwin) {} void ui_show_room_role_list(ProfMucWin *mucwin, muc_role_t role) {} void ui_show_room_affiliation_list(ProfMucWin *mucwin, muc_affiliation_t affiliation) {} void ui_handle_room_info_error(const char * const roomjid, const char * const error) {} void ui_show_room_disco_info(const char * const roomjid, GSList *identities, GSList *features) {} void ui_room_destroyed(const char * const roomjid, const char * const reason, const char * const new_jid, const char * const password) {} void ui_room_kicked(const char * const roomjid, const char * const actor, const char * const reason) {} void ui_room_member_kicked(const char * const roomjid, const char * const nick, const char * const actor, const char * const reason) {} void ui_room_banned(const char * const roomjid, const char * const actor, const char * const reason) {} void ui_room_member_banned(const char * const roomjid, const char * const nick, const char * const actor, const char * const reason) {} void ui_leave_room(const char * const roomjid) {} void ui_room_broadcast(const char * const roomjid, const char * const message) {} void ui_room_member_offline(const char * const roomjid, const char * const nick) {} void ui_room_member_online(const char * const roomjid, const char * const nick, const char * const roles, const char * const affiliation, const char * const show, const char * const status) {} void ui_room_member_nick_change(const char * const roomjid, const char * const old_nick, const char * const nick) {} void ui_room_nick_change(const char * const roomjid, const char * const nick) {} void ui_room_member_presence(const char * const roomjid, const char * const nick, const char * const show, const char * const status) {} void ui_room_update_occupants(const char * const roomjid) {} void ui_room_show_occupants(const char * const roomjid) {} void ui_room_hide_occupants(const char * const roomjid) {} void ui_show_roster(void) {} void ui_hide_roster(void) {} void ui_roster_add(const char * const barejid, const char * const name) {} void ui_roster_remove(const char * const barejid) {} void ui_contact_already_in_group(const char * const contact, const char * const group) {} void ui_contact_not_in_group(const char * const contact, const char * const group) {} void ui_group_added(const char * const contact, const char * const group) {} void ui_group_removed(const char * const contact, const char * const group) {} void ui_chat_win_contact_online(PContact contact, Resource *resource, GDateTime *last_activity) {} void ui_chat_win_contact_offline(PContact contact, char *resource, char *status) {} gboolean ui_chat_win_exists(const char * const barejid) { return TRUE; } void ui_contact_offline(char *barejid, char *resource, char *status) {} void ui_handle_recipient_not_found(const char * const recipient, const char * const err_msg) { check_expected(recipient); check_expected(err_msg); } void ui_handle_recipient_error(const char * const recipient, const char * const err_msg) { check_expected(recipient); check_expected(err_msg); } void ui_handle_error(const char * const err_msg) { check_expected(err_msg); } void ui_clear_win_title(void) {} void ui_goodbye_title(void) {} void ui_handle_room_join_error(const char * const roomjid, const char * const err) {} void ui_handle_room_configuration(const char * const roomjid, DataForm *form) {} void ui_handle_room_configuration_form_error(const char * const roomjid, const char * const message) {} void ui_handle_room_config_submit_result(const char * const roomjid) {} void ui_handle_room_config_submit_result_error(const char * const roomjid, const char * const message) {} void ui_handle_room_affiliation_list_error(const char * const roomjid, const char * const affiliation, const char * const error) {} void ui_handle_room_affiliation_list(const char * const roomjid, const char * const affiliation, GSList *jids) {} void ui_handle_room_affiliation_set_error(const char * const roomjid, const char * const jid, const char * const affiliation, const char * const error) {} void ui_handle_room_role_set_error(const char * const roomjid, const char * const nick, const char * const role, const char * const error) {} void ui_handle_room_role_list_error(const char * const roomjid, const char * const role, const char * const error) {} void ui_handle_room_role_list(const char * const roomjid, const char * const role, GSList *nicks) {} void ui_handle_room_kick_error(const char * const roomjid, const char * const nick, const char * const error) {} void ui_show_form(ProfMucConfWin *confwin) {} void ui_show_form_field(ProfWin *window, DataForm *form, char *tag) {} void ui_show_form_help(ProfMucConfWin *confwin) {} void ui_show_form_field_help(ProfMucConfWin *confwin, char *tag) {} void ui_show_lines(ProfWin *window, const gchar** lines) {} void ui_redraw_all_room_rosters(void) {} void ui_show_all_room_rosters(void) {} void ui_hide_all_room_rosters(void) {} gboolean ui_tidy_wins(void) { return TRUE; } void ui_prune_wins(void) {} gboolean ui_swap_wins(int source_win, int target_win) { return FALSE; } void ui_auto_away(void) {} void ui_end_auto_away(void) {} void ui_titlebar_presence(contact_presence_t presence) {} void ui_handle_login_account_success(ProfAccount *account) {} void ui_update_presence(const resource_presence_t resource_presence, const char * const message, const char * const show) {} void ui_about(void) {} void ui_statusbar_new(const int win) {} char* ui_readline(void) { return NULL; } void ui_inp_history_append(char *inp) {} void ui_input_clear(void) {} void ui_input_nonblocking(gboolean reset) {} void ui_invalid_command_usage(const char * const usage, void (*setting_func)(void)) {} void ui_create_xmlconsole_win(void) {} gboolean ui_xmlconsole_exists(void) { return FALSE; } void ui_open_xmlconsole_win(void) {} gboolean ui_win_has_unsaved_form(int num) { return FALSE; } void ui_write(char *line, int offset) {} // console window actions void cons_show(const char * const msg, ...) { va_list args; va_start(args, msg); vsnprintf(output, sizeof(output), msg, args); check_expected(output); va_end(args); } void cons_show_padded(int pad, const char * const msg, ...) {} void cons_show_help(Command *command) {} void cons_about(void) {} void cons_help(void) {} void cons_navigation_help(void) {} void cons_prefs(void) {} void cons_show_ui_prefs(void) {} void cons_show_desktop_prefs(void) {} void cons_show_chat_prefs(void) {} void cons_show_log_prefs(void) {} void cons_show_presence_prefs(void) {} void cons_show_connection_prefs(void) {} void cons_show_otr_prefs(void) {} void cons_show_pgp_prefs(void) {} void cons_show_account(ProfAccount *account) { check_expected(account); } void cons_debug(const char * const msg, ...) {} void cons_show_time(void) {} void cons_show_word(const char * const word) {} void cons_show_error(const char * const cmd, ...) { va_list args; va_start(args, cmd); vsnprintf(output, sizeof(output), cmd, args); check_expected(output); va_end(args); } void cons_show_contacts(GSList * list) {} void cons_show_roster(GSList * list) { check_expected(list); } void cons_bad_cmd_usage(const char * const cmd) { check_expected(cmd); } void cons_show_roster_group(const char * const group, GSList * list) {} void cons_show_wins(void) {} void cons_show_status(const char * const barejid) {} void cons_show_info(PContact pcontact) {} void cons_show_caps(const char * const fulljid, resource_presence_t presence) {} void cons_show_themes(GSList *themes) {} void cons_show_aliases(GList *aliases) { check_expected(aliases); } void cons_show_login_success(ProfAccount *account) {} void cons_show_software_version(const char * const jid, const char * const presence, const char * const name, const char * const version, const char * const os) {} void cons_show_account_list(gchar **accounts) { check_expected(accounts); } void cons_show_room_list(GSList *room, const char * const conference_node) {} void cons_show_bookmarks(const GList *list) { check_expected(list); } void cons_show_disco_items(GSList *items, const char * const jid) {} void cons_show_disco_info(const char *from, GSList *identities, GSList *features) {} void cons_show_room_invite(const char * const invitor, const char * const room, const char * const reason) {} void cons_check_version(gboolean not_available_msg) {} void cons_show_typing(const char * const barejid) {} void cons_show_incoming_message(const char * const short_from, const int win_index) {} void cons_show_room_invites(GSList *invites) {} void cons_show_received_subs(void) {} void cons_show_sent_subs(void) {} void cons_alert(void) {} void cons_theme_setting(void) {} void cons_privileges_setting(void) {} void cons_beep_setting(void) {} void cons_flash_setting(void) {} void cons_splash_setting(void) {} void cons_vercheck_setting(void) {} void cons_resource_setting(void) {} void cons_occupants_setting(void) {} void cons_roster_setting(void) {} void cons_presence_setting(void) {} void cons_wrap_setting(void) {} void cons_winstidy_setting(void) {} void cons_encwarn_setting(void) {} void cons_time_setting(void) {} void cons_mouse_setting(void) {} void cons_statuses_setting(void) {} void cons_titlebar_setting(void) {} void cons_notify_setting(void) {} void cons_states_setting(void) {} void cons_outtype_setting(void) {} void cons_intype_setting(void) {} void cons_gone_setting(void) {} void cons_history_setting(void) {} void cons_carbons_setting(void) {} void cons_receipts_setting(void) {} void cons_log_setting(void) {} void cons_chlog_setting(void) {} void cons_grlog_setting(void) {} void cons_autoaway_setting(void) {} void cons_reconnect_setting(void) {} void cons_autoping_setting(void) {} void cons_priority_setting(void) {} void cons_autoconnect_setting(void) {} void cons_inpblock_setting(void) {} void cons_show_contact_online(PContact contact, Resource *resource, GDateTime *last_activity) { check_expected(contact); check_expected(resource); check_expected(last_activity); } void cons_show_contact_offline(PContact contact, char *resource, char *status) {} void cons_theme_colours(void) {} // status bar void status_bar_inactive(const int win) {} void status_bar_active(const int win) {} void status_bar_new(const int win) {} void status_bar_set_all_inactive(void) {} // roster window void rosterwin_roster(void) {} // occupants window void occupantswin_occupants(const char * const room) {} // window interface ProfWin* win_create_console(void) { return NULL; } ProfWin* win_create_xmlconsole(void) { return NULL; } ProfWin* win_create_chat(const char * const barejid) { return (ProfWin*)mock(); } ProfWin* win_create_muc(const char * const roomjid) { return NULL; } ProfWin* win_create_muc_config(const char * const title, DataForm *form) { return NULL; } ProfWin* win_create_private(const char * const fulljid) { return NULL; } void win_update_virtual(ProfWin *window) {} void win_free(ProfWin *window) {} int win_unread(ProfWin *window) { return 0; } void win_resize(ProfWin *window) {} void win_hide_subwin(ProfWin *window) {} void win_show_subwin(ProfWin *window) {} void win_refresh_without_subwin(ProfWin *window) {} void win_refresh_with_subwin(ProfWin *window) {} void win_print(ProfWin *window, const char show_char, int pad_indent, GDateTime *timestamp, int flags, theme_item_t theme_item, const char * const from, const char * const message) {} void win_vprint(ProfWin *window, const char show_char, int pad_indent, GDateTime *timestamp, int flags, theme_item_t theme_item, const char * const from, const char * const message, ...) {} char* win_get_title(ProfWin *window) { return NULL; } void win_show_occupant(ProfWin *window, Occupant *occupant) {} void win_show_occupant_info(ProfWin *window, const char * const room, Occupant *occupant) {} void win_show_contact(ProfWin *window, PContact contact) {} void win_show_info(ProfWin *window, PContact contact) {} void win_println(ProfWin *window, int pad, const char * const message) {} // desktop notifier actions void notifier_uninit(void) {} void notify_typing(const char * const handle) {} void notify_message(ProfWin *window, const char * const name, const char * const text) {} void notify_room_message(const char * const handle, const char * const room, int win, const char * const text) {} void notify_remind(void) {} void notify_invite(const char * const from, const char * const room, const char * const reason) {} void notify_subscription(const char * const from) {} profanity-0.4.7/tests/unittests/ui/stub_ui.h000066400000000000000000000004441257755232500212200ustar00rootroot00000000000000void expect_cons_show(char *expected); void expect_any_cons_show(void); void expect_cons_show_error(char *expected); void expect_any_cons_show_error(void); void expect_ui_current_print_line(char *message); void expect_ui_current_print_formatted_line(char show_char, int attrs, char *message);profanity-0.4.7/tests/unittests/unittests.c000066400000000000000000000726601257755232500211770ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "config.h" #include "chat_session.h" #include "helpers.h" #include "test_autocomplete.h" #include "test_chat_session.h" #include "test_common.h" #include "test_contact.h" #include "test_cmd_connect.h" #include "test_cmd_account.h" #include "test_cmd_rooms.h" #include "test_cmd_sub.h" #include "test_cmd_statuses.h" #include "test_cmd_otr.h" #include "test_cmd_pgp.h" #include "test_jid.h" #include "test_parser.h" #include "test_roster_list.h" #include "test_preferences.h" #include "test_server_events.h" #include "test_cmd_alias.h" #include "test_cmd_bookmark.h" #include "test_cmd_join.h" #include "test_muc.h" #include "test_cmd_roster.h" #include "test_cmd_disconnect.h" #include "test_form.h" int main(int argc, char* argv[]) { const UnitTest all_tests[] = { unit_test(replace_one_substr), unit_test(replace_one_substr_beginning), unit_test(replace_one_substr_end), unit_test(replace_two_substr), unit_test(replace_char), unit_test(replace_when_none), unit_test(replace_when_match), unit_test(replace_when_string_empty), unit_test(replace_when_string_null), unit_test(replace_when_sub_empty), unit_test(replace_when_sub_null), unit_test(replace_when_new_empty), unit_test(replace_when_new_null), unit_test(compare_win_nums_less), unit_test(compare_win_nums_equal), unit_test(compare_win_nums_greater), unit_test(compare_0s_equal), unit_test(compare_0_greater_than_1), unit_test(compare_1_less_than_0), unit_test(compare_0_less_than_11), unit_test(compare_11_greater_than_0), unit_test(compare_0_greater_than_9), unit_test(compare_9_less_than_0), unit_test(next_available_when_only_console), unit_test(next_available_3_at_end), unit_test(next_available_9_at_end), unit_test(next_available_0_at_end), unit_test(next_available_2_in_first_gap), unit_test(next_available_9_in_first_gap), unit_test(next_available_0_in_first_gap), unit_test(next_available_11_in_first_gap), unit_test(next_available_24_first_big_gap), unit_test(test_online_is_valid_resource_presence_string), unit_test(test_chat_is_valid_resource_presence_string), unit_test(test_away_is_valid_resource_presence_string), unit_test(test_xa_is_valid_resource_presence_string), unit_test(test_dnd_is_valid_resource_presence_string), unit_test(test_available_is_not_valid_resource_presence_string), unit_test(test_unavailable_is_not_valid_resource_presence_string), unit_test(test_blah_is_not_valid_resource_presence_string), unit_test(test_p_sha1_hash1), unit_test(test_p_sha1_hash2), unit_test(test_p_sha1_hash3), unit_test(test_p_sha1_hash4), unit_test(test_p_sha1_hash5), unit_test(test_p_sha1_hash6), unit_test(test_p_sha1_hash7), unit_test(utf8_display_len_null_str), unit_test(utf8_display_len_1_non_wide), unit_test(utf8_display_len_1_wide), unit_test(utf8_display_len_non_wide), unit_test(utf8_display_len_wide), unit_test(utf8_display_len_all_wide), unit_test(strip_quotes_does_nothing_when_no_quoted), unit_test(strip_quotes_strips_first), unit_test(strip_quotes_strips_last), unit_test(strip_quotes_strips_both), unit_test(str_not_contains_str), unit_test(str_contains_str_at_start), unit_test(str_contains_str_at_end), unit_test(str_contains_str_in_middle), unit_test(str_contains_str_whole), unit_test(str_empty_not_contains_str), unit_test(str_not_contains_str_empty), unit_test(str_empty_not_contains_str_empty), unit_test(clear_empty), unit_test(reset_after_create), unit_test(find_after_create), unit_test(get_after_create_returns_null), unit_test(add_one_and_complete), unit_test(add_two_and_complete_returns_first), unit_test(add_two_and_complete_returns_second), unit_test(add_two_adds_two), unit_test(add_two_same_adds_one), unit_test(add_two_same_updates), unit_test(create_jid_from_null_returns_null), unit_test(create_jid_from_empty_string_returns_null), unit_test(create_jid_from_full_returns_full), unit_test(create_jid_from_full_returns_bare), unit_test(create_jid_from_full_returns_resourcepart), unit_test(create_jid_from_full_returns_localpart), unit_test(create_jid_from_full_returns_domainpart), unit_test(create_jid_from_full_nolocal_returns_full), unit_test(create_jid_from_full_nolocal_returns_bare), unit_test(create_jid_from_full_nolocal_returns_resourcepart), unit_test(create_jid_from_full_nolocal_returns_domainpart), unit_test(create_jid_from_full_nolocal_returns_null_localpart), unit_test(create_jid_from_bare_returns_null_full), unit_test(create_jid_from_bare_returns_null_resource), unit_test(create_jid_from_bare_returns_bare), unit_test(create_jid_from_bare_returns_localpart), unit_test(create_jid_from_bare_returns_domainpart), unit_test(create_room_jid_returns_room), unit_test(create_room_jid_returns_nick), unit_test(create_with_slash_in_resource), unit_test(create_with_at_in_resource), unit_test(create_with_at_and_slash_in_resource), unit_test(create_full_with_trailing_slash), unit_test(returns_fulljid_when_exists), unit_test(returns_barejid_when_fulljid_not_exists), unit_test(parse_null_returns_null), unit_test(parse_empty_returns_null), unit_test(parse_space_returns_null), unit_test(parse_cmd_no_args_returns_null), unit_test(parse_cmd_with_space_returns_null), unit_test(parse_cmd_with_too_few_returns_null), unit_test(parse_cmd_with_too_many_returns_null), unit_test(parse_cmd_one_arg), unit_test(parse_cmd_two_args), unit_test(parse_cmd_three_args), unit_test(parse_cmd_three_args_with_spaces), unit_test(parse_cmd_with_freetext), unit_test(parse_cmd_one_arg_with_freetext), unit_test(parse_cmd_two_args_with_freetext), unit_test(parse_cmd_min_zero), unit_test(parse_cmd_min_zero_with_freetext), unit_test(parse_cmd_with_quoted), unit_test(parse_cmd_with_quoted_and_space), unit_test(parse_cmd_with_quoted_and_many_spaces), unit_test(parse_cmd_with_many_quoted_and_many_spaces), unit_test(parse_cmd_freetext_with_quoted), unit_test(parse_cmd_freetext_with_quoted_and_space), unit_test(parse_cmd_freetext_with_quoted_and_many_spaces), unit_test(parse_cmd_freetext_with_many_quoted_and_many_spaces), unit_test(parse_cmd_with_quoted_freetext), unit_test(parse_cmd_with_third_arg_quoted_0_min_3_max), unit_test(parse_cmd_with_second_arg_quoted_0_min_3_max), unit_test(parse_cmd_with_second_and_third_arg_quoted_0_min_3_max), unit_test(count_one_token), unit_test(count_one_token_quoted_no_whitespace), unit_test(count_one_token_quoted_with_whitespace), unit_test(count_two_tokens), unit_test(count_two_tokens_first_quoted), unit_test(count_two_tokens_second_quoted), unit_test(count_two_tokens_both_quoted), unit_test(get_first_of_one), unit_test(get_first_of_two), unit_test(get_first_two_of_three), unit_test(get_first_two_of_three_first_quoted), unit_test(get_first_two_of_three_second_quoted), unit_test(get_first_two_of_three_first_and_second_quoted), unit_test(parse_options_when_none_returns_empty_hasmap), unit_test(parse_options_when_opt1_no_val_sets_error), unit_test(parse_options_when_one_returns_map), unit_test(parse_options_when_opt2_no_val_sets_error), unit_test(parse_options_when_two_returns_map), unit_test(parse_options_when_opt3_no_val_sets_error), unit_test(parse_options_when_three_returns_map), unit_test(parse_options_when_unknown_opt_sets_error), unit_test(parse_options_with_duplicated_option_sets_error), unit_test(empty_list_when_none_added), unit_test(contains_one_element), unit_test(first_element_correct), unit_test(contains_two_elements), unit_test(first_and_second_elements_correct), unit_test(contains_three_elements), unit_test(first_three_elements_correct), unit_test(add_twice_at_beginning_adds_once), unit_test(add_twice_in_middle_adds_once), unit_test(add_twice_at_end_adds_once), unit_test(find_first_exists), unit_test(find_second_exists), unit_test(find_third_exists), unit_test(find_returns_null), unit_test(find_on_empty_returns_null), unit_test(find_twice_returns_second_when_two_match), unit_test(find_five_times_finds_fifth), unit_test(find_twice_returns_first_when_two_match_and_reset), unit_test_setup_teardown(returns_false_when_chat_session_does_not_exist, init_chat_sessions, close_chat_sessions), unit_test_setup_teardown(creates_chat_session_on_recipient_activity, init_chat_sessions, close_chat_sessions), unit_test_setup_teardown(replaces_chat_session_on_recipient_activity_with_different_resource, init_chat_sessions, close_chat_sessions), unit_test_setup_teardown(removes_chat_session, init_chat_sessions, close_chat_sessions), unit_test_setup_teardown(cmd_connect_shows_message_when_disconnecting, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_message_when_connecting, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_message_when_connected, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_message_when_undefined, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_when_no_account, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_fail_message, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_lowercases_argument, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_asks_password_when_not_in_account, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_usage_when_no_server_value, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_message_when_connecting_with_account, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_connects_with_account, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_usage_when_server_no_port_value, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_usage_when_no_port_value, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_usage_when_port_no_server_value, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_message_when_port_0, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_message_when_port_minus1, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_message_when_port_65536, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_message_when_port_contains_chars, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_with_server_when_provided, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_with_port_when_provided, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_with_server_and_port_when_provided, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_usage_when_server_provided_twice, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_usage_when_port_provided_twice, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_usage_when_invalid_first_property, load_preferences, close_preferences), unit_test_setup_teardown(cmd_connect_shows_usage_when_invalid_second_property, load_preferences, close_preferences), unit_test(cmd_rooms_shows_message_when_disconnected), unit_test(cmd_rooms_shows_message_when_disconnecting), unit_test(cmd_rooms_shows_message_when_connecting), unit_test(cmd_rooms_shows_message_when_started), unit_test(cmd_rooms_shows_message_when_undefined), unit_test(cmd_rooms_uses_account_default_when_no_arg), unit_test(cmd_rooms_arg_used_when_passed), unit_test(cmd_account_shows_usage_when_not_connected_and_no_args), unit_test(cmd_account_shows_account_when_connected_and_no_args), unit_test(cmd_account_list_shows_accounts), unit_test(cmd_account_show_shows_usage_when_no_arg), unit_test(cmd_account_show_shows_message_when_account_does_not_exist), unit_test(cmd_account_show_shows_account_when_exists), unit_test(cmd_account_add_shows_usage_when_no_arg), unit_test(cmd_account_add_adds_account), unit_test(cmd_account_enable_shows_usage_when_no_arg), unit_test(cmd_account_enable_enables_account), unit_test(cmd_account_enable_shows_message_when_account_doesnt_exist), unit_test(cmd_account_disable_shows_usage_when_no_arg), unit_test(cmd_account_disable_disables_account), unit_test(cmd_account_disable_shows_message_when_account_doesnt_exist), unit_test(cmd_account_rename_shows_usage_when_no_args), unit_test(cmd_account_rename_shows_usage_when_one_arg), unit_test(cmd_account_rename_renames_account), unit_test(cmd_account_rename_shows_message_when_not_renamed), unit_test(cmd_account_set_shows_usage_when_no_args), unit_test(cmd_account_set_shows_usage_when_one_arg), unit_test(cmd_account_set_shows_usage_when_two_args), unit_test(cmd_account_set_shows_message_when_account_doesnt_exist), unit_test(cmd_account_set_jid_shows_message_for_malformed_jid), unit_test(cmd_account_set_jid_sets_barejid), unit_test(cmd_account_set_jid_sets_resource), unit_test(cmd_account_set_server_sets_server), unit_test(cmd_account_set_resource_sets_resource), unit_test(cmd_account_set_resource_sets_resource_with_online_message), unit_test(cmd_account_set_password_sets_password), unit_test(cmd_account_set_eval_password_sets_eval_password), unit_test(cmd_account_set_password_when_eval_password_set), unit_test(cmd_account_set_eval_password_when_password_set), unit_test(cmd_account_set_muc_sets_muc), unit_test(cmd_account_set_nick_sets_nick), #ifdef HAVE_LIBOTR unit_test(cmd_account_show_message_for_missing_otr_policy), unit_test(cmd_account_show_message_for_invalid_otr_policy), unit_test(cmd_account_set_otr_sets_otr), #endif unit_test(cmd_account_set_status_shows_message_when_invalid_status), unit_test(cmd_account_set_status_sets_status_when_valid), unit_test(cmd_account_set_status_sets_status_when_last), unit_test(cmd_account_set_invalid_presence_string_priority_shows_message), unit_test(cmd_account_set_last_priority_shows_message), unit_test(cmd_account_set_online_priority_sets_preference), unit_test(cmd_account_set_chat_priority_sets_preference), unit_test(cmd_account_set_away_priority_sets_preference), unit_test(cmd_account_set_xa_priority_sets_preference), unit_test(cmd_account_set_dnd_priority_sets_preference), unit_test(cmd_account_set_priority_too_low_shows_message), unit_test(cmd_account_set_priority_too_high_shows_message), unit_test(cmd_account_set_priority_when_not_number_shows_message), unit_test(cmd_account_set_priority_when_empty_shows_message), unit_test(cmd_account_set_priority_updates_presence_when_account_connected_with_presence), unit_test(cmd_account_clear_shows_usage_when_no_args), unit_test(cmd_account_clear_shows_usage_when_one_arg), unit_test(cmd_account_clear_shows_message_when_account_doesnt_exist), unit_test(cmd_account_clear_shows_message_when_invalid_property), unit_test(cmd_sub_shows_message_when_not_connected), unit_test(cmd_sub_shows_usage_when_no_arg), unit_test(contact_in_group), unit_test(contact_not_in_group), unit_test(contact_name_when_name_exists), unit_test(contact_jid_when_name_not_exists), unit_test(contact_string_when_name_exists), unit_test(contact_string_when_name_not_exists), unit_test(contact_string_when_default_resource), unit_test(contact_presence_offline), unit_test(contact_presence_uses_highest_priority), unit_test(contact_presence_chat_when_same_prioroty), unit_test(contact_presence_online_when_same_prioroty), unit_test(contact_presence_away_when_same_prioroty), unit_test(contact_presence_xa_when_same_prioroty), unit_test(contact_presence_dnd), unit_test(contact_subscribed_when_to), unit_test(contact_subscribed_when_both), unit_test(contact_not_subscribed_when_from), unit_test(contact_not_subscribed_when_no_subscription_value), unit_test(contact_not_available), unit_test(contact_not_available_when_highest_priority_away), unit_test(contact_not_available_when_highest_priority_xa), unit_test(contact_not_available_when_highest_priority_dnd), unit_test(contact_available_when_highest_priority_online), unit_test(contact_available_when_highest_priority_chat), unit_test(cmd_statuses_shows_usage_when_bad_subcmd), unit_test(cmd_statuses_shows_usage_when_bad_console_setting), unit_test(cmd_statuses_shows_usage_when_bad_chat_setting), unit_test(cmd_statuses_shows_usage_when_bad_muc_setting), unit_test_setup_teardown(cmd_statuses_console_sets_all, load_preferences, close_preferences), unit_test_setup_teardown(cmd_statuses_console_sets_online, load_preferences, close_preferences), unit_test_setup_teardown(cmd_statuses_console_sets_none, load_preferences, close_preferences), unit_test_setup_teardown(cmd_statuses_chat_sets_all, load_preferences, close_preferences), unit_test_setup_teardown(cmd_statuses_chat_sets_online, load_preferences, close_preferences), unit_test_setup_teardown(cmd_statuses_chat_sets_none, load_preferences, close_preferences), unit_test_setup_teardown(cmd_statuses_muc_sets_all, load_preferences, close_preferences), unit_test_setup_teardown(cmd_statuses_muc_sets_online, load_preferences, close_preferences), unit_test_setup_teardown(cmd_statuses_muc_sets_none, load_preferences, close_preferences), unit_test_setup_teardown(statuses_console_defaults_to_all, load_preferences, close_preferences), unit_test_setup_teardown(statuses_chat_defaults_to_all, load_preferences, close_preferences), unit_test_setup_teardown(statuses_muc_defaults_to_all, load_preferences, close_preferences), unit_test_setup_teardown(console_shows_online_presence_when_set_online, load_preferences, close_preferences), unit_test_setup_teardown(console_shows_online_presence_when_set_all, load_preferences, close_preferences), unit_test_setup_teardown(console_shows_dnd_presence_when_set_all, load_preferences, close_preferences), unit_test(handle_offline_removes_chat_session), unit_test(lost_connection_clears_chat_sessions), unit_test(cmd_alias_add_shows_usage_when_no_args), unit_test(cmd_alias_add_shows_usage_when_no_value), unit_test(cmd_alias_remove_shows_usage_when_no_args), unit_test(cmd_alias_show_usage_when_invalid_subcmd), unit_test_setup_teardown(cmd_alias_add_adds_alias, load_preferences, close_preferences), unit_test_setup_teardown(cmd_alias_add_shows_message_when_exists, load_preferences, close_preferences), unit_test_setup_teardown(cmd_alias_remove_removes_alias, load_preferences, close_preferences), unit_test_setup_teardown(cmd_alias_remove_shows_message_when_no_alias, load_preferences, close_preferences), unit_test_setup_teardown(cmd_alias_list_shows_all_aliases, load_preferences, close_preferences), unit_test_setup_teardown(test_muc_invites_add, muc_before_test, muc_after_test), unit_test_setup_teardown(test_muc_remove_invite, muc_before_test, muc_after_test), unit_test_setup_teardown(test_muc_invites_count_0, muc_before_test, muc_after_test), unit_test_setup_teardown(test_muc_invites_count_5, muc_before_test, muc_after_test), unit_test_setup_teardown(test_muc_room_is_not_active, muc_before_test, muc_after_test), unit_test_setup_teardown(test_muc_active, muc_before_test, muc_after_test), unit_test(cmd_bookmark_shows_message_when_disconnected), unit_test(cmd_bookmark_shows_message_when_disconnecting), unit_test(cmd_bookmark_shows_message_when_connecting), unit_test(cmd_bookmark_shows_message_when_started), unit_test(cmd_bookmark_shows_message_when_undefined), unit_test(cmd_bookmark_shows_usage_when_no_args), unit_test(cmd_bookmark_list_shows_bookmarks), unit_test(cmd_bookmark_add_shows_message_when_invalid_jid), unit_test(cmd_bookmark_add_adds_bookmark_with_jid), unit_test(cmd_bookmark_add_adds_bookmark_with_jid_nick), unit_test(cmd_bookmark_add_adds_bookmark_with_jid_autojoin), unit_test(cmd_bookmark_add_adds_bookmark_with_jid_nick_autojoin), unit_test(cmd_bookmark_remove_removes_bookmark), unit_test(cmd_bookmark_remove_shows_message_when_no_bookmark), #ifdef HAVE_LIBOTR unit_test(cmd_otr_shows_usage_when_no_args), unit_test(cmd_otr_shows_usage_when_invalid_subcommand), unit_test(cmd_otr_log_shows_usage_when_no_args), unit_test(cmd_otr_log_shows_usage_when_invalid_subcommand), unit_test_setup_teardown(cmd_otr_log_on_enables_logging, load_preferences, close_preferences), unit_test_setup_teardown(cmd_otr_log_off_disables_logging, load_preferences, close_preferences), unit_test_setup_teardown(cmd_otr_redact_redacts_logging, load_preferences, close_preferences), unit_test_setup_teardown(cmd_otr_log_on_shows_warning_when_chlog_disabled, load_preferences, close_preferences), unit_test_setup_teardown(cmd_otr_log_redact_shows_warning_when_chlog_disabled, load_preferences, close_preferences), unit_test(cmd_otr_libver_shows_libotr_version), unit_test(cmd_otr_gen_shows_message_when_not_connected), unit_test(cmd_otr_gen_generates_key_for_connected_account), unit_test(cmd_otr_gen_shows_message_when_disconnected), unit_test(cmd_otr_gen_shows_message_when_undefined), unit_test(cmd_otr_gen_shows_message_when_started), unit_test(cmd_otr_gen_shows_message_when_connecting), unit_test(cmd_otr_gen_shows_message_when_disconnecting), unit_test(cmd_otr_myfp_shows_message_when_disconnected), unit_test(cmd_otr_myfp_shows_message_when_undefined), unit_test(cmd_otr_myfp_shows_message_when_started), unit_test(cmd_otr_myfp_shows_message_when_connecting), unit_test(cmd_otr_myfp_shows_message_when_disconnecting), unit_test(cmd_otr_myfp_shows_message_when_no_key), unit_test(cmd_otr_myfp_shows_my_fingerprint), unit_test(cmd_otr_theirfp_shows_message_when_in_console), unit_test(cmd_otr_theirfp_shows_message_when_in_muc), unit_test(cmd_otr_theirfp_shows_message_when_in_private), unit_test(cmd_otr_theirfp_shows_message_when_non_otr_chat_window), unit_test(cmd_otr_theirfp_shows_fingerprint), unit_test(cmd_otr_start_shows_message_when_in_console), unit_test(cmd_otr_start_shows_message_when_in_muc), unit_test(cmd_otr_start_shows_message_when_in_private), unit_test(cmd_otr_start_shows_message_when_already_started), unit_test(cmd_otr_start_shows_message_when_no_key), unit_test_setup_teardown(cmd_otr_start_sends_otr_query_message_to_current_recipeint, load_preferences, close_preferences), #else unit_test(cmd_otr_shows_message_when_otr_unsupported), #endif #ifdef HAVE_LIBGPGME unit_test(cmd_pgp_shows_usage_when_no_args), unit_test(cmd_pgp_start_shows_message_when_disconnected), unit_test(cmd_pgp_start_shows_message_when_disconnecting), unit_test(cmd_pgp_start_shows_message_when_connecting), unit_test(cmd_pgp_start_shows_message_when_undefined), unit_test(cmd_pgp_start_shows_message_when_started), unit_test(cmd_pgp_start_shows_message_when_no_arg_in_console), unit_test(cmd_pgp_start_shows_message_when_no_arg_in_muc), unit_test(cmd_pgp_start_shows_message_when_no_arg_in_mucconf), unit_test(cmd_pgp_start_shows_message_when_no_arg_in_private), unit_test(cmd_pgp_start_shows_message_when_no_arg_in_xmlconsole), #else unit_test(cmd_pgp_shows_message_when_pgp_unsupported), #endif unit_test(cmd_join_shows_message_when_disconnecting), unit_test(cmd_join_shows_message_when_connecting), unit_test(cmd_join_shows_message_when_disconnected), unit_test(cmd_join_shows_message_when_undefined), unit_test(cmd_join_shows_error_message_when_invalid_room_jid), unit_test(cmd_join_uses_account_mucservice_when_no_service_specified), unit_test(cmd_join_uses_supplied_nick), unit_test(cmd_join_uses_account_nick_when_not_supplied), unit_test(cmd_join_uses_password_when_supplied), unit_test(cmd_roster_shows_message_when_disconnecting), unit_test(cmd_roster_shows_message_when_connecting), unit_test(cmd_roster_shows_message_when_disconnected), unit_test(cmd_roster_shows_message_when_undefined), unit_test(cmd_roster_shows_roster_when_no_args), unit_test(cmd_roster_add_shows_message_when_no_jid), unit_test(cmd_roster_add_sends_roster_add_request), unit_test(cmd_roster_remove_shows_message_when_no_jid), unit_test(cmd_roster_remove_sends_roster_remove_request), unit_test(cmd_roster_nick_shows_message_when_no_jid), unit_test(cmd_roster_nick_shows_message_when_no_nick), unit_test(cmd_roster_nick_shows_message_when_no_contact_exists), unit_test(cmd_roster_nick_sends_name_change_request), unit_test(cmd_roster_clearnick_shows_message_when_no_jid), unit_test(cmd_roster_clearnick_shows_message_when_no_contact_exists), unit_test(cmd_roster_clearnick_sends_name_change_request_with_empty_nick), unit_test(get_form_type_field_returns_null_no_fields), unit_test(get_form_type_field_returns_null_when_not_present), unit_test(get_form_type_field_returns_value_when_present), unit_test(get_field_type_returns_unknown_when_no_fields), unit_test(get_field_type_returns_correct_type), unit_test(set_value_adds_when_none), unit_test(set_value_updates_when_one), unit_test(add_unique_value_adds_when_none), unit_test(add_unique_value_does_nothing_when_exists), unit_test(add_unique_value_adds_when_doesnt_exist), unit_test(add_value_adds_when_none), unit_test(add_value_adds_when_some), unit_test(add_value_adds_when_exists), unit_test(remove_value_does_nothing_when_none), unit_test(remove_value_does_nothing_when_doesnt_exist), unit_test(remove_value_removes_when_one), unit_test(remove_value_removes_when_many), unit_test(remove_text_multi_value_does_nothing_when_none), unit_test(remove_text_multi_value_does_nothing_when_doesnt_exist), unit_test(remove_text_multi_value_removes_when_one), unit_test(remove_text_multi_value_removes_when_many), unit_test(clears_chat_sessions), }; return run_tests(all_tests); } profanity-0.4.7/tests/unittests/xmpp/000077500000000000000000000000001257755232500177425ustar00rootroot00000000000000profanity-0.4.7/tests/unittests/xmpp/stub_xmpp.c000066400000000000000000000142711257755232500221340ustar00rootroot00000000000000#include #include #include #include #include "xmpp/xmpp.h" // connection functions void jabber_init(const int disable_tls) {} jabber_conn_status_t jabber_connect_with_details(const char * const jid, const char * const passwd, const char * const altdomain, const int port) { check_expected(jid); check_expected(passwd); check_expected(altdomain); check_expected(port); return (jabber_conn_status_t)mock(); } jabber_conn_status_t jabber_connect_with_account(const ProfAccount * const account) { check_expected(account); return (jabber_conn_status_t)mock(); } void jabber_disconnect(void) {} void jabber_shutdown(void) {} void jabber_process_events(int millis) {} const char * jabber_get_fulljid(void) { return (char *)mock(); } const char * jabber_get_domain(void) { return NULL; } jabber_conn_status_t jabber_get_connection_status(void) { return (jabber_conn_status_t)mock(); } char* jabber_get_presence_message(void) { return (char*)mock(); } char* jabber_get_account_name(void) { return (char*)mock(); } GList * jabber_get_available_resources(void) { return NULL; } // message functions char* message_send_chat(const char * const barejid, const char * const msg) { check_expected(barejid); check_expected(msg); return NULL; } char* message_send_chat_otr(const char * const barejid, const char * const msg) { check_expected(barejid); check_expected(msg); return NULL; } char* message_send_chat_pgp(const char * const barejid, const char * const msg) { return NULL; } void message_send_private(const char * const fulljid, const char * const msg) {} void message_send_groupchat(const char * const roomjid, const char * const msg) {} void message_send_groupchat_subject(const char * const roomjid, const char * const subject) {} void message_send_inactive(const char * const barejid) {} void message_send_composing(const char * const barejid) {} void message_send_paused(const char * const barejid) {} void message_send_gone(const char * const barejid) {} void message_send_invite(const char * const room, const char * const contact, const char * const reason) {} // presence functions void presence_subscription(const char * const jid, const jabber_subscr_t action) {} GSList* presence_get_subscription_requests(void) { return NULL; } gint presence_sub_request_count(void) { return 0; } void presence_reset_sub_request_search(void) {} char * presence_sub_request_find(const char * const search_str) { return NULL; } void presence_join_room(char *room, char *nick, char * passwd) { check_expected(room); check_expected(nick); check_expected(passwd); } void presence_change_room_nick(const char * const room, const char * const nick) {} void presence_leave_chat_room(const char * const room_jid) {} void presence_send(resource_presence_t status, const char * const msg, int idle, char *signed_status) { check_expected(status); check_expected(msg); check_expected(idle); check_expected(signed_status); } gboolean presence_sub_request_exists(const char * const bare_jid) { return FALSE; } // iq functions void iq_disable_carbons() {}; void iq_enable_carbons() {}; void iq_send_software_version(const char * const fulljid) {} void iq_room_list_request(gchar *conferencejid) { check_expected(conferencejid); } void iq_disco_info_request(gchar *jid) {} void iq_disco_items_request(gchar *jid) {} void iq_set_autoping(int seconds) {} void iq_confirm_instant_room(const char * const room_jid) {} void iq_destroy_room(const char * const room_jid) {} void iq_request_room_config_form(const char * const room_jid) {} void iq_submit_room_config(const char * const room, DataForm *form) {} void iq_room_config_cancel(const char * const room_jid) {} void iq_send_ping(const char * const target) {} void iq_send_caps_request(const char * const to, const char * const id, const char * const node, const char * const ver) {} void iq_send_caps_request_for_jid(const char * const to, const char * const id, const char * const node, const char * const ver) {} void iq_send_caps_request_legacy(const char * const to, const char * const id, const char * const node, const char * const ver) {} void iq_room_info_request(const char * const room, gboolean display) {} void iq_room_affiliation_list(const char * const room, char *affiliation) {} void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation, const char * const reason) {} void iq_room_kick_occupant(const char * const room, const char * const nick, const char * const reason) {} void iq_room_role_set(const char * const room, const char * const nick, char *role, const char * const reason) {} void iq_room_role_list(const char * const room, char *role) {} // caps functions Capabilities* caps_lookup(const char * const jid) { return NULL; } void caps_close(void) {} void caps_destroy(Capabilities *caps) {} gboolean bookmark_add(const char *jid, const char *nick, const char *password, const char *autojoin_str) { check_expected(jid); check_expected(nick); check_expected(password); check_expected(autojoin_str); return (gboolean)mock(); } gboolean bookmark_update(const char *jid, const char *nick, const char *password, const char *autojoin_str) { return FALSE; } gboolean bookmark_remove(const char *jid) { check_expected(jid); return (gboolean)mock(); } gboolean bookmark_join(const char *jid) { return FALSE; } const GList * bookmark_get_list(void) { return (GList *)mock(); } char * bookmark_find(const char * const search_str) { return NULL; } void bookmark_autocomplete_reset(void) {} void roster_send_name_change(const char * const barejid, const char * const new_name, GSList *groups) { check_expected(barejid); check_expected(new_name); check_expected(groups); } void roster_send_add_to_group(const char * const group, PContact contact) {} void roster_send_remove_from_group(const char * const group, PContact contact) {} void roster_send_add_new(const char * const barejid, const char * const name) { check_expected(barejid); check_expected(name); } void roster_send_remove(const char * const barejid) { check_expected(barejid); } profanity-0.4.7/theme_template000066400000000000000000000017241257755232500164760ustar00rootroot00000000000000[colours] bkgnd= titlebar= titlebar.text= titlebar.brackets= titlebar.unencrypted= titlebar.encrypted= titlebar.untrusted= titlebar.trusted= titlebar.online= titlebar.offline= titlebar.away= titlebar.chat= titlebar.dnd= titlebar.xa= statusbar= statusbar.text= statusbar.brackets= statusbar.active= statusbar.new= main.text= main.text.me= main.text.them= main.splash= main.time= input.text= subscribed= unsubscribed= otr.started.trusted= otr.started.untrusted= otr.ended= otr.trusted= otr.untrusted= online= away= chat= dnd= xa= offline= incoming= typing= gone= error= roominfo= roommention= me= them= roster.header= occupants.header= receipt.sent= [ui] beep= flash= splash= wrap= time= time.statusbar= privileges= presence= intype= enc.warn= resource.title= resource.message= statuses.console= statuses.chat= statuses.muc= roster= roster.offline= roster.resource= roster.by= roster.size= roster.empty= occupants= occupants.size= occupants.jid= wins.autotidy= otr.char= pgp.char= profanity-0.4.7/themes/000077500000000000000000000000001257755232500150375ustar00rootroot00000000000000profanity-0.4.7/themes/aqua000066400000000000000000000016731257755232500157200ustar00rootroot00000000000000[colours] bkgnd=default titlebar=blue titlebar.text=bold_white titlebar.brackets=white titlebar.unencrypted=cyan titlebar.encrypted=white titlebar.untrusted=cyan titlebar.trusted=white titlebar.online=bold_white titlebar.offline=cyan titlebar.away=white titlebar.chat=bold_white titlebar.dnd=cyan titlebar.xa=bold_cyan statusbar=blue statusbar.text=bold_white statusbar.brackets=white statusbar.active=cyan statusbar.new=white main.text=blue main.text.me=bold_cyan main.text.them=bold_white main.splash=bold_white main.time=cyan input.text=white subscribed=bold_cyan unsubscribed=blue otr.started.trusted=white otr.started.untrusted=cyan otr.ended=cyan otr.trusted=white otr.untrusted=cyan online=bold_cyan away=bold_blue chat=white dnd=blue xa=cyan offline=bold_black incoming=bold_cyan typing=cyan gone=blue error=bold_white roominfo=white roommention=bold_blue me=cyan them=white roster.header=bold_white occupants.header=bold_white receipt.sent=white profanity-0.4.7/themes/batman000066400000000000000000000016331257755232500162270ustar00rootroot00000000000000[colours] bkgnd=default titlebar=yellow statusbar=yellow titlebar.text=black titlebar.brackets=black statusbar.text=magenta statusbar.brackets=black statusbar.active=magenta statusbar.new=magenta main.text=white input.text=yellow main.time=white main.splash=yellow online=green away=yellow chat=green dnd=green xa=yellow offline=bold_black typing=cyan gone=red error=red incoming=yellow roominfo=green me=black_bold them=yellow titlebar.unencrypted=red titlebar.encrypted=green titlebar.untrusted=red titlebar.trusted=green otr.started.trusted=green otr.started.untrusted=red otr.ended=yellow otr.trusted=green otr.untrusted=red titlebar.online=magenta titlebar.offline=black titlebar.away=magenta titlebar.chat=magenta titlebar.dnd=magenta titlebar.xa=magenta main.text.me=white main.text.them=white subscribed=magenta unsubscribed=black_bold roommention=cyan roster.header=yellow occupants.header=yellow receipt.sent=red profanity-0.4.7/themes/boothj5000066400000000000000000000026721257755232500163430ustar00rootroot00000000000000[colours] bkgnd=default titlebar=blue titlebar.text=bold_white titlebar.brackets=white titlebar.unencrypted=bold_red titlebar.encrypted=bold_white titlebar.untrusted=bold_yellow titlebar.trusted=bold_white titlebar.online=bold_green titlebar.offline=bold_red titlebar.away=bold_cyan titlebar.xa=bold_cyan titlebar.dnd=bold_red titlebar.chat=bold_green statusbar=blue statusbar.text=bold_white statusbar.brackets=white statusbar.active=bold_cyan statusbar.new=bold_white main.text=white main.text.me=cyan main.text.them=bold_white main.splash=bold_red main.time=yellow input.text=bold_green subscribed=bold_green unsubscribed=red otr.started.trusted=green otr.started.untrusted=yellow otr.ended=red otr.trusted=green otr.untrusted=yellow online=bold_green away=bold_cyan chat=bold_white dnd=magenta xa=bold_blue offline=red incoming=bold_yellow typing=yellow gone=red error=red roominfo=yellow roommention=bold_red me=blue them=bold_green roster.header=bold_yellow occupants.header=bold_yellow receipt.sent=bold_black [ui] beep=false flash=false splash=true wrap=true time=%d-%m-%y %H:%M time.statusbar=%H:%M:%S privileges=true presence=true intype=true enc.warn=true resource.title=true resource.message=true statuses.console=all statuses.chat=all statuses.muc=all roster=true roster.offline=true roster.resource=false roster.by=presence roster.size=25 roster.empty=true occupants=true occupants.size=15 occupants.jid=false wins.autotidy=true otr.char=@ pgp.char=% profanity-0.4.7/themes/complex000066400000000000000000000006171257755232500164350ustar00rootroot00000000000000[ui] beep=false flash=false splash=true wrap=true time=%H:%M:%S time.statusbar=$H:$M:%S resource.title=true resource.message=true statuses.console=all statuses.chat=all statuses.muc=all occupants=true occupants.size=15 occupants.jid=true roster=true roster.offline=true roster.resource=true roster.by=presence roster.size=25 roster.empty=true privileges=true presence=true intype=true enc.warn=true profanity-0.4.7/themes/forest000066400000000000000000000017141257755232500162670ustar00rootroot00000000000000[colours] bkgnd=default titlebar=cyan titlebar.text=black titlebar.brackets=black titlebar.unencrypted=black titlebar.encrypted=white titlebar.untrusted=white titlebar.trusted=white titlebar.online=white titlebar.offline=white titlebar.away=white titlebar.chat=white titlebar.dnd=white titlebar.xa=white statusbar=green statusbar.text=black statusbar.brackets=black statusbar.active=bold_green statusbar.new=white main.text=bold_cyan main.text.me=yellow main.text.them=green main.splash=bold_yellow main.time=bold_green input.text=bold_blue subscribed=green unsubscribed=bold_black otr.started.trusted=green otr.started.untrusted=yellow otr.ended=red otr.trusted=green otr.untrusted=yellow online=green away=blue chat=green dnd=bold_black xa=blue offline=bold_black incoming=bold_yellow typing=yellow gone=bold_black error=bold_black roominfo=yellow roommention=bold_cyan me=blue them=bold_blue roster.header=bold_green occupants.header=bold_green receipt.sent=bold_black profanity-0.4.7/themes/hacker000066400000000000000000000017001257755232500162150ustar00rootroot00000000000000[colours] bkgnd=default titlebar=green titlebar.text=black titlebar.brackets=black titlebar.unencrypted=black titlebar.encrypted=black titlebar.untrusted=black titlebar.trusted=black titlebar.online=black titlebar.offline=black titlebar.away=black titlebar.chat=black titlebar.dnd=black titlebar.xa=black statusbar=green statusbar.text=black statusbar.brackets=black statusbar.active=black statusbar.new=black main.text=green main.text.me=green main.text.them=green main.splash=bold_green main.time=bold_green input.text=bold_green subscribed=bold_green unsubscribed=green otr.started.trusted=green otr.started.untrusted=green otr.ended=green otr.trusted=green otr.untrusted=green online=bold_green away=green chat=bold_green dnd=green xa=green offline=green incoming=bold_green typing=green gone=green error=bold_green roominfo=green roommention=bold_green me=green them=bold_green roster.header=bold_green occupants.header=bold_green receipt.sent=bold_black profanity-0.4.7/themes/headache000066400000000000000000000016271257755232500165120ustar00rootroot00000000000000[colours] bkgnd=default titlebar=magenta titlebar.text=white titlebar.brackets=white titlebar.unencrypted=black titlebar.encrypted=cyan titlebar.untrusted=yellow titlebar.trusted=cyan titlebar.online=white titlebar.offline=black titlebar.away=white titlebar.chat=white titlebar.dnd=black titlebar.xa=white statusbar=default statusbar.text=white statusbar.brackets=red statusbar.active=cyan statusbar.new=white main.text=blue main.text.me=white main.text.them=bold_white main.splash=red main.time=green input.text=yellow subscribed=bold_magenta unsubscribed=bold_black otr.started.trusted=cyan otr.started.untrusted=yellow otr.ended=blue otr.trusted=cyan otr.untrusted=yellow online=red away=cyan chat=green dnd=megenta xa=cyan offline=green incoming=yellow typing=magenta gone=yellow error=red roominfo=white roommention=bold_green me=white them=white roster.header=bold_cyan occupants.header=bold_cyan receipt.sent=redprofanity-0.4.7/themes/joker000066400000000000000000000016011257755232500160720ustar00rootroot00000000000000[colours] bkgnd=default titlebar=magenta titlebar.text=white titlebar.brackets=cyan titlebar.unencrypted=red titlebar.encrypted=green titlebar.untrusted=red titlebar.trusted=green titlebar.online=white titlebar.offline=black titlebar.away=white titlebar.chat=white titlebar.dnd=black titlebar.xa=white statusbar=magenta statusbar.text=green statusbar.brackets=cyan statusbar.active=green statusbar.new=white main.text=white main.text.me=white main.text.them=white main.splash=green main.time=white input.text=green subscribed=green unsubscribed=white otr.started.trusted=green otr.started.untrusted=red otr.ended=yellow otr.trusted=green otr.untrusted=red online=green away=yellow chat=green dnd=green xa=yellow offline=bold_black incoming=yellow typing=green gone=red error=red roominfo=green roommention=green me=magenta them=green roster.header=magenta occupants.header=magenta receipt.sent=redprofanity-0.4.7/themes/mono000066400000000000000000000015761257755232500157430ustar00rootroot00000000000000[colours] bkgnd=default titlebar=white titlebar.text=black titlebar.brackets=black titlebar.unencrypted=black titlebar.encrypted=black titlebar.untrusted=black titlebar.trusted=black titlebar.online=black titlebar.offline=black titlebar.away=black titlebar.chat=black titlebar.dnd=black titlebar.xa=black statusbar=white statusbar.text=black statusbar.brackets=black statusbar.active=black statusbar.new=black main.text=white main.text.me=white main.text.them=white main.splash=white main.time=white input.text=white subscribed=white unsubscribed=white otr.started.trusted=white otr.started.untrusted=white otr.ended=white otr.trusted=white otr.untrusted=white online=white away=white chat=white dnd=white xa=white offline=white incoming=white typing=white gone=white error=white roominfo=white roommention=white me=white them=white roster.header=white occupants.header=white receipt.sent=whiteprofanity-0.4.7/themes/orange000066400000000000000000000015531257755232500162410ustar00rootroot00000000000000[colours] bkgnd=yellow titlebar=red titlebar.text=black titlebar.brackets=blue titlebar.unencrypted=black titlebar.encrypted=white titlebar.untrusted=white titlebar.trusted=green titlebar.online=white titlebar.offline=black titlebar.away=white titlebar.chat=white titlebar.dnd=black titlebar.xa=white statusbar=green statusbar.text=black statusbar.brackets=blue statusbar.active=white statusbar.new=white main.text=black main.text.me=black main.text.them=green main.splash=blue main.time=blue input.text=black subscribed=blue unsubscribed=white otr.started.trusted=green otr.started.untrusted=white otr.ended=red otr.trusted=green otr.untrusted=white online=blue away=white chat=blue dnd=white xa=white offline=white incoming=blue typing=black gone=green error=red roominfo=blue roommention=blue me=black them=black roster.header=black occupants.header=black receipt.sent=redprofanity-0.4.7/themes/original000066400000000000000000000015631257755232500165730ustar00rootroot00000000000000[colours] bkgnd=default titlebar=blue titlebar.text=white titlebar.brackets=cyan titlebar.unencrypted=red titlebar.encrypted=white titlebar.untrusted=yellow titlebar.trusted=white titlebar.online=white titlebar.offline=white titlebar.away=white titlebar.chat=white titlebar.dnd=white titlebar.xa=white statusbar=blue statusbar.text=white statusbar.brackets=cyan statusbar.active=cyan statusbar.new=white main.text=white main.text.me=white main.text.them=white main.splash=cyan main.time=white input.text=white subscribed=green unsubscribed=red otr.started.trusted=green otr.started.untrusted=yellow otr.ended=red otr.trusted=green otr.untrusted=yellow online=green away=cyan chat=green dnd=red xa=cyan offline=red incoming=yellow typing=yellow gone=yellow error=red roominfo=yellow roommention=yellow me=yellow them=green roster.header=yellow occupants.header=yellow receipt.sent=redprofanity-0.4.7/themes/original_bright000066400000000000000000000021321257755232500201230ustar00rootroot00000000000000[colours] bkgnd=default titlebar=blue titlebar.text=bold_white titlebar.brackets=bold_cyan titlebar.unencrypted=bold_red titlebar.encrypted=bold_white titlebar.untrusted=bold_yellow titlebar.trusted=bold_white titlebar.online=bold_white titlebar.offline=bold_white titlebar.away=bold_white titlebar.chat=bold_white titlebar.dnd=bold_white titlebar.xa=bold_white statusbar=blue statusbar.text=bold_white statusbar.brackets=bold_cyan statusbar.active=bold_cyan statusbar.new=bold_white main.text=bold_white main.text.me=bold_white main.text.them=bold_white main.splash=bold_cyan main.time=bold_white input.text=bold_white subscribed=bold_green unsubscribed=bold_red otr.started.trusted=bold_green otr.started.untrusted=bold_yellow otr.ended=bold_red otr.trusted=bold_green otr.untrusted=bold_yellow online=bold_green away=bold_cyan chat=bold_green dnd=bold_red xa=bold_cyan offline=bold_red incoming=bold_yellow typing=bold_yellow gone=bold_yellow error=bold_red roominfo=bold_yellow roommention=bold_yellow me=bold_yellow them=bold_green roster.header=bold_yellow occupants.header=bold_yellow receipt.sent=bold_red profanity-0.4.7/themes/shade000066400000000000000000000016121257755232500160460ustar00rootroot00000000000000[colours] bkgnd=default titlebar=default titlebar.text=white titlebar.brackets=magenta titlebar.unencrypted=red titlebar.encrypted=green titlebar.untrusted=red titlebar.trusted=green titlebar.online=green titlebar.offline=red titlebar.away=green titlebar.chat=green titlebar.dnd=red titlebar.xa=green statusbar=default statusbar.text=magenta statusbar.brackets=magenta statusbar.active=white statusbar.new=green main.text=white main.text.me=white main.text.them=white main.splash=magenta main.time=magenta input.text=white subscribed=green unsubscribed=yallow otr.started.trusted=green otr.started.untrusted=red otr.ended=yellow otr.trusted=green otr.untrusted=red online=green away=yellow chat=green dnd=green xa=yellow offline=white incoming=yellow typing=green gone=red error=red roominfo=green roommention=green me=bold_black them=magenta roster.header=magenta occupants.header=magenta receipt.sent=redprofanity-0.4.7/themes/simple000066400000000000000000000006211257755232500162520ustar00rootroot00000000000000[ui] beep=false flash=false splash=true wrap=true time=%H:%M time.statusbar= resource.title=false resource.message=false statuses.console=none statuses.chat=none statuses.muc=none occupants=true occupants.size=15 roster=true roster.offline=false roster.resource=false roster.by=presence roster.size=25 roster.empty=false privileges=false presence=false intype=false enc.warn=false wins.autotidy=false profanity-0.4.7/themes/spawn000066400000000000000000000015541257755232500161170ustar00rootroot00000000000000[colours] bkgnd=default titlebar=red titlebar.text=yellow titlebar.brackets=green titlebar.unencrypted=red titlebar.encrypted=green titlebar.untrusted=red titlebar.trusted=green titlebar.online=green titlebar.offline=red titlebar.away=green titlebar.chat=green titlebar.dnd=red titlebar.xa=green statusbar=red statusbar.text=yellow statusbar.brackets=green statusbar.active=white statusbar.new=green main.text=white main.text.me=white main.text.them=white main.splash=red main.time=red input.text=green subscribed=green unsubscribed=red otr.started.trusted=green otr.started.untrusted=red otr.ended=yellow otr.trusted=green otr.untrusted=red online=green away=yellow chat=green dnd=green xa=yellow offline=bold_black incoming=yellow typing=green gone=red error=red roominfo=green roommention=red me=green them=yellow roster.header=white occupants.header=white receipt.sent=redprofanity-0.4.7/themes/whiteness000066400000000000000000000015541257755232500170000ustar00rootroot00000000000000[colours] bkgnd=white titlebar=blue titlebar.text=white titlebar.brackets=white titlebar.unencrypted=red titlebar.encrypted=white titlebar.untrusted=yellow titlebar.trusted=white titlebar.online=white titlebar.offline=red titlebar.away=white titlebar.chat=white titlebar.dnd=red titlebar.xa=white statusbar=blue statusbar.text=white statusbar.brackets=white statusbar.active=megenta statusbar.new=red main.text=black main.text.me=black main.text.them=black main.splash=black main.time=black input.text=black subscribed=green unsubscribed=red otr.started.trusted=green otr.started.untrusted=yellow otr.ended=red otr.trusted=green otr.untrusted=yellow online=green away=cyan chat=green dnd=red xa=cyan offline=red incoming=yellow typing=yellow gone=red error=red roominfo=yellow roommention=yellow me=black them=black roster.header=black occupants.header=black receipt.sent=red