toxcore 0.0.2 → 0.2.0
raw patch · 13 files changed
+3870/−1854 lines, 13 filesdep +base16-bytestringdep +directorynew-component:exe:groupbot
Dependencies added: base16-bytestring, directory
Files
- LICENSE.md +592/−9
- src/Network/Tox/C.hs +4/−0
- src/Network/Tox/C/CEnum.hs +1/−0
- src/Network/Tox/C/Callbacks.hs +69/−40
- src/Network/Tox/C/Constants.hs +50/−0
- src/Network/Tox/C/Options.hs +317/−0
- src/Network/Tox/C/Tox.hs +2404/−1797
- src/Network/Tox/C/Type.hs +17/−0
- src/Network/Tox/C/Version.hs +27/−0
- test/Network/Tox/C/ToxSpec.hs +119/−0
- test/Network/Tox/CSpec.hs +96/−0
- tools/groupbot/Main.hs +143/−0
- toxcore.cabal +31/−8
LICENSE.md view
@@ -1,12 +1,595 @@-The software is licensed under [AGPLv3](licenses/gnu-agpl-v3.0.md).+GNU General Public License+========================== -The documentation is the Markdown text extracted from the Software. The parts-of the extracted documentation that were originally part of the-[Tox-Docs](https://github.com/Tox-Docs/Text/commit/8f77b8a7c935871eea48cc5abeef26dfa42a108a)-repository are licensed under [MIT](licenses/mit.md). The parts that were not-originally part of that repository are licensed under AGPLv3.+_Version 3, 29 June 2007_+_Copyright © 2007 Free Software Foundation, Inc. <<http://fsf.org/>>_ -The copyright of all contributions is owned by their respective contributors.-The TokTok project will not accept, request, or perform copyright assignments.+Everyone is permitted to copy and distribute verbatim copies of this license+document, but changing it is not allowed. -Contact Iphigenia Df <iphydf@gmail.com> for license inquiries.+## Preamble++The GNU General Public License is a free, copyleft license for software and other+kinds of works.++The licenses for most software and other practical works are designed to take away+your freedom to share and change the works. By contrast, the GNU General Public+License is intended to guarantee your freedom to share and change all versions of a+program--to make sure it remains free software for all its users. We, the Free+Software Foundation, use the GNU General Public License for most of our software; it+applies also to any other work released this way by its authors. You can apply it to+your programs, too.++When we speak of free software, we are referring to freedom, not price. Our General+Public Licenses are designed to make sure that you have the freedom to distribute+copies of free software (and charge for them if you wish), that you receive source+code or can get it if you want it, that you can change the software or use pieces of+it in new free programs, and that you know you can do these things.++To protect your rights, we need to prevent others from denying you these rights or+asking you to surrender the rights. Therefore, you have certain responsibilities if+you distribute copies of the software, or if you modify it: responsibilities to+respect the freedom of others.++For example, if you distribute copies of such a program, whether gratis or for a fee,+you must pass on to the recipients the same freedoms that you received. You must make+sure that they, too, receive or can get the source code. And you must show them these+terms so they know their rights.++Developers that use the GNU GPL protect your rights with two steps: **(1)** assert+copyright on the software, and **(2)** offer you this License giving you legal permission+to copy, distribute and/or modify it.++For the developers' and authors' protection, the GPL clearly explains that there is+no warranty for this free software. For both users' and authors' sake, the GPL+requires that modified versions be marked as changed, so that their problems will not+be attributed erroneously to authors of previous versions.++Some devices are designed to deny users access to install or run modified versions of+the software inside them, although the manufacturer can do so. This is fundamentally+incompatible with the aim of protecting users' freedom to change the software. The+systematic pattern of such abuse occurs in the area of products for individuals to+use, which is precisely where it is most unacceptable. Therefore, we have designed+this version of the GPL to prohibit the practice for those products. If such problems+arise substantially in other domains, we stand ready to extend this provision to+those domains in future versions of the GPL, as needed to protect the freedom of+users.++Finally, every program is threatened constantly by software patents. States should+not allow patents to restrict development and use of software on general-purpose+computers, but in those that do, we wish to avoid the special danger that patents+applied to a free program could make it effectively proprietary. To prevent this, the+GPL assures that patents cannot be used to render the program non-free.++The precise terms and conditions for copying, distribution and modification follow.++## TERMS AND CONDITIONS++### 0. Definitions++“This License” refers to version 3 of the GNU General Public License.++“Copyright” also means copyright-like laws that apply to other kinds of+works, such as semiconductor masks.++“The Program” refers to any copyrightable work licensed under this+License. Each licensee is addressed as “you”. “Licensees” and+“recipients” may be individuals or organizations.++To “modify” a work means to copy from or adapt all or part of the work in+a fashion requiring copyright permission, other than the making of an exact copy. The+resulting work is called a “modified version” of the earlier work or a+work “based on” the earlier work.++A “covered work” means either the unmodified Program or a work based on+the Program.++To “propagate” a work means to do anything with it that, without+permission, would make you directly or secondarily liable for infringement under+applicable copyright law, except executing it on a computer or modifying a private+copy. Propagation includes copying, distribution (with or without modification),+making available to the public, and in some countries other activities as well.++To “convey” a work means any kind of propagation that enables other+parties to make or receive copies. Mere interaction with a user through a computer+network, with no transfer of a copy, is not conveying.++An interactive user interface displays “Appropriate Legal Notices” to the+extent that it includes a convenient and prominently visible feature that **(1)**+displays an appropriate copyright notice, and **(2)** tells the user that there is no+warranty for the work (except to the extent that warranties are provided), that+licensees may convey the work under this License, and how to view a copy of this+License. If the interface presents a list of user commands or options, such as a+menu, a prominent item in the list meets this criterion.++### 1. Source Code++The “source code” for a work means the preferred form of the work for+making modifications to it. “Object code” means any non-source form of a+work.++A “Standard Interface” means an interface that either is an official+standard defined by a recognized standards body, or, in the case of interfaces+specified for a particular programming language, one that is widely used among+developers working in that language.++The “System Libraries” of an executable work include anything, other than+the work as a whole, that **(a)** is included in the normal form of packaging a Major+Component, but which is not part of that Major Component, and **(b)** serves only to+enable use of the work with that Major Component, or to implement a Standard+Interface for which an implementation is available to the public in source code form.+A “Major Component”, in this context, means a major essential component+(kernel, window system, and so on) of the specific operating system (if any) on which+the executable work runs, or a compiler used to produce the work, or an object code+interpreter used to run it.++The “Corresponding Source” for a work in object code form means all the+source code needed to generate, install, and (for an executable work) run the object+code and to modify the work, including scripts to control those activities. However,+it does not include the work's System Libraries, or general-purpose tools or+generally available free programs which are used unmodified in performing those+activities but which are not part of the work. For example, Corresponding Source+includes interface definition files associated with source files for the work, and+the source code for shared libraries and dynamically linked subprograms that the work+is specifically designed to require, such as by intimate data communication or+control flow between those subprograms and other parts of the work.++The Corresponding Source need not include anything that users can regenerate+automatically from other parts of the Corresponding Source.++The Corresponding Source for a work in source code form is that same work.++### 2. Basic Permissions++All rights granted under this License are granted for the term of copyright on the+Program, and are irrevocable provided the stated conditions are met. This License+explicitly affirms your unlimited permission to run the unmodified Program. The+output from running a covered work is covered by this License only if the output,+given its content, constitutes a covered work. This License acknowledges your rights+of fair use or other equivalent, as provided by copyright law.++You may make, run and propagate covered works that you do not convey, without+conditions so long as your license otherwise remains in force. You may convey covered+works to others for the sole purpose of having them make modifications exclusively+for you, or provide you with facilities for running those works, provided that you+comply with the terms of this License in conveying all material for which you do not+control copyright. Those thus making or running the covered works for you must do so+exclusively on your behalf, under your direction and control, on terms that prohibit+them from making any copies of your copyrighted material outside their relationship+with you.++Conveying under any other circumstances is permitted solely under the conditions+stated below. Sublicensing is not allowed; section 10 makes it unnecessary.++### 3. Protecting Users' Legal Rights From Anti-Circumvention Law++No covered work shall be deemed part of an effective technological measure under any+applicable law fulfilling obligations under article 11 of the WIPO copyright treaty+adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention+of such measures.++When you convey a covered work, you waive any legal power to forbid circumvention of+technological measures to the extent such circumvention is effected by exercising+rights under this License with respect to the covered work, and you disclaim any+intention to limit operation or modification of the work as a means of enforcing,+against the work's users, your or third parties' legal rights to forbid circumvention+of technological measures.++### 4. Conveying Verbatim Copies++You may convey verbatim copies of the Program's source code as you receive it, in any+medium, provided that you conspicuously and appropriately publish on each copy an+appropriate copyright notice; keep intact all notices stating that this License and+any non-permissive terms added in accord with section 7 apply to the code; keep+intact all notices of the absence of any warranty; and give all recipients a copy of+this License along with the Program.++You may charge any price or no price for each copy that you convey, and you may offer+support or warranty protection for a fee.++### 5. Conveying Modified Source Versions++You may convey a work based on the Program, or the modifications to produce it from+the Program, in the form of source code under the terms of section 4, provided that+you also meet all of these conditions:++* **a)** The work must carry prominent notices stating that you modified it, and giving a+relevant date.+* **b)** The work must carry prominent notices stating that it is released under this+License and any conditions added under section 7. This requirement modifies the+requirement in section 4 to “keep intact all notices”.+* **c)** You must license the entire work, as a whole, under this License to anyone who+comes into possession of a copy. This License will therefore apply, along with any+applicable section 7 additional terms, to the whole of the work, and all its parts,+regardless of how they are packaged. This License gives no permission to license the+work in any other way, but it does not invalidate such permission if you have+separately received it.+* **d)** If the work has interactive user interfaces, each must display Appropriate Legal+Notices; however, if the Program has interactive interfaces that do not display+Appropriate Legal Notices, your work need not make them do so.++A compilation of a covered work with other separate and independent works, which are+not by their nature extensions of the covered work, and which are not combined with+it such as to form a larger program, in or on a volume of a storage or distribution+medium, is called an “aggregate” if the compilation and its resulting+copyright are not used to limit the access or legal rights of the compilation's users+beyond what the individual works permit. Inclusion of a covered work in an aggregate+does not cause this License to apply to the other parts of the aggregate.++### 6. Conveying Non-Source Forms++You may convey a covered work in object code form under the terms of sections 4 and+5, provided that you also convey the machine-readable Corresponding Source under the+terms of this License, in one of these ways:++* **a)** Convey the object code in, or embodied in, a physical product (including a+physical distribution medium), accompanied by the Corresponding Source fixed on a+durable physical medium customarily used for software interchange.+* **b)** Convey the object code in, or embodied in, a physical product (including a+physical distribution medium), accompanied by a written offer, valid for at least+three years and valid for as long as you offer spare parts or customer support for+that product model, to give anyone who possesses the object code either **(1)** a copy of+the Corresponding Source for all the software in the product that is covered by this+License, on a durable physical medium customarily used for software interchange, for+a price no more than your reasonable cost of physically performing this conveying of+source, or **(2)** access to copy the Corresponding Source from a network server at no+charge.+* **c)** Convey individual copies of the object code with a copy of the written offer to+provide the Corresponding Source. This alternative is allowed only occasionally and+noncommercially, and only if you received the object code with such an offer, in+accord with subsection 6b.+* **d)** Convey the object code by offering access from a designated place (gratis or for+a charge), and offer equivalent access to the Corresponding Source in the same way+through the same place at no further charge. You need not require recipients to copy+the Corresponding Source along with the object code. If the place to copy the object+code is a network server, the Corresponding Source may be on a different server+(operated by you or a third party) that supports equivalent copying facilities,+provided you maintain clear directions next to the object code saying where to find+the Corresponding Source. Regardless of what server hosts the Corresponding Source,+you remain obligated to ensure that it is available for as long as needed to satisfy+these requirements.+* **e)** Convey the object code using peer-to-peer transmission, provided you inform+other peers where the object code and Corresponding Source of the work are being+offered to the general public at no charge under subsection 6d.++A separable portion of the object code, whose source code is excluded from the+Corresponding Source as a System Library, need not be included in conveying the+object code work.++A “User Product” is either **(1)** a “consumer product”, which+means any tangible personal property which is normally used for personal, family, or+household purposes, or **(2)** anything designed or sold for incorporation into a+dwelling. In determining whether a product is a consumer product, doubtful cases+shall be resolved in favor of coverage. For a particular product received by a+particular user, “normally used” refers to a typical or common use of+that class of product, regardless of the status of the particular user or of the way+in which the particular user actually uses, or expects or is expected to use, the+product. A product is a consumer product regardless of whether the product has+substantial commercial, industrial or non-consumer uses, unless such uses represent+the only significant mode of use of the product.++“Installation Information” for a User Product means any methods,+procedures, authorization keys, or other information required to install and execute+modified versions of a covered work in that User Product from a modified version of+its Corresponding Source. The information must suffice to ensure that the continued+functioning of the modified object code is in no case prevented or interfered with+solely because modification has been made.++If you convey an object code work under this section in, or with, or specifically for+use in, a User Product, and the conveying occurs as part of a transaction in which+the right of possession and use of the User Product is transferred to the recipient+in perpetuity or for a fixed term (regardless of how the transaction is+characterized), the Corresponding Source conveyed under this section must be+accompanied by the Installation Information. But this requirement does not apply if+neither you nor any third party retains the ability to install modified object code+on the User Product (for example, the work has been installed in ROM).++The requirement to provide Installation Information does not include a requirement to+continue to provide support service, warranty, or updates for a work that has been+modified or installed by the recipient, or for the User Product in which it has been+modified or installed. Access to a network may be denied when the modification itself+materially and adversely affects the operation of the network or violates the rules+and protocols for communication across the network.++Corresponding Source conveyed, and Installation Information provided, in accord with+this section must be in a format that is publicly documented (and with an+implementation available to the public in source code form), and must require no+special password or key for unpacking, reading or copying.++### 7. Additional Terms++“Additional permissions” are terms that supplement the terms of this+License by making exceptions from one or more of its conditions. Additional+permissions that are applicable to the entire Program shall be treated as though they+were included in this License, to the extent that they are valid under applicable+law. If additional permissions apply only to part of the Program, that part may be+used separately under those permissions, but the entire Program remains governed by+this License without regard to the additional permissions.++When you convey a copy of a covered work, you may at your option remove any+additional permissions from that copy, or from any part of it. (Additional+permissions may be written to require their own removal in certain cases when you+modify the work.) You may place additional permissions on material, added by you to a+covered work, for which you have or can give appropriate copyright permission.++Notwithstanding any other provision of this License, for material you add to a+covered work, you may (if authorized by the copyright holders of that material)+supplement the terms of this License with terms:++* **a)** Disclaiming warranty or limiting liability differently from the terms of+sections 15 and 16 of this License; or+* **b)** Requiring preservation of specified reasonable legal notices or author+attributions in that material or in the Appropriate Legal Notices displayed by works+containing it; or+* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that+modified versions of such material be marked in reasonable ways as different from the+original version; or+* **d)** Limiting the use for publicity purposes of names of licensors or authors of the+material; or+* **e)** Declining to grant rights under trademark law for use of some trade names,+trademarks, or service marks; or+* **f)** Requiring indemnification of licensors and authors of that material by anyone+who conveys the material (or modified versions of it) with contractual assumptions of+liability to the recipient, for any liability that these contractual assumptions+directly impose on those licensors and authors.++All other non-permissive additional terms are considered “further+restrictions” within the meaning of section 10. If the Program as you received+it, or any part of it, contains a notice stating that it is governed by this License+along with a term that is a further restriction, you may remove that term. If a+license document contains a further restriction but permits relicensing or conveying+under this License, you may add to a covered work material governed by the terms of+that license document, provided that the further restriction does not survive such+relicensing or conveying.++If you add terms to a covered work in accord with this section, you must place, in+the relevant source files, a statement of the additional terms that apply to those+files, or a notice indicating where to find the applicable terms.++Additional terms, permissive or non-permissive, may be stated in the form of a+separately written license, or stated as exceptions; the above requirements apply+either way.++### 8. Termination++You may not propagate or modify a covered work except as expressly provided under+this License. Any attempt otherwise to propagate or modify it is void, and will+automatically terminate your rights under this License (including any patent licenses+granted under the third paragraph of section 11).++However, if you cease all violation of this License, then your license from a+particular copyright holder is reinstated **(a)** provisionally, unless and until the+copyright holder explicitly and finally terminates your license, and **(b)** permanently,+if the copyright holder fails to notify you of the violation by some reasonable means+prior to 60 days after the cessation.++Moreover, your license from a particular copyright holder is reinstated permanently+if the copyright holder notifies you of the violation by some reasonable means, this+is the first time you have received notice of violation of this License (for any+work) from that copyright holder, and you cure the violation prior to 30 days after+your receipt of the notice.++Termination of your rights under this section does not terminate the licenses of+parties who have received copies or rights from you under this License. If your+rights have been terminated and not permanently reinstated, you do not qualify to+receive new licenses for the same material under section 10.++### 9. Acceptance Not Required for Having Copies++You are not required to accept this License in order to receive or run a copy of the+Program. Ancillary propagation of a covered work occurring solely as a consequence of+using peer-to-peer transmission to receive a copy likewise does not require+acceptance. However, nothing other than this License grants you permission to+propagate or modify any covered work. These actions infringe copyright if you do not+accept this License. Therefore, by modifying or propagating a covered work, you+indicate your acceptance of this License to do so.++### 10. Automatic Licensing of Downstream Recipients++Each time you convey a covered work, the recipient automatically receives a license+from the original licensors, to run, modify and propagate that work, subject to this+License. You are not responsible for enforcing compliance by third parties with this+License.++An “entity transaction” is a transaction transferring control of an+organization, or substantially all assets of one, or subdividing an organization, or+merging organizations. If propagation of a covered work results from an entity+transaction, each party to that transaction who receives a copy of the work also+receives whatever licenses to the work the party's predecessor in interest had or+could give under the previous paragraph, plus a right to possession of the+Corresponding Source of the work from the predecessor in interest, if the predecessor+has it or can get it with reasonable efforts.++You may not impose any further restrictions on the exercise of the rights granted or+affirmed under this License. For example, you may not impose a license fee, royalty,+or other charge for exercise of rights granted under this License, and you may not+initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging+that any patent claim is infringed by making, using, selling, offering for sale, or+importing the Program or any portion of it.++### 11. Patents++A “contributor” is a copyright holder who authorizes use under this+License of the Program or a work on which the Program is based. The work thus+licensed is called the contributor's “contributor version”.++A contributor's “essential patent claims” are all patent claims owned or+controlled by the contributor, whether already acquired or hereafter acquired, that+would be infringed by some manner, permitted by this License, of making, using, or+selling its contributor version, but do not include claims that would be infringed+only as a consequence of further modification of the contributor version. For+purposes of this definition, “control” includes the right to grant patent+sublicenses in a manner consistent with the requirements of this License.++Each contributor grants you a non-exclusive, worldwide, royalty-free patent license+under the contributor's essential patent claims, to make, use, sell, offer for sale,+import and otherwise run, modify and propagate the contents of its contributor+version.++In the following three paragraphs, a “patent license” is any express+agreement or commitment, however denominated, not to enforce a patent (such as an+express permission to practice a patent or covenant not to sue for patent+infringement). To “grant” such a patent license to a party means to make+such an agreement or commitment not to enforce a patent against the party.++If you convey a covered work, knowingly relying on a patent license, and the+Corresponding Source of the work is not available for anyone to copy, free of charge+and under the terms of this License, through a publicly available network server or+other readily accessible means, then you must either **(1)** cause the Corresponding+Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the+patent license for this particular work, or **(3)** arrange, in a manner consistent with+the requirements of this License, to extend the patent license to downstream+recipients. “Knowingly relying” means you have actual knowledge that, but+for the patent license, your conveying the covered work in a country, or your+recipient's use of the covered work in a country, would infringe one or more+identifiable patents in that country that you have reason to believe are valid.++If, pursuant to or in connection with a single transaction or arrangement, you+convey, or propagate by procuring conveyance of, a covered work, and grant a patent+license to some of the parties receiving the covered work authorizing them to use,+propagate, modify or convey a specific copy of the covered work, then the patent+license you grant is automatically extended to all recipients of the covered work and+works based on it.++A patent license is “discriminatory” if it does not include within the+scope of its coverage, prohibits the exercise of, or is conditioned on the+non-exercise of one or more of the rights that are specifically granted under this+License. You may not convey a covered work if you are a party to an arrangement with+a third party that is in the business of distributing software, under which you make+payment to the third party based on the extent of your activity of conveying the+work, and under which the third party grants, to any of the parties who would receive+the covered work from you, a discriminatory patent license **(a)** in connection with+copies of the covered work conveyed by you (or copies made from those copies), or **(b)**+primarily for and in connection with specific products or compilations that contain+the covered work, unless you entered into that arrangement, or that patent license+was granted, prior to 28 March 2007.++Nothing in this License shall be construed as excluding or limiting any implied+license or other defenses to infringement that may otherwise be available to you+under applicable patent law.++### 12. No Surrender of Others' Freedom++If conditions are imposed on you (whether by court order, agreement or otherwise)+that contradict the conditions of this License, they do not excuse you from the+conditions of this License. If you cannot convey a covered work so as to satisfy+simultaneously your obligations under this License and any other pertinent+obligations, then as a consequence you may not convey it at all. For example, if you+agree to terms that obligate you to collect a royalty for further conveying from+those to whom you convey the Program, the only way you could satisfy both those terms+and this License would be to refrain entirely from conveying the Program.++### 13. Use with the GNU Affero General Public License++Notwithstanding any other provision of this License, you have permission to link or+combine any covered work with a work licensed under version 3 of the GNU Affero+General Public License into a single combined work, and to convey the resulting work.+The terms of this License will continue to apply to the part which is the covered+work, but the special requirements of the GNU Affero General Public License, section+13, concerning interaction through a network will apply to the combination as such.++### 14. Revised Versions of this License++The Free Software Foundation may publish revised and/or new versions of the GNU+General Public License from time to time. Such new versions will be similar in spirit+to the present version, but may differ in detail to address new problems or concerns.++Each version is given a distinguishing version number. If the Program specifies that+a certain numbered version of the GNU General Public License “or any later+version” applies to it, you have the option of following the terms and+conditions either of that numbered version or of any later version published by the+Free Software Foundation. If the Program does not specify a version number of the GNU+General Public License, you may choose any version ever published by the Free+Software Foundation.++If the Program specifies that a proxy can decide which future versions of the GNU+General Public License can be used, that proxy's public statement of acceptance of a+version permanently authorizes you to choose that version for the Program.++Later license versions may give you additional or different permissions. However, no+additional obligations are imposed on any author or copyright holder as a result of+your choosing to follow a later version.++### 15. Disclaimer of Warranty++THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES+PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER+EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE+QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE+DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.++### 16. Limitation of Liability++IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY+COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS+PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,+INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE+PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE+OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE+WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE+POSSIBILITY OF SUCH DAMAGES.++### 17. Interpretation of Sections 15 and 16++If the disclaimer of warranty and limitation of liability provided above cannot be+given local legal effect according to their terms, reviewing courts shall apply local+law that most closely approximates an absolute waiver of all civil liability in+connection with the Program, unless a warranty or assumption of liability accompanies+a copy of the Program in return for a fee.++_END OF TERMS AND CONDITIONS_++## How to Apply These Terms to Your New Programs++If you develop a new program, and you want it to be of the greatest possible use to+the public, the best way to achieve this is to make it free software which everyone+can redistribute and change under these terms.++To do so, attach the following notices to the program. It is safest to attach them+to the start of each source file to most effectively state the exclusion of warranty;+and each file should have at least the “copyright” line and a pointer to+where the full notice is found.++ <one line to give the program's name and a brief idea of what it does.>+ Copyright (C) <year> <name of author>++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.++Also add information on how to contact you by electronic and paper mail.++If the program does terminal interaction, make it output a short notice like this+when it starts in an interactive mode:++ <program> Copyright (C) <year> <name of author>+ This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'.+ This is free software, and you are welcome to redistribute it+ under certain conditions; type 'show c' for details.++The hypothetical commands `show w` and `show c` should show the appropriate parts of+the General Public License. Of course, your program's commands might be different;+for a GUI interface, you would use an “about box”.++You should also get your employer (if you work as a programmer) or school, if any, to+sign a “copyright disclaimer” for the program, if necessary. For more+information on this, and how to apply and follow the GNU GPL, see+<<http://www.gnu.org/licenses/>>.++The GNU General Public License does not permit incorporating your program into+proprietary programs. If your program is a subroutine library, you may consider it+more useful to permit linking proprietary applications with the library. If this is+what you want to do, use the GNU Lesser General Public License instead of this+License. But first, please read+<<http://www.gnu.org/philosophy/why-not-lgpl.html>>.
src/Network/Tox/C.hs view
@@ -3,4 +3,8 @@ ) where import Network.Tox.C.Callbacks as M+import Network.Tox.C.Constants as M+import Network.Tox.C.Options as M import Network.Tox.C.Tox as M+import Network.Tox.C.Type as M+import Network.Tox.C.Version as M
src/Network/Tox/C/CEnum.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE Trustworthy #-} module Network.Tox.C.CEnum where import Control.Applicative ((<$>))
src/Network/Tox/C/Callbacks.hs view
@@ -1,54 +1,83 @@ module Network.Tox.C.Callbacks where -import Control.Exception (bracket)-import Foreign.Ptr (FunPtr, freeHaskellFunPtr, nullFunPtr)+import Control.Exception (bracket)+import Foreign.Ptr (freeHaskellFunPtr, nullFunPtr) -import Network.Tox.C.Tox (Tox)-import qualified Network.Tox.C.Tox as Tox+import qualified Network.Tox.C.Tox as Tox+import Network.Tox.C.Type (Tox) -- | Low level event handler. The functions in this class are directly--- registered with the corresponding C callback. Since userdata @a@ needs to be--- in C memory, we recommend to keep it small, so marshalling costs are kept to--- a minimum. Use 'StablePtr' to pass larger opaque Haskell values around in C.+-- registered with the corresponding C callback. We use 'StablePtr' to pass+-- opaque Haskell values around in C. class CHandler a where- cSelfConnectionStatus :: Tox.SelfConnectionStatusCb a- cFriendName :: Tox.FriendNameCb a- cFriendStatusMessage :: Tox.FriendStatusMessageCb a- cFriendStatus :: Tox.FriendStatusCb a- cFriendConnectionStatus :: Tox.FriendConnectionStatusCb a- cFriendTyping :: Tox.FriendTypingCb a- cFriendReadReceipt :: Tox.FriendReadReceiptCb a- cFriendRequest :: Tox.FriendRequestCb a- cFriendMessage :: Tox.FriendMessageCb a- cFileRecvControl :: Tox.FileRecvControlCb a- cFileChunkRequest :: Tox.FileChunkRequestCb a- cFileRecv :: Tox.FileRecvCb a- cFileRecvChunk :: Tox.FileRecvChunkCb a- cFriendLossyPacket :: Tox.FriendLossyPacketCb a- cFriendLosslessPacket :: Tox.FriendLosslessPacketCb a+ cSelfConnectionStatus :: Tox.SelfConnectionStatusCb a+ cSelfConnectionStatus _ _ = return+ cFriendName :: Tox.FriendNameCb a+ cFriendName _ _ _ = return+ cFriendStatusMessage :: Tox.FriendStatusMessageCb a+ cFriendStatusMessage _ _ _ = return+ cFriendStatus :: Tox.FriendStatusCb a+ cFriendStatus _ _ _ = return+ cFriendConnectionStatus :: Tox.FriendConnectionStatusCb a+ cFriendConnectionStatus _ _ _ = return+ cFriendTyping :: Tox.FriendTypingCb a+ cFriendTyping _ _ _ = return+ cFriendReadReceipt :: Tox.FriendReadReceiptCb a+ cFriendReadReceipt _ _ _ = return+ cFriendRequest :: Tox.FriendRequestCb a+ cFriendRequest _ _ _ = return+ cFriendMessage :: Tox.FriendMessageCb a+ cFriendMessage _ _ _ _ = return+ cFileRecvControl :: Tox.FileRecvControlCb a+ cFileRecvControl _ _ _ _ = return+ cFileChunkRequest :: Tox.FileChunkRequestCb a+ cFileChunkRequest _ _ _ _ _ = return+ cFileRecv :: Tox.FileRecvCb a+ cFileRecv _ _ _ _ _ _ = return+ cFileRecvChunk :: Tox.FileRecvChunkCb a+ cFileRecvChunk _ _ _ _ _ = return+ cConferenceInvite :: Tox.ConferenceInviteCb a+ cConferenceInvite _ _ _ _ = return+ cConferenceMessage :: Tox.ConferenceMessageCb a+ cConferenceMessage _ _ _ _ _ = return+ cConferenceTitle :: Tox.ConferenceTitleCb a+ cConferenceTitle _ _ _ _ = return+ cConferencePeerName :: Tox.ConferencePeerNameCb a+ cConferencePeerName _ _ _ _ = return+ cConferencePeerListChanged :: Tox.ConferencePeerListChangedCb a+ cConferencePeerListChanged _ _ = return+ cFriendLossyPacket :: Tox.FriendLossyPacketCb a+ cFriendLossyPacket _ _ _ = return+ cFriendLosslessPacket :: Tox.FriendLosslessPacketCb a+ cFriendLosslessPacket _ _ _ = return -- | Installs an event handler into the passed 'Tox' instance. After performing -- the IO action, all event handlers are reset to null. This function does not -- save the original event handlers.-withHandler :: CHandler a => Tox a -> IO r -> IO r-withHandler tox =- install Tox.tox_callback_self_connection_status (Tox.wrapSelfConnectionStatusCb cSelfConnectionStatus ) .- install Tox.tox_callback_friend_name (Tox.wrapFriendNameCb cFriendName ) .- install Tox.tox_callback_friend_status_message (Tox.wrapFriendStatusMessageCb cFriendStatusMessage ) .- install Tox.tox_callback_friend_status (Tox.wrapFriendStatusCb cFriendStatus ) .- install Tox.tox_callback_friend_connection_status (Tox.wrapFriendConnectionStatusCb cFriendConnectionStatus) .- install Tox.tox_callback_friend_typing (Tox.wrapFriendTypingCb cFriendTyping ) .- install Tox.tox_callback_friend_read_receipt (Tox.wrapFriendReadReceiptCb cFriendReadReceipt ) .- install Tox.tox_callback_friend_request (Tox.wrapFriendRequestCb cFriendRequest ) .- install Tox.tox_callback_friend_message (Tox.wrapFriendMessageCb cFriendMessage ) .- install Tox.tox_callback_file_recv_control (Tox.wrapFileRecvControlCb cFileRecvControl ) .- install Tox.tox_callback_file_chunk_request (Tox.wrapFileChunkRequestCb cFileChunkRequest ) .- install Tox.tox_callback_file_recv (Tox.wrapFileRecvCb cFileRecv ) .- install Tox.tox_callback_file_recv_chunk (Tox.wrapFileRecvChunkCb cFileRecvChunk ) .- install Tox.tox_callback_friend_lossy_packet (Tox.wrapFriendLossyPacketCb cFriendLossyPacket ) .- install Tox.tox_callback_friend_lossless_packet (Tox.wrapFriendLosslessPacketCb cFriendLosslessPacket )+withCHandler :: CHandler a => Tox a -> IO r -> IO r+withCHandler tox =+ install Tox.tox_callback_self_connection_status (Tox.selfConnectionStatusCb cSelfConnectionStatus ) .+ install Tox.tox_callback_friend_name (Tox.friendNameCb cFriendName ) .+ install Tox.tox_callback_friend_status_message (Tox.friendStatusMessageCb cFriendStatusMessage ) .+ install Tox.tox_callback_friend_status (Tox.friendStatusCb cFriendStatus ) .+ install Tox.tox_callback_friend_connection_status (Tox.friendConnectionStatusCb cFriendConnectionStatus ) .+ install Tox.tox_callback_friend_typing (Tox.friendTypingCb cFriendTyping ) .+ install Tox.tox_callback_friend_read_receipt (Tox.friendReadReceiptCb cFriendReadReceipt ) .+ install Tox.tox_callback_friend_request (Tox.friendRequestCb cFriendRequest ) .+ install Tox.tox_callback_friend_message (Tox.friendMessageCb cFriendMessage ) .+ install Tox.tox_callback_file_recv_control (Tox.fileRecvControlCb cFileRecvControl ) .+ install Tox.tox_callback_file_chunk_request (Tox.fileChunkRequestCb cFileChunkRequest ) .+ install Tox.tox_callback_file_recv (Tox.fileRecvCb cFileRecv ) .+ install Tox.tox_callback_file_recv_chunk (Tox.fileRecvChunkCb cFileRecvChunk ) .+ install Tox.tox_callback_conference_invite (Tox.conferenceInviteCb cConferenceInvite ) .+ install Tox.tox_callback_conference_message (Tox.conferenceMessageCb cConferenceMessage ) .+ install Tox.tox_callback_conference_title (Tox.conferenceTitleCb cConferenceTitle ) .+ install Tox.tox_callback_conference_peer_name (Tox.conferencePeerNameCb cConferencePeerName ) .+ install Tox.tox_callback_conference_peer_list_changed (Tox.conferencePeerListChangedCb cConferencePeerListChanged ) .+ install Tox.tox_callback_friend_lossy_packet (Tox.friendLossyPacketCb cFriendLossyPacket ) .+ install Tox.tox_callback_friend_lossless_packet (Tox.friendLosslessPacketCb cFriendLosslessPacket ) where install cInstall wrapper action = bracket wrapper (uninstall cInstall) $ \cb -> do@@ -56,5 +85,5 @@ action uninstall cInstall cb = do- () <- cInstall tox nullFunPtr freeHaskellFunPtr cb+ cInstall tox nullFunPtr
+ src/Network/Tox/C/Constants.hs view
@@ -0,0 +1,50 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE Trustworthy #-}+module Network.Tox.C.Constants where++import Data.Word (Word32)+++--------------------------------------------------------------------------------+--+-- :: Numeric constants+--+--------------------------------------------------------------------------------++-- | The size of a Tox Public Key in bytes.+foreign import ccall tox_public_key_size :: Word32++-- | The size of a Tox Secret Key in bytes.+foreign import ccall tox_secret_key_size :: Word32++-- | The size of a Tox address in bytes. Tox addresses are in the format+-- [Public Key ('tox_public_key_size' bytes)][nospam (4 bytes)][checksum (2 bytes)].+--+-- The checksum is computed over the Public Key and the nospam value. The first+-- byte is an XOR of all the even bytes (0, 2, 4, ...), the second byte is an+-- XOR of all the odd bytes (1, 3, 5, ...) of the Public Key and nospam.+foreign import ccall tox_address_size :: Word32++-- | Maximum length of a nickname in bytes.+foreign import ccall tox_max_name_length :: Word32++-- | Maximum length of a status message in bytes.+foreign import ccall tox_max_status_message_length :: Word32++-- | Maximum length of a friend request message in bytes.+foreign import ccall tox_max_friend_request_length :: Word32++-- | Maximum length of a single message after which it should be split.+foreign import ccall tox_max_message_length :: Word32++-- | Maximum size of custom packets. TODO: should be LENGTH?+foreign import ccall tox_max_custom_packet_size :: Word32++-- | The number of bytes in a hash generated by tox_hash.+foreign import ccall tox_hash_length :: Word32++-- | The number of bytes in a file id.+foreign import ccall tox_file_id_length :: Word32++-- | Maximum file name length for file transfers.+foreign import ccall tox_max_filename_length :: Word32
+ src/Network/Tox/C/Options.hs view
@@ -0,0 +1,317 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE Safe #-}+module Network.Tox.C.Options where++import Control.Applicative ((<$>))+import Control.Exception (bracket)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import Data.Default.Class (Default (..))+import Data.Word (Word16)+import Foreign.C.String (CString, peekCString, withCString)+import Foreign.C.Types (CInt (..), CSize (..))+import Foreign.Ptr (Ptr, nullPtr)+import GHC.Generics (Generic)++import Network.Tox.C.CEnum++--------------------------------------------------------------------------------+--+-- :: Startup options+--+--------------------------------------------------------------------------------+++-- | Type of proxy used to connect to TCP relays.+data ProxyType+ = ProxyTypeNone+ -- Don't use a proxy.+ | ProxyTypeHttp+ -- HTTP proxy using CONNECT.+ | ProxyTypeSocks5+ -- SOCKS proxy for simple socket pipes.+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+++-- Type of savedata to create the Tox instance from.+data SavedataType+ = SavedataTypeNone+ -- No savedata.+ | SavedataTypeToxSave+ -- Savedata is one that was obtained from tox_get_savedata+ | SavedataTypeSecretKey+ -- Savedata is a secret key of length 'tox_secret_key_size'+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+++-- This struct contains all the startup options for Tox. You can either allocate+-- this object yourself, and pass it to tox_options_default, or call+-- tox_options_new to get a new default options object.+data Options = Options+ { ipv6Enabled :: Bool+ -- The type of socket to create.+ --+ -- If this is set to false, an IPv4 socket is created, which subsequently+ -- only allows IPv4 communication.+ -- If it is set to true, an IPv6 socket is created, allowing both IPv4 and+ -- IPv6 communication.++ , udpEnabled :: Bool+ -- Enable the use of UDP communication when available.+ --+ -- Setting this to false will force Tox to use TCP only. Communications will+ -- need to be relayed through a TCP relay node, potentially slowing them+ -- down. Disabling UDP support is necessary when using anonymous proxies or+ -- Tor.++ , proxyType :: ProxyType+ -- Pass communications through a proxy.++ , proxyHost :: String+ -- The IP address or DNS name of the proxy to be used.+ --+ -- If used, this must be non-'nullPtr' and be a valid DNS name. The name+ -- must not exceed 255 ('tox_max_filename_length') characters, and be in a+ -- NUL-terminated C string format (255 chars + 1 NUL byte).+ --+ -- This member is ignored (it can be 'nullPtr') if proxy_type is+ -- ProxyTypeNone.++ , proxyPort :: Word16+ -- The port to use to connect to the proxy server.+ --+ -- Ports must be in the range (1, 65535). The value is ignored if proxy_type+ -- is ProxyTypeNone.++ , startPort :: Word16+ -- The start port of the inclusive port range to attempt to use.+ --+ -- If both 'startPort' and 'endPort' are 0, the default port range will be+ -- used: [33445, 33545].+ --+ -- If either 'startPort' or 'endPort' is 0 while the other is non-zero, the+ -- non-zero port will be the only port in the range.+ --+ -- Having 'startPort' > 'endport' will yield the same behavior as if+ -- 'startPort' and 'endPort' were swapped.++ , endPort :: Word16+ -- The end port of the inclusive port range to attempt to use.++ , tcpPort :: Word16+ -- The port to use for the TCP server (relay). If 0, the TCP server is+ -- disabled.+ --+ -- Enabling it is not required for Tox to function properly.+ --+ -- When enabled, your Tox instance can act as a TCP relay for other Tox+ -- instance. This leads to increased traffic, thus when writing a client it+ -- is recommended to enable TCP server only if the user has an option to+ -- disable it.++ , savedataType :: SavedataType+ -- The type of savedata to load from.++ , savedataData :: ByteString+ -- The savedata bytes.+ }+ deriving (Eq, Read, Show, Generic)+++instance Default Options where+ def = Options+ { ipv6Enabled = True+ , udpEnabled = True+ , proxyType = ProxyTypeNone+ , proxyHost = ""+ , proxyPort = 0+ , startPort = 0+ , endPort = 0+ , tcpPort = 0+ , savedataType = SavedataTypeNone+ , savedataData = BS.empty+ }+++data OptionsStruct+type OptionsPtr = Ptr OptionsStruct+++foreign import ccall tox_options_get_ipv6_enabled :: OptionsPtr -> IO Bool+foreign import ccall tox_options_get_udp_enabled :: OptionsPtr -> IO Bool+foreign import ccall tox_options_get_proxy_type :: OptionsPtr -> IO (CEnum ProxyType)+foreign import ccall tox_options_get_proxy_host :: OptionsPtr -> IO CString+foreign import ccall tox_options_get_proxy_port :: OptionsPtr -> IO Word16+foreign import ccall tox_options_get_start_port :: OptionsPtr -> IO Word16+foreign import ccall tox_options_get_end_port :: OptionsPtr -> IO Word16+foreign import ccall tox_options_get_tcp_port :: OptionsPtr -> IO Word16+foreign import ccall tox_options_get_savedata_type :: OptionsPtr -> IO (CEnum SavedataType)+foreign import ccall tox_options_get_savedata_data :: OptionsPtr -> IO CString+foreign import ccall tox_options_get_savedata_length :: OptionsPtr -> IO CSize++foreign import ccall tox_options_set_ipv6_enabled :: OptionsPtr -> Bool -> IO ()+foreign import ccall tox_options_set_udp_enabled :: OptionsPtr -> Bool -> IO ()+foreign import ccall tox_options_set_proxy_type :: OptionsPtr -> CEnum ProxyType -> IO ()+foreign import ccall tox_options_set_proxy_host :: OptionsPtr -> CString -> IO ()+foreign import ccall tox_options_set_proxy_port :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_set_start_port :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_set_end_port :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_set_tcp_port :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_set_savedata_type :: OptionsPtr -> CEnum SavedataType -> IO ()+foreign import ccall tox_options_set_savedata_data :: OptionsPtr -> CString -> CSize -> IO ()+foreign import ccall tox_options_set_savedata_length :: OptionsPtr -> CSize -> IO ()+++data ErrOptionsNew+ = ErrOptionsNewOk+ -- The function returned successfully.++ | ErrOptionsNewMalloc+ -- The function was unable to allocate enough memory to store the internal+ -- structures for the Tox options object.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Allocates a new Tox_Options object and initialises it with the default+-- options. This function can be used to preserve long term ABI compatibility by+-- giving the responsibility of allocation and deallocation to the Tox library.+--+-- Objects returned from this function must be freed using the tox_options_free+-- function.+--+-- @return A new 'OptionsPtr' with default options or 'nullPtr' on failure.+foreign import ccall tox_options_new :: CErr ErrOptionsNew -> IO OptionsPtr++toxOptionsNew :: IO (Either ErrOptionsNew OptionsPtr)+toxOptionsNew = callErrFun tox_options_new+++-- | Releases all resources associated with an options objects.+--+-- Passing a pointer that was not returned by tox_options_new results in+-- undefined behaviour.+foreign import ccall tox_options_free :: OptionsPtr -> IO ()+++withToxOptions :: (OptionsPtr -> IO r) -> IO (Either ErrOptionsNew r)+withToxOptions f =+ bracket toxOptionsNew (either (const $ return ()) tox_options_free) $ \case+ Left err -> return $ Left err+ Right ok -> Right <$> f ok+++-- | Read 'Options' from an 'OptionsPtr'.+--+-- If the passed pointer is 'nullPtr', the behaviour is undefined.+peekToxOptions :: OptionsPtr -> IO Options+peekToxOptions ptr = do+ cIpv6Enabled <- tox_options_get_ipv6_enabled ptr+ cUdpEnabled <- tox_options_get_udp_enabled ptr+ cProxyType <- tox_options_get_proxy_type ptr+ cProxyHost <- tox_options_get_proxy_host ptr >>= peekNullableString+ cProxyPort <- tox_options_get_proxy_port ptr+ cStartPort <- tox_options_get_start_port ptr+ cEndPort <- tox_options_get_end_port ptr+ cTcpPort <- tox_options_get_tcp_port ptr+ cSavedataType <- tox_options_get_savedata_type ptr+ cSavedataData <- tox_options_get_savedata_data ptr+ cSavedataLength <- tox_options_get_savedata_length ptr+ cSavedata <- BS.packCStringLen+ ( cSavedataData+ , fromIntegral cSavedataLength)+ return Options+ { ipv6Enabled = cIpv6Enabled+ , udpEnabled = cUdpEnabled+ , proxyType = fromCEnum cProxyType+ , proxyHost = cProxyHost+ , proxyPort = cProxyPort+ , startPort = cStartPort+ , endPort = cEndPort+ , tcpPort = cTcpPort+ , savedataType = fromCEnum cSavedataType+ , savedataData = cSavedata+ }++ where+ -- 'peekCString' doesn't handle NULL strings as empty, unlike+ -- 'packCStringLen', which ignores the pointer to zero-length 'CString's.+ peekNullableString p =+ if p == nullPtr+ then return ""+ else peekCString p+++-- | Save the options from the passed 'OptionsPtr', perform an IO action, and+-- restore the original values.+--+-- If the passed pointer is 'nullPtr', the behaviour is undefined.+saveToxOptions :: OptionsPtr -> IO r -> IO r+saveToxOptions ptr =+ bracket saveOptions restoreOptions . const+ where+ saveOptions = do+ v0 <- tox_options_get_ipv6_enabled ptr+ v1 <- tox_options_get_udp_enabled ptr+ v2 <- tox_options_get_proxy_type ptr+ v3 <- tox_options_get_proxy_host ptr+ v4 <- tox_options_get_proxy_port ptr+ v5 <- tox_options_get_start_port ptr+ v6 <- tox_options_get_end_port ptr+ v7 <- tox_options_get_tcp_port ptr+ v8 <- tox_options_get_savedata_type ptr+ sd <- tox_options_get_savedata_data ptr+ sl <- tox_options_get_savedata_length ptr+ return (v0, v1, v2, v3, v4, v5, v6, v7, v8, sd, sl)++ restoreOptions (v0, v1, v2, v3, v4, v5, v6, v7, v8, sd, sl) = do+ tox_options_set_ipv6_enabled ptr v0+ tox_options_set_udp_enabled ptr v1+ tox_options_set_proxy_type ptr v2+ tox_options_set_proxy_host ptr v3+ tox_options_set_proxy_port ptr v4+ tox_options_set_start_port ptr v5+ tox_options_set_end_port ptr v6+ tox_options_set_tcp_port ptr v7+ tox_options_set_savedata_type ptr v8+ tox_options_set_savedata_data ptr sd sl+ tox_options_set_savedata_length ptr sl+++-- | Fill in the 'Options' values into the 'OptionsPtr' and perform the IO+-- action afterwards.+--+-- This function restores the original values from the 'OptionsPtr' after+-- performing the action.+--+-- If the passed pointer is 'nullPtr', the behaviour is undefined.+pokeToxOptions :: Options -> OptionsPtr -> IO r -> IO r+pokeToxOptions options ptr action =+ saveToxOptions ptr $+ withCString (proxyHost options) $ \host ->+ BS.useAsCStringLen (savedataData options) $ \(saveData, saveLenInt) -> do+ let saveLen = fromIntegral saveLenInt+ tox_options_set_ipv6_enabled ptr $ ipv6Enabled options+ tox_options_set_udp_enabled ptr $ udpEnabled options+ tox_options_set_proxy_type ptr $ toCEnum $ proxyType options+ tox_options_set_proxy_host ptr host+ tox_options_set_proxy_port ptr $ proxyPort options+ tox_options_set_start_port ptr $ startPort options+ tox_options_set_end_port ptr $ endPort options+ tox_options_set_tcp_port ptr $ tcpPort options+ tox_options_set_savedata_type ptr $ toCEnum $ savedataType options+ tox_options_set_savedata_data ptr saveData saveLen+ tox_options_set_savedata_length ptr saveLen+ action+++-- | Allocate a new C options pointer, fills in the values from 'Options',+-- calls the processor function, and deallocates the options pointer.+--+-- The 'OptionsPtr' passed to the processor function is never 'nullPtr'. If+-- allocation fails, the IO action evaluates to 'Left' with an appropriate+-- error code.+withOptions :: Options -> (OptionsPtr -> IO r) -> IO (Either ErrOptionsNew r)+withOptions options f =+ withToxOptions $ \ptr ->+ pokeToxOptions options ptr (f ptr)
src/Network/Tox/C/Tox.hs view
@@ -1,1798 +1,2405 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE Trustworthy #-}--- | Public core API for Tox clients.------ Every function that can fail takes a function-specific error code pointer--- that can be used to diagnose problems with the Tox state or the function--- arguments. The error code pointer can be 'nullPtr', which does not influence--- the function's behaviour, but can be done if the reason for failure is--- irrelevant to the client.------ The exception to this rule are simple allocation functions whose only failure--- mode is allocation failure. They return 'nullPtr' in that case, and do not--- set an error code.------ Every error code type has an OK value to which functions will set their error--- code value on success. Clients can keep their error code uninitialised before--- passing it to a function. The library guarantees that after returning, the--- value pointed to by the error code pointer has been initialised.------ Functions with pointer parameters often have a 'nullPtr' error code, meaning--- they could not perform any operation, because one of the required parameters--- was 'nullPtr'. Some functions operate correctly or are defined as effectless--- on 'nullPtr'.------ Some functions additionally return a value outside their return type domain,--- or a bool containing true on success and false on failure.------ All functions that take a Tox instance pointer will cause undefined behaviour--- when passed a 'nullPtr' Tox pointer.------ All integer values are expected in host byte order.------ Functions with parameters with enum types cause unspecified behaviour if the--- enumeration value is outside the valid range of the type. If possible, the--- function will try to use a sane default, but there will be no error code, and--- one possible action for the function to take is to have no effect.------ \subsection events Events and callbacks------ Events are handled by callbacks. One callback can be registered per event.--- All events have a callback function type named `tox_{event}_cb` and a--- function to register it named `tox_callback_{event}`. Passing a 'nullPtr'--- callback will result in no callback being registered for that event. Only one--- callback per event can be registered, so if a client needs multiple event--- listeners, it needs to implement the dispatch functionality itself.------ \subsection threading Threading implications------ It is possible to run multiple concurrent threads with a Tox instance for--- each thread. It is also possible to run all Tox instances in the same thread.--- A common way to run Tox (multiple or single instance) is to have one thread--- running a simple tox_iterate loop, sleeping for tox_iteration_interval--- milliseconds on each iteration.------ If you want to access a single Tox instance from multiple threads, access to--- the instance must be synchronised. While multiple threads can concurrently--- access multiple different Tox instances, no more than one API function can--- operate on a single instance at any given time.------ Functions that write to variable length byte arrays will always have a size--- function associated with them. The result of this size function is only valid--- until another mutating function (one that takes a pointer to non-const Tox)--- is called. Thus, clients must ensure that no other thread calls a mutating--- function between the call to the size function and the call to the retrieval--- function.------ E.g. to get the current nickname, one would write------ \code--- CSize length = tox_self_get_name_size(tox);--- CString name = malloc(length);--- if (!name) abort();--- tox_self_get_name(tox, name);--- \endcode------ If any other thread calls tox_self_set_name while this thread is allocating--- memory, the length may have become invalid, and the call to tox_self_get_name--- may cause undefined behaviour.----module Network.Tox.C.Tox where--import Control.Applicative ((<$>), (<*>))-import Control.Exception (bracket)-import qualified Crypto.Saltine.Class as Sodium (encode)-import Crypto.Saltine.Core.Box (CombinedKey, Nonce, PublicKey,- SecretKey)-import Data.ByteString (ByteString)-import qualified Data.ByteString as BS-import Data.ByteString.Arbitrary (fromABS)-import Data.Default.Class (Default (..))-import Data.Word (Word16, Word32, Word64)-import Foreign.C.String (CString, peekCString, withCString)-import Foreign.C.Types (CInt (..), CSize (..))-import Foreign.Ptr (FunPtr, Ptr, nullPtr)-import GHC.Generics (Generic)-import Test.QuickCheck.Arbitrary (Arbitrary (..),- arbitraryBoundedEnum)--import Network.Tox.C.CEnum---- | The Tox instance type. All the state associated with a connection is held--- within the instance. Multiple instances can exist and operate concurrently.--- The maximum number of Tox instances that can exist on a single network device--- is limited. Note that this is not just a per-process limit, since the--- limiting factor is the number of usable ports on a device.-data ToxStruct a-type Tox a = Ptr (ToxStruct a)----------------------------------------------------------------------------------------- :: API version---------------------------------------------------------------------------------------- | The major version number. Incremented when the API or ABI changes in an--- incompatible way.-foreign import ccall tox_version_major :: Word32---- | The minor version number. Incremented when functionality is added without--- breaking the API or ABI. Set to 0 when the major version number is--- incremented.-foreign import ccall tox_version_minor :: Word32---- | The patch or revision number. Incremented when bugfixes are applied without--- changing any functionality or API or ABI.-foreign import ccall tox_version_patch :: Word32---- | Return whether the compiled library version is compatible with the passed--- version numbers.-foreign import ccall tox_version_is_compatible :: Word32 -> Word32 -> Word32 -> Bool----------------------------------------------------------------------------------------- :: Numeric constants---------------------------------------------------------------------------------------- | The size of a Tox Public Key in bytes.-foreign import ccall tox_public_key_size :: Word32---- | The size of a Tox Secret Key in bytes.-foreign import ccall tox_secret_key_size :: Word32---- | The size of a Tox address in bytes. Tox addresses are in the format--- [Public Key ('tox_public_key_size' bytes)][nospam (4 bytes)][checksum (2 bytes)].------ The checksum is computed over the Public Key and the nospam value. The first--- byte is an XOR of all the even bytes (0, 2, 4, ...), the second byte is an--- XOR of all the odd bytes (1, 3, 5, ...) of the Public Key and nospam.-foreign import ccall tox_address_size :: Word32---- | Maximum length of a nickname in bytes.-foreign import ccall tox_max_name_length :: Word32---- | Maximum length of a status message in bytes.-foreign import ccall tox_max_status_message_length :: Word32---- | Maximum length of a friend request message in bytes.-foreign import ccall tox_max_friend_request_length :: Word32---- | Maximum length of a single message after which it should be split.-foreign import ccall tox_max_message_length :: Word32---- | Maximum size of custom packets. TODO: should be LENGTH?-foreign import ccall tox_max_custom_packet_size :: Word32---- | The number of bytes in a hash generated by tox_hash.-foreign import ccall tox_hash_length :: Word32---- | The number of bytes in a file id.-foreign import ccall tox_file_id_length :: Word32---- | Maximum file name length for file transfers.-foreign import ccall tox_max_filename_length :: Word32----------------------------------------------------------------------------------------- :: Global enumerations----------------------------------------------------------------------------------------- | Represents the possible statuses a client can have.-data UserStatus- = UserStatusNone- -- ^ User is online and available.- | UserStatusAway- -- ^ User is away. Clients can set this e.g. after a user defined inactivity- -- time.- | UserStatusBusy- -- ^ User is busy. Signals to other clients that this client does not- -- currently wish to communicate.- deriving (Eq, Ord, Enum, Bounded, Read, Show)--instance Arbitrary UserStatus where- arbitrary = arbitraryBoundedEnum----- | Represents message types for tox_friend_send_message and group chat--- messages.-data MessageType- = MessageTypeNormal- -- ^ Normal text message. Similar to PRIVMSG on IRC.- | MessageTypeAction- -- ^ A message describing an user action. This is similar to /me (CTCP- -- ACTION) on IRC.- deriving (Eq, Ord, Enum, Bounded, Read, Show)--instance Arbitrary MessageType where- arbitrary = arbitraryBoundedEnum----------------------------------------------------------------------------------------- :: Startup options----------------------------------------------------------------------------------------- | Type of proxy used to connect to TCP relays.-data ProxyType- = ProxyTypeNone- -- Don't use a proxy.- | ProxyTypeHttp- -- HTTP proxy using CONNECT.- | ProxyTypeSocks5- -- SOCKS proxy for simple socket pipes.- deriving (Eq, Ord, Enum, Bounded, Read, Show)--instance Arbitrary ProxyType where- arbitrary = arbitraryBoundedEnum----- Type of savedata to create the Tox instance from.-data SavedataType- = SavedataTypeNone- -- No savedata.- | SavedataTypeToxSave- -- Savedata is one that was obtained from tox_get_savedata- | SavedataTypeSecretKey- -- Savedata is a secret key of length 'tox_secret_key_size'- deriving (Eq, Ord, Enum, Bounded, Read, Show)--instance Arbitrary SavedataType where- arbitrary = arbitraryBoundedEnum----- This struct contains all the startup options for Tox. You can either allocate--- this object yourself, and pass it to tox_options_default, or call--- tox_options_new to get a new default options object.-data Options = Options- { ipv6Enabled :: Bool- -- The type of socket to create.- --- -- If this is set to false, an IPv4 socket is created, which subsequently- -- only allows IPv4 communication.- -- If it is set to true, an IPv6 socket is created, allowing both IPv4 and- -- IPv6 communication.-- , udpEnabled :: Bool- -- Enable the use of UDP communication when available.- --- -- Setting this to false will force Tox to use TCP only. Communications will- -- need to be relayed through a TCP relay node, potentially slowing them- -- down. Disabling UDP support is necessary when using anonymous proxies or- -- Tor.-- , proxyType :: ProxyType- -- Pass communications through a proxy.-- , proxyHost :: String- -- The IP address or DNS name of the proxy to be used.- --- -- If used, this must be non-'nullPtr' and be a valid DNS name. The name- -- must not exceed 255 ('tox_max_filename_length') characters, and be in a- -- NUL-terminated C string format (255 chars + 1 NUL byte).- --- -- This member is ignored (it can be 'nullPtr') if proxy_type is- -- ProxyTypeNone.-- , proxyPort :: Word16- -- The port to use to connect to the proxy server.- --- -- Ports must be in the range (1, 65535). The value is ignored if proxy_type- -- is ProxyTypeNone.-- , startPort :: Word16- -- The start port of the inclusive port range to attempt to use.- --- -- If both 'startPort' and 'endPort' are 0, the default port range will be- -- used: [33445, 33545].- --- -- If either 'startPort' or 'endPort' is 0 while the other is non-zero, the- -- non-zero port will be the only port in the range.- --- -- Having 'startPort' > 'endport' will yield the same behavior as if- -- 'startPort' and 'endPort' were swapped.-- , endPort :: Word16- -- The end port of the inclusive port range to attempt to use.-- , tcpPort :: Word16- -- The port to use for the TCP server (relay). If 0, the TCP server is- -- disabled.- --- -- Enabling it is not required for Tox to function properly.- --- -- When enabled, your Tox instance can act as a TCP relay for other Tox- -- instance. This leads to increased traffic, thus when writing a client it- -- is recommended to enable TCP server only if the user has an option to- -- disable it.-- , savedataType :: SavedataType- -- The type of savedata to load from.-- , savedataData :: ByteString- -- The savedata bytes.- }- deriving (Eq, Read, Show, Generic)---instance Default Options where- def = Options- { ipv6Enabled = True- , udpEnabled = True- , proxyType = ProxyTypeNone- , proxyHost = ""- , proxyPort = 0- , startPort = 0- , endPort = 0- , tcpPort = 0- , savedataType = SavedataTypeNone- , savedataData = BS.empty- }---instance Arbitrary Options where- arbitrary = Options- <$> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitraryCString- <*> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitrary- <*> (fromABS <$> arbitrary)- where- arbitraryCString = filter (/= '\NUL') <$> arbitrary---data OptionsStruct-type OptionsPtr = Ptr OptionsStruct---foreign import ccall tox_options_get_ipv6_enabled :: OptionsPtr -> IO Bool-foreign import ccall tox_options_get_udp_enabled :: OptionsPtr -> IO Bool-foreign import ccall tox_options_get_proxy_type :: OptionsPtr -> IO (CEnum ProxyType)-foreign import ccall tox_options_get_proxy_host :: OptionsPtr -> IO CString-foreign import ccall tox_options_get_proxy_port :: OptionsPtr -> IO Word16-foreign import ccall tox_options_get_start_port :: OptionsPtr -> IO Word16-foreign import ccall tox_options_get_end_port :: OptionsPtr -> IO Word16-foreign import ccall tox_options_get_tcp_port :: OptionsPtr -> IO Word16-foreign import ccall tox_options_get_savedata_type :: OptionsPtr -> IO (CEnum SavedataType)-foreign import ccall tox_options_get_savedata_data :: OptionsPtr -> IO CString-foreign import ccall tox_options_get_savedata_length :: OptionsPtr -> IO CSize--foreign import ccall tox_options_set_ipv6_enabled :: OptionsPtr -> Bool -> IO ()-foreign import ccall tox_options_set_udp_enabled :: OptionsPtr -> Bool -> IO ()-foreign import ccall tox_options_set_proxy_type :: OptionsPtr -> CEnum ProxyType -> IO ()-foreign import ccall tox_options_set_proxy_host :: OptionsPtr -> CString -> IO ()-foreign import ccall tox_options_set_proxy_port :: OptionsPtr -> Word16 -> IO ()-foreign import ccall tox_options_set_start_port :: OptionsPtr -> Word16 -> IO ()-foreign import ccall tox_options_set_end_port :: OptionsPtr -> Word16 -> IO ()-foreign import ccall tox_options_set_tcp_port :: OptionsPtr -> Word16 -> IO ()-foreign import ccall tox_options_set_savedata_type :: OptionsPtr -> CEnum SavedataType -> IO ()-foreign import ccall tox_options_set_savedata_data :: OptionsPtr -> CString -> CSize -> IO ()-foreign import ccall tox_options_set_savedata_length :: OptionsPtr -> CSize -> IO ()---data ErrOptionsNew- = ErrOptionsNewOk- -- The function returned successfully.-- | ErrOptionsNewMalloc- -- The function was unable to allocate enough memory to store the internal- -- structures for the Tox options object.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Allocates a new Tox_Options object and initialises it with the default--- options. This function can be used to preserve long term ABI compatibility by--- giving the responsibility of allocation and deallocation to the Tox library.------ Objects returned from this function must be freed using the tox_options_free--- function.------ @return A new 'OptionsPtr' with default options or 'nullPtr' on failure.-foreign import ccall tox_options_new :: CErr ErrOptionsNew -> IO OptionsPtr--toxOptionsNew :: IO (Either ErrOptionsNew OptionsPtr)-toxOptionsNew = callErrFun tox_options_new----- | Releases all resources associated with an options objects.------ Passing a pointer that was not returned by tox_options_new results in--- undefined behaviour.-foreign import ccall tox_options_free :: OptionsPtr -> IO ()---withToxOptions :: (OptionsPtr -> IO r) -> IO (Either ErrOptionsNew r)-withToxOptions f =- bracket toxOptionsNew (either (const $ return ()) tox_options_free) $ \case- Left err -> return $ Left err- Right ok -> Right <$> f ok----- | Read 'Options' from an 'OptionsPtr'.------ If the passed pointer is 'nullPtr', the behaviour is undefined.-peekToxOptions :: OptionsPtr -> IO Options-peekToxOptions ptr = do- cIpv6Enabled <- tox_options_get_ipv6_enabled ptr- cUdpEnabled <- tox_options_get_udp_enabled ptr- cProxyType <- tox_options_get_proxy_type ptr- cProxyHost <- tox_options_get_proxy_host ptr >>= peekNullableString- cProxyPort <- tox_options_get_proxy_port ptr- cStartPort <- tox_options_get_start_port ptr- cEndPort <- tox_options_get_end_port ptr- cTcpPort <- tox_options_get_tcp_port ptr- cSavedataType <- tox_options_get_savedata_type ptr- cSavedataData <- tox_options_get_savedata_data ptr- cSavedataLength <- tox_options_get_savedata_length ptr- cSavedata <- BS.packCStringLen- ( cSavedataData- , fromIntegral cSavedataLength)- return Options- { ipv6Enabled = cIpv6Enabled- , udpEnabled = cUdpEnabled- , proxyType = fromCEnum cProxyType- , proxyHost = cProxyHost- , proxyPort = cProxyPort- , startPort = cStartPort- , endPort = cEndPort- , tcpPort = cTcpPort- , savedataType = fromCEnum cSavedataType- , savedataData = cSavedata- }-- where- -- 'peekCString' doesn't handle NULL strings as empty, unlike- -- 'packCStringLen', which ignores the pointer to zero-length 'CString's.- peekNullableString p =- if p == nullPtr- then return ""- else peekCString p----- | Save the options from the passed 'OptionsPtr', perform an IO action, and--- restore the original values.------ If the passed pointer is 'nullPtr', the behaviour is undefined.-saveToxOptions :: OptionsPtr -> IO r -> IO r-saveToxOptions ptr =- bracket saveOptions restoreOptions . const- where- saveOptions = do- v0 <- tox_options_get_ipv6_enabled ptr- v1 <- tox_options_get_udp_enabled ptr- v2 <- tox_options_get_proxy_type ptr- v3 <- tox_options_get_proxy_host ptr- v4 <- tox_options_get_proxy_port ptr- v5 <- tox_options_get_start_port ptr- v6 <- tox_options_get_end_port ptr- v7 <- tox_options_get_tcp_port ptr- v8 <- tox_options_get_savedata_type ptr- sd <- tox_options_get_savedata_data ptr- sl <- tox_options_get_savedata_length ptr- return (v0, v1, v2, v3, v4, v5, v6, v7, v8, sd, sl)-- restoreOptions (v0, v1, v2, v3, v4, v5, v6, v7, v8, sd, sl) = do- tox_options_set_ipv6_enabled ptr v0- tox_options_set_udp_enabled ptr v1- tox_options_set_proxy_type ptr v2- tox_options_set_proxy_host ptr v3- tox_options_set_proxy_port ptr v4- tox_options_set_start_port ptr v5- tox_options_set_end_port ptr v6- tox_options_set_tcp_port ptr v7- tox_options_set_savedata_type ptr v8- tox_options_set_savedata_data ptr sd sl- tox_options_set_savedata_length ptr sl----- | Fill in the 'Options' values into the 'OptionsPtr' and perform the IO--- action afterwards.------ This function restores the original values from the 'OptionsPtr' after--- performing the action.------ If the passed pointer is 'nullPtr', the behaviour is undefined.-pokeToxOptions :: Options -> OptionsPtr -> IO r -> IO r-pokeToxOptions options ptr action =- saveToxOptions ptr $- withCString (proxyHost options) $ \host ->- BS.useAsCStringLen (savedataData options) $ \(saveData, saveLenInt) -> do- let saveLen = fromIntegral saveLenInt- tox_options_set_ipv6_enabled ptr $ ipv6Enabled options- tox_options_set_udp_enabled ptr $ udpEnabled options- tox_options_set_proxy_type ptr $ toCEnum $ proxyType options- tox_options_set_proxy_host ptr host- tox_options_set_proxy_port ptr $ proxyPort options- tox_options_set_start_port ptr $ startPort options- tox_options_set_end_port ptr $ endPort options- tox_options_set_tcp_port ptr $ tcpPort options- tox_options_set_savedata_type ptr $ toCEnum $ savedataType options- tox_options_set_savedata_data ptr saveData saveLen- tox_options_set_savedata_length ptr saveLen- action----- | Allocate a new C options pointer, fills in the values from 'Options',--- calls the processor function, and deallocates the options pointer.------ The 'OptionsPtr' passed to the processor function is never 'nullPtr'. If--- allocation fails, the IO action evaluates to 'Left' with an appropriate--- error code.-withOptions :: Options -> (OptionsPtr -> IO r) -> IO (Either ErrOptionsNew r)-withOptions options f =- withToxOptions $ \ptr ->- pokeToxOptions options ptr (f ptr)----------------------------------------------------------------------------------------- :: Creation and destruction---------------------------------------------------------------------------------------data ErrNew- = ErrNewOk- -- The function returned successfully.-- | ErrNewNull- -- One of the arguments to the function was 'nullPtr' when it was not- -- expected.-- | ErrNewMalloc- -- The function was unable to allocate enough memory to store the internal- -- structures for the Tox object.-- | ErrNewPortAlloc- -- The function was unable to bind to a port. This may mean that all ports- -- have already been bound, e.g. by other Tox instances, or it may mean a- -- permission error. You may be able to gather more information from errno.-- | ErrNewProxyBadType- -- proxy_type was invalid.-- | ErrNewProxyBadHost- -- proxy_type was valid but the proxy_host passed had an invalid format or- -- was 'nullPtr'.-- | ErrNewProxyBadPort- -- proxy_type was valid, but the proxy_port was invalid.-- | ErrNewProxyNotFound- -- The proxy address passed could not be resolved.-- | ErrNewLoadEncrypted- -- The byte array to be loaded contained an encrypted save.-- | ErrNewLoadBadFormat- -- The data format was invalid. This can happen when loading data that was- -- saved by an older version of Tox, or when the data has been corrupted.- -- When loading from badly formatted data, some data may have been loaded,- -- and the rest is discarded. Passing an invalid length parameter also- -- causes this error.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- @brief Creates and initialises a new Tox instance with the options passed.------ This function will bring the instance into a valid state. Running the event--- loop with a new instance will operate correctly.------ If loading failed or succeeded only partially, the new or partially loaded--- instance is returned and an error code is set.------ @param options An options object as described above. If this parameter is--- 'nullPtr', the default options are used.------ @see tox_iterate for the event loop.------ @return A new Tox instance pointer on success or 'nullPtr' on failure.-foreign import ccall tox_new :: OptionsPtr -> CErr ErrNew -> IO (Tox a)--toxNew :: OptionsPtr -> IO (Either ErrNew (Tox a))-toxNew = callErrFun . tox_new---- | Releases all resources associated with the Tox instance and disconnects--- from the network.------ After calling this function, the Tox pointer becomes invalid. No other--- functions can be called, and the pointer value can no longer be read.-foreign import ccall tox_kill :: Tox a -> IO ()--withTox :: OptionsPtr -> (Tox a -> IO r) -> IO (Either ErrNew r)-withTox options f =- bracket (toxNew options) (either (const $ return ()) tox_kill) $ \case- Left err -> return $ Left err- Right ok -> Right <$> f ok---withDefaultTox :: (Tox a -> IO r) -> IO (Either ErrNew r)-withDefaultTox = withTox nullPtr----- | Calculates the number of bytes required to store the tox instance with--- tox_get_savedata. This function cannot fail. The result is always greater--- than 0.------ @see threading for concurrency implications.-foreign import ccall tox_get_savedata_size :: Tox a -> IO CSize---- | Store all information associated with the tox instance to a byte array.------ @param data A memory region large enough to store the tox instance data.--- Call tox_get_savedata_size to find the number of bytes required. If this--- parameter is 'nullPtr', this function has no effect.-foreign import ccall tox_get_savedata :: Tox a -> CString -> IO ()----------------------------------------------------------------------------------------- :: Connection lifecycle and event loop---------------------------------------------------------------------------------------data ErrBootstrap- = ErrBootstrapOk- -- The function returned successfully.-- | ErrBootstrapNull- -- One of the arguments to the function was 'nullPtr' when it was not- -- expected.-- | ErrBootstrapBadHost- -- The address could not be resolved to an IP address, or the IP address- -- passed was invalid.-- | ErrBootstrapBadPort- -- The port passed was invalid. The valid port range is (1, 65535).- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Sends a "get nodes" request to the given bootstrap node with IP, port, and--- public key to setup connections.------ This function will attempt to connect to the node using UDP. You must use--- this function even if COptions.udp_enabled was set to false.------ @param address The hostname or IP address (IPv4 or IPv6) of the node.--- @param port The port on the host on which the bootstrap Tox instance is--- listening.--- @param public_key The long term public key of the bootstrap node--- ('tox_public_key_size' bytes).--- @return true on success.-foreign import ccall tox_bootstrap :: Tox a -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO ()--callBootstrapFun- :: (Tox a -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO ())- -> Tox a -> String -> Word16 -> PublicKey -> IO (Either ErrBootstrap ())-callBootstrapFun f tox address port pubKey =- withCString address $ \address' ->- BS.useAsCString (Sodium.encode pubKey) $ \pubKey' ->- callErrFun $ f tox address' (fromIntegral port) pubKey'--toxBootstrap :: Tox a -> String -> Word16 -> PublicKey -> IO (Either ErrBootstrap ())-toxBootstrap = callBootstrapFun tox_bootstrap----- | Adds additional host:port pair as TCP relay.------ This function can be used to initiate TCP connections to different ports on--- the same bootstrap node, or to add TCP relays without using them as--- bootstrap nodes.------ @param address The hostname or IP address (IPv4 or IPv6) of the TCP relay.--- @param port The port on the host on which the TCP relay is listening.--- @param public_key The long term public key of the TCP relay--- ('tox_public_key_size' bytes).--- @return true on success.-foreign import ccall tox_add_tcp_relay :: Tox a -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO ()--toxAddTcpRelay :: Tox a -> String -> Word16 -> PublicKey -> IO (Either ErrBootstrap ())-toxAddTcpRelay = callBootstrapFun tox_add_tcp_relay----- | Protocols that can be used to connect to the network or friends.-data Connection- = ConnectionNone- -- There is no connection. This instance, or the friend the state change is- -- about, is now offline.-- | ConnectionTcp- -- A TCP connection has been established. For the own instance, this means- -- it is connected through a TCP relay, only. For a friend, this means that- -- the connection to that particular friend goes through a TCP relay.-- | ConnectionUdp- -- A UDP connection has been established. For the own instance, this means- -- it is able to send UDP packets to DHT nodes, but may still be connected- -- to a TCP relay. For a friend, this means that the connection to that- -- particular friend was built using direct UDP packets.- deriving (Eq, Ord, Enum, Bounded, Read, Show)--instance Arbitrary Connection where- arbitrary = arbitraryBoundedEnum----- | @param connection_status Whether we are connected to the DHT.-type SelfConnectionStatusCb a = Tox a -> CEnum Connection -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapSelfConnectionStatusCb :: SelfConnectionStatusCb a -> IO (FunPtr (SelfConnectionStatusCb a))----- | Set the callback for the `self_connection_status` event. Pass 'nullPtr' to--- unset.------ This event is triggered whenever there is a change in the DHT connection--- state. When disconnected, a client may choose to call tox_bootstrap again, to--- reconnect to the DHT. Note that this state may frequently change for short--- amounts of time. Clients should therefore not immediately bootstrap on--- receiving a disconnect.------ TODO: how long should a client wait before bootstrapping again?-foreign import ccall tox_callback_self_connection_status :: Tox a -> FunPtr (SelfConnectionStatusCb a) -> IO ()---- | Return the time in milliseconds before tox_iterate() should be called again--- for optimal performance.-foreign import ccall tox_iteration_interval :: Tox a -> IO Word32---- | The main loop that needs to be run in intervals of tox_iteration_interval()--- milliseconds.-foreign import ccall tox_iterate :: Tox a -> Ptr a -> IO ()----------------------------------------------------------------------------------------- :: Internal client information (Tox address/id)----------------------------------------------------------------------------------------- | Writes the Tox friend address of the client to a byte array. The address is--- not in human-readable format. If a client wants to display the address,--- formatting is required.------ @param address A memory region of at least 'tox_address_size' bytes. If this--- parameter is 'nullPtr', this function has no effect.--- @see 'tox_address_size' for the address format.-foreign import ccall tox_self_get_address :: Tox a -> CString -> IO ()---- | Set the 4-byte nospam part of the address.------ @param nospam Any 32 bit unsigned integer.-foreign import ccall tox_self_set_nospam :: Tox a -> Word32 -> IO ()---- | Get the 4-byte nospam part of the address.-foreign import ccall tox_self_get_nospam :: Tox a -> IO Word32---- | Copy the Tox Public Key (long term) from the Tox object.------ @param public_key A memory region of at least 'tox_public_key_size' bytes. If--- this parameter is 'nullPtr', this function has no effect.-foreign import ccall tox_self_get_public_key :: Tox a -> CString -> IO ()---- | Copy the Tox Secret Key from the Tox object.------ @param secret_key A memory region of at least 'tox_secret_key_size' bytes. If--- this parameter is 'nullPtr', this function has no effect.-foreign import ccall tox_self_get_secret_key :: Tox a -> CString -> IO ()----------------------------------------------------------------------------------------- :: User-visible client information (nickname/status)----------------------------------------------------------------------------------------- | Common error codes for all functions that set a piece of user-visible--- client information.-data ErrSetInfo- = ErrSetInfoOk- -- The function returned successfully.-- | ErrSetInfoNull- -- One of the arguments to the function was 'nullPtr' when it was not- -- expected.-- | ErrSetInfoTooLong- -- Information length exceeded maximum permissible size.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Set the nickname for the Tox client.------ Nickname length cannot exceed 'tox_max_name_length'. If length is 0, the name--- parameter is ignored (it can be 'nullPtr'), and the nickname is set back to--- empty.------ @param name A byte array containing the new nickname.--- @param length The size of the name byte array.------ @return true on success.-foreign import ccall tox_self_set_name :: Tox a -> CString -> CSize -> CErr ErrSetInfo -> IO ()---- | Set the client's status message.------ Status message length cannot exceed 'tox_max_status_message_length'. If--- length is 0, the status parameter is ignored (it can be 'nullPtr'), and the--- user status is set back to empty.-foreign import ccall tox_self_set_status_message :: Tox a -> CString -> CSize -> CErr ErrSetInfo -> IO ()---- | Set the client's user status.------ @param user_status One of the user statuses listed in the enumeration above.-foreign import ccall tox_self_set_status :: Tox a -> CEnum UserStatus -> IO ()----------------------------------------------------------------------------------------- :: Friend list management---------------------------------------------------------------------------------------data ErrFriendAdd- = ErrFriendAddOk- -- The function returned successfully.-- | ErrFriendAddNull- -- One of the arguments to the function was 'nullPtr' when it was not- -- expected.-- | ErrFriendAddTooLong- -- The length of the friend request message exceeded- -- 'tox_max_friend_request_length'.-- | ErrFriendAddNoMessage- -- The friend request message was empty. This, and the TooLong code will- -- never be returned from tox_friend_add_norequest.-- | ErrFriendAddOwnKey- -- The friend address belongs to the sending client.-- | ErrFriendAddAlreadySent- -- A friend request has already been sent, or the address belongs to a- -- friend that is already on the friend list.-- | ErrFriendAddBadChecksum- -- The friend address checksum failed.-- | ErrFriendAddSetNewNospam- -- The friend was already there, but the nospam value was different.-- | ErrFriendAddMalloc- -- A memory allocation failed when trying to increase the friend list size.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Add a friend to the friend list and send a friend request.------ A friend request message must be at least 1 byte long and at most--- 'tox_max_friend_request_length'.------ Friend numbers are unique identifiers used in all functions that operate on--- friends. Once added, a friend number is stable for the lifetime of the Tox--- object. After saving the state and reloading it, the friend numbers may not--- be the same as before. Deleting a friend creates a gap in the friend number--- set, which is filled by the next adding of a friend. Any pattern in friend--- numbers should not be relied on.------ If more than INT32_MAX friends are added, this function causes undefined--- behaviour.------ @param address The address of the friend (returned by tox_self_get_address of--- the friend you wish to add) it must be 'tox_address_size' bytes.--- @param message The message that will be sent along with the friend request.--- @param length The length of the data byte array.------ @return the friend number on success, UINT32_MAX on failure.-foreign import ccall tox_friend_add :: Tox a -> CString -> CString -> CSize -> CErr ErrFriendAdd -> IO Word32---- | Add a friend without sending a friend request.------ This function is used to add a friend in response to a friend request. If the--- client receives a friend request, it can be reasonably sure that the other--- client added this client as a friend, eliminating the need for a friend--- request.------ This function is also useful in a situation where both instances are--- controlled by the same entity, so that this entity can perform the mutual--- friend adding. In this case, there is no need for a friend request, either.------ @param public_key A byte array of length 'tox_public_key_size' containing the--- Public Key (not the Address) of the friend to add.------ @return the friend number on success, UINT32_MAX on failure.--- @see tox_friend_add for a more detailed description of friend numbers.-foreign import ccall tox_friend_add_norequest :: Tox a -> CString -> CErr ErrFriendAdd -> IO Word32---data ErrFriendDelete- = ErrFriendDeleteOk- -- The function returned successfully.-- | ErrFriendDeleteFriendNotFound- -- There was no friend with the given friend number. No friends were- -- deleted.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Remove a friend from the friend list.------ This does not notify the friend of their deletion. After calling this--- function, this client will appear offline to the friend and no communication--- can occur between the two.------ @param friend_number Friend number for the friend to be deleted.------ @return true on success.-foreign import ccall tox_friend_delete :: Tox a -> Word32 -> CErr ErrFriendDelete -> IO ()----------------------------------------------------------------------------------------- :: Friend list queries---------------------------------------------------------------------------------------data ErrFriendByPublicKey- = ErrFriendByPublicKeyOk- -- The function returned successfully.-- | ErrFriendByPublicKeyNull- -- One of the arguments to the function was 'nullPtr' when it was not- -- expected.-- | ErrFriendByPublicKeyNotFound- -- No friend with the given Public Key exists on the friend list.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Return the friend number associated with that Public Key.------ @return the friend number on success, UINT32_MAX on failure.--- @param public_key A byte array containing the Public Key.-foreign import ccall tox_friend_by_public_key :: Tox a -> CString -> CErr ErrFriendByPublicKey -> IO Word32---- | Checks if a friend with the given friend number exists and returns true if--- it does.-foreign import ccall tox_friend_exists :: Tox a -> Word32 -> IO Bool---- | Return the number of friends on the friend list.------ This function can be used to determine how much memory to allocate for--- tox_self_get_friend_list.-foreign import ccall tox_self_get_friend_list_size :: Tox a -> IO CSize---- | Copy a list of valid friend numbers into an array.------ Call tox_self_get_friend_list_size to determine the number of elements to--- allocate.------ @param list A memory region with enough space to hold the friend list. If--- this parameter is 'nullPtr', this function has no effect.-foreign import ccall tox_self_get_friend_list :: Tox a -> Ptr Word32 -> IO ()--data ErrFriendGetPublicKey- = ErrFriendGetPublicKeyOk- -- The function returned successfully.-- | ErrFriendGetPublicKeyFriendNotFound- -- No friend with the given number exists on the friend list.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Copies the Public Key associated with a given friend number to a byte--- array.------ @param friend_number The friend number you want the Public Key of.--- @param public_key A memory region of at least 'tox_public_key_size' bytes. If--- this parameter is 'nullPtr', this function has no effect.------ @return true on success.-foreign import ccall tox_friend_get_public_key :: Tox a -> Word32 -> CString -> CErr ErrFriendGetPublicKey -> IO Bool----------------------------------------------------------------------------------------- :: Friend-specific state queries (can also be received through callbacks)----------------------------------------------------------------------------------------- | @param friend_number The friend number of the friend whose name changed.--- @param name A byte array containing the same data as--- tox_friend_get_name would write to its `name` parameter.--- @param length A value equal to the return value of--- tox_friend_get_name_size.-type FriendNameCb a = Tox a -> Word32 -> CString -> CSize -> Ptr a-foreign import ccall "wrapper" wrapFriendNameCb :: FriendNameCb a -> IO (FunPtr (FriendNameCb a))---- | Set the callback for the `friend_name` event. Pass 'nullPtr' to unset.------ This event is triggered when a friend changes their name.-foreign import ccall tox_callback_friend_name :: Tox a -> FunPtr (FriendNameCb a) -> IO ()----- | @param friend_number The friend number of the friend whose status message--- changed.--- @param message A byte array containing the same data as--- tox_friend_get_status_message would write to its `status_message`--- parameter.--- @param length A value equal to the return value of--- tox_friend_get_status_message_size.-type FriendStatusMessageCb a = Tox a -> Word32 -> CString -> CSize -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFriendStatusMessageCb :: FriendStatusMessageCb a -> IO (FunPtr (FriendStatusMessageCb a))---- | Set the callback for the `friend_status_message` event. Pass 'nullPtr' to--- unset.------ This event is triggered when a friend changes their status message.-foreign import ccall tox_callback_friend_status_message :: Tox a -> FunPtr (FriendStatusMessageCb a) -> IO ()----- | @param friend_number The friend number of the friend whose user status--- changed.--- @param status The new user status.-type FriendStatusCb a = Tox a -> Word32 -> CEnum UserStatus -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFriendStatusCb :: FriendStatusCb a -> IO (FunPtr (FriendStatusCb a))----- | Set the callback for the `friend_status` event. Pass 'nullPtr' to unset.------ This event is triggered when a friend changes their user status.-foreign import ccall tox_callback_friend_status :: Tox a -> FunPtr (FriendStatusCb a) -> IO ()----- | @param friend_number The friend number of the friend whose connection--- status changed.--- @param connection_status The result of calling--- tox_friend_get_connection_status on the passed friend_number.-type FriendConnectionStatusCb a = Tox a -> Word32 -> CEnum Connection -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFriendConnectionStatusCb :: FriendConnectionStatusCb a -> IO (FunPtr (FriendConnectionStatusCb a))---- | Set the callback for the `friend_connection_status` event. Pass 'nullPtr'--- to unset.------ This event is triggered when a friend goes offline after having been online,--- or when a friend goes online.------ This callback is not called when adding friends. It is assumed that when--- adding friends, their connection status is initially offline.-foreign import ccall tox_callback_friend_connection_status :: Tox a -> FunPtr (FriendConnectionStatusCb a) -> IO ()----- | @param friend_number The friend number of the friend who started or stopped--- typing.--- @param is_typing The result of calling tox_friend_get_typing on the passed--- friend_number.-type FriendTypingCb a = Tox a -> Word32 -> Bool -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFriendTypingCb :: FriendTypingCb a -> IO (FunPtr (FriendTypingCb a))---- | Set the callback for the `friend_typing` event. Pass 'nullPtr' to unset.------ This event is triggered when a friend starts or stops typing.-foreign import ccall tox_callback_friend_typing :: Tox a -> FunPtr (FriendTypingCb a) -> IO ()----------------------------------------------------------------------------------------- :: Sending private messages---------------------------------------------------------------------------------------data ErrSetTyping- = ErrSetTypingOk- -- The function returned successfully.-- | ErrSetTypingFriendNotFound- -- The friend number did not designate a valid friend.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Set the client's typing status for a friend.------ The client is responsible for turning it on or off.------ @param friend_number The friend to which the client is typing a message.--- @param typing The typing status. True means the client is typing.------ @return true on success.-foreign import ccall tox_self_set_typing :: Tox a -> Word32 -> Bool -> CErr ErrSetTyping -> IO Bool--data ErrFriendSendMessage- = ErrFriendSendMessageOk- -- The function returned successfully.-- | ErrFriendSendMessageNull- -- One of the arguments to the function was 'nullPtr' when it was not- -- expected.-- | ErrFriendSendMessageFriendNotFound- -- The friend number did not designate a valid friend.-- | ErrFriendSendMessageFriendNotConnected- -- This client is currently not connected to the friend.-- | ErrFriendSendMessageSendq- -- An allocation error occurred while increasing the send queue size.-- | ErrFriendSendMessageTooLong- -- Message length exceeded 'tox_max_message_length'.-- | ErrFriendSendMessageEmpty- -- Attempted to send a zero-length message.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Send a text chat message to an online friend.------ This function creates a chat message packet and pushes it into the send--- queue.------ The message length may not exceed 'tox_max_message_length'. Larger messages--- must be split by the client and sent as separate messages. Other clients can--- then reassemble the fragments. Messages may not be empty.------ The return value of this function is the message ID. If a read receipt is--- received, the triggered `friend_read_receipt` event will be passed this--- message ID.------ Message IDs are unique per friend. The first message ID is 0. Message IDs are--- incremented by 1 each time a message is sent. If UINT32_MAX messages were--- sent, the next message ID is 0.------ @param type Message type (normal, action, ...).--- @param friend_number The friend number of the friend to send the message to.--- @param message A non-'nullPtr' pointer to the first element of a byte array--- containing the message text.--- @param length Length of the message to be sent.-foreign import ccall tox_friend_send_message :: Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrFriendSendMessage -> IO Word32---- | @param friend_number The friend number of the friend who received the--- message.--- @param message_id The message ID as returned from tox_friend_send_message--- corresponding to the message sent.-type FriendReadReceiptCb a = Tox a -> Word32 -> Word32 -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFriendReadReceiptCb :: FriendReadReceiptCb a -> IO (FunPtr (FriendReadReceiptCb a))----- | Set the callback for the `friend_read_receipt` event. Pass 'nullPtr' to--- unset.------ This event is triggered when the friend receives the message sent with--- tox_friend_send_message with the corresponding message ID.-foreign import ccall tox_callback_friend_read_receipt :: Tox a -> FunPtr (FriendReadReceiptCb a) -> IO ()----------------------------------------------------------------------------------------- :: Receiving private messages and friend requests----------------------------------------------------------------------------------------- | @param public_key The Public Key of the user who sent the friend request.--- @param time_delta A delta in seconds between when the message was composed--- and when it is being transmitted. For messages that are sent immediately,--- it will be 0. If a message was written and couldn't be sent immediately--- (due to a connection failure, for example), the time_delta is an--- approximation of when it was composed.--- @param message The message they sent along with the request.--- @param length The size of the message byte array.-type FriendRequestCb a = Tox a -> CString -> CString -> CSize -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFriendRequestCb :: FriendRequestCb a -> IO (FunPtr (FriendRequestCb a))----- | Set the callback for the `friend_request` event. Pass 'nullPtr' to unset.------ This event is triggered when a friend request is received.-foreign import ccall tox_callback_friend_request :: Tox a -> FunPtr (FriendRequestCb a) -> IO ()---- | @param friend_number The friend number of the friend who sent the message.--- @param time_delta Time between composition and sending.--- @param message The message data they sent.--- @param length The size of the message byte array.------ @see friend_request for more information on time_delta.-type FriendMessageCb a = Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFriendMessageCb :: FriendMessageCb a -> IO (FunPtr (FriendMessageCb a))----- | Set the callback for the `friend_message` event. Pass 'nullPtr' to unset.------ This event is triggered when a message from a friend is received.-foreign import ccall tox_callback_friend_message :: Tox a -> FunPtr (FriendMessageCb a) -> IO ()----------------------------------------------------------------------------------------- :: File transmission: common between sending and receiving----------------------------------------------------------------------------------------- | Generates a cryptographic hash of the given data.------ This function may be used by clients for any purpose, but is provided--- primarily for validating cached avatars. This use is highly recommended to--- avoid unnecessary avatar updates.------ If hash is 'nullPtr' or data is 'nullPtr' while length is not 0 the function--- returns false, otherwise it returns true.------ This function is a wrapper to internal message-digest functions.------ @param hash A valid memory location the hash data. It must be at least--- 'tox_hash_length' bytes in size.--- @param data Data to be hashed or 'nullPtr'.--- @param length Size of the data array or 0.------ @return true if hash was not 'nullPtr'.-foreign import ccall tox_hash :: CString -> CString -> CSize -> IO Bool--data FileKind-- = FileKindData- -- Arbitrary file data. Clients can choose to handle it based on the file- -- name or magic or any other way they choose.-- | FileKindAvatar- -- Avatar file_id. This consists of tox_hash(image). Avatar data. This- -- consists of the image data.- --- -- Avatars can be sent at any time the client wishes. Generally, a client- -- will send the avatar to a friend when that friend comes online, and to- -- all friends when the avatar changed. A client can save some traffic by- -- remembering which friend received the updated avatar already and only- -- send it if the friend has an out of date avatar.- --- -- Clients who receive avatar send requests can reject it (by sending- -- FileControlCancel before any other controls), or accept it (by sending- -- FileControlResume). The file_id of length 'tox_hash_length' bytes (same- -- length as 'tox_file_id_length') will contain the hash. A client can- -- compare this hash with a saved hash and send FileControlCancel to- -- terminate the avatar transfer if it matches.- --- -- When file_size is set to 0 in the transfer request it means that the- -- client has no avatar.- deriving (Eq, Ord, Enum, Bounded, Read, Show)--instance Arbitrary FileKind where- arbitrary = arbitraryBoundedEnum---data FileControl- = FileControlResume- -- Sent by the receiving side to accept a file send request. Also sent after- -- a FileControlPause command to continue sending or receiving.-- | FileControlPause- -- Sent by clients to pause the file transfer. The initial state of a file- -- transfer is always paused on the receiving side and running on the- -- sending side. If both the sending and receiving side pause the transfer,- -- then both need to send FileControlResume for the transfer to resume.-- | FileControlCancel- -- Sent by the receiving side to reject a file send request before any other- -- commands are sent. Also sent by either side to terminate a file transfer.- deriving (Eq, Ord, Enum, Bounded, Read, Show)--instance Arbitrary FileControl where- arbitrary = arbitraryBoundedEnum---data ErrFileControl- = ErrFileControlOk- -- The function returned successfully.-- | ErrFileControlFriendNotFound- -- The friend_number passed did not designate a valid friend.-- | ErrFileControlFriendNotConnected- -- This client is currently not connected to the friend.-- | ErrFileControlNotFound- -- No file transfer with the given file number was found for the given friend.-- | ErrFileControlNotPaused- -- A Resume control was sent, but the file transfer is running normally.-- | ErrFileControlDenied- -- A Resume control was sent, but the file transfer was paused by the other- -- party. Only the party that paused the transfer can resume it.-- | ErrFileControlAlreadyPaused- -- A Pause control was sent, but the file transfer was already paused.-- | ErrFileControlSendq- -- Packet queue is full.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Sends a file control command to a friend for a given file transfer.------ @param friend_number The friend number of the friend the file is being--- transferred to or received from.--- @param file_number The friend-specific identifier for the file transfer.--- @param control The control command to send.------ @return true on success.-foreign import ccall tox_file_control :: Tox a -> Word32 -> Word32 -> CEnum FileControl -> CErr ErrFileControl -> IO Bool---- | When receiving FileControlCancel, the client should release the--- resources associated with the file number and consider the transfer failed.------ @param friend_number The friend number of the friend who is sending the file.--- @param file_number The friend-specific file number the data received is--- associated with.--- @param control The file control command received.-type FileRecvControlCb a = Tox a -> Word32 -> Word32 -> CEnum FileControl -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFileRecvControlCb :: FileRecvControlCb a -> IO (FunPtr (FileRecvControlCb a))----- | Set the callback for the `file_recv_control` event. Pass 'nullPtr' to--- unset.------ This event is triggered when a file control command is received from a--- friend.-foreign import ccall tox_callback_file_recv_control :: Tox a -> FunPtr (FileRecvControlCb a) -> IO ()--data ErrFileSeek- = ErrFileSeekOk- -- The function returned successfully.-- | ErrFileSeekFriendNotFound- -- The friend_number passed did not designate a valid friend.-- | ErrFileSeekFriendNotConnected- -- This client is currently not connected to the friend.-- | ErrFileSeekNotFound- -- No file transfer with the given file number was found for the given friend.-- | ErrFileSeekDenied- -- File was not in a state where it could be seeked.-- | ErrFileSeekInvalidPosition- -- Seek position was invalid-- | ErrFileSeekSendq- -- Packet queue is full.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Sends a file seek control command to a friend for a given file transfer.------ This function can only be called to resume a file transfer right before--- FileControlResume is sent.------ @param friend_number The friend number of the friend the file is being--- received from.--- @param file_number The friend-specific identifier for the file transfer.--- @param position The position that the file should be seeked to.-foreign import ccall tox_file_seek :: Tox a -> Word32 -> Word32 -> Word64 -> CErr ErrFileSeek -> IO Bool--data ErrFileGet- = ErrFileGetOk- -- The function returned successfully.-- | ErrFileGetNull- -- One of the arguments to the function was 'nullPtr' when it was not- -- expected.-- | ErrFileGetFriendNotFound- -- The friend_number passed did not designate a valid friend.-- | ErrFileGetNotFound- -- No file transfer with the given file number was found for the given friend.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Copy the file id associated to the file transfer to a byte array.------ @param friend_number The friend number of the friend the file is being--- transferred to or received from.--- @param file_number The friend-specific identifier for the file transfer.--- @param file_id A memory region of at least 'tox_file_id_length' bytes. If--- this parameter is 'nullPtr', this function has no effect.------ @return true on success.-foreign import ccall tox_file_get_file_id :: Tox a -> Word32 -> Word32 -> CString -> CErr ErrFileGet -> IO Bool----------------------------------------------------------------------------------------- :: File transmission: sending---------------------------------------------------------------------------------------data ErrFileSend- = ErrFileSendOk- -- The function returned successfully.-- | ErrFileSendNull- -- One of the arguments to the function was 'nullPtr' when it was not- -- expected.-- | ErrFileSendFriendNotFound- -- The friend_number passed did not designate a valid friend.-- | ErrFileSendFriendNotConnected- -- This client is currently not connected to the friend.-- | ErrFileSendNameTooLong- -- Filename length exceeded 'tox_max_filename_length' bytes.-- | ErrFileSendTooMany- -- Too many ongoing transfers. The maximum number of concurrent file transfers- -- is 256 per friend per direction (sending and receiving).- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Send a file transmission request.------ Maximum filename length is 'tox_max_filename_length' bytes. The filename--- should generally just be a file name, not a path with directory names.------ If a non-UINT64_MAX file size is provided, it can be used by both sides to--- determine the sending progress. File size can be set to UINT64_MAX for--- streaming data of unknown size.------ File transmission occurs in chunks, which are requested through the--- `file_chunk_request` event.------ When a friend goes offline, all file transfers associated with the friend are--- purged from core.------ If the file contents change during a transfer, the behaviour is unspecified--- in general. What will actually happen depends on the mode in which the file--- was modified and how the client determines the file size.------ - If the file size was increased--- - and sending mode was streaming (file_size = UINT64_MAX), the behaviour--- will be as expected.--- - and sending mode was file (file_size != UINT64_MAX), the--- file_chunk_request callback will receive length = 0 when Core thinks--- the file transfer has finished. If the client remembers the file size as--- it was when sending the request, it will terminate the transfer normally.--- If the client re-reads the size, it will think the friend cancelled the--- transfer.--- - If the file size was decreased--- - and sending mode was streaming, the behaviour is as expected.--- - and sending mode was file, the callback will return 0 at the new--- (earlier) end-of-file, signalling to the friend that the transfer was--- cancelled.--- - If the file contents were modified--- - at a position before the current read, the two files (local and remote)--- will differ after the transfer terminates.--- - at a position after the current read, the file transfer will succeed as--- expected.--- - In either case, both sides will regard the transfer as complete and--- successful.------ @param friend_number The friend number of the friend the file send request--- should be sent to.--- @param kind The meaning of the file to be sent.--- @param file_size Size in bytes of the file the client wants to send,--- UINT64_MAX if unknown or streaming.--- @param file_id A file identifier of length 'tox_file_id_length' that can be--- used to uniquely identify file transfers across core restarts. If--- 'nullPtr', a random one will be generated by core. It can then be obtained--- by using tox_file_get_file_id().--- @param filename Name of the file. Does not need to be the actual name. This--- name will be sent along with the file send request.--- @param filename_length Size in bytes of the filename.------ @return A file number used as an identifier in subsequent callbacks. This--- number is per friend. File numbers are reused after a transfer terminates.--- On failure, this function returns UINT32_MAX. Any pattern in file numbers--- should not be relied on.-foreign import ccall tox_file_send :: Tox a -> Word32 -> Word32 -> Word64 -> CString -> CString -> CSize -> CErr ErrFileSend -> IO Word32--data ErrFileSendChunk- = ErrFileSendChunkOk- -- The function returned successfully.-- | ErrFileSendChunkNull- -- The length parameter was non-zero, but data was 'nullPtr'.-- | ErrFileSendChunkFriendNotFound- -- The friend_number passed did not designate a valid friend.-- | ErrFileSendChunkFriendNotConnected- -- This client is currently not connected to the friend.-- | ErrFileSendChunkNotFound- -- No file transfer with the given file number was found for the given friend.-- | ErrFileSendChunkNotTransferring- -- File transfer was found but isn't in a transferring state: (paused, done,- -- broken, etc...) (happens only when not called from the request chunk- -- callback).-- | ErrFileSendChunkInvalidLength- -- Attempted to send more or less data than requested. The requested data- -- size is adjusted according to maximum transmission unit and the expected- -- end of the file. Trying to send less or more than requested will return- -- this error.-- | ErrFileSendChunkSendq- -- Packet queue is full.-- | ErrFileSendChunkWrongPosition- -- Position parameter was wrong.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Send a chunk of file data to a friend.------ This function is called in response to the `file_chunk_request` callback.--- The length parameter should be equal to the one received though the--- callback. If it is zero, the transfer is assumed complete. For files with--- known size, Core will know that the transfer is complete after the last byte--- has been received, so it is not necessary (though not harmful) to send a--- zero-length chunk to terminate. For streams, core will know that the--- transfer is finished if a chunk with length less than the length requested--- in the callback is sent.------ @param friend_number The friend number of the receiving friend for this file.--- @param file_number The file transfer identifier returned by tox_file_send.--- @param position The file or stream position from which to continue reading.--- @return true on success.-foreign import ccall tox_file_send_chunk :: Tox a -> Word32 -> Word32 -> Word64 -> CString -> CSize -> CErr ErrFileSendChunk -> IO Bool---- | If the length parameter is 0, the file transfer is finished, and the--- client's resources associated with the file number should be released. After--- a call with zero length, the file number can be reused for future file--- transfers.------ If the requested position is not equal to the client's idea of the current--- file or stream position, it will need to seek. In case of read-once streams,--- the client should keep the last read chunk so that a seek back can be--- supported. A seek-back only ever needs to read from the last requested--- chunk. This happens when a chunk was requested, but the send failed. A--- seek-back request can occur an arbitrary number of times for any given--- chunk.------ In response to receiving this callback, the client should call the function--- `tox_file_send_chunk` with the requested chunk. If the number of bytes sent--- through that function is zero, the file transfer is assumed complete. A--- client must send the full length of data requested with this callback.------ @param friend_number The friend number of the receiving friend for this file.--- @param file_number The file transfer identifier returned by tox_file_send.--- @param position The file or stream position from which to continue reading.--- @param length The number of bytes requested for the current chunk.-type FileChunkRequestCb a = Tox a -> Word32 -> Word32 -> Word64 -> CSize -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFileChunkRequestCb :: FileChunkRequestCb a -> IO (FunPtr (FileChunkRequestCb a))----- | Set the callback for the `file_chunk_request` event. Pass 'nullPtr' to--- unset.------ This event is triggered when Core is ready to send more file data.-foreign import ccall tox_callback_file_chunk_request :: Tox a -> FunPtr (FileChunkRequestCb a) -> IO ()----------------------------------------------------------------------------------------- :: File transmission: receiving----------------------------------------------------------------------------------------- | The client should acquire resources to be associated with the file--- transfer. Incoming file transfers start in the Paused state. After this--- callback returns, a transfer can be rejected by sending a FileControlCancel--- control command before any other control commands. It can be accepted by--- sending FileControlResume.------ @param friend_number The friend number of the friend who is sending the file--- transfer request.--- @param file_number The friend-specific file number the data received is--- associated with.--- @param kind The meaning of the file to be sent.--- @param file_size Size in bytes of the file the client wants to send,--- UINT64_MAX if unknown or streaming.--- @param filename Name of the file. Does not need to be the actual name. This--- name will be sent along with the file send request.--- @param filename_length Size in bytes of the filename.-type FileRecvCb a = Tox a -> Word32 -> Word32 -> Word32 -> Word64 -> CString -> CSize -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFileRecvCb :: FileRecvCb a -> IO (FunPtr (FileRecvCb a))----- | Set the callback for the `file_recv` event. Pass 'nullPtr' to unset.------ This event is triggered when a file transfer request is received.-foreign import ccall tox_callback_file_recv :: Tox a -> FunPtr (FileRecvCb a) -> IO ()---- | When length is 0, the transfer is finished and the client should release--- the resources it acquired for the transfer. After a call with length = 0,--- the file number can be reused for new file transfers.------ If position is equal to file_size (received in the file_receive callback)--- when the transfer finishes, the file was received completely. Otherwise, if--- file_size was UINT64_MAX, streaming ended successfully when length is 0.------ @param friend_number The friend number of the friend who is sending the file.--- @param file_number The friend-specific file number the data received is--- associated with.--- @param position The file position of the first byte in data.--- @param data A byte array containing the received chunk.--- @param length The length of the received chunk.-type FileRecvChunkCb a = Tox a -> Word32 -> Word32 -> Word64 -> CString -> CSize -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFileRecvChunkCb :: FileRecvChunkCb a -> IO (FunPtr (FileRecvChunkCb a))----- | Set the callback for the `file_recv_chunk` event. Pass 'nullPtr' to unset.------ This event is first triggered when a file transfer request is received, and--- subsequently when a chunk of file data for an accepted request was received.-foreign import ccall tox_callback_file_recv_chunk :: Tox a -> FunPtr (FileRecvChunkCb a) -> IO ()----------------------------------------------------------------------------------------- :: Group chat management----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- :: Group chat message sending and receiving----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- :: Low-level custom packet sending and receiving---------------------------------------------------------------------------------------data ErrFriendCustomPacket- = ErrFriendCustomPacketOk- -- The function returned successfully.-- | ErrFriendCustomPacketNull- -- One of the arguments to the function was 'nullPtr' when it was not- -- expected.-- | ErrFriendCustomPacketFriendNotFound- -- The friend number did not designate a valid friend.-- | ErrFriendCustomPacketFriendNotConnected- -- This client is currently not connected to the friend.-- | ErrFriendCustomPacketInvalid- -- The first byte of data was not in the specified range for the packet- -- type. This range is 200-254 for lossy, and 160-191 for lossless packets.-- | ErrFriendCustomPacketEmpty- -- Attempted to send an empty packet.-- | ErrFriendCustomPacketTooLong- -- Packet data length exceeded 'tox_max_custom_packet_size'.-- | ErrFriendCustomPacketSendq- -- Packet queue is full.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Send a custom lossy packet to a friend.------ The first byte of data must be in the range 200-254. Maximum length of a--- custom packet is 'tox_max_custom_packet_size'.------ Lossy packets behave like UDP packets, meaning they might never reach the--- other side or might arrive more than once (if someone is messing with the--- connection) or might arrive in the wrong order.------ Unless latency is an issue, it is recommended that you use lossless custom--- packets instead.------ @param friend_number The friend number of the friend this lossy packet--- should be sent to.--- @param data A byte array containing the packet data.--- @param length The length of the packet data byte array.------ @return true on success.-foreign import ccall tox_friend_send_lossy_packet :: Tox a -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool---- | Send a custom lossless packet to a friend.------ The first byte of data must be in the range 160-191. Maximum length of a--- custom packet is 'tox_max_custom_packet_size'.------ Lossless packet behaviour is comparable to TCP (reliability, arrive in order)--- but with packets instead of a stream.------ @param friend_number The friend number of the friend this lossless packet--- should be sent to.--- @param data A byte array containing the packet data.--- @param length The length of the packet data byte array.------ @return true on success.-foreign import ccall tox_friend_send_lossless_packet :: Tox a -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool---- | @param friend_number The friend number of the friend who sent a lossy--- packet.--- @param data A byte array containing the received packet data.--- @param length The length of the packet data byte array.-type FriendLossyPacketCb a = Tox a -> Word32 -> CString -> CSize -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFriendLossyPacketCb :: FriendLossyPacketCb a -> IO (FunPtr (FriendLossyPacketCb a))----- | Set the callback for the `friend_lossy_packet` event. Pass 'nullPtr' to--- unset.----foreign import ccall tox_callback_friend_lossy_packet :: Tox a -> FunPtr (FriendLossyPacketCb a) -> IO ()---- | @param friend_number The friend number of the friend who sent the packet.--- @param data A byte array containing the received packet data.--- @param length The length of the packet data byte array.-type FriendLosslessPacketCb a = Tox a -> Word32 -> CString -> CSize -> Ptr a -> IO ()-foreign import ccall "wrapper" wrapFriendLosslessPacketCb :: FriendLosslessPacketCb a -> IO (FunPtr (FriendLosslessPacketCb a))----- | Set the callback for the `friend_lossless_packet` event. Pass 'nullPtr' to--- unset.----foreign import ccall tox_callback_friend_lossless_packet :: Tox a -> FunPtr (FriendLosslessPacketCb a) -> IO ()----------------------------------------------------------------------------------------- :: Low-level network information----------------------------------------------------------------------------------------- | Writes the temporary DHT public key of this instance to a byte array.------ This can be used in combination with an externally accessible IP address and--- the bound port (from tox_self_get_udp_port) to run a temporary bootstrap--- node.------ Be aware that every time a new instance is created, the DHT public key--- changes, meaning this cannot be used to run a permanent bootstrap node.------ @param dht_id A memory region of at least 'tox_public_key_size' bytes. If--- this parameter is 'nullPtr', this function has no effect.-foreign import ccall tox_self_get_dht_id :: Tox a -> CString -> IO ()--data ErrGetPort- = ErrGetPortOk- -- The function returned successfully.-- | ErrGetPortNotBound- -- The instance was not bound to any port.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Return the UDP port this Tox instance is bound to.-foreign import ccall tox_self_get_udp_port :: Tox a -> CErr ErrGetPort -> IO Word16---- | Return the TCP port this Tox instance is bound to. This is only relevant if--- the instance is acting as a TCP relay.-foreign import ccall tox_self_get_tcp_port :: Tox a -> CErr ErrGetPort -> IO Word16+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE Safe #-}+-- | Public core API for Tox clients.+--+-- Every function that can fail takes a function-specific error code pointer+-- that can be used to diagnose problems with the Tox state or the function+-- arguments. The error code pointer can be 'nullPtr', which does not influence+-- the function's behaviour, but can be done if the reason for failure is+-- irrelevant to the client.+--+-- The exception to this rule are simple allocation functions whose only failure+-- mode is allocation failure. They return 'nullPtr' in that case, and do not+-- set an error code.+--+-- Every error code type has an OK value to which functions will set their error+-- code value on success. Clients can keep their error code uninitialised before+-- passing it to a function. The library guarantees that after returning, the+-- value pointed to by the error code pointer has been initialised.+--+-- Functions with pointer parameters often have a 'nullPtr' error code, meaning+-- they could not perform any operation, because one of the required parameters+-- was 'nullPtr'. Some functions operate correctly or are defined as effectless+-- on 'nullPtr'.+--+-- Some functions additionally return a value outside their return type domain,+-- or a bool containing true on success and false on failure.+--+-- All functions that take a Tox instance pointer will cause undefined behaviour+-- when passed a 'nullPtr' Tox pointer.+--+-- All integer values are expected in host byte order.+--+-- Functions with parameters with enum types cause unspecified behaviour if the+-- enumeration value is outside the valid range of the type. If possible, the+-- function will try to use a sane default, but there will be no error code, and+-- one possible action for the function to take is to have no effect.+--+-- \subsection events Events and callbacks+--+-- Events are handled by callbacks. One callback can be registered per event.+-- All events have a callback function type named `tox_{event}_cb` and a+-- function to register it named `tox_callback_{event}`. Passing a 'nullPtr'+-- callback will result in no callback being registered for that event. Only one+-- callback per event can be registered, so if a client needs multiple event+-- listeners, it needs to implement the dispatch functionality itself.+--+-- \subsection threading Threading implications+--+-- It is possible to run multiple concurrent threads with a Tox instance for+-- each thread. It is also possible to run all Tox instances in the same thread.+-- A common way to run Tox (multiple or single instance) is to have one thread+-- running a simple tox_iterate loop, sleeping for tox_iteration_interval+-- milliseconds on each iteration.+--+-- If you want to access a single Tox instance from multiple threads, access to+-- the instance must be synchronised. While multiple threads can concurrently+-- access multiple different Tox instances, no more than one API function can+-- operate on a single instance at any given time.+--+-- Functions that write to variable length byte arrays will always have a size+-- function associated with them. The result of this size function is only valid+-- until another mutating function (one that takes a pointer to non-const Tox)+-- is called. Thus, clients must ensure that no other thread calls a mutating+-- function between the call to the size function and the call to the retrieval+-- function.+--+-- E.g. to get the current nickname, one would write+--+-- \code+-- CSize length = tox_self_get_name_size(tox);+-- CString name = malloc(length);+-- if (!name) abort();+-- tox_self_get_name(tox, name);+-- \endcode+--+-- If any other thread calls tox_self_set_name while this thread is allocating+-- memory, the length may have become invalid, and the call to tox_self_get_name+-- may cause undefined behaviour.+--+module Network.Tox.C.Tox where++import Control.Applicative ((<$>))+import Control.Concurrent.MVar (MVar, modifyMVar_)+import Control.Exception (bracket)+import Control.Monad ((>=>))+import qualified Data.ByteString as BS+import Data.Word (Word16, Word32, Word64)+import Foreign.C.String (CString, peekCStringLen, withCString,+ withCStringLen)+import Foreign.C.Types (CChar (..), CInt (..), CSize (..),+ CTime (..))+import Foreign.Marshal.Alloc (alloca)+import Foreign.Marshal.Array (allocaArray, peekArray)+import Foreign.Ptr (FunPtr, Ptr, nullPtr)+import Foreign.StablePtr (deRefStablePtr, freeStablePtr,+ newStablePtr)+import Foreign.Storable (peek)+import System.Posix.Types (EpochTime)++import Network.Tox.C.CEnum+import Network.Tox.C.Constants+import Network.Tox.C.Options+import Network.Tox.C.Type+++--------------------------------------------------------------------------------+--+-- :: Global types+--+--------------------------------------------------------------------------------++-- Should we introduce such types?+-- newtype FriendNum = FriendNum { friendNum :: Word32 } deriving (Eq, Ord, Read, Show)+-- newtype ConferenceNum = ConferenceNum { conferenceNum :: Word32 } deriving (Eq, Ord, Read, Show)+-- newtype PeerNum = PeerNum { peerNum :: Word32 } deriving (Eq, Ord, Read, Show)+-- newtype FileNum = FileNum { fileNum :: Word32 } deriving (Eq, Ord, Read, Show)++-- | Represents the possible statuses a client can have.+data UserStatus+ = UserStatusNone+ -- ^ User is online and available.+ | UserStatusAway+ -- ^ User is away. Clients can set this e.g. after a user defined inactivity+ -- time.+ | UserStatusBusy+ -- ^ User is busy. Signals to other clients that this client does not+ -- currently wish to communicate.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Represents message types for tox_friend_send_message and group chat+-- messages.+data MessageType+ = MessageTypeNormal+ -- ^ Normal text message. Similar to PRIVMSG on IRC.+ | MessageTypeAction+ -- ^ A message describing an user action. This is similar to /me (CTCP+ -- ACTION) on IRC.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++--------------------------------------------------------------------------------+--+-- :: Creation and destruction+--+--------------------------------------------------------------------------------+++data ErrNew+ = ErrNewOk+ -- The function returned successfully.++ | ErrNewNull+ -- One of the arguments to the function was 'nullPtr' when it was not+ -- expected.++ | ErrNewMalloc+ -- The function was unable to allocate enough memory to store the internal+ -- structures for the Tox object.++ | ErrNewPortAlloc+ -- The function was unable to bind to a port. This may mean that all ports+ -- have already been bound, e.g. by other Tox instances, or it may mean a+ -- permission error. You may be able to gather more information from errno.++ | ErrNewProxyBadType+ -- proxy_type was invalid.++ | ErrNewProxyBadHost+ -- proxy_type was valid but the proxy_host passed had an invalid format or+ -- was 'nullPtr'.++ | ErrNewProxyBadPort+ -- proxy_type was valid, but the proxy_port was invalid.++ | ErrNewProxyNotFound+ -- The proxy address passed could not be resolved.++ | ErrNewLoadEncrypted+ -- The byte array to be loaded contained an encrypted save.++ | ErrNewLoadBadFormat+ -- The data format was invalid. This can happen when loading data that was+ -- saved by an older version of Tox, or when the data has been corrupted.+ -- When loading from badly formatted data, some data may have been loaded,+ -- and the rest is discarded. Passing an invalid length parameter also+ -- causes this error.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- @brief Creates and initialises a new Tox instance with the options passed.+--+-- This function will bring the instance into a valid state. Running the event+-- loop with a new instance will operate correctly.+--+-- If loading failed or succeeded only partially, the new or partially loaded+-- instance is returned and an error code is set.+--+-- @param options An options object as described above. If this parameter is+-- 'nullPtr', the default options are used.+--+-- @see tox_iterate for the event loop.+--+-- @return A new Tox instance pointer on success or 'nullPtr' on failure.+foreign import ccall tox_new :: OptionsPtr -> CErr ErrNew -> IO (Tox a)++toxNew :: OptionsPtr -> IO (Either ErrNew (Tox a))+toxNew = callErrFun . tox_new++-- | Releases all resources associated with the Tox instance and disconnects+-- from the network.+--+-- After calling this function, the Tox pointer becomes invalid. No other+-- functions can be called, and the pointer value can no longer be read.+foreign import ccall tox_kill :: Tox a -> IO ()++toxKill :: Tox a -> IO ()+toxKill = tox_kill++withTox :: OptionsPtr -> (Tox a -> IO r) -> IO (Either ErrNew r)+withTox options f =+ bracket (toxNew options) (either (const $ return ()) toxKill) $ \case+ Left err -> return $ Left err+ Right ok -> Right <$> f ok+++withDefaultTox :: (Tox a -> IO r) -> IO (Either ErrNew r)+withDefaultTox = withTox nullPtr+++-- | Calculates the number of bytes required to store the tox instance with+-- tox_get_savedata. This function cannot fail. The result is always greater+-- than 0.+--+-- @see threading for concurrency implications.+foreign import ccall tox_get_savedata_size :: Tox a -> IO CSize++-- | Store all information associated with the tox instance to a byte array.+--+-- @param data A memory region large enough to store the tox instance data.+-- Call tox_get_savedata_size to find the number of bytes required. If this+-- parameter is 'nullPtr', this function has no effect.+foreign import ccall tox_get_savedata :: Tox a -> CString -> IO ()++toxGetSavedata :: Tox a -> IO BS.ByteString+toxGetSavedata tox = do+ savedataLen <- tox_get_savedata_size tox+ allocaArray (fromIntegral savedataLen) $ \savedataPtr -> do+ tox_get_savedata tox savedataPtr+ BS.packCStringLen (savedataPtr, fromIntegral savedataLen)+++--------------------------------------------------------------------------------+--+-- :: Connection lifecycle and event loop+--+--------------------------------------------------------------------------------+++data ErrBootstrap+ = ErrBootstrapOk+ -- The function returned successfully.++ | ErrBootstrapNull+ -- One of the arguments to the function was 'nullPtr' when it was not+ -- expected.++ | ErrBootstrapBadHost+ -- The address could not be resolved to an IP address, or the IP address+ -- passed was invalid.++ | ErrBootstrapBadPort+ -- The port passed was invalid. The valid port range is (1, 65535).+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Sends a "get nodes" request to the given bootstrap node with IP, port, and+-- public key to setup connections.+--+-- This function will attempt to connect to the node using UDP. You must use+-- this function even if Options.udp_enabled was set to false.+--+-- @param address The hostname or IP address (IPv4 or IPv6) of the node.+-- @param port The port on the host on which the bootstrap Tox instance is+-- listening.+-- @param public_key The long term public key of the bootstrap node+-- ('tox_public_key_size' bytes).+-- @return true on success.+foreign import ccall tox_bootstrap :: Tox a -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO ()++callBootstrapFun+ :: (Tox a -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO ())+ -> Tox a -> String -> Word16 -> BS.ByteString -> IO (Either ErrBootstrap ())+callBootstrapFun f tox address port pubKey =+ withCString address $ \address' ->+ BS.useAsCString pubKey $ \pubKey' ->+ callErrFun $ f tox address' (fromIntegral port) pubKey'++toxBootstrap :: Tox a -> String -> Word16 -> BS.ByteString -> IO (Either ErrBootstrap ())+toxBootstrap = callBootstrapFun tox_bootstrap+++-- | Adds additional host:port pair as TCP relay.+--+-- This function can be used to initiate TCP connections to different ports on+-- the same bootstrap node, or to add TCP relays without using them as+-- bootstrap nodes.+--+-- @param address The hostname or IP address (IPv4 or IPv6) of the TCP relay.+-- @param port The port on the host on which the TCP relay is listening.+-- @param public_key The long term public key of the TCP relay+-- ('tox_public_key_size' bytes).+-- @return true on success.+foreign import ccall tox_add_tcp_relay :: Tox a -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO ()++toxAddTcpRelay :: Tox a -> String -> Word16 -> BS.ByteString -> IO (Either ErrBootstrap ())+toxAddTcpRelay = callBootstrapFun tox_add_tcp_relay+++-- | Protocols that can be used to connect to the network or friends.+data Connection+ = ConnectionNone+ -- There is no connection. This instance, or the friend the state change is+ -- about, is now offline.++ | ConnectionTcp+ -- A TCP connection has been established. For the own instance, this means+ -- it is connected through a TCP relay, only. For a friend, this means that+ -- the connection to that particular friend goes through a TCP relay.++ | ConnectionUdp+ -- A UDP connection has been established. For the own instance, this means+ -- it is able to send UDP packets to DHT nodes, but may still be connected+ -- to a TCP relay. For a friend, this means that the connection to that+ -- particular friend was built using direct UDP packets.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | @param connection_status Whether we are connected to the DHT.+type SelfConnectionStatusCb a = Tox a -> Connection -> a -> IO a+type CSelfConnectionStatusCb a = Tox a -> CEnum Connection -> UserData a -> IO ()+foreign import ccall "wrapper" wrapSelfConnectionStatusCb :: CSelfConnectionStatusCb a -> IO (FunPtr (CSelfConnectionStatusCb a))++callSelfConnectionStatusCb :: SelfConnectionStatusCb a -> CSelfConnectionStatusCb a+callSelfConnectionStatusCb f tox conn = deRefStablePtr >=> (`modifyMVar_` f tox (fromCEnum conn))++selfConnectionStatusCb :: SelfConnectionStatusCb a -> IO (FunPtr (CSelfConnectionStatusCb a))+selfConnectionStatusCb = wrapSelfConnectionStatusCb . callSelfConnectionStatusCb+++-- | Set the callback for the `self_connection_status` event. Pass 'nullPtr' to+-- unset.+--+-- This event is triggered whenever there is a change in the DHT connection+-- state. When disconnected, a client may choose to call tox_bootstrap again, to+-- reconnect to the DHT. Note that this state may frequently change for short+-- amounts of time. Clients should therefore not immediately bootstrap on+-- receiving a disconnect.+--+-- TODO: how long should a client wait before bootstrapping again?+foreign import ccall tox_callback_self_connection_status :: Tox a -> FunPtr (CSelfConnectionStatusCb a) -> IO ()++-- | Return the time in milliseconds before tox_iterate() should be called again+-- for optimal performance.+foreign import ccall tox_iteration_interval :: Tox a -> IO Word32+toxIterationInterval :: Tox a -> IO Word32+toxIterationInterval = tox_iteration_interval++-- | The main loop that needs to be run in intervals of tox_iteration_interval()+-- milliseconds.+foreign import ccall tox_iterate :: Tox a -> UserData a -> IO ()+toxIterate :: Tox a -> MVar a -> IO ()+toxIterate tox ud = bracket (newStablePtr ud) freeStablePtr (tox_iterate tox)+++--------------------------------------------------------------------------------+--+-- :: Internal client information (Tox address/id)+--+--------------------------------------------------------------------------------+++-- | Writes the Tox friend address of the client to a byte array. The address is+-- not in human-readable format. If a client wants to display the address,+-- formatting is required.+--+-- @param address A memory region of at least 'tox_address_size' bytes. If this+-- parameter is 'nullPtr', this function has no effect.+-- @see 'tox_address_size' for the address format.+foreign import ccall tox_self_get_address :: Tox a -> CString -> IO ()++toxSelfGetAddress :: Tox a -> IO BS.ByteString+toxSelfGetAddress tox =+ let addrLen = fromIntegral tox_address_size in+ allocaArray addrLen $ \addrPtr -> do+ tox_self_get_address tox addrPtr+ BS.packCStringLen (addrPtr, addrLen)++-- | Set the 4-byte nospam part of the address.+--+-- @param nospam Any 32 bit unsigned integer.+foreign import ccall tox_self_set_nospam :: Tox a -> Word32 -> IO ()+toxSelfSetNospam :: Tox a -> Word32 -> IO ()+toxSelfSetNospam = tox_self_set_nospam++-- | Get the 4-byte nospam part of the address.+foreign import ccall tox_self_get_nospam :: Tox a -> IO Word32+toxSelfGetNospam :: Tox a -> IO Word32+toxSelfGetNospam = tox_self_get_nospam++-- | Copy the Tox Public Key (long term) from the Tox object.+--+-- @param public_key A memory region of at least 'tox_public_key_size' bytes. If+-- this parameter is 'nullPtr', this function has no effect.+foreign import ccall tox_self_get_public_key :: Tox a -> CString -> IO ()++toxSelfGetPublicKey :: Tox a -> IO BS.ByteString+toxSelfGetPublicKey tox =+ let pkLen = fromIntegral tox_public_key_size in+ allocaArray pkLen $ \pkPtr -> do+ tox_self_get_public_key tox pkPtr+ BS.packCStringLen (pkPtr, pkLen)++-- | Copy the Tox Secret Key from the Tox object.+--+-- @param secret_key A memory region of at least 'tox_secret_key_size' bytes. If+-- this parameter is 'nullPtr', this function has no effect.+foreign import ccall tox_self_get_secret_key :: Tox a -> CString -> IO ()++toxSelfGetSecretKey :: Tox a -> IO BS.ByteString+toxSelfGetSecretKey tox =+ let skLen = fromIntegral tox_secret_key_size in+ allocaArray skLen $ \skPtr -> do+ tox_self_get_secret_key tox skPtr+ BS.packCStringLen (skPtr, skLen)+++--------------------------------------------------------------------------------+--+-- :: User-visible client information (nickname/status)+--+--------------------------------------------------------------------------------+++-- | Common error codes for all functions that set a piece of user-visible+-- client information.+data ErrSetInfo+ = ErrSetInfoOk+ -- The function returned successfully.++ | ErrSetInfoNull+ -- One of the arguments to the function was 'nullPtr' when it was not+ -- expected.++ | ErrSetInfoTooLong+ -- Information length exceeded maximum permissible size.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Set the nickname for the Tox client.+--+-- Nickname length cannot exceed 'tox_max_name_length'. If length is 0, the name+-- parameter is ignored (it can be 'nullPtr'), and the nickname is set back to+-- empty.+--+-- @param name A byte array containing the new nickname.+-- @param length The size of the name byte array.+--+-- @return true on success.+foreign import ccall tox_self_set_name :: Tox a -> CString -> CSize -> CErr ErrSetInfo -> IO ()+callSelfSetNameFun :: (Tox a -> CString -> CSize -> CErr ErrSetInfo -> IO ()) ->+ Tox a -> String -> IO (Either ErrSetInfo ())+callSelfSetNameFun f tox name =+ withCStringLen name $ \(nameStr, nameLen) ->+ callErrFun $ f tox nameStr (fromIntegral nameLen)++toxSelfSetName :: Tox a -> String -> IO (Either ErrSetInfo ())+toxSelfSetName = callSelfSetNameFun tox_self_set_name+++-- | Return the length of the current nickname as passed to tox_self_set_name.+--+-- If no nickname was set before calling this function, the name is empty,+-- and this function returns 0.+--+-- @see threading for concurrency implications.+foreign import ccall tox_self_get_name_size :: Tox a -> IO CSize++-- | Write the nickname set by tox_self_set_name to a byte array.+--+-- If no nickname was set before calling this function, the name is empty,+-- and this function has no effect.+--+-- Call tox_self_get_name_size to find out how much memory to allocate for+-- the result.+--+-- @param name A valid memory location large enough to hold the nickname.+-- If this parameter is NULL, the function has no effect.+foreign import ccall tox_self_get_name :: Tox a -> CString -> IO ()++toxSelfGetName :: Tox a -> IO String+toxSelfGetName tox = do+ nameLen <- tox_self_get_name_size tox+ allocaArray (fromIntegral nameLen) $ \namePtr -> do+ tox_self_get_name tox namePtr+ peekCStringLen (namePtr, fromIntegral nameLen)+++-- | Set the client's status message.+--+-- Status message length cannot exceed 'tox_max_status_message_length'. If+-- length is 0, the status parameter is ignored (it can be 'nullPtr'), and the+-- user status is set back to empty.+foreign import ccall tox_self_set_status_message :: Tox a -> CString -> CSize -> CErr ErrSetInfo -> IO ()+callSelfSetStatusMessageFun :: (Tox a -> CString -> CSize -> CErr ErrSetInfo -> IO ()) ->+ Tox a -> String -> IO (Either ErrSetInfo ())+callSelfSetStatusMessageFun f tox statusMsg =+ withCStringLen statusMsg $ \(statusMsgStr, statusMsgLen) ->+ callErrFun $ f tox statusMsgStr (fromIntegral statusMsgLen)++toxSelfSetStatusMessage :: Tox a -> String -> IO (Either ErrSetInfo ())+toxSelfSetStatusMessage = callSelfSetStatusMessageFun tox_self_set_status_message+++-- | Return the length of the current status message as passed to tox_self_set_status_message.+--+-- If no status message was set before calling this function, the status+-- is empty, and this function returns 0.+--+-- @see threading for concurrency implications.+foreign import ccall tox_self_get_status_message_size :: Tox a -> IO CSize+++-- | Write the status message set by tox_self_set_status_message to a byte array.+--+-- If no status message was set before calling this function, the status is+-- empty, and this function has no effect.+--+-- Call tox_self_get_status_message_size to find out how much memory to allocate for+-- the result.+--+-- @param status_message A valid memory location large enough to hold the+-- status message. If this parameter is NULL, the function has no effect.+foreign import ccall tox_self_get_status_message :: Tox a -> CString -> IO ()++toxSelfGetStatusMessage :: Tox a -> IO String+toxSelfGetStatusMessage tox = do+ statusMessageLen <- tox_self_get_status_message_size tox+ allocaArray (fromIntegral statusMessageLen) $ \statusMessagePtr -> do+ tox_self_get_status_message tox statusMessagePtr+ peekCStringLen (statusMessagePtr, fromIntegral statusMessageLen)+++-- | Set the client's user status.+--+-- @param user_status One of the user statuses listed in the enumeration above.+foreign import ccall tox_self_set_status :: Tox a -> CEnum UserStatus -> IO ()+toxSelfSetStatus :: Tox a -> UserStatus -> IO ()+toxSelfSetStatus tox userStatus = tox_self_set_status tox $ toCEnum userStatus+++--------------------------------------------------------------------------------+--+-- :: Friend list management+--+--------------------------------------------------------------------------------+++data ErrFriendAdd+ = ErrFriendAddOk+ -- The function returned successfully.++ | ErrFriendAddNull+ -- One of the arguments to the function was 'nullPtr' when it was not+ -- expected.++ | ErrFriendAddTooLong+ -- The length of the friend request message exceeded+ -- 'tox_max_friend_request_length'.++ | ErrFriendAddNoMessage+ -- The friend request message was empty. This, and the TooLong code will+ -- never be returned from tox_friend_add_norequest.++ | ErrFriendAddOwnKey+ -- The friend address belongs to the sending client.++ | ErrFriendAddAlreadySent+ -- A friend request has already been sent, or the address belongs to a+ -- friend that is already on the friend list.++ | ErrFriendAddBadChecksum+ -- The friend address checksum failed.++ | ErrFriendAddSetNewNospam+ -- The friend was already there, but the nospam value was different.++ | ErrFriendAddMalloc+ -- A memory allocation failed when trying to increase the friend list size.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Add a friend to the friend list and send a friend request.+--+-- A friend request message must be at least 1 byte long and at most+-- 'tox_max_friend_request_length'.+--+-- Friend numbers are unique identifiers used in all functions that operate on+-- friends. Once added, a friend number is stable for the lifetime of the Tox+-- object. After saving the state and reloading it, the friend numbers may not+-- be the same as before. Deleting a friend creates a gap in the friend number+-- set, which is filled by the next adding of a friend. Any pattern in friend+-- numbers should not be relied on.+--+-- If more than INT32_MAX friends are added, this function causes undefined+-- behaviour.+--+-- @param address The address of the friend (returned by tox_self_get_address of+-- the friend you wish to add) it must be 'tox_address_size' bytes.+-- @param message The message that will be sent along with the friend request.+-- @param length The length of the data byte array.+--+-- @return the friend number on success, UINT32_MAX on failure.+foreign import ccall tox_friend_add :: Tox a -> CString -> CString -> CSize -> CErr ErrFriendAdd -> IO Word32+callFriendAddFun :: (Tox a -> CString -> CString -> CSize -> CErr ErrFriendAdd -> IO Word32) ->+ Tox a -> BS.ByteString -> String -> IO (Either ErrFriendAdd Word32)+callFriendAddFun f tox address message =+ withCStringLen message $ \(msgStr, msgLen) ->+ BS.useAsCString address $ \addr' ->+ callErrFun $ f tox addr' msgStr (fromIntegral msgLen)++toxFriendAdd :: Tox a -> BS.ByteString -> String -> IO (Either ErrFriendAdd Word32)+toxFriendAdd = callFriendAddFun tox_friend_add++-- | Add a friend without sending a friend request.+--+-- This function is used to add a friend in response to a friend request. If the+-- client receives a friend request, it can be reasonably sure that the other+-- client added this client as a friend, eliminating the need for a friend+-- request.+--+-- This function is also useful in a situation where both instances are+-- controlled by the same entity, so that this entity can perform the mutual+-- friend adding. In this case, there is no need for a friend request, either.+--+-- @param public_key A byte array of length 'tox_public_key_size' containing the+-- Public Key (not the Address) of the friend to add.+--+-- @return the friend number on success, UINT32_MAX on failure.+-- @see tox_friend_add for a more detailed description of friend numbers.+foreign import ccall tox_friend_add_norequest :: Tox a -> CString -> CErr ErrFriendAdd -> IO Word32+callFriendAddNorequestFun :: (Tox a -> CString -> CErr ErrFriendAdd -> IO Word32) ->+ Tox a -> BS.ByteString -> IO (Either ErrFriendAdd Word32)+callFriendAddNorequestFun f tox address =+ BS.useAsCString address $ \addr' ->+ callErrFun $ f tox addr'++toxFriendAddNorequest :: Tox a -> BS.ByteString -> IO (Either ErrFriendAdd Word32)+toxFriendAddNorequest = callFriendAddNorequestFun tox_friend_add_norequest+++data ErrFriendDelete+ = ErrFriendDeleteOk+ -- The function returned successfully.++ | ErrFriendDeleteFriendNotFound+ -- There was no friend with the given friend number. No friends were+ -- deleted.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Remove a friend from the friend list.+--+-- This does not notify the friend of their deletion. After calling this+-- function, this client will appear offline to the friend and no communication+-- can occur between the two.+--+-- @param friend_number Friend number for the friend to be deleted.+--+-- @return true on success.+foreign import ccall tox_friend_delete :: Tox a -> Word32 -> CErr ErrFriendDelete -> IO ()++toxFriendDelete :: Tox a -> Word32 -> IO (Either ErrFriendDelete ())+toxFriendDelete tox fn = callErrFun $ tox_friend_delete tox fn+++--------------------------------------------------------------------------------+--+-- :: Friend list queries+--+--------------------------------------------------------------------------------+++data ErrFriendByPublicKey+ = ErrFriendByPublicKeyOk+ -- The function returned successfully.++ | ErrFriendByPublicKeyNull+ -- One of the arguments to the function was 'nullPtr' when it was not+ -- expected.++ | ErrFriendByPublicKeyNotFound+ -- No friend with the given Public Key exists on the friend list.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Return the friend number associated with that Public Key.+--+-- @return the friend number on success, UINT32_MAX on failure.+-- @param public_key A byte array containing the Public Key.+foreign import ccall tox_friend_by_public_key :: Tox a -> CString -> CErr ErrFriendByPublicKey -> IO Word32+callFriendByPublicKey :: (Tox a -> CString -> CErr ErrFriendByPublicKey -> IO Word32) ->+ Tox a -> BS.ByteString -> IO (Either ErrFriendByPublicKey Word32)+callFriendByPublicKey f tox address =+ BS.useAsCString address $ \addr' ->+ callErrFun $ f tox addr'++toxFriendByPublicKey :: Tox a -> BS.ByteString -> IO (Either ErrFriendByPublicKey Word32)+toxFriendByPublicKey = callFriendByPublicKey tox_friend_by_public_key++-- | Checks if a friend with the given friend number exists and returns true if+-- it does.+foreign import ccall tox_friend_exists :: Tox a -> Word32 -> IO Bool+toxFriendExists :: Tox a -> Word32 -> IO Bool+toxFriendExists = tox_friend_exists++-- | Return the number of friends on the friend list.+--+-- This function can be used to determine how much memory to allocate for+-- tox_self_get_friend_list.+foreign import ccall tox_self_get_friend_list_size :: Tox a -> IO CSize++-- | Copy a list of valid friend numbers into an array.+--+-- Call tox_self_get_friend_list_size to determine the number of elements to+-- allocate.+--+-- @param list A memory region with enough space to hold the friend list. If+-- this parameter is 'nullPtr', this function has no effect.+foreign import ccall tox_self_get_friend_list :: Tox a -> Ptr Word32 -> IO ()++toxSelfGetFriendList :: Tox a -> IO [Word32]+toxSelfGetFriendList tox = do+ friendListSize <- tox_self_get_friend_list_size tox+ allocaArray (fromIntegral friendListSize) $ \friendListPtr -> do+ tox_self_get_friend_list tox friendListPtr+ peekArray (fromIntegral friendListSize) friendListPtr++data ErrFriendGetPublicKey+ = ErrFriendGetPublicKeyOk+ -- The function returned successfully.++ | ErrFriendGetPublicKeyFriendNotFound+ -- No friend with the given number exists on the friend list.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Copies the Public Key associated with a given friend number to a byte+-- array.+--+-- @param friend_number The friend number you want the Public Key of.+-- @param public_key A memory region of at least 'tox_public_key_size' bytes. If+-- this parameter is 'nullPtr', this function has no effect.+--+-- @return true on success.+foreign import ccall tox_friend_get_public_key :: Tox a -> Word32 -> CString -> CErr ErrFriendGetPublicKey -> IO Bool+callFriendGetPublicKey :: (Tox a -> Word32 -> CString -> CErr ErrFriendGetPublicKey -> IO Bool) ->+ Tox a -> Word32 -> IO (Either ErrFriendGetPublicKey BS.ByteString)+callFriendGetPublicKey f tox fn =+ let pkLen = fromIntegral tox_public_key_size in+ alloca $ \errPtr ->+ allocaArray pkLen $ \pkPtr -> do+ _ <- f tox fn pkPtr errPtr+ callGetPublicKey errPtr pkPtr pkLen++callGetPublicKey+ :: (Bounded err, Enum err, Eq err)+ => Ptr (CEnum err)+ -> Ptr CChar+ -> Int+ -> IO (Either err BS.ByteString)+callGetPublicKey errPtr pkPtr pkLen = do+ err <- toEnum . fromIntegral . unCEnum <$> peek errPtr+ str <- BS.packCStringLen (pkPtr, pkLen)+ return $ if err /= minBound+ then Left err+ else Right str++toxFriendGetPublicKey :: Tox a -> Word32 -> IO (Either ErrFriendGetPublicKey BS.ByteString)+toxFriendGetPublicKey = callFriendGetPublicKey tox_friend_get_public_key+++data ErrFriendGetLastOnline+ = ErrFriendGetLastOnlineOk+ -- The function returned successfully.++ | ErrFriendGetLastOnlineFriendNotFound+ -- No friend with the given number exists on the friend list.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Return a unix-time timestamp of the last time the friend associated with a given+-- friend number was seen online. This function will return UINT64_MAX on error.+--+-- @param friend_number The friend number you want to query.+foreign import ccall tox_friend_get_last_online :: Tox a -> Word32 -> CErr ErrFriendGetLastOnline -> IO Word64+callFriendGetLastOnline :: (Tox a -> Word32 -> CErr ErrFriendGetLastOnline -> IO Word64) ->+ Tox a -> Word32 -> IO (Either ErrFriendGetLastOnline EpochTime)+callFriendGetLastOnline f tox fn = callErrFun (f tox fn >=> (return . CTime . fromIntegral))++toxFriendGetLastOnline :: Tox a -> Word32 -> IO (Either ErrFriendGetLastOnline EpochTime)+toxFriendGetLastOnline = callFriendGetLastOnline tox_friend_get_last_online+++--------------------------------------------------------------------------------+--+-- :: Friend-specific state queries (can also be received through callbacks)+--+--------------------------------------------------------------------------------+++-- | Common error codes for friend state query functions.+data ErrFriendQuery+ = ErrFriendQueryOk+ -- The function returned successfully.++ | ErrFriendQueryNull+ -- The pointer parameter for storing the query result (name, message) was+ -- NULL. Unlike the `_self_` variants of these functions, which have no effect+ -- when a parameter is NULL, these functions return an error in that case.++ | ErrFriendQueryFriendNotFound+ -- The friend_number did not designate a valid friend.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Return the length of the friend's name. If the friend number is invalid, the+-- return value is unspecified.+--+-- The return value is equal to the `length` argument received by the last+-- `friend_name` callback.+foreign import ccall tox_friend_get_name_size :: Tox a -> Word32 -> CErr ErrFriendQuery -> IO CSize++-- | Write the name of the friend designated by the given friend number to a byte+-- array.+--+-- Call tox_friend_get_name_size to determine the allocation size for the `name`+-- parameter.+--+-- The data written to `name` is equal to the data received by the last+-- `friend_name` callback.+--+-- @param name A valid memory region large enough to store the friend's name.+--+-- @return true on success.+foreign import ccall tox_friend_get_name :: Tox a -> Word32 -> CString -> CErr ErrFriendQuery -> IO Bool++toxFriendGetName :: Tox a -> Word32 -> IO (Either ErrFriendQuery String)+toxFriendGetName tox fn = do+ nameLenRes <- callErrFun $ tox_friend_get_name_size tox fn+ case nameLenRes of+ Left err -> return $ Left err+ Right nameLen -> allocaArray (fromIntegral nameLen) $ \namePtr -> do+ nameRes <- callErrFun $ tox_friend_get_name tox fn namePtr+ case nameRes of+ Left err -> return $ Left err+ Right _ ->+ Right <$> peekCStringLen (namePtr, fromIntegral nameLen)+++-- | @param friend_number The friend number of the friend whose name changed.+-- @param name A byte array containing the same data as+-- tox_friend_get_name would write to its `name` parameter.+-- @param length A value equal to the return value of+-- tox_friend_get_name_size.+type FriendNameCb a = Tox a -> Word32 -> String -> a -> IO a+type CFriendNameCb a = Tox a -> Word32 -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFriendNameCb :: CFriendNameCb a -> IO (FunPtr (CFriendNameCb a))++callFriendNameCb :: FriendNameCb a -> CFriendNameCb a+callFriendNameCb f tox fn nameStr nameLen udPtr = do+ ud <- deRefStablePtr udPtr+ name <- peekCStringLen (nameStr, fromIntegral nameLen)+ modifyMVar_ ud $ f tox fn name++friendNameCb :: FriendNameCb a -> IO (FunPtr (CFriendNameCb a))+friendNameCb = wrapFriendNameCb . callFriendNameCb+++-- | Set the callback for the `friend_name` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a friend changes their name.+foreign import ccall tox_callback_friend_name :: Tox a -> FunPtr (CFriendNameCb a) -> IO ()+++-- | @param friend_number The friend number of the friend whose status message+-- changed.+-- @param message A byte array containing the same data as+-- tox_friend_get_status_message would write to its `status_message`+-- parameter.+-- @param length A value equal to the return value of+-- tox_friend_get_status_message_size.+type FriendStatusMessageCb a = Tox a -> Word32 -> String -> a -> IO a+type CFriendStatusMessageCb a = Tox a -> Word32 -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFriendStatusMessageCb :: CFriendStatusMessageCb a -> IO (FunPtr (CFriendStatusMessageCb a))++callFriendStatusMessageCb :: FriendStatusMessageCb a -> CFriendStatusMessageCb a+callFriendStatusMessageCb f tox fn statusMessageStr statusMessageLen udPtr = do+ ud <- deRefStablePtr udPtr+ statusMessage <- peekCStringLen (statusMessageStr, fromIntegral statusMessageLen)+ modifyMVar_ ud $ f tox fn statusMessage++friendStatusMessageCb :: FriendStatusMessageCb a -> IO (FunPtr (CFriendStatusMessageCb a))+friendStatusMessageCb = wrapFriendStatusMessageCb . callFriendStatusMessageCb+++-- | Return the length of the friend's status message. If the friend number is+-- invalid, the return value is SIZE_MAX.+foreign import ccall tox_friend_get_status_message_size :: Tox a -> Word32 -> CErr ErrFriendQuery -> IO CSize++-- | Write the status message of the friend designated by the given friend number to a byte+-- array.+--+-- Call tox_friend_get_status_message_size to determine the allocation size for the `status_name`+-- parameter.+--+-- The data written to `status_message` is equal to the data received by the last+-- `friend_status_message` callback.+--+-- @param status_message A valid memory region large enough to store the friend's status message.+foreign import ccall tox_friend_get_status_message :: Tox a -> Word32 -> CString -> CErr ErrFriendQuery -> IO Bool++toxFriendGetStatusMessage :: Tox a -> Word32 -> IO (Either ErrFriendQuery String)+toxFriendGetStatusMessage tox fn = do+ statusMessageLenRes <- callErrFun $ tox_friend_get_status_message_size tox fn+ case statusMessageLenRes of+ Left err -> return $ Left err+ Right statusMessageLen -> allocaArray (fromIntegral statusMessageLen) $ \statusMessagePtr -> do+ statusMessageRes <- callErrFun $ tox_friend_get_status_message tox fn statusMessagePtr+ case statusMessageRes of+ Left err -> return $ Left err+ Right _ ->+ Right <$> peekCStringLen (statusMessagePtr, fromIntegral statusMessageLen)+++-- | Set the callback for the `friend_status_message` event. Pass 'nullPtr' to+-- unset.+--+-- This event is triggered when a friend changes their status message.+foreign import ccall tox_callback_friend_status_message :: Tox a -> FunPtr (CFriendStatusMessageCb a) -> IO ()+++-- | @param friend_number The friend number of the friend whose user status+-- changed.+-- @param status The new user status.+type FriendStatusCb a = Tox a -> Word32 -> UserStatus -> a -> IO a+type CFriendStatusCb a = Tox a -> Word32 -> CEnum UserStatus -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFriendStatusCb :: CFriendStatusCb a -> IO (FunPtr (CFriendStatusCb a))++callFriendStatusCb :: FriendStatusCb a -> CFriendStatusCb a+callFriendStatusCb f tox fn status = deRefStablePtr >=> (`modifyMVar_` f tox fn (fromCEnum status))++friendStatusCb :: FriendStatusCb a -> IO (FunPtr (CFriendStatusCb a))+friendStatusCb = wrapFriendStatusCb . callFriendStatusCb+++-- | Set the callback for the `friend_status` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a friend changes their user status.+foreign import ccall tox_callback_friend_status :: Tox a -> FunPtr (CFriendStatusCb a) -> IO ()+++-- | Check whether a friend is currently connected to this client.+--+-- The result of this function is equal to the last value received by the+-- `friend_connection_status` callback.+--+-- @param friend_number The friend number for which to query the connection+-- status.+--+-- @return the friend's connection status as it was received through the+-- `friend_connection_status` event.+foreign import ccall tox_friend_get_connection_status :: Tox a -> Word32 -> CErr ErrFriendQuery -> IO (CEnum Connection)++callFriendGetConnectionStatus :: (Tox a -> Word32 -> CErr ErrFriendQuery -> IO (CEnum Connection)) ->+ Tox a -> Word32 -> IO (Either ErrFriendQuery Connection)+callFriendGetConnectionStatus f tox fn = callErrFun (f tox fn >=> (return . fromCEnum))++toxFriendGetConnectionStatus :: Tox a -> Word32 -> IO (Either ErrFriendQuery Connection)+toxFriendGetConnectionStatus = callFriendGetConnectionStatus tox_friend_get_connection_status+++-- | @param friend_number The friend number of the friend whose connection+-- status changed.+-- @param connection_status The result of calling+-- tox_friend_get_connection_status on the passed friend_number.+type FriendConnectionStatusCb a = Tox a -> Word32 -> Connection -> a -> IO a+type CFriendConnectionStatusCb a = Tox a -> Word32 -> CEnum Connection -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFriendConnectionStatusCb :: CFriendConnectionStatusCb a -> IO (FunPtr (CFriendConnectionStatusCb a))++callFriendConnectionStatusCb :: FriendConnectionStatusCb a -> CFriendConnectionStatusCb a+callFriendConnectionStatusCb f tox fn connectionStatus = deRefStablePtr >=> (`modifyMVar_` f tox fn (fromCEnum connectionStatus))++friendConnectionStatusCb :: FriendConnectionStatusCb a -> IO (FunPtr (CFriendConnectionStatusCb a))+friendConnectionStatusCb = wrapFriendConnectionStatusCb . callFriendConnectionStatusCb+++-- | Set the callback for the `friend_connection_status` event. Pass 'nullPtr'+-- to unset.+--+-- This event is triggered when a friend goes offline after having been online,+-- or when a friend goes online.+--+-- This callback is not called when adding friends. It is assumed that when+-- adding friends, their connection status is initially offline.+foreign import ccall tox_callback_friend_connection_status :: Tox a -> FunPtr (CFriendConnectionStatusCb a) -> IO ()+++-- | Check whether a friend is currently typing a message.+--+-- @param friend_number The friend number for which to query the typing status.+--+-- @return true if the friend is typing.+-- @return false if the friend is not typing, or the friend number was+-- invalid. Inspect the error code to determine which case it is.+foreign import ccall tox_friend_get_typing :: Tox a -> Word32 -> CErr ErrFriendQuery -> IO Bool++callFriendGetTyping :: (Tox a -> Word32 -> CErr ErrFriendQuery -> IO Bool) ->+ Tox a -> Word32 -> IO (Either ErrFriendQuery Bool)+callFriendGetTyping f tox fn = callErrFun $ f tox fn++toxFriendGetTyping :: Tox a -> Word32 -> IO (Either ErrFriendQuery Bool)+toxFriendGetTyping = callFriendGetTyping tox_friend_get_typing+++-- | @param friend_number The friend number of the friend who started or stopped+-- typing.+-- @param is_typing The result of calling tox_friend_get_typing on the passed+-- friend_number.+type FriendTypingCb a = Tox a -> Word32 -> Bool -> a -> IO a+type CFriendTypingCb a = Tox a -> Word32 -> Bool -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFriendTypingCb :: CFriendTypingCb a -> IO (FunPtr (CFriendTypingCb a))++callFriendTypingCb :: FriendTypingCb a -> CFriendTypingCb a+callFriendTypingCb f tox fn typing = deRefStablePtr >=> (`modifyMVar_` f tox fn typing)++friendTypingCb :: FriendTypingCb a -> IO (FunPtr (CFriendTypingCb a))+friendTypingCb = wrapFriendTypingCb . callFriendTypingCb++-- | Set the callback for the `friend_typing` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a friend starts or stops typing.+foreign import ccall tox_callback_friend_typing :: Tox a -> FunPtr (CFriendTypingCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Sending private messages+--+--------------------------------------------------------------------------------+++data ErrSetTyping+ = ErrSetTypingOk+ -- The function returned successfully.++ | ErrSetTypingFriendNotFound+ -- The friend number did not designate a valid friend.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Set the client's typing status for a friend.+--+-- The client is responsible for turning it on or off.+--+-- @param friend_number The friend to which the client is typing a message.+-- @param typing The typing status. True means the client is typing.+--+-- @return true on success.+foreign import ccall tox_self_set_typing :: Tox a -> Word32 -> Bool -> CErr ErrSetTyping -> IO Bool+callSelfSetTyping :: (Tox a -> Word32 -> Bool -> CErr ErrSetTyping -> IO Bool) ->+ Tox a -> Word32 -> Bool -> IO (Either ErrSetTyping Bool)+callSelfSetTyping f tox fn typing = callErrFun $ f tox fn typing++toxSelfSetTyping :: Tox a -> Word32 -> Bool -> IO (Either ErrSetTyping Bool)+toxSelfSetTyping = callSelfSetTyping tox_self_set_typing++data ErrFriendSendMessage+ = ErrFriendSendMessageOk+ -- The function returned successfully.++ | ErrFriendSendMessageNull+ -- One of the arguments to the function was 'nullPtr' when it was not+ -- expected.++ | ErrFriendSendMessageFriendNotFound+ -- The friend number did not designate a valid friend.++ | ErrFriendSendMessageFriendNotConnected+ -- This client is currently not connected to the friend.++ | ErrFriendSendMessageSendq+ -- An allocation error occurred while increasing the send queue size.++ | ErrFriendSendMessageTooLong+ -- Message length exceeded 'tox_max_message_length'.++ | ErrFriendSendMessageEmpty+ -- Attempted to send a zero-length message.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Send a text chat message to an online friend.+--+-- This function creates a chat message packet and pushes it into the send+-- queue.+--+-- The message length may not exceed 'tox_max_message_length'. Larger messages+-- must be split by the client and sent as separate messages. Other clients can+-- then reassemble the fragments. Messages may not be empty.+--+-- The return value of this function is the message ID. If a read receipt is+-- received, the triggered `friend_read_receipt` event will be passed this+-- message ID.+--+-- Message IDs are unique per friend. The first message ID is 0. Message IDs are+-- incremented by 1 each time a message is sent. If UINT32_MAX messages were+-- sent, the next message ID is 0.+--+-- @param type Message type (normal, action, ...).+-- @param friend_number The friend number of the friend to send the message to.+-- @param message A non-'nullPtr' pointer to the first element of a byte array+-- containing the message text.+-- @param length Length of the message to be sent.+foreign import ccall tox_friend_send_message :: Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrFriendSendMessage -> IO Word32+callFriendSendMessage :: (Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrFriendSendMessage -> IO Word32) ->+ Tox a -> Word32 -> MessageType -> String -> IO (Either ErrFriendSendMessage Word32)+callFriendSendMessage f tox fn messageType message =+ withCStringLen message $ \(msgStr, msgLen) ->+ callErrFun $ f tox fn (toCEnum messageType) msgStr (fromIntegral msgLen)++toxFriendSendMessage :: Tox a -> Word32 -> MessageType -> String -> IO (Either ErrFriendSendMessage Word32)+toxFriendSendMessage = callFriendSendMessage tox_friend_send_message+++-- | @param friend_number The friend number of the friend who received the+-- message.+-- @param message_id The message ID as returned from tox_friend_send_message+-- corresponding to the message sent.+type FriendReadReceiptCb a = Tox a -> Word32 -> Word32 -> a -> IO a+type CFriendReadReceiptCb a = Tox a -> Word32 -> Word32 -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFriendReadReceiptCb :: CFriendReadReceiptCb a -> IO (FunPtr (CFriendReadReceiptCb a))++callFriendReadReceiptCb :: FriendReadReceiptCb a -> CFriendReadReceiptCb a+callFriendReadReceiptCb f tox fn msgId = deRefStablePtr >=> (`modifyMVar_` f tox fn msgId)++friendReadReceiptCb :: FriendReadReceiptCb a -> IO (FunPtr (CFriendReadReceiptCb a))+friendReadReceiptCb = wrapFriendReadReceiptCb . callFriendReadReceiptCb+++-- | Set the callback for the `friend_read_receipt` event. Pass 'nullPtr' to+-- unset.+--+-- This event is triggered when the friend receives the message sent with+-- tox_friend_send_message with the corresponding message ID.+foreign import ccall tox_callback_friend_read_receipt :: Tox a -> FunPtr (CFriendReadReceiptCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Receiving private messages and friend requests+--+--------------------------------------------------------------------------------+++-- | @param public_key The Public Key of the user who sent the friend request.+-- @param time_delta A delta in seconds between when the message was composed+-- and when it is being transmitted. For messages that are sent immediately,+-- it will be 0. If a message was written and couldn't be sent immediately+-- (due to a connection failure, for example), the time_delta is an+-- approximation of when it was composed.+-- @param message The message they sent along with the request.+-- @param length The size of the message byte array.+type FriendRequestCb a = Tox a -> BS.ByteString -> String -> a -> IO a+type CFriendRequestCb a = Tox a -> CString -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFriendRequestCb :: CFriendRequestCb a -> IO (FunPtr (CFriendRequestCb a))++callFriendRequestCb :: FriendRequestCb a -> CFriendRequestCb a+callFriendRequestCb f tox addrPtr nameStr nameLen udPtr = do+ let addrLen = fromIntegral tox_address_size+ ud <- deRefStablePtr udPtr+ addr <- BS.packCStringLen (addrPtr, addrLen)+ name <- peekCStringLen (nameStr, fromIntegral nameLen)+ modifyMVar_ ud $ f tox addr name++friendRequestCb :: FriendRequestCb a -> IO (FunPtr (CFriendRequestCb a))+friendRequestCb = wrapFriendRequestCb . callFriendRequestCb+++-- | Set the callback for the `friend_request` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a friend request is received.+foreign import ccall tox_callback_friend_request :: Tox a -> FunPtr (CFriendRequestCb a) -> IO ()++-- | @param friend_number The friend number of the friend who sent the message.+-- @param time_delta Time between composition and sending.+-- @param message The message data they sent.+-- @param length The size of the message byte array.+--+-- @see friend_request for more information on time_delta.+type FriendMessageCb a = Tox a -> Word32 -> MessageType -> String -> a -> IO a+type CFriendMessageCb a = Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFriendMessageCb :: CFriendMessageCb a -> IO (FunPtr (CFriendMessageCb a))++callFriendMessageCb :: FriendMessageCb a -> CFriendMessageCb a+callFriendMessageCb f tox fn msgType msgStr msgLen udPtr = do+ ud <- deRefStablePtr udPtr+ msg <- peekCStringLen (msgStr, fromIntegral msgLen)+ modifyMVar_ ud $ f tox fn (fromCEnum msgType) msg++friendMessageCb :: FriendMessageCb a -> IO (FunPtr (CFriendMessageCb a))+friendMessageCb = wrapFriendMessageCb . callFriendMessageCb+++-- | Set the callback for the `friend_message` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a message from a friend is received.+foreign import ccall tox_callback_friend_message :: Tox a -> FunPtr (CFriendMessageCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: File transmission: common between sending and receiving+--+--------------------------------------------------------------------------------+++-- | Generates a cryptographic hash of the given data.+--+-- This function may be used by clients for any purpose, but is provided+-- primarily for validating cached avatars. This use is highly recommended to+-- avoid unnecessary avatar updates.+--+-- If hash is 'nullPtr' or data is 'nullPtr' while length is not 0 the function+-- returns false, otherwise it returns true.+--+-- This function is a wrapper to internal message-digest functions.+--+-- @param hash A valid memory location the hash data. It must be at least+-- 'tox_hash_length' bytes in size.+-- @param data Data to be hashed or 'nullPtr'.+-- @param length Size of the data array or 0.+--+-- @return true if hash was not 'nullPtr'.+foreign import ccall tox_hash :: CString -> CString -> CSize -> IO Bool++toxHash :: BS.ByteString -> IO BS.ByteString+toxHash d =+ let hashLen = fromIntegral tox_hash_length in+ allocaArray hashLen $ \hashPtr ->+ BS.useAsCStringLen d $ \(dataPtr, dataLen) -> do+ _ <- tox_hash hashPtr dataPtr (fromIntegral dataLen)+ BS.packCStringLen (dataPtr, fromIntegral dataLen)++data FileKind+ = FileKindData+ -- Arbitrary file data. Clients can choose to handle it based on the file+ -- name or magic or any other way they choose.++ | FileKindAvatar+ -- Avatar file_id. This consists of tox_hash(image). Avatar data. This+ -- consists of the image data.+ --+ -- Avatars can be sent at any time the client wishes. Generally, a client+ -- will send the avatar to a friend when that friend comes online, and to+ -- all friends when the avatar changed. A client can save some traffic by+ -- remembering which friend received the updated avatar already and only+ -- send it if the friend has an out of date avatar.+ --+ -- Clients who receive avatar send requests can reject it (by sending+ -- FileControlCancel before any other controls), or accept it (by sending+ -- FileControlResume). The file_id of length 'tox_hash_length' bytes (same+ -- length as 'tox_file_id_length') will contain the hash. A client can+ -- compare this hash with a saved hash and send FileControlCancel to+ -- terminate the avatar transfer if it matches.+ --+ -- When file_size is set to 0 in the transfer request it means that the+ -- client has no avatar.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++data FileControl+ = FileControlResume+ -- Sent by the receiving side to accept a file send request. Also sent after+ -- a FileControlPause command to continue sending or receiving.++ | FileControlPause+ -- Sent by clients to pause the file transfer. The initial state of a file+ -- transfer is always paused on the receiving side and running on the+ -- sending side. If both the sending and receiving side pause the transfer,+ -- then both need to send FileControlResume for the transfer to resume.++ | FileControlCancel+ -- Sent by the receiving side to reject a file send request before any other+ -- commands are sent. Also sent by either side to terminate a file transfer.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++data ErrFileControl+ = ErrFileControlOk+ -- The function returned successfully.++ | ErrFileControlFriendNotFound+ -- The friend_number passed did not designate a valid friend.++ | ErrFileControlFriendNotConnected+ -- This client is currently not connected to the friend.++ | ErrFileControlNotFound+ -- No file transfer with the given file number was found for the given friend.++ | ErrFileControlNotPaused+ -- A Resume control was sent, but the file transfer is running normally.++ | ErrFileControlDenied+ -- A Resume control was sent, but the file transfer was paused by the other+ -- party. Only the party that paused the transfer can resume it.++ | ErrFileControlAlreadyPaused+ -- A Pause control was sent, but the file transfer was already paused.++ | ErrFileControlSendq+ -- Packet queue is full.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Sends a file control command to a friend for a given file transfer.+--+-- @param friend_number The friend number of the friend the file is being+-- transferred to or received from.+-- @param file_number The friend-specific identifier for the file transfer.+-- @param control The control command to send.+--+-- @return true on success.+foreign import ccall tox_file_control :: Tox a -> Word32 -> Word32 -> CEnum FileControl -> CErr ErrFileControl -> IO Bool++callFileControl :: (Tox a -> Word32 -> Word32 -> CEnum FileControl -> CErr ErrFileControl -> IO Bool) ->+ Tox a -> Word32 -> Word32 -> FileControl -> IO (Either ErrFileControl Bool)+callFileControl f tox fn fileNum control = callErrFun $ f tox fn fileNum (toCEnum control)++toxFileControl :: Tox a -> Word32 -> Word32 -> FileControl -> IO (Either ErrFileControl Bool)+toxFileControl = callFileControl tox_file_control++-- | When receiving FileControlCancel, the client should release the+-- resources associated with the file number and consider the transfer failed.+--+-- @param friend_number The friend number of the friend who is sending the file.+-- @param file_number The friend-specific file number the data received is+-- associated with.+-- @param control The file control command received.+type FileRecvControlCb a = Tox a -> Word32 -> Word32 -> FileControl -> a -> IO a+type CFileRecvControlCb a = Tox a -> Word32 -> Word32 -> CEnum FileControl -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFileRecvControlCb :: CFileRecvControlCb a -> IO (FunPtr (CFileRecvControlCb a))++callFileRecvControlCb :: FileRecvControlCb a -> CFileRecvControlCb a+callFileRecvControlCb f tox fn fileNum ctrlCmd = deRefStablePtr >=> (`modifyMVar_` f tox fn fileNum (fromCEnum ctrlCmd))++fileRecvControlCb :: FileRecvControlCb a -> IO (FunPtr (CFileRecvControlCb a))+fileRecvControlCb = wrapFileRecvControlCb . callFileRecvControlCb+++-- | Set the callback for the `file_recv_control` event. Pass 'nullPtr' to+-- unset.+--+-- This event is triggered when a file control command is received from a+-- friend.+foreign import ccall tox_callback_file_recv_control :: Tox a -> FunPtr (CFileRecvControlCb a) -> IO ()++data ErrFileSeek+ = ErrFileSeekOk+ -- The function returned successfully.++ | ErrFileSeekFriendNotFound+ -- The friend_number passed did not designate a valid friend.++ | ErrFileSeekFriendNotConnected+ -- This client is currently not connected to the friend.++ | ErrFileSeekNotFound+ -- No file transfer with the given file number was found for the given friend.++ | ErrFileSeekDenied+ -- File was not in a state where it could be seeked.++ | ErrFileSeekInvalidPosition+ -- Seek position was invalid++ | ErrFileSeekSendq+ -- Packet queue is full.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Sends a file seek control command to a friend for a given file transfer.+--+-- This function can only be called to resume a file transfer right before+-- FileControlResume is sent.+--+-- @param friend_number The friend number of the friend the file is being+-- received from.+-- @param file_number The friend-specific identifier for the file transfer.+-- @param position The position that the file should be seeked to.+foreign import ccall tox_file_seek :: Tox a -> Word32 -> Word32 -> Word64 -> CErr ErrFileSeek -> IO Bool++callFileSeek :: (Tox a -> Word32 -> Word32 -> Word64 -> CErr ErrFileSeek -> IO Bool) ->+ Tox a -> Word32 -> Word32 -> Word64 -> IO (Either ErrFileSeek Bool)+callFileSeek f tox fn fileNum pos = callErrFun $ f tox fn fileNum pos++toxFileSeek :: Tox a -> Word32 -> Word32 -> Word64 -> IO (Either ErrFileSeek Bool)+toxFileSeek = callFileSeek tox_file_seek+++data ErrFileGet+ = ErrFileGetOk+ -- The function returned successfully.++ | ErrFileGetNull+ -- One of the arguments to the function was 'nullPtr' when it was not+ -- expected.++ | ErrFileGetFriendNotFound+ -- The friend_number passed did not designate a valid friend.++ | ErrFileGetNotFound+ -- No file transfer with the given file number was found for the given friend.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Copy the file id associated to the file transfer to a byte array.+--+-- @param friend_number The friend number of the friend the file is being+-- transferred to or received from.+-- @param file_number The friend-specific identifier for the file transfer.+-- @param file_id A memory region of at least 'tox_file_id_length' bytes. If+-- this parameter is 'nullPtr', this function has no effect.+--+-- @return true on success.+foreign import ccall tox_file_get_file_id :: Tox a -> Word32 -> Word32 -> CString -> CErr ErrFileGet -> IO Bool++callFileGetFileId :: (Tox a -> Word32 -> Word32 -> CString -> CErr ErrFileGet -> IO Bool) ->+ Tox a -> Word32 -> Word32 -> IO (Either ErrFileGet BS.ByteString)+callFileGetFileId f tox fn fileNum =+ let fileIdLen = fromIntegral tox_file_id_length in+ alloca $ \errPtr ->+ allocaArray fileIdLen $ \fileIdPtr -> do+ _ <- f tox fn fileNum fileIdPtr errPtr+ err <- toEnum . fromIntegral . unCEnum <$> peek errPtr+ fileId <- BS.packCStringLen (fileIdPtr, fileIdLen)+ return $ if err /= minBound+ then Left err+ else Right fileId++toxFileGetFileId :: Tox a -> Word32 -> Word32 -> IO (Either ErrFileGet BS.ByteString)+toxFileGetFileId = callFileGetFileId tox_file_get_file_id+++--------------------------------------------------------------------------------+--+-- :: File transmission: sending+--+--------------------------------------------------------------------------------+++data ErrFileSend+ = ErrFileSendOk+ -- The function returned successfully.++ | ErrFileSendNull+ -- One of the arguments to the function was 'nullPtr' when it was not+ -- expected.++ | ErrFileSendFriendNotFound+ -- The friend_number passed did not designate a valid friend.++ | ErrFileSendFriendNotConnected+ -- This client is currently not connected to the friend.++ | ErrFileSendNameTooLong+ -- Filename length exceeded 'tox_max_filename_length' bytes.++ | ErrFileSendTooMany+ -- Too many ongoing transfers. The maximum number of concurrent file transfers+ -- is 256 per friend per direction (sending and receiving).+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Send a file transmission request.+--+-- Maximum filename length is 'tox_max_filename_length' bytes. The filename+-- should generally just be a file name, not a path with directory names.+--+-- If a non-UINT64_MAX file size is provided, it can be used by both sides to+-- determine the sending progress. File size can be set to UINT64_MAX for+-- streaming data of unknown size.+--+-- File transmission occurs in chunks, which are requested through the+-- `file_chunk_request` event.+--+-- When a friend goes offline, all file transfers associated with the friend are+-- purged from core.+--+-- If the file contents change during a transfer, the behaviour is unspecified+-- in general. What will actually happen depends on the mode in which the file+-- was modified and how the client determines the file size.+--+-- - If the file size was increased+-- - and sending mode was streaming (file_size = UINT64_MAX), the behaviour+-- will be as expected.+-- - and sending mode was file (file_size != UINT64_MAX), the+-- file_chunk_request callback will receive length = 0 when Core thinks+-- the file transfer has finished. If the client remembers the file size as+-- it was when sending the request, it will terminate the transfer normally.+-- If the client re-reads the size, it will think the friend cancelled the+-- transfer.+-- - If the file size was decreased+-- - and sending mode was streaming, the behaviour is as expected.+-- - and sending mode was file, the callback will return 0 at the new+-- (earlier) end-of-file, signalling to the friend that the transfer was+-- cancelled.+-- - If the file contents were modified+-- - at a position before the current read, the two files (local and remote)+-- will differ after the transfer terminates.+-- - at a position after the current read, the file transfer will succeed as+-- expected.+-- - In either case, both sides will regard the transfer as complete and+-- successful.+--+-- @param friend_number The friend number of the friend the file send request+-- should be sent to.+-- @param kind The meaning of the file to be sent.+-- @param file_size Size in bytes of the file the client wants to send,+-- UINT64_MAX if unknown or streaming.+-- @param file_id A file identifier of length 'tox_file_id_length' that can be+-- used to uniquely identify file transfers across core restarts. If+-- 'nullPtr', a random one will be generated by core. It can then be obtained+-- by using tox_file_get_file_id().+-- @param filename Name of the file. Does not need to be the actual name. This+-- name will be sent along with the file send request.+-- @param filename_length Size in bytes of the filename.+--+-- @return A file number used as an identifier in subsequent callbacks. This+-- number is per friend. File numbers are reused after a transfer terminates.+-- On failure, this function returns UINT32_MAX. Any pattern in file numbers+-- should not be relied on.+foreign import ccall tox_file_send :: Tox a -> Word32 -> CEnum FileKind -> Word64 -> CString -> CString -> CSize -> CErr ErrFileSend -> IO Word32+callFileSend :: (Tox a -> Word32 -> CEnum FileKind -> Word64 -> CString -> CString -> CSize -> CErr ErrFileSend -> IO Word32) ->+ Tox a -> Word32 -> FileKind -> Word64 -> String -> IO (Either ErrFileSend Word32)+callFileSend f tox fn fileKind fileSize fileName =+ withCStringLen fileName $ \(fileNamePtr, fileNameLen) ->+ callErrFun $ f tox fn (toCEnum fileKind) fileSize nullPtr fileNamePtr (fromIntegral fileNameLen)++toxFileSend :: Tox a -> Word32 -> FileKind -> Word64 -> String -> IO (Either ErrFileSend Word32)+toxFileSend = callFileSend tox_file_send++data ErrFileSendChunk+ = ErrFileSendChunkOk+ -- The function returned successfully.++ | ErrFileSendChunkNull+ -- The length parameter was non-zero, but data was 'nullPtr'.++ | ErrFileSendChunkFriendNotFound+ -- The friend_number passed did not designate a valid friend.++ | ErrFileSendChunkFriendNotConnected+ -- This client is currently not connected to the friend.++ | ErrFileSendChunkNotFound+ -- No file transfer with the given file number was found for the given friend.++ | ErrFileSendChunkNotTransferring+ -- File transfer was found but isn't in a transferring state: (paused, done,+ -- broken, etc...) (happens only when not called from the request chunk+ -- callback).++ | ErrFileSendChunkInvalidLength+ -- Attempted to send more or less data than requested. The requested data+ -- size is adjusted according to maximum transmission unit and the expected+ -- end of the file. Trying to send less or more than requested will return+ -- this error.++ | ErrFileSendChunkSendq+ -- Packet queue is full.++ | ErrFileSendChunkWrongPosition+ -- Position parameter was wrong.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Send a chunk of file data to a friend.+--+-- This function is called in response to the `file_chunk_request` callback.+-- The length parameter should be equal to the one received though the+-- callback. If it is zero, the transfer is assumed complete. For files with+-- known size, Core will know that the transfer is complete after the last byte+-- has been received, so it is not necessary (though not harmful) to send a+-- zero-length chunk to terminate. For streams, core will know that the+-- transfer is finished if a chunk with length less than the length requested+-- in the callback is sent.+--+-- @param friend_number The friend number of the receiving friend for this file.+-- @param file_number The file transfer identifier returned by tox_file_send.+-- @param position The file or stream position from which to continue reading.+-- @return true on success.+foreign import ccall tox_file_send_chunk :: Tox a -> Word32 -> Word32 -> Word64 -> CString -> CSize -> CErr ErrFileSendChunk -> IO Bool+callFileSendChunk :: (Tox a -> Word32 -> Word32 -> Word64 -> CString -> CSize -> CErr ErrFileSendChunk -> IO Bool) ->+ Tox a -> Word32 -> Word32 -> Word64 -> BS.ByteString -> IO (Either ErrFileSendChunk Bool)+callFileSendChunk f tox fn fileNum pos d =+ BS.useAsCStringLen d $ \(dataPtr, dataLen) ->+ callErrFun $ f tox fn fileNum pos dataPtr (fromIntegral dataLen)++toxFileSendChunk :: Tox a -> Word32 -> Word32 -> Word64 -> BS.ByteString -> IO (Either ErrFileSendChunk Bool)+toxFileSendChunk = callFileSendChunk tox_file_send_chunk++-- | If the length parameter is 0, the file transfer is finished, and the+-- client's resources associated with the file number should be released. After+-- a call with zero length, the file number can be reused for future file+-- transfers.+--+-- If the requested position is not equal to the client's idea of the current+-- file or stream position, it will need to seek. In case of read-once streams,+-- the client should keep the last read chunk so that a seek back can be+-- supported. A seek-back only ever needs to read from the last requested+-- chunk. This happens when a chunk was requested, but the send failed. A+-- seek-back request can occur an arbitrary number of times for any given+-- chunk.+--+-- In response to receiving this callback, the client should call the function+-- `tox_file_send_chunk` with the requested chunk. If the number of bytes sent+-- through that function is zero, the file transfer is assumed complete. A+-- client must send the full length of data requested with this callback.+--+-- @param friend_number The friend number of the receiving friend for this file.+-- @param file_number The file transfer identifier returned by tox_file_send.+-- @param position The file or stream position from which to continue reading.+-- @param length The number of bytes requested for the current chunk.+type FileChunkRequestCb a = Tox a -> Word32 -> Word32 -> Word64 -> CSize -> a -> IO a+type CFileChunkRequestCb a = Tox a -> Word32 -> Word32 -> Word64 -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFileChunkRequestCb :: CFileChunkRequestCb a -> IO (FunPtr (CFileChunkRequestCb a))++callFileChunkRequestCb :: FileChunkRequestCb a -> CFileChunkRequestCb a+callFileChunkRequestCb f tox fn fileNum pos len = deRefStablePtr >=> (`modifyMVar_` f tox fn fileNum pos len)++fileChunkRequestCb :: FileChunkRequestCb a -> IO (FunPtr (CFileChunkRequestCb a))+fileChunkRequestCb = wrapFileChunkRequestCb . callFileChunkRequestCb++-- | Set the callback for the `file_chunk_request` event. Pass 'nullPtr' to+-- unset.+--+-- This event is triggered when Core is ready to send more file data.+foreign import ccall tox_callback_file_chunk_request :: Tox a -> FunPtr (CFileChunkRequestCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: File transmission: receiving+--+--------------------------------------------------------------------------------+++-- | The client should acquire resources to be associated with the file+-- transfer. Incoming file transfers start in the Paused state. After this+-- callback returns, a transfer can be rejected by sending a FileControlCancel+-- control command before any other control commands. It can be accepted by+-- sending FileControlResume.+--+-- @param friend_number The friend number of the friend who is sending the file+-- transfer request.+-- @param file_number The friend-specific file number the data received is+-- associated with.+-- @param kind The meaning of the file to be sent.+-- @param file_size Size in bytes of the file the client wants to send,+-- UINT64_MAX if unknown or streaming.+-- @param filename Name of the file. Does not need to be the actual name. This+-- name will be sent along with the file send request.+-- @param filename_length Size in bytes of the filename.+type FileRecvCb a = Tox a -> Word32 -> Word32 -> FileKind -> Word64 -> String -> a -> IO a+type CFileRecvCb a = Tox a -> Word32 -> Word32 -> CEnum FileKind -> Word64 -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFileRecvCb :: CFileRecvCb a -> IO (FunPtr (CFileRecvCb a))++callFileRecvCb :: FileRecvCb a -> CFileRecvCb a+callFileRecvCb f tox fn fileNum fileKind fileSize fileNameStr fileNameLen udPtr = do+ ud <- deRefStablePtr udPtr+ fileName <- peekCStringLen (fileNameStr, fromIntegral fileNameLen)+ modifyMVar_ ud $ f tox fn fileNum (fromCEnum fileKind) fileSize fileName++fileRecvCb :: FileRecvCb a -> IO (FunPtr (CFileRecvCb a))+fileRecvCb = wrapFileRecvCb . callFileRecvCb+++-- | Set the callback for the `file_recv` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a file transfer request is received.+foreign import ccall tox_callback_file_recv :: Tox a -> FunPtr (CFileRecvCb a) -> IO ()++-- | When length is 0, the transfer is finished and the client should release+-- the resources it acquired for the transfer. After a call with length = 0,+-- the file number can be reused for new file transfers.+--+-- If position is equal to file_size (received in the file_receive callback)+-- when the transfer finishes, the file was received completely. Otherwise, if+-- file_size was UINT64_MAX, streaming ended successfully when length is 0.+--+-- @param friend_number The friend number of the friend who is sending the file.+-- @param file_number The friend-specific file number the data received is+-- associated with.+-- @param position The file position of the first byte in data.+-- @param data A byte array containing the received chunk.+-- @param length The length of the received chunk.+type FileRecvChunkCb a = Tox a -> Word32 -> Word32 -> Word64 -> BS.ByteString -> a -> IO a+type CFileRecvChunkCb a = Tox a -> Word32 -> Word32 -> Word64 -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFileRecvChunkCb :: CFileRecvChunkCb a -> IO (FunPtr (CFileRecvChunkCb a))++callFileRecvChunkCb :: FileRecvChunkCb a -> CFileRecvChunkCb a+callFileRecvChunkCb f tox fn fileNum pos dataPtr dataLen udPtr = do+ ud <- deRefStablePtr udPtr+ d <- BS.packCStringLen (dataPtr, fromIntegral dataLen)+ modifyMVar_ ud $ f tox fn fileNum pos d++fileRecvChunkCb :: FileRecvChunkCb a -> IO (FunPtr (CFileRecvChunkCb a))+fileRecvChunkCb = wrapFileRecvChunkCb . callFileRecvChunkCb+++-- | Set the callback for the `file_recv_chunk` event. Pass 'nullPtr' to unset.+--+-- This event is first triggered when a file transfer request is received, and+-- subsequently when a chunk of file data for an accepted request was received.+foreign import ccall tox_callback_file_recv_chunk :: Tox a -> FunPtr (CFileRecvChunkCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Conference management+--+--------------------------------------------------------------------------------+++-- | Conference types for the conference_invite event.+data ConferenceType+ = ConferenceTypeText+ -- Text-only conferences that must be accepted with the tox_conference_join function.++ | ConferenceTypeAv+ -- Video conference. The function to accept these is in toxav.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | The invitation will remain valid until the inviting friend goes offline+-- or exits the conference.+--+-- @param friend_number The friend who invited us.+-- @param type The conference type (text only or audio/video).+-- @param cookie A piece of data of variable length required to join the+-- conference.+-- @param length The length of the cookie.+type ConferenceInviteCb a = Tox a -> Word32 -> ConferenceType -> BS.ByteString -> a -> IO a+type CConferenceInviteCb a = Tox a -> Word32 -> CEnum ConferenceType -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapConferenceInviteCb :: CConferenceInviteCb a -> IO (FunPtr (CConferenceInviteCb a))++callConferenceInviteCb :: ConferenceInviteCb a -> CConferenceInviteCb a+callConferenceInviteCb f tox fn confType cookiePtr cookieLen udPtr = do+ ud <- deRefStablePtr udPtr+ cookie <- BS.packCStringLen (cookiePtr, fromIntegral cookieLen)+ modifyMVar_ ud $ f tox fn (fromCEnum confType) cookie++conferenceInviteCb :: ConferenceInviteCb a -> IO (FunPtr (CConferenceInviteCb a))+conferenceInviteCb = wrapConferenceInviteCb . callConferenceInviteCb+++-- | Set the callback for the `conference_invite` event. Pass NULL to unset.+--+-- This event is triggered when the client is invited to join a conference.+foreign import ccall tox_callback_conference_invite :: Tox a -> FunPtr (CConferenceInviteCb a) -> IO ()+++-- | @param conference_number The conference number of the conference the message is intended for.+-- @param peer_number The ID of the peer who sent the message.+-- @param type The type of message (normal, action, ...).+-- @param message The message data.+-- @param length The length of the message.+type ConferenceMessageCb a = Tox a -> Word32 -> Word32 -> MessageType -> String -> a -> IO a+type CConferenceMessageCb a = Tox a -> Word32 -> Word32 -> CEnum MessageType -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapConferenceMessageCb :: CConferenceMessageCb a -> IO (FunPtr (CConferenceMessageCb a))++callConferenceMessageCb :: ConferenceMessageCb a -> CConferenceMessageCb a+callConferenceMessageCb f tox gn pn msgType msgStr msgLen udPtr = do+ ud <- deRefStablePtr udPtr+ msg <- peekCStringLen (msgStr, fromIntegral msgLen)+ modifyMVar_ ud $ f tox gn pn (fromCEnum msgType) msg++conferenceMessageCb :: ConferenceMessageCb a -> IO (FunPtr (CConferenceMessageCb a))+conferenceMessageCb = wrapConferenceMessageCb . callConferenceMessageCb+++-- | Set the callback for the `conference_message` event. Pass NULL to unset.+--+-- This event is triggered when the client receives a conference message.+foreign import ccall tox_callback_conference_message :: Tox a -> FunPtr (CConferenceMessageCb a) -> IO ()+++-- | @param conference_number The conference number of the conference the title change is intended for.+-- @param peer_number The ID of the peer who changed the title.+-- @param title The title data.+-- @param length The title length.+type ConferenceTitleCb a = Tox a -> Word32 -> Word32 -> String -> a -> IO a+type CConferenceTitleCb a = Tox a -> Word32 -> Word32 -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapConferenceTitleCb :: CConferenceTitleCb a -> IO (FunPtr (CConferenceTitleCb a))++callConferenceTitleCb :: ConferenceTitleCb a -> CConferenceTitleCb a+callConferenceTitleCb f tox gn pn titleStr titleLen udPtr = do+ ud <- deRefStablePtr udPtr+ title <- peekCStringLen (titleStr, fromIntegral titleLen)+ modifyMVar_ ud $ f tox gn pn title++conferenceTitleCb :: ConferenceTitleCb a -> IO (FunPtr (CConferenceTitleCb a))+conferenceTitleCb = wrapConferenceTitleCb . callConferenceTitleCb+++-- | Set the callback for the `conference_title` event. Pass NULL to unset.+--+-- This event is triggered when a peer changes the conference title.+--+-- If peer_number == UINT32_MAX, then author is unknown (e.g. initial joining the conference).+foreign import ccall tox_callback_conference_title :: Tox a -> FunPtr (CConferenceTitleCb a) -> IO ()+++-- | @param conference_number The conference number of the conference the peer is in.+-- @param peer_number The ID of the peer who changed their name.+-- @param name The new name of the peer.+type ConferencePeerNameCb a = Tox a -> Word32 -> Word32 -> String -> a -> IO a+type CConferencePeerNameCb a = Tox a -> Word32 -> Word32 -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapConferencePeerNameCb :: CConferencePeerNameCb a -> IO (FunPtr (CConferencePeerNameCb a))++callConferencePeerNameCb :: ConferencePeerNameCb a -> CConferencePeerNameCb a+callConferencePeerNameCb f tox gn pn nameStr nameLen udPtr = do+ ud <- deRefStablePtr udPtr+ name <- peekCStringLen (nameStr, fromIntegral nameLen)+ modifyMVar_ ud $ f tox gn pn name++conferencePeerNameCb :: ConferencePeerNameCb a -> IO (FunPtr (CConferencePeerNameCb a))+conferencePeerNameCb = wrapConferencePeerNameCb . callConferencePeerNameCb+++-- | Set the callback for the `conference_peer_name` event. Pass NULL to unset.+--+-- This event is triggered when the peer changes their nickname.+foreign import ccall tox_callback_conference_peer_name :: Tox a -> FunPtr (CConferencePeerNameCb a) -> IO ()+++-- | @param conference_number The conference number of the conference for which the peer list changed.+type ConferencePeerListChangedCb a = Tox a -> Word32 -> a -> IO a+type CConferencePeerListChangedCb a = Tox a -> Word32 -> UserData a -> IO ()+foreign import ccall "wrapper" wrapConferencePeerListChangedCb :: CConferencePeerListChangedCb a -> IO (FunPtr (CConferencePeerListChangedCb a))++callConferencePeerListChangedCb :: ConferencePeerListChangedCb a -> CConferencePeerListChangedCb a+callConferencePeerListChangedCb f tox gn = deRefStablePtr >=> (`modifyMVar_` f tox gn)++conferencePeerListChangedCb :: ConferencePeerListChangedCb a -> IO (FunPtr (CConferencePeerListChangedCb a))+conferencePeerListChangedCb = wrapConferencePeerListChangedCb . callConferencePeerListChangedCb+++-- | Set the callback for the `conference_peer_list_changed` event. Pass NULL to unset.+--+-- This event is triggered when the peer list changes (peer join, peer exit).+foreign import ccall tox_callback_conference_peer_list_changed :: Tox a -> FunPtr (CConferencePeerListChangedCb a) -> IO ()+++data ErrConferenceNew+ = ErrConferenceNewOk+ -- The function returned successfully.++ | ErrConferenceNewInit+ -- The conference instance failed to initialize.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Creates a new conference.+--+-- This function creates a new text conference.+--+-- @return conference number on success, or UINT32_MAX on failure.+foreign import ccall tox_conference_new :: Tox a -> CErr ErrConferenceNew -> IO Word32+callConferenceNew :: (Tox a -> CErr ErrConferenceNew -> IO Word32) ->+ Tox a -> IO (Either ErrConferenceNew Word32)+callConferenceNew f tox = callErrFun $ f tox++toxConferenceNew :: Tox a -> IO (Either ErrConferenceNew Word32)+toxConferenceNew = callConferenceNew tox_conference_new+++data ErrConferenceDelete+ = ErrConferenceDeleteOk+ -- The function returned successfully.++ | ErrConferenceDeleteConferenceNotFound+ -- The conference number passed did not designate a valid conference.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | This function deletes a conference.+--+-- @param conference_number The conference number of the conference to be deleted.+--+-- @return true on success.+foreign import ccall tox_conference_delete :: Tox a -> Word32 -> CErr ErrConferenceDelete -> IO Bool+callConferenceDelete :: (Tox a -> Word32 -> CErr ErrConferenceDelete -> IO Bool) ->+ Tox a -> Word32 -> IO (Either ErrConferenceDelete Bool)+callConferenceDelete f tox gn = callErrFun $ f tox gn++toxConferenceDelete :: Tox a -> Word32 -> IO (Either ErrConferenceDelete Bool)+toxConferenceDelete = callConferenceDelete tox_conference_delete+++-- | Error codes for peer info queries.+data ErrConferencePeerQuery+ = ErrConferencePeerQueryOk+ -- The function returned successfully.++ | ErrConferencePeerQueryConferenceNotFound+ -- The conference number passed did not designate a valid conference.++ | ErrConferencePeerQueryPeerNotFound+ -- The peer number passed did not designate a valid peer.++ | ErrConferencePeerQueryNoConnection+ -- The client is not connected to the conference.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)++++-- | Return the number of peers in the conference. Return value is unspecified on failure.+foreign import ccall tox_conference_peer_count :: Tox a -> Word32 -> CErr ErrConferencePeerQuery -> IO Word32+callConferencePeerCount :: (Tox a -> Word32 -> CErr ErrConferencePeerQuery -> IO Word32) ->+ Tox a -> Word32 -> IO (Either ErrConferencePeerQuery Word32)+callConferencePeerCount f tox gn = callErrFun $ f tox gn++toxConferencePeerCount :: Tox a -> Word32 -> IO (Either ErrConferencePeerQuery Word32)+toxConferencePeerCount = callConferencePeerCount tox_conference_peer_count+++-- | Return the length of the peer's name. Return value is unspecified on failure.+foreign import ccall tox_conference_peer_get_name_size :: Tox a -> Word32 -> Word32 -> CErr ErrConferencePeerQuery -> IO CSize+++-- | Copy the name of peer_number who is in conference_number to name.+-- name must be at least TOX_MAX_NAME_LENGTH long.+--+-- @return true on success.+foreign import ccall tox_conference_peer_get_name :: Tox a -> Word32 -> Word32 -> CString -> CErr ErrConferencePeerQuery -> IO Bool++toxConferencePeerGetName :: Tox a -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery String)+toxConferencePeerGetName tox gn pn = do+ nameLenRes <- callErrFun $ tox_conference_peer_get_name_size tox gn pn+ case nameLenRes of+ Left err -> return $ Left err+ Right nameLen -> allocaArray (fromIntegral nameLen) $ \namePtr -> do+ nameRes <- callErrFun $ tox_conference_peer_get_name tox gn pn namePtr+ case nameRes of+ Left err -> return $ Left err+ Right _ ->+ Right <$> peekCStringLen (namePtr, fromIntegral nameLen)+++-- | Copy the public key of peer_number who is in conference_number to public_key.+-- public_key must be TOX_PUBLIC_KEY_SIZE long.+--+-- @return true on success.+foreign import ccall tox_conference_peer_get_public_key :: Tox a -> Word32 -> Word32 -> CString -> CErr ErrConferencePeerQuery -> IO Bool+callConferencePeerGetPublicKey :: (Tox a -> Word32 -> Word32 -> CString -> CErr ErrConferencePeerQuery -> IO Bool) ->+ Tox a -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery BS.ByteString)+callConferencePeerGetPublicKey f tox gn pn =+ let pkLen = fromIntegral tox_public_key_size in+ alloca $ \errPtr ->+ allocaArray pkLen $ \pkPtr -> do+ _ <- f tox gn pn pkPtr errPtr+ callGetPublicKey errPtr pkPtr pkLen++toxConferencePeerGetPublicKey :: Tox a -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery BS.ByteString)+toxConferencePeerGetPublicKey = callConferencePeerGetPublicKey tox_conference_peer_get_public_key+++-- | Return true if passed peer_number corresponds to our own.+foreign import ccall tox_conference_peer_number_is_ours :: Tox a -> Word32 -> Word32 -> CErr ErrConferencePeerQuery -> IO Bool+callConferencePeerNumberIsOurs :: (Tox a -> Word32 -> Word32 -> CErr ErrConferencePeerQuery -> IO Bool) ->+ Tox a -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery Bool)+callConferencePeerNumberIsOurs f tox gn pn = callErrFun $ f tox gn pn++toxConferencePeerNumberIsOurs :: Tox a -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery Bool)+toxConferencePeerNumberIsOurs = callConferencePeerNumberIsOurs tox_conference_peer_number_is_ours+++data ErrConferenceInvite+ = ErrConferenceInviteOk+ -- The function returned successfully.++ | ErrConferenceInviteConferenceNotFound+ -- The conference number passed did not designate a valid conference.++ | ErrConferenceInviteFailSend+ -- The invite packet failed to send.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)++++-- | Invites a friend to a conference.+--+-- @param friend_number The friend number of the friend we want to invite.+-- @param conference_number The conference number of the conference we want to invite the friend to.+--+-- @return true on success.+foreign import ccall tox_conference_invite :: Tox a -> Word32 -> Word32 -> CErr ErrConferenceInvite -> IO Bool+callConferenceInvite :: (Tox a -> Word32 -> Word32 -> CErr ErrConferenceInvite -> IO Bool) ->+ Tox a -> Word32 -> Word32 -> IO (Either ErrConferenceInvite Bool)+callConferenceInvite f tox fn gn = callErrFun $ f tox fn gn++toxConferenceInvite :: Tox a -> Word32 -> Word32 -> IO (Either ErrConferenceInvite Bool)+toxConferenceInvite = callConferenceInvite tox_conference_invite+++data ErrConferenceJoin+ = ErrConferenceJoinOk+ -- The function returned successfully.++ | ErrConferenceJoinInvalidLength+ -- The cookie passed has an invalid length.++ | ErrConferenceJoinWrongType+ -- The conference is not the expected type. This indicates an invalid cookie.++ | ErrConferenceJoinFriendNotFound+ -- The friend number passed does not designate a valid friend.++ | ErrConferenceJoinDuplicate+ -- Client is already in this conference.++ | ErrConferenceJoinInitFail+ -- Conference instance failed to initialize.++ | ErrConferenceJoinFailSend+ -- The join packet failed to send.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)++++-- | Joins a conference that the client has been invited to.+--+-- @param friend_number The friend number of the friend who sent the invite.+-- @param cookie Received via the `conference_invite` event.+-- @param length The size of cookie.+--+-- @return conference number on success, UINT32_MAX on failure.+foreign import ccall tox_conference_join :: Tox a -> Word32 -> CString -> CSize -> CErr ErrConferenceJoin -> IO Word32+callConferenceJoin :: (Tox a -> Word32 -> CString -> CSize -> CErr ErrConferenceJoin -> IO Word32) ->+ Tox a -> Word32 -> BS.ByteString -> IO (Either ErrConferenceJoin Word32)+callConferenceJoin f tox fn cookie =+ BS.useAsCStringLen cookie $ \(cookiePtr, cookieLen) ->+ callErrFun $ f tox fn cookiePtr (fromIntegral cookieLen)++toxConferenceJoin :: Tox a -> Word32 -> BS.ByteString -> IO (Either ErrConferenceJoin Word32)+toxConferenceJoin = callConferenceJoin tox_conference_join+++data ErrConferenceSendMessage+ = ErrConferenceSendMessageOk+ -- The function returned successfully.++ | ErrConferenceSendMessageConferenceNotFound+ -- The conference number passed did not designate a valid conference.++ | ErrConferenceSendMessageTooLong+ -- The message is too long.++ | ErrConferenceSendMessageNoConnection+ -- The client is not connected to the conference.++ | ErrConferenceSendMessageFailSend+ -- The message packet failed to send.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)++++-- | Send a text chat message to the conference.+--+-- This function creates a conference message packet and pushes it into the send+-- queue.+--+-- The message length may not exceed TOX_MAX_MESSAGE_LENGTH. Larger messages+-- must be split by the client and sent as separate messages. Other clients can+-- then reassemble the fragments.+--+-- @param conference_number The conference number of the conference the message is intended for.+-- @param type Message type (normal, action, ...).+-- @param message A non-NULL pointer to the first element of a byte array+-- containing the message text.+-- @param length Length of the message to be sent.+--+-- @return true on success.+foreign import ccall tox_conference_send_message :: Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrConferenceSendMessage -> IO Bool+callConferenceSendMessage :: (Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrConferenceSendMessage -> IO Bool) ->+ Tox a -> Word32 -> MessageType -> String -> IO (Either ErrConferenceSendMessage Bool)+callConferenceSendMessage f tox gn messageType message =+ withCStringLen message $ \(msgPtr, msgLen) ->+ callErrFun $ f tox gn (toCEnum messageType) msgPtr (fromIntegral msgLen)++toxConferenceSendMessage :: Tox a -> Word32 -> MessageType -> String -> IO (Either ErrConferenceSendMessage Bool)+toxConferenceSendMessage = callConferenceSendMessage tox_conference_send_message+++data ErrConferenceTitle+ = ErrConferenceTitleOk+ -- The function returned successfully.++ | ErrConferenceTitleConferenceNotFound+ -- The conference number passed did not designate a valid conference.++ | ErrConferenceTitleInvalidLength+ -- The title is too long or empty.++ | ErrConferenceTitleFailSend+ -- The title packet failed to send.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)++++-- | Return the length of the conference title. Return value is unspecified on failure.+--+-- The return value is equal to the `length` argument received by the last+-- `conference_title` callback.+foreign import ccall tox_conference_get_title_size :: Tox a -> Word32 -> CErr ErrConferenceTitle -> IO CSize+++-- | Write the title designated by the given conference number to a byte array.+--+-- Call tox_conference_get_title_size to determine the allocation size for the `title` parameter.+--+-- The data written to `title` is equal to the data received by the last+-- `conference_title` callback.+--+-- @param title A valid memory region large enough to store the title.+-- If this parameter is NULL, this function has no effect.+--+-- @return true on success.+foreign import ccall tox_conference_get_title :: Tox a -> Word32 -> CString -> CErr ErrConferenceTitle -> IO Bool++toxConferenceGetTitle :: Tox a -> Word32 -> IO (Either ErrConferenceTitle String)+toxConferenceGetTitle tox gn = do+ titleLenRes <- callErrFun $ tox_conference_get_title_size tox gn+ case titleLenRes of+ Left err -> return $ Left err+ Right titleLen -> allocaArray (fromIntegral titleLen) $ \titlePtr -> do+ titleRes <- callErrFun $ tox_conference_get_title tox gn titlePtr+ case titleRes of+ Left err -> return $ Left err+ Right _ ->+ Right <$> peekCStringLen (titlePtr, fromIntegral titleLen)++-- | Set the conference title and broadcast it to the rest of the conference.+--+-- Title length cannot be longer than TOX_MAX_NAME_LENGTH.+--+-- @return true on success.+foreign import ccall tox_conference_set_title :: Tox a -> Word32 -> CString -> CSize -> CErr ErrConferenceTitle -> IO Bool+callConferenceSetTitle :: (Tox a -> Word32 -> CString -> CSize -> CErr ErrConferenceTitle -> IO Bool) ->+ Tox a -> Word32 -> String -> IO (Either ErrConferenceTitle Bool)+callConferenceSetTitle f tox gn title =+ withCStringLen title $ \(titlePtr, titleLen) ->+ callErrFun $ f tox gn titlePtr (fromIntegral titleLen)++toxConferenceSetTitle :: Tox a -> Word32 -> String -> IO (Either ErrConferenceTitle Bool)+toxConferenceSetTitle = callConferenceSetTitle tox_conference_set_title+++-- | Return the number of conferences in the Tox instance.+-- This should be used to determine how much memory to allocate for `tox_conference_get_chatlist`.+foreign import ccall tox_conference_get_chatlist_size :: Tox a -> IO CSize+++-- | Copy a list of valid conference IDs into the array chatlist. Determine how much space+-- to allocate for the array with the `tox_conference_get_chatlist_size` function.+foreign import ccall tox_conference_get_chatlist :: Tox a -> Ptr Word32 -> IO ()++toxConferenceGetChatlist :: Tox a -> IO [Word32]+toxConferenceGetChatlist tox = do+ chatListSize <- tox_conference_get_chatlist_size tox+ allocaArray (fromIntegral chatListSize) $ \chatListPtr -> do+ tox_conference_get_chatlist tox chatListPtr+ peekArray (fromIntegral chatListSize) chatListPtr++-- | Returns the type of conference (TOX_CONFERENCE_TYPE) that conference_number is. Return value is+-- unspecified on failure.+data ErrConferenceGetType+ = ErrConferenceGetTypeOk+ -- The function returned successfully.++ | ErrConferenceGetTypeConferenceNotFound+ -- The conference number passed did not designate a valid conference.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)++foreign import ccall tox_conference_get_type :: Tox a -> Word32 -> CErr ErrConferenceGetType -> IO (CEnum ConferenceType)+callConferenceGetType :: (Tox a -> Word32 -> CErr ErrConferenceGetType -> IO (CEnum ConferenceType)) ->+ Tox a -> Word32 -> IO (Either ErrConferenceGetType ConferenceType)+callConferenceGetType f tox gn = callErrFun (f tox gn >=> (return . fromCEnum))++toxConferenceGetType :: Tox a -> Word32 -> IO (Either ErrConferenceGetType ConferenceType)+toxConferenceGetType = callConferenceGetType tox_conference_get_type+++--------------------------------------------------------------------------------+--+-- :: Low-level custom packet sending and receiving+--+--------------------------------------------------------------------------------+++data ErrFriendCustomPacket+ = ErrFriendCustomPacketOk+ -- The function returned successfully.++ | ErrFriendCustomPacketNull+ -- One of the arguments to the function was 'nullPtr' when it was not+ -- expected.++ | ErrFriendCustomPacketFriendNotFound+ -- The friend number did not designate a valid friend.++ | ErrFriendCustomPacketFriendNotConnected+ -- This client is currently not connected to the friend.++ | ErrFriendCustomPacketInvalid+ -- The first byte of data was not in the specified range for the packet+ -- type. This range is 200-254 for lossy, and 160-191 for lossless packets.++ | ErrFriendCustomPacketEmpty+ -- Attempted to send an empty packet.++ | ErrFriendCustomPacketTooLong+ -- Packet data length exceeded 'tox_max_custom_packet_size'.++ | ErrFriendCustomPacketSendq+ -- Packet queue is full.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Send a custom lossy packet to a friend.+--+-- The first byte of data must be in the range 200-254. Maximum length of a+-- custom packet is 'tox_max_custom_packet_size'.+--+-- Lossy packets behave like UDP packets, meaning they might never reach the+-- other side or might arrive more than once (if someone is messing with the+-- connection) or might arrive in the wrong order.+--+-- Unless latency is an issue, it is recommended that you use lossless custom+-- packets instead.+--+-- @param friend_number The friend number of the friend this lossy packet+-- should be sent to.+-- @param data A byte array containing the packet data.+-- @param length The length of the packet data byte array.+--+-- @return true on success.+foreign import ccall tox_friend_send_lossy_packet :: Tox a -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool+callFriendLossyPacket :: (Tox a -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool) ->+ Tox a -> Word32 -> BS.ByteString -> IO (Either ErrFriendCustomPacket Bool)+callFriendLossyPacket f tox fn d =+ BS.useAsCStringLen d $ \(dataPtr, dataLen) ->+ callErrFun $ f tox fn dataPtr (fromIntegral dataLen)++toxFriendLossyPacket :: Tox a -> Word32 -> BS.ByteString -> IO (Either ErrFriendCustomPacket Bool)+toxFriendLossyPacket = callFriendLossyPacket tox_friend_send_lossy_packet++-- | Send a custom lossless packet to a friend.+--+-- The first byte of data must be in the range 160-191. Maximum length of a+-- custom packet is 'tox_max_custom_packet_size'.+--+-- Lossless packet behaviour is comparable to TCP (reliability, arrive in order)+-- but with packets instead of a stream.+--+-- @param friend_number The friend number of the friend this lossless packet+-- should be sent to.+-- @param data A byte array containing the packet data.+-- @param length The length of the packet data byte array.+--+-- @return true on success.+foreign import ccall tox_friend_send_lossless_packet :: Tox a -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool+callFriendLosslessPacket :: (Tox a -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool) ->+ Tox a -> Word32 -> BS.ByteString -> IO (Either ErrFriendCustomPacket Bool)+callFriendLosslessPacket f tox fn d =+ BS.useAsCStringLen d $ \(dataPtr, dataLen) ->+ callErrFun $ f tox fn dataPtr (fromIntegral dataLen)++toxFriendLosslessPacket :: Tox a -> Word32 -> BS.ByteString -> IO (Either ErrFriendCustomPacket Bool)+toxFriendLosslessPacket = callFriendLosslessPacket tox_friend_send_lossless_packet++callFriendCustomPacketCb :: FriendLosslessPacketCb a -> CFriendLosslessPacketCb a+callFriendCustomPacketCb f tox fn dataPtr dataLen udPtr = do+ ud <- deRefStablePtr udPtr+ d <- BS.packCStringLen (dataPtr, fromIntegral dataLen)+ modifyMVar_ ud $ f tox fn d++-- | @param friend_number The friend number of the friend who sent a lossy+-- packet.+-- @param data A byte array containing the received packet data.+-- @param length The length of the packet data byte array.+type FriendLossyPacketCb a = Tox a -> Word32 -> BS.ByteString -> a -> IO a+type CFriendLossyPacketCb a = Tox a -> Word32 -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFriendLossyPacketCb :: CFriendLossyPacketCb a -> IO (FunPtr (CFriendLossyPacketCb a))++callFriendLossyPacketCb :: FriendLossyPacketCb a -> CFriendLossyPacketCb a+callFriendLossyPacketCb = callFriendCustomPacketCb++friendLossyPacketCb :: FriendLossyPacketCb a -> IO (FunPtr (CFriendLossyPacketCb a))+friendLossyPacketCb = wrapFriendLossyPacketCb . callFriendLossyPacketCb+++-- | Set the callback for the `friend_lossy_packet` event. Pass 'nullPtr' to+-- unset.+--+foreign import ccall tox_callback_friend_lossy_packet :: Tox a -> FunPtr (CFriendLossyPacketCb a) -> IO ()++-- | @param friend_number The friend number of the friend who sent the packet.+-- @param data A byte array containing the received packet data.+-- @param length The length of the packet data byte array.+type FriendLosslessPacketCb a = Tox a -> Word32 -> BS.ByteString -> a -> IO a+type CFriendLosslessPacketCb a = Tox a -> Word32 -> CString -> CSize -> UserData a -> IO ()+foreign import ccall "wrapper" wrapFriendLosslessPacketCb :: CFriendLosslessPacketCb a -> IO (FunPtr (CFriendLosslessPacketCb a))++callFriendLosslessPacketCb :: FriendLosslessPacketCb a -> CFriendLosslessPacketCb a+callFriendLosslessPacketCb = callFriendCustomPacketCb++friendLosslessPacketCb :: FriendLosslessPacketCb a -> IO (FunPtr (CFriendLosslessPacketCb a))+friendLosslessPacketCb = wrapFriendLosslessPacketCb . callFriendLosslessPacketCb+++-- | Set the callback for the `friend_lossless_packet` event. Pass 'nullPtr' to+-- unset.+--+foreign import ccall tox_callback_friend_lossless_packet :: Tox a -> FunPtr (CFriendLosslessPacketCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Low-level network information+--+--------------------------------------------------------------------------------+++-- | Writes the temporary DHT public key of this instance to a byte array.+--+-- This can be used in combination with an externally accessible IP address and+-- the bound port (from tox_self_get_udp_port) to run a temporary bootstrap+-- node.+--+-- Be aware that every time a new instance is created, the DHT public key+-- changes, meaning this cannot be used to run a permanent bootstrap node.+--+-- @param dht_id A memory region of at least 'tox_public_key_size' bytes. If+-- this parameter is 'nullPtr', this function has no effect.+foreign import ccall tox_self_get_dht_id :: Tox a -> CString -> IO ()++toxSelfGetDhtId :: Tox a -> IO BS.ByteString+toxSelfGetDhtId tox =+ let idLen = fromIntegral tox_public_key_size in+ allocaArray idLen $ \idPtr -> do+ tox_self_get_dht_id tox idPtr+ BS.packCStringLen (idPtr, idLen)++data ErrGetPort+ = ErrGetPortOk+ -- The function returned successfully.++ | ErrGetPortNotBound+ -- The instance was not bound to any port.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Return the UDP port this Tox instance is bound to.+foreign import ccall tox_self_get_udp_port :: Tox a -> CErr ErrGetPort -> IO Word16+callSelfGetUdpPort :: (Tox a -> CErr ErrGetPort -> IO Word16) ->+ Tox a -> IO (Either ErrGetPort Word16)+callSelfGetUdpPort f tox = callErrFun $ f tox++toxSelfGetUdpPort :: Tox a -> IO (Either ErrGetPort Word16)+toxSelfGetUdpPort = callSelfGetUdpPort tox_self_get_udp_port++-- | Return the TCP port this Tox instance is bound to. This is only relevant if+-- the instance is acting as a TCP relay.+foreign import ccall tox_self_get_tcp_port :: Tox a -> CErr ErrGetPort -> IO Word16+callSelfGetTcpPort :: (Tox a -> CErr ErrGetPort -> IO Word16) ->+ Tox a -> IO (Either ErrGetPort Word16)+callSelfGetTcpPort f tox = callErrFun $ f tox++toxSelfGetTcpPort :: Tox a -> IO (Either ErrGetPort Word16)+toxSelfGetTcpPort = callSelfGetTcpPort tox_self_get_udp_port
+ src/Network/Tox/C/Type.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE Safe #-}+module Network.Tox.C.Type where++import Control.Concurrent.MVar (MVar)+import Foreign.Ptr (Ptr)+import Foreign.StablePtr (StablePtr)+++-- | The Tox instance type. All the state associated with a connection is held+-- within the instance. Multiple instances can exist and operate concurrently.+-- The maximum number of Tox instances that can exist on a single network device+-- is limited. Note that this is not just a per-process limit, since the+-- limiting factor is the number of usable ports on a device.+data ToxStruct a+type Tox a = Ptr (ToxStruct a)++type UserData a = StablePtr (MVar a)
+ src/Network/Tox/C/Version.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE Trustworthy #-}+module Network.Tox.C.Version where++import Data.Word (Word32)++--------------------------------------------------------------------------------+--+-- :: API version+--+--------------------------------------------------------------------------------++-- | The major version number. Incremented when the API or ABI changes in an+-- incompatible way.+foreign import ccall tox_version_major :: Word32++-- | The minor version number. Incremented when functionality is added without+-- breaking the API or ABI. Set to 0 when the major version number is+-- incremented.+foreign import ccall tox_version_minor :: Word32++-- | The patch or revision number. Incremented when bugfixes are applied without+-- changing any functionality or API or ABI.+foreign import ccall tox_version_patch :: Word32++-- | Return whether the compiled library version is compatible with the passed+-- version numbers.+foreign import ccall tox_version_is_compatible :: Word32 -> Word32 -> Word32 -> Bool
+ test/Network/Tox/C/ToxSpec.hs view
@@ -0,0 +1,119 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE Trustworthy #-}+module Network.Tox.C.ToxSpec where++import Control.Applicative ((<$>), (<*>))+import qualified Crypto.Saltine.Internal.ByteSizes as Sodium (boxPK, boxSK)+import qualified Data.ByteString as BS+import Data.ByteString.Arbitrary (fromABS)+import Data.Default.Class (def)+import Test.Hspec+import Test.QuickCheck+import Test.QuickCheck.Arbitrary (arbitraryBoundedEnum,+ genericShrink)++import qualified Network.Tox.C as C+++instance Arbitrary C.ProxyType where+ shrink = genericShrink+ arbitrary = arbitraryBoundedEnum++instance Arbitrary C.SavedataType where+ shrink = genericShrink+ arbitrary = arbitraryBoundedEnum++instance Arbitrary BS.ByteString where+ shrink bs = if BS.null bs then [] else BS.inits bs+ arbitrary = fromABS <$> arbitrary++-- | Ensure that the hostname has a chance of being valid.+filterHost :: C.Options -> C.Options+filterHost o@C.Options{C.proxyHost = h} = o{C.proxyHost = filter (`elem` hostChars) h}+ where+ hostChars = ".-_" ++ ['0'..'9'] ++ ['a'..'z'] ++ ['A'..'Z']++instance Arbitrary C.Options where+ shrink = map filterHost . genericShrink+ arbitrary = fmap filterHost $ C.Options+ <$> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+++getRight :: (Monad m, Show a) => Either a b -> m b+getRight (Left l) = fail $ show l+getRight (Right r) = return r+++must :: Show a => IO (Either a b) -> IO b+must = (getRight =<<)+++spec :: Spec+spec = do+ describe "tox_version_is_compatible" $+ it "is compatible with the major/minor/patch of the linked library" $+ C.tox_version_is_compatible+ C.tox_version_major+ C.tox_version_minor+ C.tox_version_patch+ `shouldBe` True++ describe "Constants" $+ it "has constants equal to the hstox expected key size" $ do+ fromIntegral C.tox_public_key_size `shouldBe` Sodium.boxPK+ fromIntegral C.tox_secret_key_size `shouldBe` Sodium.boxSK+ C.tox_address_size `shouldBe` C.tox_public_key_size + 6+ C.tox_max_name_length `shouldBe` 128+ C.tox_max_status_message_length `shouldBe` 1007+ C.tox_max_friend_request_length `shouldBe` 1016+ C.tox_max_message_length `shouldBe` C.tox_max_custom_packet_size - 1+ C.tox_max_custom_packet_size `shouldBe` 1373+ C.tox_max_filename_length `shouldBe` 255+ C.tox_hash_length `shouldBe` C.tox_file_id_length++ describe "Options" $ do+ it "can be marshalled to C and back" $+ property $ \options -> do+ res <- C.withOptions options C.peekToxOptions+ res `shouldBe` Right options++ it "is saved correctly by pokeToxOptions" $+ property $ \options0 options1 -> do+ res <- C.withOptions options0 $ \ptr -> do+ C.pokeToxOptions options1 ptr (return ())+ C.peekToxOptions ptr+ res `shouldBe` Right options0++ it "has a 'def' that is equivalent to the C default options" $ do+ res <- C.withToxOptions C.peekToxOptions+ res `shouldBe` Right def++ describe "nospam" $+ it "can be retrieved after being set" $+ property $ \nospam ->+ must $ C.withDefaultTox $ \tox -> do+ C.tox_self_set_nospam tox nospam+ nospam' <- C.tox_self_get_nospam tox+ nospam' `shouldBe` nospam++ describe "public key" $ do+ it "is a prefix of the address" $+ must $ C.withDefaultTox $ \tox -> do+ pk <- C.toxSelfGetPublicKey tox+ addr <- C.toxSelfGetAddress tox+ BS.unpack addr `shouldStartWith` BS.unpack pk++ it "is not equal to the secret key" $+ must $ C.withDefaultTox $ \tox -> do+ pk <- C.toxSelfGetPublicKey tox+ sk <- C.toxSelfGetSecretKey tox+ pk `shouldNotBe` sk
+ test/Network/Tox/CSpec.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE Trustworthy #-}+module Network.Tox.CSpec where++import Control.Applicative ((<$>))+import Control.Concurrent (threadDelay)+import Control.Concurrent.MVar (MVar, newMVar, readMVar)+import Control.Exception (bracket)+import Control.Monad (when)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Base16 as Base16+import Data.String (fromString)+import Foreign.StablePtr (StablePtr, freeStablePtr,+ newStablePtr)+import Foreign.Storable (Storable (..))+import Test.Hspec++import qualified Network.Tox.C as C+++bootstrapKey :: BS.ByteString+bootstrapKey =+ fst . Base16.decode . fromString $+ "15E9C309CFCB79FDDF0EBA057DABB49FE15F3803B1BFF06536AE2E5BA5E4690E"++bootstrapHost :: String+bootstrapHost = "tox.ngc.zone"+++options :: C.Options+options = C.Options+ { C.ipv6Enabled = True+ , C.udpEnabled = True+ , C.proxyType = C.ProxyTypeNone+ , C.proxyHost = ""+ , C.proxyPort = 0+ , C.startPort = 33445+ , C.endPort = 33545+ , C.tcpPort = 3128+ , C.savedataType = C.SavedataTypeNone+ , C.savedataData = BS.empty+ }+++while :: IO Bool -> IO () -> IO ()+while cond io = do+ continue <- cond+ when continue $ io >> while cond io+++getRight :: (Monad m, Show a) => Either a b -> m b+getRight (Left l) = fail $ show l+getRight (Right r) = return r+++must :: Show a => IO (Either a b) -> IO b+must = (getRight =<<)+++newtype UserData = UserData Int+ deriving (Eq, Storable, Read, Show)++instance C.CHandler UserData where+ cSelfConnectionStatus _ conn ud = do+ print conn+ print ud+ return $ UserData 4321+++withStablePtr :: a -> (StablePtr a -> IO b) -> IO b+withStablePtr x = bracket (newStablePtr x) freeStablePtr+++toxIterate :: MVar a -> C.Tox a -> IO ()+toxIterate ud tox =+ withStablePtr ud (C.tox_iterate tox)+++spec :: Spec+spec =+ describe "toxcore" $+ it "can bootstrap" $+ must $ C.withOptions options $ \optPtr ->+ must $ C.withTox optPtr $ \tox -> do+ must $ C.toxBootstrap tox bootstrapHost 33445 bootstrapKey+ must $ C.toxAddTcpRelay tox bootstrapHost 33445 bootstrapKey++ C.withCHandler tox $ do+ ud <- newMVar (UserData 1234)+ while ((/= UserData 4321) <$> readMVar ud) $ do+ toxIterate ud tox+ putStrLn "tox_iterate"+ interval <- C.tox_iteration_interval tox+ threadDelay $ fromIntegral $ interval * 10000+ putStrLn "done"
+ tools/groupbot/Main.hs view
@@ -0,0 +1,143 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase #-}+module Main (main) where++import Control.Concurrent (threadDelay)+import Control.Concurrent.MVar (MVar, newMVar)+import Control.Exception (AsyncException (UserInterrupt), catch,+ throwIO)+import Control.Monad (forever)+import qualified Data.ByteString.Base16 as Base16+import qualified Data.ByteString.Char8 as BS+import Data.String (fromString)+import Data.Word (Word32)+import Foreign.Storable (Storable (..))+import System.Directory (doesFileExist)+import System.Exit (exitSuccess)++import qualified Network.Tox.C as C+++bootstrapKey :: BS.ByteString+bootstrapKey =+ fst . Base16.decode . fromString $+ "15E9C309CFCB79FDDF0EBA057DABB49FE15F3803B1BFF06536AE2E5BA5E4690E"++isMasterKey :: BS.ByteString -> Bool+isMasterKey key =+ (key ==) . fst . Base16.decode . fromString $+ "040F75B5C8995F9525F9A8692A6C355286BBD3CF248C984560733421274F0365"++botName :: String+botName = "groupbot"++bootstrapHost :: String+bootstrapHost = "tox.ngc.zone"++savedataFilename :: String+savedataFilename = "groupbot.tox"++options :: BS.ByteString -> C.Options+options savedata = C.Options+ { C.ipv6Enabled = True+ , C.udpEnabled = True+ , C.proxyType = C.ProxyTypeNone+ , C.proxyHost = ""+ , C.proxyPort = 0+ , C.startPort = 33445+ , C.endPort = 33545+ , C.tcpPort = 3128+ , C.savedataType = if savedata == BS.empty then C.SavedataTypeNone else C.SavedataTypeToxSave+ , C.savedataData = savedata+ }+++getRight :: (Monad m, Show a) => Either a b -> m b+getRight (Left l) = fail $ show l+getRight (Right r) = return r+++must :: Show a => IO (Either a b) -> IO b+must = (getRight =<<)+++newtype UserData = UserData Word32+ deriving (Eq, Storable, Read, Show)++instance C.CHandler UserData where+ cSelfConnectionStatus _ conn ud = do+ putStrLn "SelfConnectionStatusCb"+ print conn+ return ud++ cFriendRequest tox pk msg ud = do+ putStrLn "FriendRequestCb"+ Right fn <- C.toxFriendAddNorequest tox pk+ putStrLn $ (BS.unpack . Base16.encode) pk+ putStrLn msg+ print fn+ return ud++ cFriendConnectionStatus tox fn status ud@(UserData gn) = do+ putStrLn "FriendConnectionStatusCb"+ print fn+ print status+ if status /= C.ConnectionNone+ then do+ putStrLn "Inviting!"+ _ <- C.toxConferenceInvite tox fn gn+ return ()+ else+ putStrLn "Friend offline"+ return ud++ cFriendMessage tox fn msgType msg ud = do+ putStrLn "FriendMessage"+ print fn+ print msgType+ putStrLn msg+ _ <- C.toxFriendSendMessage tox fn msgType msg+ return ud++ cConferenceInvite tox fn _confType cookie ud = do+ putStrLn "ConferenceInvite"+ print fn+ pk <- getRight =<< C.toxFriendGetPublicKey tox fn+ if isMasterKey pk+ then do+ putStrLn "Joining!"+ gn <- getRight =<< C.toxConferenceJoin tox fn cookie+ return $ UserData gn+ else do+ putStrLn "Not master!"+ return ud+++loop :: MVar ud -> C.Tox ud -> IO a+loop ud tox =+ forever $ do+ C.toxIterate tox ud+ interval <- C.tox_iteration_interval tox+ threadDelay $ fromIntegral $ interval * 10000+++main :: IO ()+main = do+ exists <- doesFileExist savedataFilename+ loadedSavedata <- if exists then BS.readFile savedataFilename else return BS.empty+ must $ C.withOptions (options loadedSavedata) $ \optPtr ->+ must $ C.withTox optPtr $ \tox -> do+ must $ C.toxBootstrap tox bootstrapHost 33445 bootstrapKey++ C.withCHandler tox $ do+ adr <- C.toxSelfGetAddress tox+ putStrLn $ (BS.unpack . Base16.encode) adr+ _ <- C.toxSelfSetName tox botName+ gn <- getRight =<< C.toxConferenceNew tox+ ud <- newMVar (UserData gn)+ catch (loop ud tox) $ \case+ e@UserInterrupt -> throwIO e+ _ -> do+ savedSavedata <- C.toxGetSavedata tox+ BS.writeFile savedataFilename savedSavedata+ exitSuccess
toxcore.cabal view
@@ -1,13 +1,13 @@ name: toxcore synopsis: Haskell bindings to the C reference implementation of Tox-version: 0.0.2+version: 0.2.0 cabal-version: >= 1.10-license: AGPL-3+license: GPL-3 license-file: LICENSE.md build-type: Simple author: iphy maintainer: iphy-copyright: © 2016 iphy+copyright: © 2016-2018 iphy homepage: https://toktok.github.io category: Network description:@@ -25,21 +25,38 @@ src ghc-options: -Wall- -fno-warn-unused-imports+ -- -fno-warn-unused-imports extra-libraries: toxcore build-depends: base < 5- , QuickCheck >= 2.9.1 , bytestring- , bytestring-arbitrary , data-default-class- , saltine exposed-modules: Network.Tox.C- Network.Tox.C.Callbacks Network.Tox.C.CEnum+ Network.Tox.C.Callbacks+ Network.Tox.C.Constants+ Network.Tox.C.Options Network.Tox.C.Tox+ Network.Tox.C.Type+ Network.Tox.C.Version +executable groupbot+ default-language: Haskell2010+ hs-source-dirs:+ tools/groupbot+ ghc-options:+ -Wall+ -fno-warn-unused-imports+ extra-libraries: toxcore+ build-depends:+ base < 5+ , base16-bytestring+ , bytestring+ , directory+ , toxcore+ main-is: Main.hs+ test-suite testsuite default-language: Haskell2010 type: exitcode-stdio-1.0@@ -51,8 +68,14 @@ build-depends: base < 5 , QuickCheck >= 2.9.1+ , base16-bytestring+ , bytestring+ , bytestring-arbitrary , data-default-class , hspec , saltine , toxcore main-is: testsuite.hs+ other-modules:+ Network.Tox.C.ToxSpec+ Network.Tox.CSpec