├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples └── test.rs └── src ├── av.rs ├── av ├── errors.rs └── ll.rs ├── core.rs ├── core ├── errors.rs └── ll.rs ├── encryptsave.rs ├── encryptsave ├── errors.rs └── ll.rs └── lib.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Install Toxcore 18 | run: | 19 | sudo apt-get install -y build-essential libtool autotools-dev automake checkinstall \ 20 | cmake check git yasm pkg-config libvpx-dev libopus-dev 21 | 22 | git clone -b 1.0.17 git://github.com/jedisct1/libsodium.git 23 | cd libsodium 24 | ./autogen.sh 25 | ./configure && make 26 | sudo checkinstall --install --pkgname libsodium --pkgversion 1.0.17 --nodoc -y 27 | cd .. 28 | 29 | git clone -b v0.2.9 https://github.com/TokTok/c-toxcore.git 30 | cd c-toxcore 31 | mkdir _build && cd _build 32 | cmake .. && make 33 | sudo make install 34 | cd .. 35 | - name: Build 36 | run: cargo build --verbose 37 | - name: Run tests 38 | run: cargo test --verbose 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "rstox" 4 | version = "0.0.1" 5 | authors = ["Сухарик "] 6 | 7 | edition = "2018" 8 | 9 | [dependencies] 10 | libc = "*" 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rstox 2 | 3 | [![Build Status](https://travis-ci.org/tox-rs/rstox.svg)](https://travis-ci.org/tox-rs/rstox) 4 | 5 | **rstox** is a Rust wrapper for [toxcore]. 6 | 7 | You need to have `toxcore` installed as dependency to use `rstox`. Follow the [install instructions](https://github.com/TokTok/c-toxcore/blob/master/INSTALL.md). 8 | 9 | To use `rstox` in your project, add to your `Cargo.toml`: 10 | 11 | ``` 12 | [dependencies.rstox] 13 | git = "https://github.com/tox-rs/rstox.git" 14 | ``` 15 | and make something - [example](/examples/test.rs) 16 | 17 | Toxcore [API documentation](https://github.com/TokTok/c-toxcore/blob/master/toxcore/tox.h) 18 | 19 | **rstox** is licensed under [GPLv3+](LICENSE) 20 | 21 | [toxcore]:https://github.com/TokTok/c-toxcore 22 | -------------------------------------------------------------------------------- /examples/test.rs: -------------------------------------------------------------------------------- 1 | extern crate rstox; 2 | 3 | use rstox::core::*; 4 | 5 | static BOOTSTRAP_IP: &'static str = "192.254.75.98"; 6 | static BOOTSTRAP_PORT: u16 = 33445; 7 | static BOOTSTRAP_KEY: &'static str = 8 | "951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F"; 9 | static BOT_NAME: &'static str = "yuppi"; 10 | 11 | fn main() { 12 | let mut tox = Tox::new(ToxOptions::new(), None).unwrap(); 13 | tox.set_name(BOT_NAME).unwrap(); 14 | let bootstrap_key = BOOTSTRAP_KEY.parse().unwrap(); 15 | tox.bootstrap(BOOTSTRAP_IP, BOOTSTRAP_PORT, bootstrap_key).unwrap(); 16 | 17 | println!("{}", tox.get_address()); 18 | 19 | loop { 20 | for ev in tox.iter() { 21 | match ev { 22 | FriendRequest(cid, _) => { 23 | tox.add_friend_norequest(&cid).unwrap(); 24 | }, 25 | ev => { println!("Tox event: {:?}", ev); }, 26 | } 27 | } 28 | 29 | tox.wait(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/av.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2015 Сухарик 3 | Copyright © 2015 Zetok Zalbavar 4 | 5 | 6 | This file is part of rstox. 7 | 8 | rstox is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | rstox is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with rstox. If not, see . 20 | */ 21 | 22 | //! Safe interface to `toxav`. 23 | 24 | 25 | //use std::cell::RefCell; 26 | 27 | 28 | use libc::{/*c_int,*/ c_uint, c_void}; 29 | use std::thread::sleep; 30 | use std::cmp::max; 31 | use std::slice; 32 | use std::time::Duration; 33 | use std::mem; 34 | use std::sync::mpsc::Sender; 35 | 36 | use crate::core::{Tox, Event}; 37 | 38 | pub mod ll; 39 | pub mod errors; 40 | 41 | //////////////////////// 42 | // ToxAV API Version // 43 | ////////////////////// 44 | /// Return the major version of the `toxav` library. 45 | pub fn av_version_major() -> u32 { 46 | unsafe { ll::toxav_version_major() } 47 | } 48 | 49 | #[test] 50 | // Current major version should equal to `0` 51 | fn test_av_version_major() { 52 | assert_eq!(av_version_major(), 0); 53 | } 54 | 55 | 56 | /// Return the minor version of the `toxav` library. 57 | pub fn av_version_minor() -> u32 { 58 | unsafe { ll::toxav_version_major() } 59 | } 60 | 61 | #[test] 62 | // Current minor version should equal to `0` 63 | fn test_av_version_minor() { 64 | assert_eq!(av_version_minor(), 0); 65 | } 66 | 67 | 68 | /// Return the patch version of the `toxav` library. 69 | pub fn av_version_patch() -> u32 { 70 | unsafe { ll::toxav_version_patch() } 71 | } 72 | 73 | #[test] 74 | // Current patch version should equal to `0` 75 | fn test_av_version_patch() { 76 | assert_eq!(av_version_patch(), 0); 77 | } 78 | 79 | 80 | /// Return whether the compiled library version is compatible with the passed 81 | /// version numbers. **Apparently until `toxcore` will get proper versions, it 82 | /// will always return `true`.** 83 | pub fn av_version_is_compatible(major: u32, minor: u32, patch: u32) -> bool { 84 | unsafe { ll::toxav_version_is_compatible(major, minor, patch) } 85 | } 86 | 87 | #[test] 88 | // Current version numbers should be `0, 0, 0` 89 | fn test_av_version_is_compatible() { 90 | assert_eq!(av_version_is_compatible(0, 0, 0), true); 91 | // apparently until toxcore gets proper versions it's always true 92 | // TODO: uncomment when it should work 93 | //assert_eq!(av_version_is_compatible(1, 1, 1), false); 94 | //assert_eq!(av_version_is_compatible(999999, 999999, 999999), false); 95 | } 96 | 97 | 98 | 99 | ////////////////////// 100 | 101 | macro_rules! tox_try { 102 | ($err:ident, $exp:expr) => {{ 103 | let mut $err = ::std::mem::uninitialized(); 104 | let res = $exp; 105 | match $err as c_uint { 106 | 0 => {}, 107 | _ => return Err($err), 108 | }; 109 | res 110 | }}; 111 | } 112 | 113 | ////////////////////// 114 | 115 | /// Call control 116 | #[repr(C)] 117 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 118 | pub enum CallControl { 119 | /// Resume a previously paused call. Only valid if the pause was caused by 120 | /// this client, if not, this control is ignored. Not valid before the call 121 | /// is accepted. 122 | Resume = 0, 123 | 124 | /// Put a call on hold. Not valid before the call is accepted. 125 | Pause, 126 | 127 | /// Reject a call if it iwas not answered, yet. Cancel a call after it was 128 | /// answered. 129 | Cancel, 130 | 131 | /// Request that the friend stops sending audio. Regardless of the friend's 132 | /// compilance, this will cause the `audio_receive_frame` event to stop 133 | /// being triggered on receiving an audio from from the friend. 134 | MuteAudio, 135 | 136 | /// Calling this control willl notify client to start sending audio again. 137 | UnmuteAudio, 138 | 139 | /// Request that the friend stops sending video. Regardless of the friend's 140 | /// compilance, this will cause the `video_receive_frame` event to stop 141 | /// being triggered on receiving a video frame from the friend. 142 | MuteVideo, 143 | 144 | /// Calling this control will notify client to start sending video again. 145 | UnmuteVideo, 146 | } 147 | 148 | /////////////////////// 149 | // Call state graph // 150 | ///////////////////// 151 | /// Call state graph 152 | #[repr(C)] 153 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 154 | pub enum FriendCallState { 155 | /** 156 | * Set by the AV core if an error occurred on the remote end or if friend 157 | * timed out. This is the final state after which no more state 158 | * transitions can occur for the call. This call state will never be 159 | * triggered in combination with other call states. 160 | */ 161 | Error = 1, 162 | 163 | /// The call has finished. This is the final state after which no more state 164 | /// transitions can occur for the call. This call state will never be 165 | /// triggered in combination with other call states. 166 | Finished = 2, 167 | 168 | /// The flag that marks that friend is sending audio. 169 | SendingA = 4, 170 | 171 | /// The flag that marks that friend is sending video. 172 | SendingV = 8, 173 | 174 | /// The flag that marks that friend is receiving audio. 175 | AcceptingA = 16, 176 | 177 | /// The flag that marks that friend is receiving video. 178 | AcceptingV = 32, 179 | } 180 | 181 | /////////////////////////////// 182 | // Creation and destruction // 183 | ///////////////////////////// 184 | 185 | #[derive(Clone, PartialEq, Eq)] 186 | pub struct ToxAv { 187 | av: *mut ll::ToxAV 188 | } 189 | 190 | unsafe impl Send for ToxAv {} 191 | 192 | impl ToxAv { 193 | pub fn new(tox: &mut Tox) -> Result { 194 | let mut toxav = ToxAv { 195 | av: unsafe { tox_try!(err, ll::toxav_new(tox.raw, &mut err)) } 196 | }; 197 | toxav.init(tox); 198 | Ok(toxav) 199 | } 200 | 201 | fn init(&mut self, tox: &mut Tox) { 202 | unsafe { 203 | let chan: *mut c_void = mem::transmute(&mut *tox.event_tx); 204 | ll::toxav_callback_call(self.av, on_call, chan); 205 | ll::toxav_callback_call_state(self.av, on_call_state, chan); 206 | ll::toxav_callback_bit_rate_status(self.av, on_bit_rate_status, chan); 207 | ll::toxav_callback_audio_receive_frame(self.av, on_audio_receive_frame, chan); 208 | ll::toxav_callback_video_receive_frame(self.av, on_video_receive_frame, chan); 209 | } 210 | } 211 | 212 | pub fn wait(&self) { 213 | unsafe { 214 | let delay = ll::toxav_iteration_interval(self.av); 215 | sleep(Duration::from_millis(delay as u64)); 216 | } 217 | } 218 | 219 | pub fn tick(&mut self) { 220 | unsafe { ll::toxav_iterate(self.av) }; 221 | } 222 | 223 | pub fn call( 224 | &mut self, 225 | friend_number: u32, 226 | audio_bitrate: u32, 227 | video_bitrate: u32 228 | ) -> Result { 229 | Ok(unsafe { 230 | tox_try!(err, ll::toxav_call( 231 | self.av, 232 | friend_number, 233 | audio_bitrate, 234 | video_bitrate, 235 | &mut err 236 | )) 237 | }) 238 | } 239 | 240 | pub fn answer( 241 | &mut self, 242 | friend_number: u32, 243 | audio_bitrate: u32, 244 | video_bitrate: u32 245 | ) -> Result { 246 | Ok(unsafe { 247 | tox_try!(err, ll::toxav_answer( 248 | self.av, 249 | friend_number, 250 | audio_bitrate, 251 | video_bitrate, 252 | &mut err 253 | )) 254 | }) 255 | } 256 | 257 | pub fn control( 258 | &mut self, 259 | friend_number: u32, 260 | control: CallControl 261 | ) -> Result { 262 | Ok(unsafe { 263 | tox_try!(err, ll::toxav_call_control( 264 | self.av, 265 | friend_number, 266 | control, 267 | &mut err 268 | )) 269 | }) 270 | } 271 | 272 | pub fn set_bitrate( 273 | &mut self, 274 | friend_number: u32, 275 | audio_bitrate: i32, 276 | video_bitrate: i32, 277 | ) -> Result { 278 | Ok(unsafe { 279 | tox_try!(err, ll::toxav_bit_rate_set( 280 | self.av, 281 | friend_number, 282 | audio_bitrate, 283 | video_bitrate, 284 | &mut err 285 | )) 286 | }) 287 | } 288 | 289 | pub fn send_audio( 290 | &mut self, 291 | friend_number: u32, 292 | pcm: &[i16], 293 | sample_count: usize, 294 | channels: u8, 295 | sampling_rate: u32 296 | ) -> Result { 297 | Ok(unsafe { 298 | tox_try!(err, ll::toxav_audio_send_frame( 299 | self.av, 300 | friend_number, 301 | pcm.as_ptr(), 302 | sample_count, 303 | channels, 304 | sampling_rate, 305 | &mut err 306 | )) 307 | }) 308 | } 309 | 310 | pub fn send_video( 311 | &mut self, 312 | friend_number: u32, 313 | width: u16, 314 | height: u16, 315 | y: &[u8], u: &[u8], v: &[u8] 316 | ) -> Result { 317 | Ok(unsafe { 318 | tox_try!(err, ll::toxav_video_send_frame( 319 | self.av, 320 | friend_number, 321 | width, 322 | height, 323 | y.as_ptr(), u.as_ptr(), v.as_ptr(), 324 | &mut err 325 | )) 326 | }) 327 | } 328 | } 329 | 330 | impl Drop for ToxAv { 331 | fn drop(&mut self) { 332 | unsafe { ll::toxav_kill(self.av); } 333 | } 334 | } 335 | 336 | extern fn on_call( 337 | toxav: *mut ll::ToxAV, 338 | friend_number: u32, 339 | audio_enabled: bool, 340 | video_enabled: bool, 341 | chan: *mut c_void 342 | ) { 343 | unsafe { 344 | let tx: &mut Sender = mem::transmute(chan); 345 | tx.send(Event::Call(friend_number, audio_enabled, video_enabled)).ok(); 346 | } 347 | } 348 | 349 | extern fn on_call_state( 350 | toxav: *mut ll::ToxAV, 351 | friend_number: u32, 352 | state: u32, 353 | chan: *mut c_void 354 | ) { 355 | unsafe { 356 | let tx: &mut Sender = mem::transmute(chan); 357 | tx.send(Event::CallState(friend_number, state)).ok(); 358 | } 359 | } 360 | 361 | extern fn on_bit_rate_status( 362 | toxav: *mut ll::ToxAV, 363 | friend_number: u32, 364 | audio_bitrate: u32, 365 | video_bitrate: u32, 366 | chan: *mut c_void 367 | ) { 368 | unsafe { 369 | let tx: &mut Sender = mem::transmute(chan); 370 | tx.send(Event::BitRateStatus(friend_number, audio_bitrate, video_bitrate)).ok(); 371 | } 372 | } 373 | 374 | extern fn on_audio_receive_frame( 375 | toxav: *mut ll::ToxAV, 376 | friend_number: u32, 377 | pcm: *const i16, 378 | sample_count: usize, 379 | channels: u8, 380 | sampling_rate: u32, 381 | chan: *mut c_void 382 | ) { 383 | unsafe { 384 | let tx: &mut Sender = mem::transmute(chan); 385 | let pcm = slice::from_raw_parts(pcm, sample_count * channels as usize * 2); 386 | tx.send(Event::AudioReceiveFrame(friend_number, pcm.to_vec(), sample_count, channels, sampling_rate)).ok(); 387 | } 388 | } 389 | 390 | extern fn on_video_receive_frame( 391 | toxav: *mut ll::ToxAV, 392 | friend_number: u32, 393 | width: u16, 394 | height: u16, 395 | y: *const u8, 396 | u: *const u8, 397 | v: *const u8, 398 | ystride: i32, 399 | ustride: i32, 400 | vstride: i32, 401 | chan: *mut c_void 402 | ) { 403 | unsafe { 404 | let tx: &mut Sender = mem::transmute(chan); 405 | let y = slice::from_raw_parts(y, max(width as i32, ystride.abs()) as usize * height as usize); 406 | let u = slice::from_raw_parts(u, max((width / 2) as i32, ustride.abs()) as usize * (height / 2) as usize); 407 | let v = slice::from_raw_parts(v, max((width / 2) as i32, vstride.abs()) as usize * (height / 2) as usize); 408 | tx.send(Event::VideoReceiveFrame(friend_number, width, height, y.to_vec(), u.to_vec(), v.to_vec(), ystride, ustride, vstride)).ok(); 409 | } 410 | } 411 | -------------------------------------------------------------------------------- /src/av/errors.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt; 3 | 4 | /////////////////////////////// 5 | // Creation and destruction // 6 | ///////////////////////////// 7 | /// Creation and destruction 8 | #[repr(C)] 9 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 10 | pub enum NewAvError { 11 | /// The function returned successfully. 12 | #[doc(hidden)] NoError = 0, 13 | /// One of the arguments to the function was NULL when it was not expected. 14 | NullError = 1, 15 | /// Memory allocation failure while trying to allocate structures required 16 | /// for the A/V session. 17 | MallocError, 18 | /// Attempted to create a second session for the same Tox instance. 19 | Multiple, 20 | } 21 | 22 | impl Error for NewAvError { 23 | fn description(&self) -> &str { 24 | match *self { 25 | NewAvError::NoError => "new: no error", 26 | NewAvError::NullError => "new: null", 27 | NewAvError::MallocError => "new: failed to allocate memory", 28 | NewAvError::Multiple => 29 | "new: attempted to create a second session for same Tox instance", 30 | } 31 | } 32 | } 33 | 34 | impl fmt::Display for NewAvError { 35 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 36 | write!(f, "{}", self.description()) 37 | } 38 | } 39 | 40 | 41 | ///////////////// 42 | // Call setup // 43 | /////////////// 44 | /// Call setup 45 | #[repr(C)] 46 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 47 | pub enum CallError { 48 | /// The function returned successfully. 49 | #[doc(hidden)] NoError = 0, 50 | /// A resource allocation error occured while trying to create the structures 51 | /// required for the call. 52 | MallocError, 53 | /// Synchronization error occured. 54 | SyncError, 55 | /// The friend number did not designate a valid friend. 56 | FriendNotFound, 57 | /// The friend was valid, but not currently connected. 58 | FriendNotConnected, 59 | /// Attempted to call a friend while already in an audio or video call with 60 | /// them. 61 | FriendAlreadyInCall, 62 | /// Audio or video bit rate is invalid. 63 | InvalidBitRate 64 | } 65 | 66 | impl Error for CallError { 67 | fn description(&self) -> &str { 68 | match *self { 69 | CallError::NoError => "call: no error", 70 | CallError::MallocError => "call: failed to allocate memory", 71 | CallError::SyncError => "call: synchronization error ocurred", 72 | CallError::FriendNotFound => "call: no friend with given friend number", 73 | CallError::FriendNotConnected => "call: friend is not connected", 74 | CallError::FriendAlreadyInCall => "call: aready in call with friend", 75 | CallError::InvalidBitRate => "call: invalid bit rate", 76 | } 77 | } 78 | } 79 | 80 | impl fmt::Display for CallError { 81 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 82 | write!(f, "{}", self.description()) 83 | } 84 | } 85 | 86 | 87 | 88 | ////////////////// 89 | // Call answer // 90 | //////////////// 91 | /// Call answer 92 | #[repr(C)] 93 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 94 | pub enum AnswerError { 95 | /// The function returned successfully. 96 | #[doc(hidden)] NoError = 0, 97 | 98 | /// Synchronization error occurred. 99 | SyncError, 100 | /** 101 | * Failed to initialize codecs for call session. Note that codec initiation 102 | * will fail if there is no receive callback registered for either audio or 103 | * video. 104 | */ 105 | CodecInitializationError, 106 | /// The friend number did not designate valid friend. 107 | FriendNotFound, 108 | /// The friend was valid, but they are not currently trying to initiate 109 | /// a call. This is also returned if this client is already in a call with 110 | /// the friend. 111 | FriendNotCalling, 112 | /// Audio or video bit rate is invalid. 113 | InvalidBitRate 114 | } 115 | 116 | impl Error for AnswerError { 117 | fn description(&self) -> &str { 118 | match *self { 119 | AnswerError::NoError => "answer: no error", 120 | AnswerError::SyncError => "answer: synchronization error ocurred", 121 | AnswerError::CodecInitializationError => 122 | "answer: failed to initialize codec for session", 123 | AnswerError::FriendNotFound => 124 | "answer: no friend with given friend number", 125 | AnswerError::FriendNotCalling => 126 | "answer: friend not calling or already in call", 127 | AnswerError::InvalidBitRate => "answer: invalid bit rate", 128 | } 129 | } 130 | } 131 | 132 | impl fmt::Display for AnswerError { 133 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 134 | write!(f, "{}", self.description()) 135 | } 136 | } 137 | 138 | 139 | /////////////////// 140 | // Call control // 141 | ///////////////// 142 | #[repr(C)] 143 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 144 | pub enum CallControlError { 145 | /// The function returned successfully. 146 | #[doc(hidden)] NoError = 0, 147 | 148 | /// Synchronization error occured. 149 | SyncError, 150 | 151 | /// The friend_number passed did not designate a valid friend. 152 | FriendNotFound, 153 | 154 | /// This client is currently not in a call with the friend. Before the call 155 | /// is answered, only CANCEL is a valid control. 156 | FriendNotInCall, 157 | 158 | /// Happnes if user tried to pause an already paused call or if trying to 159 | /// resume a call that is not paused. 160 | InvalidTransition 161 | } 162 | 163 | impl Error for CallControlError { 164 | fn description(&self) -> &str { 165 | match *self { 166 | CallControlError::NoError => "call_control: no error", 167 | CallControlError::SyncError => 168 | "call_control: synchronization error ocurred", 169 | CallControlError::FriendNotFound => 170 | "call_control: no friend with given friend number", 171 | CallControlError::FriendNotInCall => 172 | "call_control: not in call with friend", 173 | CallControlError::InvalidTransition => 174 | "call_control: already paused or resumed", 175 | } 176 | } 177 | } 178 | 179 | impl fmt::Display for CallControlError { 180 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 181 | write!(f, "{}", self.description()) 182 | } 183 | } 184 | 185 | 186 | 187 | //////////////////////////// 188 | // Controlling bit rates // 189 | ////////////////////////// 190 | /// Controlling bit rates 191 | #[repr(C)] 192 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 193 | pub enum BitRateSetError { 194 | /// The function returned successfully. 195 | #[doc(hidden)] NoError = 0, 196 | /// Synchronization error occurred. 197 | SyncError, 198 | /// The audio bit rate passed was not one of the supported values. 199 | InvalidAudioBitRate, 200 | /// The video bit rate passed was not one of the supported values. 201 | InvalidVideoBitRate, 202 | /// The `friend_number` passed did not designate a valid friend. 203 | FriendNotFound, 204 | /// This client is currently not in a call with the friend. 205 | FriendNotInCall 206 | } 207 | 208 | impl Error for BitRateSetError { 209 | fn description(&self) -> &str { 210 | match *self { 211 | BitRateSetError::NoError => "bit_rate: no error", 212 | BitRateSetError::SyncError => "bit_rate: synchronization error ocurred", 213 | BitRateSetError::InvalidAudioBitRate => 214 | "bit_rate: audio bit rate not supported", 215 | BitRateSetError::InvalidVideoBitRate => 216 | "bit_rate: video bit rate not supported", 217 | BitRateSetError::FriendNotFound => 218 | "bit_rate: no friend with given friend number", 219 | BitRateSetError::FriendNotInCall => 220 | "bit_rate: not in call with friend", 221 | } 222 | } 223 | } 224 | 225 | impl fmt::Display for BitRateSetError { 226 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 227 | write!(f, "{}", self.description()) 228 | } 229 | } 230 | 231 | 232 | ////////////////// 233 | // A/V sending // 234 | //////////////// 235 | /// A/V sending 236 | #[repr(C)] 237 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 238 | pub enum SendFrameError { 239 | /// The function returned successfully. 240 | #[doc(hidden)] NoError = 0, 241 | /// In case of video, one of Y, U, or V was NULL. In case of audio, the 242 | /// samples data pointer was NULL. ← FIXME 243 | NullError = 1, 244 | /// The `friend_number` passed did not sedignate a valid friend. 245 | FriendNotFound, 246 | /// This client is currently not in a call with the friend. 247 | FriendNotInCall, 248 | /// Synchronization error occurred. 249 | SyncError, 250 | /// One of the frame parameters was invalid. E.g. the resolution may be too 251 | /// small or too large, or the audio sampling rate may be unsupported. 252 | Invalid, 253 | /// Either friend turned off audio or video receiving or we turned off 254 | /// sending for the said payload. 255 | PayloadTypeDisabled, 256 | /// Failed to push frame through rtp interface. 257 | RtpFailed 258 | } 259 | 260 | impl Error for SendFrameError { 261 | fn description(&self) -> &str { 262 | match *self { 263 | SendFrameError::NoError => "send_frame: no error", 264 | SendFrameError::NullError => 265 | "send_frame: one of parameters was null", // FIXME? 266 | SendFrameError::FriendNotFound => 267 | "send_frame: no friend with given friend number", 268 | SendFrameError::FriendNotInCall => 269 | "send_frame: not in call with friend", 270 | SendFrameError::SyncError => 271 | "send_frame: synchronization error occured", 272 | SendFrameError::Invalid => 273 | "send_frame: one of parameters was invalid", 274 | SendFrameError::PayloadTypeDisabled => 275 | "send_frame: either we or friend disabled this type of payload", 276 | SendFrameError::RtpFailed => 277 | "send_frame: failed to push frame through rtp interface", 278 | } 279 | } 280 | } 281 | 282 | impl fmt::Display for SendFrameError { 283 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 284 | write!(f, "{}", self.description()) 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /src/av/ll.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2015 Сухарик 3 | Copyright © 2015 Zetok Zalbavar 4 | 5 | 6 | This file is part of rstox. 7 | 8 | rstox is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | rstox is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with rstox. If not, see . 20 | */ 21 | 22 | //! This is a low-level binding to `toxav`. Shouldn't be used directly - use 23 | //! safe interface instead. 24 | 25 | use libc::c_void; 26 | use super::CallControl; 27 | use super::errors; 28 | use crate::core::Tox_Struct; 29 | 30 | pub type Tox = Tox_Struct; 31 | 32 | 33 | /** 34 | * The `ToxAV` instance type. (This is actually an opaque C struct - see 35 | * [Rust issue #27303](https://github.com/rust-lang/rust/issues/27303) 36 | * for more details on that.) 37 | * 38 | * Each `ToxAV` instance can be bound to only one 39 | * [`Tox`](../../core/struct.Tox.html) instance, and Tox instance can have 40 | * only one `ToxAV` instance. One must make sure to close `ToxAV` instance 41 | * prior to closing `Tox` instance otherwise undefined behaviour occurs. **Upon 42 | * closing of `ToxAV` instance, all active calls will be forcibly terminated 43 | * without notifying peers.** 44 | */ 45 | pub enum ToxAV {} 46 | 47 | 48 | ///////////////// 49 | // Call setup // 50 | /////////////// 51 | /** 52 | * The function type for the [`call` callback](fn.toxav_callback_call.html). 53 | * 54 | * `friend_number` – The friend number from which the call is incoming. 55 | * 56 | * `audio_enabled` – True if friend is sending audio. 57 | * 58 | * `video_enabled` – True if friend is sending video. 59 | */ 60 | #[allow(non_camel_case_types)] 61 | pub type toxav_call_cb = 62 | extern "C" fn(toxav: *mut ToxAV, 63 | friend_number: u32, 64 | audio_enabled: bool, 65 | video_enabled: bool, 66 | user_data: *mut c_void) -> (); 67 | 68 | 69 | /////////////////////// 70 | // Call state graph // 71 | ///////////////////// 72 | /** 73 | * The function type for the [`call_state`](fn.toxav_callback_call_state.html) 74 | * callback. 75 | * 76 | * `friend_number` – The friend number for which the call state changed. 77 | * 78 | * `state` – The bitmask of the new call state which is guaranteed to be 79 | * different than the previous state. The state is set to `0` when the call is 80 | * paused. The bitmask represents all the activities currently performed by the 81 | * friend. 82 | */ 83 | #[allow(non_camel_case_types)] 84 | pub type toxav_call_state_cb = 85 | extern "C" fn(toxav: *mut ToxAV, 86 | friend_number: u32, 87 | state: u32, 88 | user_data: *mut c_void) -> (); 89 | 90 | 91 | //////////////////////////// 92 | // Controlling bit rates // 93 | ////////////////////////// 94 | /** 95 | * The function type for the 96 | * [`bit_rate_status`](fn.toxav_callback_bit_rate_status.html) callback. 97 | * 98 | * The event is triggered when the network becomes too saturated for current 99 | * bit rates at which point core suggests new bit rates. 100 | * 101 | * `friend_number` – The friend number of the friend for which to set the 102 | * bit rate. 103 | * 104 | * `audio_bit_rate` – Suggested maximum audio bit rate in Kb/sec. 105 | * 106 | * `video_bit_rate` – Suggested maximum video bit rate in Kb/sec. 107 | */ 108 | #[allow(non_camel_case_types)] 109 | pub type toxav_bit_rate_status_cb = 110 | extern "C" fn(toxav: *mut ToxAV, 111 | friend_number: u32, 112 | audio_bit_rate: u32, 113 | video_bit_rate: u32, 114 | user_data: *mut c_void) -> (); 115 | 116 | 117 | //////////////////// 118 | // A/V receiving // 119 | ////////////////// 120 | /** 121 | * The function type for the 122 | * [`audio_receive_frame`](fn.toxav_callback_audio_receive_frame.html) callback. 123 | * 124 | * The callback can be called multiple times per single iteration depending 125 | * on the amount of queued frames in the buffer. The received format is 126 | * the same as in send function. 127 | * 128 | * `friend_number` – The friend number of the friend who sent an audio frame. 129 | * 130 | * `pcm An array` – of audio samples (sample_count * channels elements). 131 | * 132 | * `sample_count` – The number of audio samples per channel in the PCM array. 133 | * 134 | * `channels` – Number of audio channels. 135 | * 136 | * `sampling_rate` – Sampling rate used in this frame. 137 | */ 138 | #[allow(non_camel_case_types)] 139 | pub type toxav_audio_receive_frame_cb = 140 | extern "C" fn(toxav: *mut ToxAV, 141 | friend_number: u32, 142 | pcm: *const i16, 143 | sample_count: usize, 144 | channels: u8, 145 | sampling_rate: u32, 146 | user_data: *mut c_void) -> (); 147 | 148 | /** 149 | * The function type for the 150 | * [`video_receive_frame`](fn.toxav_callback_video_receive_frame.html) callback. 151 | * 152 | * `friend_number The friend number of the friend who sent a video frame. 153 | * 154 | * `width Width of the frame in pixels. 155 | * 156 | * `height Height of the frame in pixels. 157 | * 158 | * `y` 159 | * `u` 160 | * `v` Plane data. 161 | * The size of plane data is derived from width and height where 162 | * `Y = MAX(width, abs(ystride)) * height`, 163 | * `U = MAX(width/2, abs(ustride)) * (height/2)` and 164 | * `V = MAX(width/2, abs(vstride)) * (height/2)`. 165 | * `ystride` 166 | * `ustride` 167 | * `vstride` – Strides data. Strides represent padding for each plane 168 | * that may or may not be present. You must handle strides in 169 | * your image processing code. Strides are negative if the 170 | * image is bottom-up hence why you MUST `abs()` it when 171 | * calculating plane buffer size. 172 | */ 173 | #[allow(non_camel_case_types)] 174 | pub type toxav_video_receive_frame_cb = 175 | extern "C" fn(toxav: *mut ToxAV, 176 | friend_number: u32, 177 | width: u16, 178 | height: u16, 179 | y: *const u8, 180 | u: *const u8, 181 | v: *const u8, 182 | ystride: i32, 183 | ustride: i32, 184 | vstride: i32, 185 | user_data: *mut c_void) -> (); 186 | 187 | 188 | #[link(name = "toxav")] 189 | extern { 190 | //////////////////////// 191 | // ToxAV API Version // 192 | ////////////////////// 193 | /** 194 | * Return the major version number of the library. 195 | * 196 | * Can be used to display the ToxAV library version or to check whether 197 | * the client is compatible with the dynamically linked version of ToxAV. 198 | */ 199 | pub fn toxav_version_major() -> u32; 200 | 201 | /// Return the minor version number of the library. 202 | pub fn toxav_version_minor() -> u32; 203 | 204 | /// Return the patch number of the library. 205 | pub fn toxav_version_patch() -> u32; 206 | 207 | /// Return whether the compiled library version is compatible with the passed 208 | /// version numbers. 209 | pub fn toxav_version_is_compatible(major: u32, minor: u32, patch: u32) -> bool; 210 | 211 | 212 | /////////////////////////////// 213 | // Creation and destruction // 214 | ///////////////////////////// 215 | /** 216 | * Start new A/V session. There can only be one session per 217 | * [`Tox`](../../core/struct.Tox.html) instance. 218 | */ 219 | pub fn toxav_new(tox: *mut Tox, error: *mut errors::NewAvError) -> *mut ToxAV; 220 | 221 | /** 222 | * Releases all resources associated with the A/V session. 223 | * 224 | * If any calls were ongoing, these will be forcibly terminated without 225 | * notifying peers. After calling this function, no other functions may be 226 | * called and the av pointer becomes invalid. 227 | */ 228 | pub fn toxav_kill(toxav: *mut ToxAV) -> (); 229 | 230 | 231 | 232 | ///////////////////// 233 | // A/V event loop // 234 | /////////////////// 235 | 236 | /** 237 | * Returns the [`Tox`](../../core/struct.Tox.html) instance for which 238 | * the A/V object was created for. 239 | */ 240 | pub fn toxav_get_tox(toxav: *const ToxAV) -> *mut Tox; 241 | 242 | /** 243 | * Returns the interval in milliseconds when the next 244 | * [`toxav_iterate`](fn.toxav_iterate.html) 245 | * call should be. 246 | * 247 | * If no call is active at the moment, this function 248 | * returns 200. 249 | */ 250 | pub fn toxav_iteration_interval(toxav: *const ToxAV) -> u32; 251 | 252 | /** 253 | * Main loop for the session. 254 | * 255 | * This function needs to be called in intervals of 256 | * [`toxav_iteration_interval()`](fn.toxav_iteration_interval.html) 257 | * milliseconds. It is best called in the separate thread from `tox_iterate`. 258 | */ 259 | pub fn toxav_iterate(toxav: *mut ToxAV) -> (); 260 | 261 | 262 | 263 | 264 | ///////////////// 265 | // Call setup // 266 | /////////////// 267 | /** 268 | * Call a friend. This will start ringing the friend. 269 | * 270 | * It is the client's responsibility to stop ringing after a certain timeout, 271 | * if such behaviour is desired. If the client does not stop ringing, the 272 | * library will not stop until the friend is disconnected. Audio and video 273 | * receiving are both enabled by default. 274 | * 275 | * `friend_number` – The friend number of the friend that should be called. 276 | * 277 | * `audio_bit_rate` Audio bit rate in Kb/sec. Set this to `0` to disable 278 | * audio sending. 279 | * 280 | * `video_bit_rate` Video bit rate in Kb/sec. Set this to `0` to disable 281 | * video sending. 282 | */ 283 | pub fn toxav_call(toxav: *mut ToxAV, 284 | friend_number: u32, 285 | audio_bit_rate: u32, 286 | video_bit_rate: u32, 287 | error: *mut errors::CallError) -> bool; 288 | 289 | 290 | /// Set the callback for the [`call`](type.toxav_call_cb.html) event. 291 | /// 292 | /// Pass NULL to unset. 293 | pub fn toxav_callback_call(toxav: *mut ToxAV, 294 | function: toxav_call_cb, 295 | user_data: *mut c_void) -> (); 296 | 297 | /** 298 | * Accept an incoming call. 299 | * 300 | * If answering fails for any reason, the call will still be pending and it 301 | * is possible to try and answer it later. Audio and video receiving are 302 | * both enabled by default. 303 | * 304 | * `friend_number` – The friend number of the friend that is calling. 305 | * 306 | * `audio_bit_rate` – Audio bit rate in Kb/sec. Set this to 0 to disable 307 | * audio sending. 308 | * 309 | * `video_bit_rate` – Video bit rate in Kb/sec. Set this to 0 to disable 310 | * video sending. 311 | */ 312 | pub fn toxav_answer(toxav: *mut ToxAV, 313 | friend_number: u32, 314 | audio_bit_rate: u32, 315 | video_bit_rate: u32, 316 | error: *mut errors::AnswerError) -> bool; 317 | 318 | 319 | /////////////////////// 320 | // Call state graph // 321 | ///////////////////// 322 | /// Set the callback for the [`call_state`](type.toxav_ event_cb.html) event. 323 | /// 324 | /// Pass NULL to unset. 325 | pub fn toxav_callback_call_state(toxav: *mut ToxAV, 326 | function: toxav_call_state_cb, 327 | user_data: *mut c_void) -> (); 328 | 329 | 330 | /////////////////// 331 | // Call control // 332 | ///////////////// 333 | /** 334 | * Sends a call control command to a friend. 335 | * 336 | * `friend_number` – The friend number of the friend this client is in 337 | * a call with. 338 | * 339 | * `control` – The control command to send. 340 | */ 341 | pub fn toxav_call_control(toxav: *mut ToxAV, 342 | friend_number: u32, 343 | control: CallControl, 344 | error: *mut errors::CallControlError) -> bool; 345 | 346 | 347 | //////////////////////////// 348 | // Controlling bit rates // 349 | ////////////////////////// 350 | /** 351 | * Set the bit rate to be used in subsequent audio/video frames. 352 | * 353 | * `friend_number` – The friend number of the friend for which to set the 354 | * bit rate. 355 | * 356 | * `audio_bit_rate` – The new audio bit rate in Kb/sec. Set to 0 to disable 357 | * audio sending. Set to -1 to leave unchanged. 358 | * 359 | * `video_bit_rate` – The new video bit rate in Kb/sec. Set to 0 to disable 360 | * video sending. Set to -1 to leave unchanged. 361 | * 362 | */ 363 | pub fn toxav_bit_rate_set(toxav: *mut ToxAV, 364 | friend_number: u32, 365 | audio_bit_rate: i32, 366 | video_bit_rate: i32, 367 | error: *mut errors::BitRateSetError) -> bool; 368 | 369 | /// Set the callback for the 370 | /// [`bit_rate_status`](type.toxav_bit_rate_status_cb.html) event. 371 | /// 372 | /// Pass NULL to unset. 373 | pub fn toxav_callback_bit_rate_status(toxav: *mut ToxAV, 374 | function: toxav_bit_rate_status_cb, 375 | user_data: *mut c_void) -> (); 376 | 377 | 378 | 379 | ////////////////// 380 | // A/V sending // 381 | //////////////// 382 | /** 383 | * Send an audio frame to a friend. 384 | * 385 | * The expected format of the PCM data is: 386 | * `[s1c1]``[s1c2]``[...]``[s2c1]``[s2c2]``[...]...` 387 | * Meaning: `sample 1` for `channel 1`, `sample 1` for `channel 2`, ... 388 | * For mono audio, this has no meaning, every sample is subsequent. For 389 | * stereo, this means the expected format is `LRLRLR...` with samples 390 | * for left and right alternating. 391 | * 392 | * `friend_number` – The friend number of the friend to which to send an 393 | * audio frame. 394 | * 395 | * `pcm` – An array of audio samples. The size of this array must be 396 | * sample_count * channels. 397 | * 398 | * `sample_count` – Number of samples in this frame. Valid numbers here are 399 | * `((sample rate) * (audio length) / 1000)`, where audio length can be 400 | * `2.5`, `5`, `10`, `20`, `40` or `60` millseconds. 401 | * 402 | * `channels` – Number of audio channels. Supported values are 1 and 2. 403 | * 404 | * `sampling_rate` – Audio sampling rate used in this frame. Valid sampling 405 | * rates are `8000`, `12000`, `16000`, `24000`, or `48000`. 406 | */ 407 | pub fn toxav_audio_send_frame(toxav: *mut ToxAV, 408 | friend_number: u32, 409 | pcm: *const i16, 410 | sample_count: usize, 411 | channels: u8, 412 | sampling_rate: u32, 413 | error: *mut errors::SendFrameError) -> bool; 414 | 415 | /** 416 | * Send a video frame to a friend. 417 | * 418 | * `Y` - plane should be of size: `height * width` 419 | * 420 | * `U` - plane should be of size: `(height/2) * (width/2)` 421 | * 422 | * `V` - plane should be of size: `(height/2) * (width/2)` 423 | * 424 | * `friend_number` – The friend number of the friend to which to send a video 425 | * frame. 426 | * 427 | * `width` – Width of the frame in pixels. 428 | * 429 | * `height` – Height of the frame in pixels. 430 | * 431 | * `y` – Y (Luminance) plane data. 432 | * 433 | * `u` – U (Chroma) plane data. 434 | * 435 | * `v` – V (Chroma) plane data. 436 | */ 437 | pub fn toxav_video_send_frame(toxav: *mut ToxAV, 438 | friend_number: u32, 439 | width: u16, 440 | height: u16, 441 | y: *const u8, 442 | u: *const u8, 443 | v: *const u8, 444 | error: *mut errors::SendFrameError) -> bool; 445 | 446 | 447 | //////////////////// 448 | // A/V receiving // 449 | ////////////////// 450 | /// Set the callback for the 451 | /// [`audio_receive_frame`](type.toxav_audio_receive_frame_cb.html) event. 452 | /// Pass NULL to unset. 453 | pub fn toxav_callback_audio_receive_frame(toxav: *mut ToxAV, 454 | function: 455 | toxav_audio_receive_frame_cb, 456 | user_data: *mut c_void) -> (); 457 | 458 | /// Set the callback for the 459 | /// [`video_receive_frame`](type.toxav_video_receive_frame_cb.html) event. 460 | /// 461 | /// Pass NULL to unset. 462 | pub fn toxav_callback_video_receive_frame(toxav: *mut ToxAV, 463 | function: 464 | toxav_video_receive_frame_cb, 465 | user_data: *mut c_void) -> (); 466 | 467 | 468 | ///////////////////////////////////////////////////////// 469 | // NOTE: THERE IS NO SUPPORT FOR OLD AUDIO GROUPCHATS // 470 | /////////////////////////////////////////////////////// 471 | } 472 | -------------------------------------------------------------------------------- /src/core.rs: -------------------------------------------------------------------------------- 1 | use std::sync::mpsc::{channel, Receiver, Sender}; 2 | use std::{slice, mem, ffi, fmt}; 3 | use std::cell::RefCell; 4 | use std::rc::Rc; 5 | use std::time::Duration; 6 | use std::thread::sleep; 7 | use std::str::FromStr; 8 | use std::mem::MaybeUninit; 9 | 10 | use libc::{c_uint, c_void}; 11 | 12 | // pub use self::ll::Tox as Tox_Struct; 13 | pub use self::Event::*; 14 | use self::errors::*; 15 | 16 | mod ll; 17 | pub mod errors; 18 | 19 | pub const PUBLIC_KEY_SIZE: usize = 32; 20 | pub const SECRET_KEY_SIZE: usize = 32; 21 | pub const ADDRESS_SIZE: usize = PUBLIC_KEY_SIZE + 6; 22 | pub const MAX_NAME_LENGTH: usize = 128; 23 | // pub const MAX_STATUSMESSAGE_LENGTH: usize = 1007; 24 | // pub const MAX_FRIENDREQUEST_LENGTH: usize = 1016; 25 | // pub const MAX_MESSAGE_LENGTH: usize = 1372; 26 | // pub const MAX_CUSTOM_PACKET_SIZE: usize = 1367; 27 | // pub const HASH_LENGTH: usize = 32; 28 | // pub const FILE_ID_LENGTH: usize = 32; 29 | // pub const MAX_FILENAME_LENGTH: usize = 255; 30 | pub const CONFERENCE_ID_SIZE: usize = 32; 31 | pub const FILE_ID_LENGTH: usize = 32; 32 | 33 | #[repr(u32)] 34 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 35 | pub enum UserStatus { 36 | None = 0, 37 | Away = 1, 38 | Busy = 2, 39 | } 40 | 41 | #[repr(u32)] 42 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 43 | pub enum MessageType { 44 | Normal = 0, 45 | Action = 1, 46 | } 47 | 48 | #[repr(u32)] 49 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 50 | pub enum ProxyType { 51 | None = 0, 52 | Http = 1, 53 | Socks5 = 2, 54 | } 55 | 56 | #[repr(u32)] 57 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 58 | pub enum SavedataType { 59 | None = 0, 60 | ToxSave = 1, 61 | SecretKey = 2, 62 | } 63 | 64 | #[repr(u32)] 65 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 66 | pub enum LogLevel { 67 | Trace = 0, 68 | Debug = 1, 69 | Info = 2, 70 | Warning = 3, 71 | Error = 4, 72 | } 73 | 74 | #[repr(u32)] 75 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 76 | pub enum Connection { 77 | None = 0, 78 | Tcp = 1, 79 | Udp = 2, 80 | } 81 | 82 | #[repr(u32)] 83 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 84 | pub enum FileKind { 85 | Data = 0, 86 | Avatar = 1, 87 | } 88 | 89 | #[repr(u32)] 90 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 91 | pub enum FileControl { 92 | Resume = 0, 93 | Pause = 1, 94 | Cancel = 2, 95 | } 96 | 97 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 98 | pub struct FileId { 99 | raw: [u8; FILE_ID_LENGTH], 100 | } 101 | 102 | impl fmt::Display for FileId { 103 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 104 | for &n in self.raw.iter() { 105 | write!(fmt, "{:02X}", n)?; 106 | } 107 | Ok(()) 108 | } 109 | } 110 | 111 | impl FromStr for FileId { 112 | type Err = (); 113 | fn from_str(s: &str) -> Result { 114 | if s.len() != 2 * FILE_ID_LENGTH { 115 | return Err(()); 116 | } 117 | 118 | let mut id = [0u8; FILE_ID_LENGTH]; 119 | 120 | parse_hex(s, &mut id[..])?; 121 | Ok(FileId { raw: id }) 122 | } 123 | } 124 | 125 | #[repr(u32)] 126 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 127 | pub enum ConferenceType { 128 | Text = 0, 129 | Av = 1, 130 | } 131 | 132 | pub struct ConferenceId { 133 | raw: [u8; CONFERENCE_ID_SIZE] 134 | } 135 | 136 | #[derive(Debug, Clone, PartialEq)] 137 | pub struct Cookie { 138 | raw: Vec 139 | } 140 | 141 | impl Cookie { 142 | pub fn into_bytes(self) -> Vec { 143 | self.raw 144 | } 145 | 146 | pub fn from_bytes(bytes: &[u8]) -> Cookie { 147 | Cookie { 148 | raw: bytes.to_owned() 149 | } 150 | } 151 | } 152 | 153 | /// A Tox address consist of `PublicKey`, nospam and checksum 154 | #[repr(C)] 155 | #[derive(PartialEq, Clone, Debug)] 156 | pub struct Address { 157 | key: PublicKey, 158 | nospam: [u8; 4], 159 | // #[allow(dead_code)] 160 | checksum: [u8; 2], 161 | } 162 | 163 | impl Address { 164 | pub fn public_key(&self) -> &PublicKey { 165 | &self.key 166 | } 167 | fn checksum(&self) -> [u8; 2] { 168 | let mut check = [0u8, 0u8]; 169 | for (i, &x) in self.key.raw.iter().enumerate() { 170 | check[i % 2] ^= x; 171 | } 172 | for i in 0..4 { 173 | check[(PUBLIC_KEY_SIZE + i) % 2] ^= self.nospam[i]; 174 | } 175 | check 176 | } 177 | } 178 | 179 | impl fmt::Display for Address { 180 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 181 | self.key.fmt(fmt)?; 182 | write!(fmt, "{:02X}", self.nospam[0])?; 183 | write!(fmt, "{:02X}", self.nospam[1])?; 184 | write!(fmt, "{:02X}", self.nospam[2])?; 185 | write!(fmt, "{:02X}", self.nospam[3])?; 186 | let check = self.checksum(); 187 | write!(fmt, "{:02X}", check[0])?; 188 | write!(fmt, "{:02X}", check[1])?; 189 | Ok(()) 190 | } 191 | } 192 | 193 | impl FromStr for Address { 194 | type Err = (); 195 | fn from_str(s: &str) -> Result { 196 | if s.len() != 2 * ADDRESS_SIZE { 197 | return Err(()); 198 | } 199 | 200 | let mut key = [0u8; 32]; 201 | let mut nospam = [0u8; 4]; 202 | let mut check = [0u8; 2]; 203 | 204 | if parse_hex(&s[0..2 * PUBLIC_KEY_SIZE], &mut key[..]).is_err() { 205 | return Err(()); 206 | } 207 | if parse_hex(&s[2 * PUBLIC_KEY_SIZE..2 * PUBLIC_KEY_SIZE + 8], 208 | &mut nospam[..]).is_err() { 209 | return Err(()); 210 | } 211 | if parse_hex(&s[2 * PUBLIC_KEY_SIZE + 8..2 * ADDRESS_SIZE], 212 | &mut check[..]).is_err() { 213 | return Err(()); 214 | } 215 | 216 | let addr = Address { key: PublicKey { raw: key }, nospam: nospam, checksum: check }; 217 | if &addr.checksum() != &check { 218 | return Err(()); 219 | } 220 | Ok(addr) 221 | } 222 | } 223 | 224 | fn parse_hex(s: &str, buf: &mut [u8]) -> Result<(),()> { 225 | if s.len() != 2*buf.len() { 226 | return Err(()); 227 | } 228 | for i in 0..buf.len() { 229 | for j in 0..2 { 230 | buf[i] = (buf[i] << 4) + match s.as_bytes()[2*i + j] as char { 231 | c @ '0' ..= '9' => (c as u8) - ('0' as u8), 232 | c @ 'a' ..= 'f' => (c as u8) - ('a' as u8) + 10, 233 | c @ 'A' ..= 'F' => (c as u8) - ('A' as u8) + 10, 234 | _ => return Err(()), 235 | } 236 | } 237 | } 238 | return Ok(()); 239 | } 240 | 241 | /// `PublicKey` is the main part of tox `Address`. Other two are nospam and checksum. 242 | #[repr(C)] 243 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] 244 | pub struct PublicKey { 245 | pub raw: [u8; PUBLIC_KEY_SIZE], 246 | } 247 | 248 | impl fmt::Display for PublicKey { 249 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 250 | for &n in self.raw.iter() { 251 | write!(fmt, "{:02X}", n)?; 252 | } 253 | Ok(()) 254 | } 255 | } 256 | 257 | impl FromStr for PublicKey { 258 | type Err = (); 259 | fn from_str(s: &str) -> Result { 260 | if s.len() != 2 * PUBLIC_KEY_SIZE { 261 | return Err(()); 262 | } 263 | 264 | let mut id = [0u8; PUBLIC_KEY_SIZE]; 265 | 266 | parse_hex(s, &mut id[..])?; 267 | Ok(PublicKey { raw: id }) 268 | } 269 | } 270 | 271 | pub struct SecretKey { 272 | pub raw: [u8; SECRET_KEY_SIZE], 273 | } 274 | 275 | impl fmt::Display for SecretKey { 276 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 277 | for &n in self.raw.iter() { 278 | write!(fmt, "{:02X}", n)?; 279 | } 280 | 281 | Ok(()) 282 | } 283 | } 284 | 285 | impl FromStr for SecretKey { 286 | type Err = (); 287 | fn from_str(s: &str) -> Result { 288 | if s.len() != 2 * SECRET_KEY_SIZE { 289 | return Err(()); 290 | } 291 | 292 | let mut id = [0u8; SECRET_KEY_SIZE]; 293 | 294 | parse_hex(s, &mut id[..])?; 295 | Ok(SecretKey { raw: id }) 296 | } 297 | } 298 | 299 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] 300 | pub struct Nospam { 301 | pub raw: [u8; 4], 302 | } 303 | 304 | impl fmt::Display for Nospam { 305 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 306 | for &n in self.raw.iter() { 307 | write!(fmt, "{:02X}", n)?; 308 | } 309 | 310 | Ok(()) 311 | } 312 | } 313 | 314 | impl FromStr for Nospam { 315 | type Err = (); 316 | fn from_str(s: &str) -> Result { 317 | if s.len() != 8 { 318 | return Err(()); 319 | } 320 | 321 | let mut id = [0u8; 4]; 322 | 323 | parse_hex(s, &mut id[..])?; 324 | Ok(Nospam { raw: id }) 325 | } 326 | } 327 | 328 | /// Tox events enum 329 | #[derive(Clone, Debug)] 330 | pub enum Event { 331 | ConnectionStatus(Connection), 332 | FriendRequest(PublicKey, String), 333 | FriendMessage(u32, MessageType, String), 334 | FriendName(u32, String), 335 | FriendStatusMessage(u32, String), 336 | FriendStatus(u32, UserStatus), 337 | FriendConnectionStatus(u32, Connection), 338 | FriendTyping(u32, bool), 339 | FriendReadReceipt { 340 | friend: u32, 341 | message_id: u32, 342 | }, 343 | 344 | FileControlReceipt { 345 | friend: u32, 346 | file_number: u32, 347 | control: FileControl, 348 | }, 349 | FileChunkRequest { 350 | friend: u32, 351 | file_number: u32, 352 | position: usize, 353 | length: usize, 354 | }, 355 | FileReceipt { 356 | friend: u32, 357 | file_number: u32, 358 | kind: u32, 359 | file_size: usize, 360 | file_name: String, 361 | }, 362 | FileChunkReceipt { 363 | friend: u32, 364 | file_number: u32, 365 | position: usize, 366 | data: Vec, 367 | }, 368 | 369 | ConferenceInvite { 370 | friend: u32, 371 | kind: ConferenceType, 372 | cookie: Cookie, 373 | }, 374 | ConferenceConnected { 375 | conference: u32 376 | }, 377 | ConferenceMessage { 378 | conference: u32, 379 | peer: u32, 380 | kind: MessageType, 381 | message: String, 382 | }, 383 | ConferenceTitle { 384 | conference: u32, 385 | peer: u32, 386 | title: String, 387 | }, 388 | ConferencePeerName { 389 | conference: u32, 390 | peer: u32, 391 | name: String, 392 | }, 393 | ConferencePeerListChanged { 394 | conference: u32 395 | }, 396 | 397 | LossyPackage(u32, Vec), 398 | LosslessPackage(u32, Vec), 399 | /// ToxAV Event 400 | Call(u32, bool, bool), 401 | CallState(u32, u32), 402 | BitRateStatus(u32, u32, u32), 403 | AudioReceiveFrame(u32, Vec, usize, u8, u32), 404 | VideoReceiveFrame(u32, u16, u16, Vec, Vec, Vec, i32, i32, i32), 405 | } 406 | 407 | // #[repr(C)] 408 | // #[derive(Copy, Clone, PartialEq, Eq, Debug)] 409 | // pub enum ProxyType { 410 | // None = 0, 411 | // Socks5, 412 | // HTTP, 413 | // } 414 | 415 | // #[repr(C)] 416 | // #[derive(Copy, Clone, PartialEq, Eq, Debug)] 417 | // pub enum SavedataType { 418 | // None = 0, 419 | // ToxSave, 420 | // SecretKey, 421 | // } 422 | 423 | /** 424 | ToxOptions provides options that tox will be initalized with. 425 | */ 426 | 427 | //#[derive(Clone, Copy)] 428 | pub struct ToxOptions { 429 | raw: ll::Tox_Options, 430 | sk_ptr: Option<*mut SecretKey>, 431 | } 432 | 433 | impl ToxOptions { 434 | /// Create a default ToxOptions struct 435 | pub fn new() -> ToxOptions { 436 | let raw_options = unsafe { 437 | let mut raw = MaybeUninit::uninit(); 438 | ll::tox_options_default(raw.as_mut_ptr()); 439 | 440 | raw.assume_init() 441 | }; 442 | 443 | ToxOptions { 444 | raw: raw_options, 445 | sk_ptr: None, 446 | } 447 | } 448 | 449 | /// Set the given SecretKey so you can restore your Tox 450 | pub fn set_secret_key(mut self, secret_key: SecretKey) -> ToxOptions { 451 | if self.sk_ptr.is_some() { 452 | panic!("SK has already been set"); 453 | } 454 | let sk_ptr = Box::into_raw(Box::new(secret_key)); 455 | self.sk_ptr = Some(sk_ptr); 456 | self.raw.savedata_type = SavedataType::SecretKey; 457 | self.raw.savedata_data = sk_ptr as *const _; 458 | self.raw.savedata_length = SECRET_KEY_SIZE; 459 | self 460 | } 461 | 462 | /// Enable ipv6 463 | pub fn ipv6(mut self) -> ToxOptions { 464 | self.raw.ipv6_enabled = true; 465 | self 466 | } 467 | 468 | /// Disable UDP 469 | pub fn no_udp(mut self) -> ToxOptions { 470 | self.raw.udp_enabled = false; 471 | self 472 | } 473 | 474 | /// Disable UDP 475 | pub fn no_lan(mut self) -> ToxOptions { 476 | self.raw.local_discovery_enabled = false; 477 | self 478 | } 479 | 480 | /* 481 | /// Use a proxy 482 | pub fn proxy(mut self, ty: ProxyType, addr: &str, port: u16) -> ToxOptions { 483 | if addr.len() >= 256 { 484 | panic!("proxy address is too long"); 485 | } 486 | 487 | self.txo.proxy_address.as_mut_slice() 488 | .clone_from_slice(addr.as_bytes()); 489 | self.txo.proxy_type = ty as u8; 490 | self.txo.proxy_port = port; 491 | self 492 | }*/ 493 | } 494 | 495 | impl Drop for ToxOptions { 496 | fn drop(&mut self) { 497 | if let Some(sk_ptr) = self.sk_ptr { 498 | unsafe { Box::from_raw(sk_ptr) }; 499 | } 500 | } 501 | } 502 | 503 | pub struct ToxIter { 504 | rx: Rc>>, 505 | } 506 | 507 | impl ToxIter { 508 | fn new(rx: Rc>>) -> ToxIter { 509 | ToxIter { rx: rx } 510 | } 511 | } 512 | 513 | impl Iterator for ToxIter { 514 | type Item = Event; 515 | fn next(&mut self) -> Option { self.rx.borrow_mut().try_recv().ok() } 516 | } 517 | 518 | macro_rules! tox_try { 519 | ($err:ident, $exp:expr) => {{ 520 | let mut $err = MaybeUninit::uninit(); 521 | let res = $exp; 522 | match $err.assume_init() as c_uint { 523 | 0 => {}, 524 | _ => return Err($err.assume_init()), 525 | }; 526 | res 527 | }}; 528 | } 529 | 530 | macro_rules! tox_option { 531 | ($err:ident, $exp:expr) => {{ 532 | let mut $err = MaybeUninit::uninit(); 533 | let res = $exp; 534 | match $err.assume_init() as c_uint { 535 | 0 => {}, 536 | _ => return None, 537 | }; 538 | res 539 | }}; 540 | } 541 | 542 | pub struct Tox { 543 | pub raw: *mut ll::Tox, 544 | pub event_tx: Box>, 545 | event_rx: Rc>>, 546 | } 547 | 548 | impl Drop for Tox { 549 | fn drop(&mut self) { 550 | unsafe { ll::tox_kill(self.raw); } 551 | } 552 | } 553 | 554 | impl Tox { 555 | /// Create a new tox instance 556 | pub fn new(mut opts: ToxOptions, data: Option<&[u8]>) -> Result { 557 | let tox = unsafe { 558 | match data { 559 | Some(data) => { 560 | opts.raw.savedata_type = SavedataType::ToxSave; 561 | opts.raw.savedata_data = data.as_ptr(); 562 | opts.raw.savedata_length = data.len(); 563 | tox_try!(err, ll::tox_new(&opts.raw, err.as_mut_ptr())) 564 | }, 565 | None => { 566 | tox_try!(err, ll::tox_new(&opts.raw, err.as_mut_ptr())) 567 | } 568 | } 569 | }; 570 | 571 | let (tx, rx) = channel::(); 572 | let event_tx = Box::new(tx); 573 | let event_rx = Rc::new(RefCell::new(rx)); 574 | 575 | unsafe { 576 | ll::tox_callback_self_connection_status(tox, Some(on_connection_status)); 577 | ll::tox_callback_friend_request(tox, Some(on_friend_request)); 578 | ll::tox_callback_friend_message(tox, Some(on_friend_message)); 579 | 580 | ll::tox_callback_friend_name(tox, Some(on_friend_name)); 581 | ll::tox_callback_friend_status_message(tox, Some(on_friend_status_message)); 582 | ll::tox_callback_friend_status(tox, Some(on_friend_status)); 583 | ll::tox_callback_friend_connection_status(tox, Some(on_friend_connection_status)); 584 | ll::tox_callback_friend_typing(tox, Some(on_friend_typing)); 585 | ll::tox_callback_friend_read_receipt(tox, Some(on_friend_read_receipt)); 586 | 587 | ll::tox_callback_file_recv_control(tox, Some(on_file_control)); 588 | ll::tox_callback_file_chunk_request(tox, Some(on_file_chunk_request)); 589 | ll::tox_callback_file_recv(tox, Some(on_file_receive)); 590 | ll::tox_callback_file_recv_chunk(tox, Some(on_file_chunk_receive)); 591 | 592 | ll::tox_callback_conference_invite(tox, Some(on_conference_invite)); 593 | ll::tox_callback_conference_connected(tox, Some(on_conference_connected)); 594 | ll::tox_callback_conference_message(tox, Some(on_conference_message)); 595 | ll::tox_callback_conference_title(tox, Some(on_conference_title)); 596 | ll::tox_callback_conference_peer_name(tox, Some(on_conference_peer_name)); 597 | ll::tox_callback_conference_peer_list_changed( 598 | tox, 599 | Some(on_conference_peer_list_changed) 600 | ); 601 | 602 | ll::tox_callback_friend_lossy_packet(tox, Some(on_lossy_package)); 603 | ll::tox_callback_friend_lossless_packet(tox, Some(on_lossless_package)); 604 | } 605 | 606 | Ok(Tox { 607 | raw: tox, 608 | event_tx, 609 | event_rx, 610 | }) 611 | } 612 | 613 | /// Ticks the Tox and returns an iterator to the Tox events 614 | pub fn iter(&mut self) -> ToxIter { 615 | self.tick(); 616 | ToxIter::new(self.event_rx.clone()) 617 | } 618 | 619 | /// This function animates tox by calling `tox_do()` It function should be called 620 | /// at least several times per second. Use `wait()` method to get optimal delays 621 | pub fn tick(&mut self) { 622 | unsafe { 623 | let chan = (&mut *self.event_tx) as *mut _ as *mut _; 624 | ll::tox_iterate(self.raw, chan); 625 | } 626 | } 627 | 628 | /// This function makes thread sleep for a some time, optimal for `tick()` method 629 | pub fn wait(&self) { 630 | unsafe { 631 | let delay = ll::tox_iteration_interval(self.raw); 632 | sleep(Duration::from_millis(delay as u64)); 633 | } 634 | } 635 | 636 | /** 637 | Sends a "get nodes" request to the given bootstrap node with IP, port, and 638 | public key to setup connections. 639 | 640 | This function will attempt to connect to the node using UDP and TCP at the 641 | same time. 642 | 643 | Tox will use the node as a TCP relay in case Tox_Options.udp_enabled was 644 | false, and also to connect to friends that are in TCP-only mode. Tox will 645 | also use the TCP connection when NAT hole punching is slow, and later switch 646 | to UDP if hole punching succeeds. 647 | 648 | ## Panics 649 | Panics if `host` string contains `\0`. 650 | */ 651 | pub fn bootstrap(&mut self, host: &str, port: u16, public_key: PublicKey) -> Result<(), BootstrapError> { 652 | unsafe { 653 | let c_host = ffi::CString::new(host).unwrap(); 654 | let c_pk: *const u8 = &public_key as *const _ as *const _; 655 | tox_try!(err, ll::tox_bootstrap(self.raw, c_host.as_ptr(), port, c_pk, err.as_mut_ptr())); 656 | } 657 | Ok(()) 658 | } 659 | 660 | /// Get self connection status 661 | pub fn get_connection_status(&self) -> Connection { 662 | unsafe { ll::tox_self_get_connection_status(self.raw) } 663 | } 664 | 665 | /// Get self tox address 666 | pub fn get_address(&self) -> Address { 667 | unsafe { 668 | let mut addr = MaybeUninit::uninit(); 669 | ll::tox_self_get_address(self.raw, &mut addr as *mut _ as *mut u8); 670 | addr.assume_init() 671 | } 672 | } 673 | 674 | /// Get self nospam 675 | pub fn get_nospam(&self) -> Nospam { 676 | unsafe { 677 | let nospam = ll::tox_self_get_nospam(self.raw); 678 | 679 | Nospam { 680 | raw: mem::transmute(nospam) 681 | } 682 | } 683 | } 684 | 685 | /// Set self nospam 686 | pub fn set_nospam(&mut self, nospam: Nospam) { 687 | unsafe { 688 | let nospam: u32 = mem::transmute(nospam.raw); 689 | ll::tox_self_set_nospam(self.raw, nospam); 690 | } 691 | } 692 | 693 | /// Get self public key 694 | pub fn get_public_key(&self) -> PublicKey { 695 | unsafe { 696 | let mut pk = MaybeUninit::uninit(); 697 | ll::tox_self_get_public_key(self.raw, &mut pk as *mut _ as *mut u8); 698 | pk.assume_init() 699 | } 700 | } 701 | 702 | /// Get secret_key 703 | pub fn get_secret_key(&self) -> SecretKey { 704 | unsafe { 705 | let mut sk = MaybeUninit::uninit(); 706 | ll::tox_self_get_secret_key(self.raw, &mut sk as *mut _ as *mut u8); 707 | sk.assume_init() 708 | } 709 | } 710 | 711 | /// Set the nickname for the Tox client 712 | pub fn set_name(&mut self, name: &str) -> Result<(), SetInfoError> { 713 | unsafe { 714 | tox_try!(err, ll::tox_self_set_name(self.raw, name.as_ptr(), name.len(), err.as_mut_ptr())); 715 | } 716 | Ok(()) 717 | } 718 | 719 | /// Get self nickname 720 | pub fn get_name(&self) -> String { 721 | unsafe { 722 | let len = ll::tox_self_get_name_size(self.raw); 723 | let mut bytes: Vec = Vec::with_capacity(len); 724 | bytes.set_len(len); 725 | ll::tox_self_get_name(self.raw, bytes.as_mut_ptr()); 726 | String::from_utf8_unchecked(bytes) 727 | } 728 | } 729 | 730 | /// Set self status message 731 | pub fn set_status_message(&mut self, message: &str) -> Result<(), SetInfoError> { 732 | unsafe { 733 | tox_try!(err, ll::tox_self_set_status_message(self.raw, message.as_ptr(), message.len(), err.as_mut_ptr())); 734 | } 735 | Ok(()) 736 | } 737 | 738 | /// Get self status message 739 | pub fn get_status_message(&self) -> String { 740 | unsafe { 741 | let len = ll::tox_self_get_status_message_size(self.raw); 742 | let mut bytes: Vec = Vec::with_capacity(len); 743 | bytes.set_len(len); 744 | ll::tox_self_get_status_message(self.raw, bytes.as_mut_ptr()); 745 | String::from_utf8_unchecked(bytes) 746 | } 747 | } 748 | 749 | /// Set self status 750 | pub fn set_status(&mut self, status: UserStatus) { 751 | unsafe { ll::tox_self_set_status(self.raw, status); } 752 | } 753 | 754 | /// Get self status 755 | pub fn get_status(&self) -> UserStatus { 756 | unsafe { ll::tox_self_get_status(self.raw) } 757 | } 758 | 759 | 760 | /** 761 | Add a friend to the friend list and send a friend request. 762 | 763 | A friend request message must be at least 1 byte long and at most 764 | `TOX_MAX_FRIEND_REQUEST_LENGTH`. 765 | 766 | Friend numbers are unique identifiers used in all functions that operate on 767 | friends. Once added, a friend number is stable for the lifetime of the Tox 768 | object. After saving the state and reloading it, the friend numbers may not 769 | be the same as before. Deleting a friend creates a gap in the friend number 770 | set, which is filled by the next adding of a friend. Any pattern in friend 771 | numbers should not be relied on. 772 | */ 773 | pub fn add_friend(&mut self, address: &Address, message: &str) -> Result<(), FriendAddError> { 774 | unsafe { 775 | let c_addr = address as *const _ as *const u8; 776 | tox_try!( 777 | err, 778 | ll::tox_friend_add(self.raw, c_addr, message.as_ptr(), message.len(), err.as_mut_ptr()) 779 | ); 780 | } 781 | Ok(()) 782 | } 783 | 784 | /** 785 | Add a friend without sending a friend request. 786 | 787 | This function is used to add a friend in response to a friend request. If the 788 | client receives a friend request, it can be reasonably sure that the other 789 | client added this client as a friend, eliminating the need for a friend 790 | request. 791 | 792 | This function is also useful in a situation where both instances are 793 | controlled by the same entity, so that this entity can perform the mutual 794 | friend adding. In this case, there is no need for a friend request, either. 795 | */ 796 | pub fn add_friend_norequest(&mut self, address: &PublicKey) -> Result<(), FriendAddError> { 797 | unsafe { 798 | let c_addr = address as *const _ as *const u8; 799 | tox_try!(err, ll::tox_friend_add_norequest(self.raw, c_addr, err.as_mut_ptr())); 800 | } 801 | Ok(()) 802 | } 803 | 804 | /** 805 | Remove a friend from the friend list. 806 | 807 | This does not notify the friend of their deletion. After calling this 808 | function, this client will appear offline to the friend and no communication 809 | can occur between the two. 810 | */ 811 | pub fn delete_friend(&mut self, fnum: u32) -> Result<(), ()> { 812 | unsafe { 813 | let mut err = MaybeUninit::uninit(); 814 | if !ll::tox_friend_delete(self.raw, fnum, err.as_mut_ptr()) { 815 | return Err(()) 816 | } 817 | } 818 | Ok(()) 819 | } 820 | 821 | // FRIEND STUFF 822 | pub fn friend_by_public_key(&self, public_key: PublicKey) -> Option { 823 | unsafe { 824 | let pk: *const u8 = &public_key as *const _ as *const _; 825 | let fnum = tox_option!(err, ll::tox_friend_by_public_key(self.raw, pk, err.as_mut_ptr())); 826 | Some(fnum) 827 | } 828 | } 829 | 830 | pub fn friend_exists(&self, fnum: u32) -> bool { 831 | unsafe { 832 | ll::tox_friend_exists(self.raw, fnum) 833 | } 834 | } 835 | 836 | pub fn get_friend_list(&self) -> Vec { 837 | unsafe { 838 | let len = ll::tox_self_get_friend_list_size(self.raw); 839 | let mut list = Vec::with_capacity(len); 840 | list.set_len(len); 841 | ll::tox_self_get_friend_list(self.raw, list.as_mut_ptr()); 842 | list 843 | } 844 | } 845 | 846 | pub fn get_friend_public_key(&self, fnum: u32) -> Option { 847 | unsafe { 848 | let mut public_key = MaybeUninit::uninit(); 849 | let pk: *mut u8 = &mut public_key as *mut _ as *mut _; 850 | tox_option!(err, ll::tox_friend_get_public_key(self.raw, fnum, pk, err.as_mut_ptr())); 851 | Some(public_key.assume_init()) 852 | } 853 | } 854 | 855 | /** 856 | Returns an `Option` with number of seconds since January 1, 1970 857 | 0:00:00 UTC (aka "UNIX timestamp"). 858 | 859 | In case where there is no friend with supplied `fnum`, `None` is 860 | returned. 861 | */ 862 | pub fn get_friend_last_online(&self, fnum: u32) -> Option { 863 | unsafe { 864 | Some(tox_option!(err, ll::tox_friend_get_last_online(self.raw, fnum, err.as_mut_ptr()))) 865 | } 866 | } 867 | 868 | /// Returns friend name, or, if friend doesn't exist, `None`. 869 | pub fn get_friend_name(&self, fnum: u32) -> Option { 870 | unsafe { 871 | let len = tox_option!(err, ll::tox_friend_get_name_size(self.raw, 872 | fnum, err.as_mut_ptr())); 873 | let mut bytes: Vec = Vec::with_capacity(len); 874 | bytes.set_len(len); 875 | tox_option!(err, ll::tox_friend_get_name(self.raw, fnum, 876 | bytes.as_mut_ptr(), err.as_mut_ptr())); 877 | Some(String::from_utf8_unchecked(bytes)) 878 | } 879 | } 880 | 881 | /// Returns status message of a friend, or, if friend doesn't exist, `None`. 882 | pub fn get_friend_status_message(&self, fnum: u32) -> Option { 883 | unsafe { 884 | let len = tox_option!(err, ll::tox_friend_get_status_message_size(self.raw, 885 | fnum, err.as_mut_ptr())); 886 | let mut bytes: Vec = Vec::with_capacity(len); 887 | bytes.set_len(len); 888 | tox_option!(err, ll::tox_friend_get_status_message(self.raw, fnum, 889 | bytes.as_mut_ptr(), err.as_mut_ptr())); 890 | Some(String::from_utf8_unchecked(bytes)) 891 | } 892 | } 893 | 894 | /// Returns friend status, or, if there is an error, `None`. 895 | pub fn get_friend_status(&self, fnum: u32) -> Option { 896 | unsafe { 897 | Some(tox_option!(err, ll::tox_friend_get_status(self.raw, fnum, err.as_mut_ptr()))) 898 | } 899 | } 900 | 901 | /// Return status of connection of friend, or if friend doesn't exist, `None`. 902 | pub fn get_friend_connection_status(&self, fnum: u32) -> Option { 903 | unsafe { 904 | Some(tox_option!(err, ll::tox_friend_get_connection_status(self.raw, fnum, err.as_mut_ptr()))) 905 | } 906 | } 907 | // END OF FRIEND STUFF 908 | /** 909 | Send a text chat message to an online friend. 910 | 911 | This function creates a chat message packet and pushes it into the send 912 | queue. 913 | 914 | The message length may not exceed `TOX_MAX_MESSAGE_LENGTH`. Larger messages 915 | must be split by the client and sent as separate messages. Other clients can 916 | then reassemble the fragments. Messages may not be empty. 917 | 918 | The return value of this function is the message ID. If a read receipt is 919 | received, the triggered `friend_read_receipt` event will be passed this message ID. 920 | 921 | Message IDs are unique per friend. The first message ID is 0. Message IDs are 922 | incremented by 1 each time a message is sent. If `UINT32_MAX` messages were 923 | sent, the next message ID is 0. 924 | */ 925 | pub fn send_friend_message( 926 | &mut self, fnum: u32, kind: MessageType, message: &str 927 | ) -> Result { 928 | let msg_id = unsafe { 929 | tox_try!( 930 | err, 931 | ll::tox_friend_send_message(self.raw, fnum, kind, message.as_ptr(), message.len(), err.as_mut_ptr()) 932 | ) 933 | }; 934 | Ok(msg_id) 935 | } 936 | 937 | pub fn control_file( 938 | &mut self, 939 | friend: u32, 940 | file_number: u32, 941 | control: FileControl 942 | ) -> Result<(), FileControlError> { 943 | unsafe { 944 | tox_try!(err, ll::tox_file_control( 945 | self.raw, 946 | friend, 947 | file_number, 948 | control, 949 | err.as_mut_ptr() 950 | )); 951 | 952 | Ok(()) 953 | } 954 | } 955 | 956 | pub fn seek_file( 957 | &mut self, 958 | friend: u32, 959 | file_number: u32, 960 | postition: usize 961 | ) -> Result<(), FileSeekError> { 962 | unsafe { 963 | tox_try!(err, ll::tox_file_seek( 964 | self.raw, 965 | friend, 966 | file_number, 967 | postition as u64, 968 | err.as_mut_ptr() 969 | )); 970 | 971 | Ok(()) 972 | } 973 | } 974 | 975 | pub fn get_file_id( 976 | &mut self, 977 | friend: u32, 978 | file_number: u32, 979 | ) -> Result { 980 | unsafe { 981 | let mut raw = MaybeUninit::<[u8; FILE_ID_LENGTH]>::uninit(); 982 | 983 | tox_try!(err, ll::tox_file_get_file_id( 984 | self.raw, 985 | friend, 986 | file_number, 987 | raw.as_mut_ptr() as *mut u8, 988 | err.as_mut_ptr() 989 | )); 990 | 991 | Ok(FileId { 992 | raw: raw.assume_init() 993 | }) 994 | } 995 | } 996 | 997 | pub fn send_file( 998 | &mut self, 999 | friend: u32, 1000 | kind: FileKind, 1001 | file_size: usize, 1002 | file_name: &str, 1003 | ) -> Result { 1004 | unsafe { 1005 | let file_number = tox_try!(err, ll::tox_file_send( 1006 | self.raw, 1007 | friend, 1008 | kind as u32, 1009 | file_size as u64, 1010 | std::ptr::null(), 1011 | file_name.as_ptr(), 1012 | file_name.len(), 1013 | err.as_mut_ptr() 1014 | )); 1015 | 1016 | Ok(file_number) 1017 | } 1018 | } 1019 | 1020 | pub fn send_file_with_id( 1021 | &mut self, 1022 | friend: u32, 1023 | kind: FileKind, 1024 | file_size: usize, 1025 | file_id: FileId, 1026 | file_name: &str, 1027 | ) -> Result { 1028 | unsafe { 1029 | let file_number = tox_try!(err, ll::tox_file_send( 1030 | self.raw, 1031 | friend, 1032 | kind as u32, 1033 | file_size as u64, 1034 | file_id.raw.as_ptr(), 1035 | file_name.as_ptr(), 1036 | file_name.len(), 1037 | err.as_mut_ptr() 1038 | )); 1039 | 1040 | Ok(file_number) 1041 | } 1042 | } 1043 | 1044 | pub fn send_file_chunk( 1045 | &mut self, 1046 | friend: u32, 1047 | file_number: u32, 1048 | position: usize, 1049 | data: &[u8] 1050 | ) -> Result<(), FileSendChunkError> { 1051 | unsafe { 1052 | tox_try!(err, ll::tox_file_send_chunk( 1053 | self.raw, 1054 | friend, 1055 | file_number, 1056 | position as u64, 1057 | data.as_ptr(), 1058 | data.len(), 1059 | err.as_mut_ptr() 1060 | )); 1061 | 1062 | Ok(()) 1063 | } 1064 | } 1065 | 1066 | // Conference stuff 1067 | 1068 | pub fn new_conference(&mut self) -> Result { 1069 | unsafe { 1070 | let mut err = MaybeUninit::uninit(); 1071 | let res = ll::tox_conference_new(self.raw, err.as_mut_ptr()); 1072 | 1073 | match err.assume_init() as c_uint { 1074 | 0 => return Ok(res), 1075 | _ => return Err(()), 1076 | }; 1077 | } 1078 | } 1079 | 1080 | pub fn delete_conference(&mut self, conference_number: u32) -> Option<()> { 1081 | unsafe { 1082 | tox_option!(err, ll::tox_conference_delete( 1083 | self.raw, 1084 | conference_number, 1085 | err.as_mut_ptr() 1086 | )); 1087 | Some(()) 1088 | } 1089 | } 1090 | 1091 | pub fn conference_peer_count( 1092 | &mut self, conference_number: u32 1093 | )-> Result { 1094 | unsafe { 1095 | let count = tox_try!(err, ll::tox_conference_peer_count( 1096 | self.raw(), 1097 | conference_number, 1098 | err.as_mut_ptr() 1099 | )); 1100 | 1101 | Ok(count) 1102 | } 1103 | } 1104 | 1105 | pub fn get_peer_name( 1106 | &mut self, 1107 | conference_number: u32, 1108 | peer_number: u32 1109 | ) -> Result { 1110 | unsafe { 1111 | let size = tox_try!(err, ll::tox_conference_peer_get_name_size( 1112 | self.raw, 1113 | conference_number, 1114 | peer_number, 1115 | err.as_mut_ptr() 1116 | )); 1117 | 1118 | let mut raw: [u8; MAX_NAME_LENGTH] = [0; MAX_NAME_LENGTH]; 1119 | 1120 | tox_try!(err, ll::tox_conference_peer_get_name( 1121 | self.raw, 1122 | conference_number, 1123 | peer_number, 1124 | raw.as_mut_ptr() as *mut u8, 1125 | err.as_mut_ptr() 1126 | )); 1127 | 1128 | 1129 | Ok(String::from_utf8_lossy(&raw[..size]).to_string()) 1130 | } 1131 | } 1132 | 1133 | pub fn get_peer_public_key( 1134 | &mut self, 1135 | conference_number: u32, 1136 | peer_number: u32, 1137 | ) -> Result { 1138 | unsafe { 1139 | let mut raw = MaybeUninit::<[u8; PUBLIC_KEY_SIZE]>::uninit(); 1140 | tox_try!(err, ll::tox_conference_peer_get_public_key( 1141 | self.raw, 1142 | conference_number, 1143 | peer_number, 1144 | raw.as_mut_ptr() as *mut u8, 1145 | err.as_mut_ptr() 1146 | )); 1147 | 1148 | Ok(PublicKey { 1149 | raw: raw.assume_init() 1150 | }) 1151 | } 1152 | } 1153 | 1154 | pub fn is_own_peer_number( 1155 | &mut self, 1156 | conference_number: u32, 1157 | peer_number: u32 1158 | ) -> Result { 1159 | unsafe { 1160 | let is_ours = 1161 | tox_try!(err, ll::tox_conference_peer_number_is_ours( 1162 | self.raw, 1163 | conference_number, 1164 | peer_number, 1165 | err.as_mut_ptr() 1166 | )); 1167 | 1168 | Ok(is_ours) 1169 | } 1170 | } 1171 | 1172 | pub fn conference_offline_peer_count( 1173 | &mut self, 1174 | conference_number: u32 1175 | ) -> Result { 1176 | unsafe { 1177 | let count = tox_try!(err, ll::tox_conference_offline_peer_count( 1178 | self.raw, 1179 | conference_number, 1180 | err.as_mut_ptr() 1181 | )); 1182 | 1183 | Ok(count) 1184 | } 1185 | } 1186 | 1187 | pub fn get_offline_peer_name( 1188 | &mut self, 1189 | conference_number: u32, 1190 | peer_number: u32, 1191 | ) -> Result { 1192 | unsafe { 1193 | let size = tox_try!(err, ll::tox_conference_offline_peer_get_name_size( 1194 | self.raw, 1195 | conference_number, 1196 | peer_number, 1197 | err.as_mut_ptr() 1198 | )); 1199 | 1200 | let mut raw: [u8; MAX_NAME_LENGTH] = [0; MAX_NAME_LENGTH]; 1201 | 1202 | tox_try!(err, ll::tox_conference_offline_peer_get_name( 1203 | self.raw, 1204 | conference_number, 1205 | peer_number, 1206 | raw.as_mut_ptr() as *mut u8, 1207 | err.as_mut_ptr() 1208 | )); 1209 | 1210 | Ok(String::from_utf8_lossy(&raw[..size]).to_string()) 1211 | } 1212 | } 1213 | 1214 | pub fn get_offline_peer_public_key( 1215 | &mut self, 1216 | conference_number: u32, 1217 | peer_number: u32 1218 | ) -> Result { 1219 | unsafe { 1220 | let mut raw = MaybeUninit::<[u8; PUBLIC_KEY_SIZE]>::uninit(); 1221 | 1222 | tox_try!(err, ll::tox_conference_peer_get_public_key( 1223 | self.raw, 1224 | conference_number, 1225 | peer_number, 1226 | raw.as_mut_ptr() as *mut u8, 1227 | err.as_mut_ptr() 1228 | )); 1229 | 1230 | Ok(PublicKey { 1231 | raw: raw.assume_init() 1232 | }) 1233 | } 1234 | } 1235 | 1236 | pub fn get_offline_peer_last_active( 1237 | &mut self, 1238 | conference_number: u32, 1239 | peer_number: u32, 1240 | ) -> Result { 1241 | unsafe { 1242 | let time = tox_try!(err, ll::tox_conference_offline_peer_get_last_active( 1243 | self.raw, 1244 | conference_number, 1245 | peer_number, 1246 | err.as_mut_ptr() 1247 | )); 1248 | 1249 | Ok(time) 1250 | } 1251 | } 1252 | 1253 | pub fn invite_to_conference( 1254 | &mut self, 1255 | friend_number: u32, 1256 | conference_number: u32 1257 | ) -> Result<(), ConferenceInviteError> { 1258 | unsafe { 1259 | tox_try!(err, ll::tox_conference_invite( 1260 | self.raw, 1261 | friend_number, 1262 | conference_number, 1263 | err.as_mut_ptr() 1264 | )); 1265 | 1266 | Ok(()) 1267 | } 1268 | } 1269 | 1270 | pub fn join_conference( 1271 | &mut self, 1272 | friend_number: u32, 1273 | cookie: &Cookie, 1274 | ) -> Result { 1275 | unsafe { 1276 | let conference = tox_try!(err, ll::tox_conference_join( 1277 | self.raw, 1278 | friend_number, 1279 | cookie.raw.as_ptr(), 1280 | cookie.raw.len(), 1281 | err.as_mut_ptr() 1282 | )); 1283 | 1284 | Ok(conference) 1285 | } 1286 | } 1287 | 1288 | pub fn send_conference_message( 1289 | &mut self, 1290 | conference_number: u32, 1291 | kind: MessageType, 1292 | message: &str 1293 | ) -> Result<(), ConferenceSendError> { 1294 | unsafe { 1295 | let msg = message.as_ptr(); 1296 | let len = message.len(); 1297 | 1298 | tox_try!(err, ll::tox_conference_send_message( 1299 | self.raw, 1300 | conference_number, 1301 | kind, 1302 | msg, 1303 | len, 1304 | err.as_mut_ptr() 1305 | )); 1306 | 1307 | Ok(()) 1308 | } 1309 | } 1310 | 1311 | pub fn get_conference_title( 1312 | &mut self, 1313 | conference_number: u32 1314 | ) -> Result { 1315 | unsafe { 1316 | let size = tox_try!(err, ll::tox_conference_get_title_size( 1317 | self.raw, 1318 | conference_number, 1319 | err.as_mut_ptr() 1320 | )); 1321 | 1322 | let mut raw: [u8; MAX_NAME_LENGTH] = [0; MAX_NAME_LENGTH]; 1323 | 1324 | tox_try!(err, ll::tox_conference_get_title( 1325 | self.raw, 1326 | conference_number, 1327 | raw.as_mut_ptr() as *mut u8, 1328 | err.as_mut_ptr() 1329 | )); 1330 | 1331 | Ok(String::from_utf8_lossy(&raw[..size]).to_string()) 1332 | } 1333 | } 1334 | 1335 | pub fn set_conference_title( 1336 | &mut self, 1337 | conference_number: u32, 1338 | title: &str 1339 | ) -> Result<(), ConferenceTitleError> { 1340 | unsafe { 1341 | let len = title.len(); 1342 | 1343 | tox_try!(err, ll::tox_conference_set_title( 1344 | self.raw, 1345 | conference_number, 1346 | title.as_ptr(), 1347 | len, 1348 | err.as_mut_ptr() 1349 | )); 1350 | 1351 | Ok(()) 1352 | } 1353 | } 1354 | 1355 | pub fn get_chatlist(&mut self) -> Vec { 1356 | unsafe { 1357 | let len = ll::tox_conference_get_chatlist_size( 1358 | self.raw 1359 | ); 1360 | 1361 | let mut chatlist = Vec::with_capacity(len); 1362 | 1363 | ll::tox_conference_get_chatlist( 1364 | self.raw, 1365 | chatlist.as_mut_ptr() 1366 | ); 1367 | 1368 | chatlist 1369 | } 1370 | } 1371 | 1372 | pub fn get_conference_type( 1373 | &mut self, 1374 | conference_number: u32 1375 | ) -> Option { 1376 | unsafe { 1377 | let kind = tox_option!(err, ll::tox_conference_get_type( 1378 | self.raw, 1379 | conference_number, 1380 | err.as_mut_ptr() 1381 | )); 1382 | 1383 | Some(kind) 1384 | } 1385 | } 1386 | 1387 | pub fn get_conference_id( 1388 | &mut self, 1389 | conference_number: u32 1390 | ) -> Option { 1391 | unsafe { 1392 | let mut raw = [0; CONFERENCE_ID_SIZE]; 1393 | 1394 | let exists = ll::tox_conference_get_id( 1395 | self.raw, 1396 | conference_number, 1397 | raw.as_mut_ptr(), 1398 | ); 1399 | 1400 | if exists { 1401 | Some(ConferenceId{ 1402 | raw, 1403 | }) 1404 | } 1405 | else { 1406 | None 1407 | } 1408 | } 1409 | } 1410 | 1411 | pub fn conference_by_id( 1412 | &mut self, 1413 | id: &ConferenceId 1414 | ) -> Option { 1415 | unsafe { 1416 | let conf_num = tox_option!(err, ll::tox_conference_by_id( 1417 | self.raw, 1418 | id.raw.as_ptr(), 1419 | err.as_mut_ptr() 1420 | )); 1421 | 1422 | Some(conf_num) 1423 | } 1424 | } 1425 | 1426 | /// Get all all information associated with the tox instance as a `Vec` 1427 | pub fn save(&self) -> Vec { 1428 | unsafe { 1429 | let len = ll::tox_get_savedata_size(self.raw); 1430 | let mut data = Vec::with_capacity(len); 1431 | data.set_len(len); 1432 | ll::tox_get_savedata(self.raw, data.as_mut_ptr()); 1433 | data 1434 | } 1435 | } 1436 | 1437 | #[inline] 1438 | #[doc(hidden)] 1439 | pub unsafe fn from_raw_tox(raw: *mut ll::Tox) -> Tox { 1440 | let mut tox = MaybeUninit::::uninit(); 1441 | (*tox.as_mut_ptr()).raw = raw; 1442 | tox.assume_init() 1443 | } 1444 | 1445 | #[inline] 1446 | #[doc(hidden)] 1447 | pub unsafe fn raw(&mut self) -> *mut ll::Tox { 1448 | self.raw 1449 | } 1450 | } 1451 | 1452 | // BEGIN: Callback pack 1453 | 1454 | extern fn on_connection_status(_: *mut ll::Tox, status: Connection, chan: *mut c_void) { 1455 | unsafe { 1456 | let tx: &mut Sender = &mut *(chan as *mut _); 1457 | tx.send(ConnectionStatus(status)).unwrap(); 1458 | } 1459 | } 1460 | 1461 | extern fn on_friend_request(_: *mut ll::Tox, public_key: *const u8, message: *const u8, length: usize, chan: *mut c_void) { 1462 | unsafe { 1463 | let tx: &mut Sender = &mut *(chan as *mut _); 1464 | let pk: &PublicKey = &*(public_key as *const _); 1465 | let message = String::from_utf8_lossy(slice::from_raw_parts(message, length)).into_owned(); 1466 | tx.send(FriendRequest(*pk, message)).unwrap(); 1467 | } 1468 | } 1469 | 1470 | extern fn on_friend_message(_: *mut ll::Tox, fnum: u32, kind: MessageType, 1471 | message: *const u8, length: usize, chan: *mut c_void) { 1472 | unsafe { 1473 | let tx: &mut Sender = &mut *(chan as *mut _); 1474 | let message = String::from_utf8_lossy(slice::from_raw_parts(message, length)).into_owned(); 1475 | tx.send(FriendMessage(fnum, kind, message)).unwrap(); 1476 | 1477 | } 1478 | } 1479 | 1480 | extern fn on_friend_name(_: *mut ll::Tox, fnum: u32, name: *const u8, length: usize, chan: *mut c_void) { 1481 | unsafe { 1482 | let tx: &mut Sender = &mut *(chan as *mut _); 1483 | let name = String::from_utf8_lossy(slice::from_raw_parts(name, length)).into_owned(); 1484 | tx.send(FriendName(fnum, name)).unwrap(); 1485 | } 1486 | } 1487 | 1488 | extern fn on_friend_status_message(_: *mut ll::Tox, fnum: u32, message: *const u8, length: usize, chan: *mut c_void) { 1489 | unsafe { 1490 | let tx: &mut Sender = &mut *(chan as *mut _); 1491 | let message = String::from_utf8_lossy(slice::from_raw_parts(message, length)).into_owned(); 1492 | tx.send(FriendStatusMessage(fnum, message)).unwrap(); 1493 | } 1494 | } 1495 | 1496 | extern fn on_friend_status(_: *mut ll::Tox, fnum: u32, status: UserStatus, chan: *mut c_void) { 1497 | unsafe { 1498 | let tx: &mut Sender = &mut *(chan as *mut _); 1499 | tx.send(FriendStatus(fnum, status)).unwrap(); 1500 | } 1501 | } 1502 | 1503 | extern fn on_friend_connection_status(_: *mut ll::Tox, fnum: u32, status: Connection, chan: *mut c_void) { 1504 | unsafe { 1505 | let tx: &mut Sender = &mut *(chan as *mut _); 1506 | tx.send(FriendConnectionStatus(fnum, status)).unwrap(); 1507 | } 1508 | } 1509 | 1510 | extern fn on_friend_typing(_: *mut ll::Tox, fnum: u32, is_typing: bool, chan: *mut c_void) { 1511 | unsafe { 1512 | let tx: &mut Sender = &mut *(chan as *mut _); 1513 | tx.send(FriendTyping(fnum, is_typing)).unwrap(); 1514 | } 1515 | } 1516 | 1517 | extern fn on_friend_read_receipt( 1518 | _: *mut ll::Tox, 1519 | friend: u32, 1520 | message_id: u32, 1521 | chan: *mut c_void 1522 | ) { 1523 | unsafe { 1524 | let tx: &mut Sender = &mut *(chan as *mut _); 1525 | tx.send(FriendReadReceipt { 1526 | friend, message_id 1527 | }).unwrap(); 1528 | } 1529 | } 1530 | 1531 | // File transfer 1532 | 1533 | extern fn on_file_control( 1534 | _: *mut ll::Tox, 1535 | friend: u32, 1536 | file_number: u32, 1537 | control: FileControl, 1538 | chan: *mut c_void 1539 | ) { 1540 | unsafe { 1541 | let tx: &mut Sender = &mut *(chan as *mut _); 1542 | tx.send(FileControlReceipt { 1543 | friend, 1544 | file_number, 1545 | control 1546 | }).unwrap() 1547 | } 1548 | } 1549 | 1550 | extern fn on_file_chunk_request( 1551 | _: *mut ll::Tox, 1552 | friend: u32, 1553 | file_number: u32, 1554 | position: u64, 1555 | length: usize, 1556 | chan: *mut c_void 1557 | ) { 1558 | unsafe { 1559 | let tx: &mut Sender = &mut *(chan as *mut _); 1560 | tx.send(FileChunkRequest { 1561 | friend, 1562 | file_number, 1563 | position: position as usize, 1564 | length: length as usize, 1565 | }).unwrap() 1566 | } 1567 | } 1568 | 1569 | extern fn on_file_receive( 1570 | _: *mut ll::Tox, 1571 | friend: u32, 1572 | file_number: u32, 1573 | kind: u32, 1574 | file_size: u64, 1575 | file_name: *const u8, 1576 | file_name_size: usize, 1577 | chan: *mut c_void 1578 | ) { 1579 | unsafe { 1580 | let tx: &mut Sender = &mut *(chan as *mut _); 1581 | let file_name = 1582 | String::from_utf8_lossy( 1583 | slice::from_raw_parts(file_name, file_name_size) 1584 | ) 1585 | .into_owned(); 1586 | tx.send(FileReceipt { 1587 | friend, 1588 | file_number, 1589 | kind, 1590 | file_size: file_size as usize, 1591 | file_name 1592 | }).unwrap() 1593 | } 1594 | } 1595 | 1596 | extern fn on_file_chunk_receive( 1597 | _: *mut ll::Tox, 1598 | friend: u32, 1599 | file_number: u32, 1600 | position: u64, 1601 | data: *const u8, 1602 | data_len: usize, 1603 | chan: *mut c_void 1604 | ) { 1605 | unsafe { 1606 | let tx: &mut Sender = &mut *(chan as *mut _); 1607 | let data = Vec::from(slice::from_raw_parts(data, data_len)); 1608 | tx.send(FileChunkReceipt { 1609 | friend, 1610 | file_number, 1611 | position: position as usize, 1612 | data 1613 | }).unwrap() 1614 | } 1615 | } 1616 | 1617 | // Conference callbacks 1618 | 1619 | extern fn on_conference_invite( 1620 | _: *mut ll::Tox, 1621 | friend: u32, 1622 | kind: ConferenceType, 1623 | cookie: *const u8, 1624 | cookie_len: usize, 1625 | chan: *mut c_void 1626 | ) { 1627 | unsafe { 1628 | let tx: &mut Sender = &mut *(chan as *mut _); 1629 | let cookie = Cookie { 1630 | raw: slice::from_raw_parts(cookie, cookie_len).into() 1631 | }; 1632 | tx.send(ConferenceInvite { 1633 | friend, kind, cookie, 1634 | }).unwrap() 1635 | } 1636 | } 1637 | 1638 | extern fn on_conference_connected( 1639 | _: *mut ll::Tox, 1640 | conference: u32, 1641 | chan: *mut c_void 1642 | ) { 1643 | unsafe { 1644 | let tx: &mut Sender = &mut *(chan as *mut _); 1645 | tx.send(ConferenceConnected { 1646 | conference 1647 | }).unwrap(); 1648 | } 1649 | } 1650 | 1651 | extern fn on_conference_message( 1652 | _: *mut ll::Tox, 1653 | conference: u32, 1654 | peer: u32, 1655 | kind: MessageType, 1656 | message: *const u8, 1657 | len: usize, 1658 | chan: *mut c_void 1659 | ) { 1660 | unsafe { 1661 | let tx: &mut Sender = &mut *(chan as *mut _); 1662 | 1663 | let message = 1664 | String::from_utf8_lossy(slice::from_raw_parts(message, len)) 1665 | .into_owned(); 1666 | 1667 | tx.send(ConferenceMessage { 1668 | conference, peer, kind, message 1669 | }).unwrap(); 1670 | } 1671 | } 1672 | 1673 | extern fn on_conference_title( 1674 | _: *mut ll::Tox, 1675 | conference: u32, 1676 | peer: u32, 1677 | title: *const u8, 1678 | len: usize, 1679 | chan: *mut c_void 1680 | ) { 1681 | unsafe { 1682 | let tx: &mut Sender = &mut *(chan as *mut _); 1683 | 1684 | let title = 1685 | String::from_utf8_lossy(slice::from_raw_parts(title, len)) 1686 | .into_owned(); 1687 | 1688 | tx.send(ConferenceTitle { 1689 | conference, peer, title 1690 | }).unwrap(); 1691 | } 1692 | } 1693 | 1694 | extern fn on_conference_peer_name( 1695 | _: *mut ll::Tox, 1696 | conference: u32, 1697 | peer: u32, 1698 | name: *const u8, 1699 | len: usize, 1700 | chan: *mut c_void 1701 | ) { 1702 | unsafe { 1703 | let tx: &mut Sender = &mut *(chan as *mut _); 1704 | 1705 | let name = 1706 | String::from_utf8_lossy(slice::from_raw_parts(name, len)) 1707 | .into_owned(); 1708 | 1709 | tx.send(ConferencePeerName { 1710 | conference, peer, name 1711 | }).unwrap(); 1712 | } 1713 | } 1714 | 1715 | extern fn on_conference_peer_list_changed( 1716 | _: *mut ll::Tox, 1717 | conference: u32, 1718 | chan: *mut c_void 1719 | ) { 1720 | unsafe { 1721 | let tx: &mut Sender = &mut *(chan as *mut _); 1722 | tx.send(ConferencePeerListChanged { 1723 | conference 1724 | }).unwrap(); 1725 | } 1726 | } 1727 | 1728 | extern fn on_lossy_package(_: *mut ll::Tox, fnum: u32, data: *const u8, length: usize, chan: *mut c_void) { 1729 | unsafe { 1730 | let tx: &mut Sender = &mut *(chan as *mut _); 1731 | let data: Vec = From::from(slice::from_raw_parts(data, length as usize)); 1732 | tx.send(LossyPackage(fnum, data)).unwrap(); 1733 | } 1734 | } 1735 | extern fn on_lossless_package(_: *mut ll::Tox, fnum: u32, data: *const u8, length: usize, chan: *mut c_void) { 1736 | unsafe { 1737 | let tx: &mut Sender = &mut *(chan as *mut _); 1738 | let data: Vec = From::from(slice::from_raw_parts(data, length as usize)); 1739 | tx.send(LosslessPackage(fnum, data)).unwrap(); 1740 | } 1741 | } 1742 | 1743 | // END: Callback pack 1744 | -------------------------------------------------------------------------------- /src/core/errors.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 3 | pub enum InitError { 4 | // `NoError` doesn't exists in rust code 5 | #[doc(hidden)] NoError = 0, 6 | NullError = 1, 7 | MallocError, 8 | PortAllocError, 9 | ProxyBadType, 10 | ProxyBadHost, 11 | ProxyBadPort, 12 | ProxyNotFound, 13 | LoadEncrypted, 14 | LoadBadFormat, 15 | } 16 | 17 | #[repr(C)] 18 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 19 | pub enum BootstrapError { 20 | #[doc(hidden)] NoError = 0, 21 | NullError = 1, 22 | BadHost, 23 | BadPort, 24 | } 25 | 26 | #[repr(C)] 27 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 28 | pub enum SetInfoError { 29 | #[doc(hidden)] NoError = 0, 30 | NullError = 1, 31 | TooLong, 32 | } 33 | 34 | #[repr(C)] 35 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 36 | pub enum FriendAddError { 37 | #[doc(hidden)] NoError = 0, 38 | NullError = 1, 39 | TooLong, 40 | NoMessage, 41 | OwnKey, 42 | AlreadySent, 43 | BadChecksum, 44 | SetNewNospam, 45 | MallocError, 46 | } 47 | 48 | #[repr(C)] 49 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 50 | pub enum FriendSendMessageError { 51 | #[doc(hidden)] NoError = 0, 52 | NullError = 1, 53 | NotFound, 54 | NotConnected, 55 | SendQ, 56 | TooLong, 57 | Empty, 58 | } 59 | 60 | #[repr(C)] 61 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 62 | pub enum FileControlError { 63 | #[doc(hidden)] NoError = 0, 64 | FriendNotFound = 1, 65 | FriendNotConnected, 66 | NotFound, 67 | NotPaused, 68 | Denied, 69 | AlreadyPaused, 70 | SendQ, 71 | } 72 | 73 | #[repr(C)] 74 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 75 | pub enum FileSeekError { 76 | #[doc(hidden)] NoError = 0, 77 | FriendNotFound = 1, 78 | FriendNotConnected, 79 | NotFound, 80 | Denied, 81 | InvalidPosition, 82 | SendQ, 83 | } 84 | 85 | #[repr(C)] 86 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 87 | pub enum FileGetError { 88 | #[doc(hidden)] NoError = 0, 89 | FriendNotFound = 1, 90 | NotFound, 91 | } 92 | 93 | #[repr(C)] 94 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 95 | pub enum FileSendError { 96 | #[doc(hidden)] NoError = 0, 97 | NullError = 1, 98 | FriendNotFound, 99 | FriendNotConnected, 100 | NameTooLong, 101 | TooMany, 102 | } 103 | 104 | #[repr(C)] 105 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 106 | pub enum FileSendChunkError { 107 | #[doc(hidden)] NoError = 0, 108 | NullError = 1, 109 | FriendNotFound, 110 | FriendNotConnected, 111 | NotFound, 112 | NotTransferring, 113 | InvalidLength, 114 | SendQ, 115 | WrongPosition, 116 | } 117 | 118 | #[repr(C)] 119 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 120 | pub enum FriendCustomPacketError { 121 | #[doc(hidden)] NoError = 0, 122 | NullError = 1, 123 | FriendNotFound, 124 | FriendNotConnected, 125 | Invalid, 126 | Empty, 127 | TooLong, 128 | SendQ, 129 | } 130 | 131 | #[repr(u32)] 132 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 133 | pub enum ConferencePeerQueryError { 134 | #[doc(hidden)] NoError = 0, 135 | ConferenceNotFound = 1, 136 | PeerNotFound = 2, 137 | PeerQueryNoConnection = 3, 138 | } 139 | 140 | #[repr(u32)] 141 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 142 | pub enum ConferenceInviteError { 143 | #[doc(hidden)] NoError = 0, 144 | ConferenceNotFound = 1, 145 | FailSend = 2, 146 | NoConnection = 3, 147 | } 148 | 149 | #[repr(u32)] 150 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 151 | pub enum ConferenceJoinError { 152 | #[doc(hidden)] NoError = 0, 153 | InvalidLength = 1, 154 | WrongType = 2, 155 | FriendNotFound = 3, 156 | Duplicate = 4, 157 | InitFail = 5, 158 | FailSend = 6, 159 | } 160 | 161 | #[repr(u32)] 162 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 163 | pub enum ConferenceSendError { 164 | #[doc(hidden)] NoError = 0, 165 | ConferenceNotFound = 1, 166 | TooLong = 2, 167 | NoConnection = 3, 168 | FailSend = 4, 169 | } 170 | 171 | #[repr(u32)] 172 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 173 | pub enum ConferenceTitleError { 174 | #[doc(hidden)] NoError = 0, 175 | ConferenceNotFound = 1, 176 | InvalidLength = 2, 177 | FailSend = 3, 178 | } 179 | -------------------------------------------------------------------------------- /src/core/ll.rs: -------------------------------------------------------------------------------- 1 | #![allow(bad_style)] 2 | 3 | use super::{ 4 | UserStatus, 5 | MessageType, 6 | ProxyType, 7 | SavedataType, 8 | LogLevel, 9 | Connection, 10 | FileControl, 11 | ConferenceType 12 | }; 13 | 14 | use super::errors::*; 15 | 16 | #[repr(C)] 17 | #[derive(Debug, Copy, Clone)] 18 | pub struct Tox { 19 | _unused: [u8; 0], 20 | } 21 | 22 | #[link(name = "toxcore")] 23 | extern "C" { 24 | pub fn tox_version_major() -> u32; 25 | pub fn tox_version_minor() -> u32; 26 | pub fn tox_version_patch() -> u32; 27 | pub fn tox_version_is_compatible(major: u32, minor: u32, patch: u32) -> bool; 28 | pub fn tox_public_key_size() -> u32; 29 | pub fn tox_secret_key_size() -> u32; 30 | pub fn tox_conference_uid_size() -> u32; 31 | pub fn tox_conference_id_size() -> u32; 32 | pub fn tox_nospam_size() -> u32; 33 | pub fn tox_address_size() -> u32; 34 | pub fn tox_max_name_length() -> u32; 35 | pub fn tox_max_status_message_length() -> u32; 36 | pub fn tox_max_friend_request_length() -> u32; 37 | pub fn tox_max_message_length() -> u32; 38 | pub fn tox_max_custom_packet_size() -> u32; 39 | pub fn tox_hash_length() -> u32; 40 | pub fn tox_file_id_length() -> u32; 41 | pub fn tox_max_filename_length() -> u32; 42 | pub fn tox_max_hostname_length() -> u32; 43 | } 44 | 45 | pub type tox_log_cb = ::std::option::Option< 46 | unsafe extern "C" fn( 47 | tox: *mut Tox, 48 | level: LogLevel, 49 | file: *const ::std::os::raw::c_char, 50 | line: u32, 51 | func: *const ::std::os::raw::c_char, 52 | message: *const ::std::os::raw::c_char, 53 | user_data: *mut ::std::os::raw::c_void, 54 | ), 55 | >; 56 | 57 | #[repr(C)] 58 | #[derive(Debug, Copy, Clone)] 59 | pub struct Tox_Options { 60 | pub ipv6_enabled: bool, 61 | pub udp_enabled: bool, 62 | pub local_discovery_enabled: bool, 63 | pub proxy_type: ProxyType, 64 | pub proxy_host: *const ::std::os::raw::c_char, 65 | pub proxy_port: u16, 66 | pub start_port: u16, 67 | pub end_port: u16, 68 | pub tcp_port: u16, 69 | pub hole_punching_enabled: bool, 70 | pub savedata_type: SavedataType, 71 | pub savedata_data: *const u8, 72 | pub savedata_length: usize, 73 | pub log_callback: tox_log_cb, 74 | pub log_user_data: *mut ::std::os::raw::c_void, 75 | } 76 | 77 | #[test] 78 | fn bindgen_test_layout_Tox_Options() { 79 | assert_eq!( 80 | ::std::mem::size_of::(), 81 | 64usize, 82 | concat!("Size of: ", stringify!(Tox_Options)) 83 | ); 84 | assert_eq!( 85 | ::std::mem::align_of::(), 86 | 8usize, 87 | concat!("Alignment of ", stringify!(Tox_Options)) 88 | ); 89 | assert_eq!( 90 | unsafe { &(*(::std::ptr::null::())).ipv6_enabled as *const _ as usize }, 91 | 0usize, 92 | concat!( 93 | "Offset of field: ", 94 | stringify!(Tox_Options), 95 | "::", 96 | stringify!(ipv6_enabled) 97 | ) 98 | ); 99 | assert_eq!( 100 | unsafe { &(*(::std::ptr::null::())).udp_enabled as *const _ as usize }, 101 | 1usize, 102 | concat!( 103 | "Offset of field: ", 104 | stringify!(Tox_Options), 105 | "::", 106 | stringify!(udp_enabled) 107 | ) 108 | ); 109 | assert_eq!( 110 | unsafe { 111 | &(*(::std::ptr::null::())).local_discovery_enabled as *const _ as usize 112 | }, 113 | 2usize, 114 | concat!( 115 | "Offset of field: ", 116 | stringify!(Tox_Options), 117 | "::", 118 | stringify!(local_discovery_enabled) 119 | ) 120 | ); 121 | assert_eq!( 122 | unsafe { &(*(::std::ptr::null::())).proxy_type as *const _ as usize }, 123 | 4usize, 124 | concat!( 125 | "Offset of field: ", 126 | stringify!(Tox_Options), 127 | "::", 128 | stringify!(proxy_type) 129 | ) 130 | ); 131 | assert_eq!( 132 | unsafe { &(*(::std::ptr::null::())).proxy_host as *const _ as usize }, 133 | 8usize, 134 | concat!( 135 | "Offset of field: ", 136 | stringify!(Tox_Options), 137 | "::", 138 | stringify!(proxy_host) 139 | ) 140 | ); 141 | assert_eq!( 142 | unsafe { &(*(::std::ptr::null::())).proxy_port as *const _ as usize }, 143 | 16usize, 144 | concat!( 145 | "Offset of field: ", 146 | stringify!(Tox_Options), 147 | "::", 148 | stringify!(proxy_port) 149 | ) 150 | ); 151 | assert_eq!( 152 | unsafe { &(*(::std::ptr::null::())).start_port as *const _ as usize }, 153 | 18usize, 154 | concat!( 155 | "Offset of field: ", 156 | stringify!(Tox_Options), 157 | "::", 158 | stringify!(start_port) 159 | ) 160 | ); 161 | assert_eq!( 162 | unsafe { &(*(::std::ptr::null::())).end_port as *const _ as usize }, 163 | 20usize, 164 | concat!( 165 | "Offset of field: ", 166 | stringify!(Tox_Options), 167 | "::", 168 | stringify!(end_port) 169 | ) 170 | ); 171 | assert_eq!( 172 | unsafe { &(*(::std::ptr::null::())).tcp_port as *const _ as usize }, 173 | 22usize, 174 | concat!( 175 | "Offset of field: ", 176 | stringify!(Tox_Options), 177 | "::", 178 | stringify!(tcp_port) 179 | ) 180 | ); 181 | assert_eq!( 182 | unsafe { 183 | &(*(::std::ptr::null::())).hole_punching_enabled as *const _ as usize 184 | }, 185 | 24usize, 186 | concat!( 187 | "Offset of field: ", 188 | stringify!(Tox_Options), 189 | "::", 190 | stringify!(hole_punching_enabled) 191 | ) 192 | ); 193 | assert_eq!( 194 | unsafe { &(*(::std::ptr::null::())).savedata_type as *const _ as usize }, 195 | 28usize, 196 | concat!( 197 | "Offset of field: ", 198 | stringify!(Tox_Options), 199 | "::", 200 | stringify!(savedata_type) 201 | ) 202 | ); 203 | assert_eq!( 204 | unsafe { &(*(::std::ptr::null::())).savedata_data as *const _ as usize }, 205 | 32usize, 206 | concat!( 207 | "Offset of field: ", 208 | stringify!(Tox_Options), 209 | "::", 210 | stringify!(savedata_data) 211 | ) 212 | ); 213 | assert_eq!( 214 | unsafe { &(*(::std::ptr::null::())).savedata_length as *const _ as usize }, 215 | 40usize, 216 | concat!( 217 | "Offset of field: ", 218 | stringify!(Tox_Options), 219 | "::", 220 | stringify!(savedata_length) 221 | ) 222 | ); 223 | assert_eq!( 224 | unsafe { &(*(::std::ptr::null::())).log_callback as *const _ as usize }, 225 | 48usize, 226 | concat!( 227 | "Offset of field: ", 228 | stringify!(Tox_Options), 229 | "::", 230 | stringify!(log_callback) 231 | ) 232 | ); 233 | assert_eq!( 234 | unsafe { &(*(::std::ptr::null::())).log_user_data as *const _ as usize }, 235 | 56usize, 236 | concat!( 237 | "Offset of field: ", 238 | stringify!(Tox_Options), 239 | "::", 240 | stringify!(log_user_data) 241 | ) 242 | ); 243 | } 244 | 245 | extern "C" { 246 | pub fn tox_options_get_ipv6_enabled(options: *const Tox_Options) -> bool; 247 | pub fn tox_options_set_ipv6_enabled(options: *mut Tox_Options, ipv6_enabled: bool); 248 | pub fn tox_options_get_udp_enabled(options: *const Tox_Options) -> bool; 249 | pub fn tox_options_set_udp_enabled(options: *mut Tox_Options, udp_enabled: bool); 250 | pub fn tox_options_get_local_discovery_enabled(options: *const Tox_Options) -> bool; 251 | pub fn tox_options_set_local_discovery_enabled( 252 | options: *mut Tox_Options, 253 | local_discovery_enabled: bool, 254 | ); 255 | pub fn tox_options_get_proxy_type(options: *const Tox_Options) -> ProxyType; 256 | pub fn tox_options_set_proxy_type(options: *mut Tox_Options, type_: ProxyType); 257 | pub fn tox_options_get_proxy_host(options: *const Tox_Options) 258 | -> *const ::std::os::raw::c_char; 259 | pub fn tox_options_set_proxy_host( 260 | options: *mut Tox_Options, 261 | host: *const ::std::os::raw::c_char, 262 | ); 263 | pub fn tox_options_get_proxy_port(options: *const Tox_Options) -> u16; 264 | pub fn tox_options_set_proxy_port(options: *mut Tox_Options, port: u16); 265 | pub fn tox_options_get_start_port(options: *const Tox_Options) -> u16; 266 | pub fn tox_options_set_start_port(options: *mut Tox_Options, start_port: u16); 267 | pub fn tox_options_get_end_port(options: *const Tox_Options) -> u16; 268 | pub fn tox_options_set_end_port(options: *mut Tox_Options, end_port: u16); 269 | pub fn tox_options_get_tcp_port(options: *const Tox_Options) -> u16; 270 | pub fn tox_options_set_tcp_port(options: *mut Tox_Options, tcp_port: u16); 271 | pub fn tox_options_get_hole_punching_enabled(options: *const Tox_Options) -> bool; 272 | pub fn tox_options_set_hole_punching_enabled( 273 | options: *mut Tox_Options, 274 | hole_punching_enabled: bool, 275 | ); 276 | pub fn tox_options_get_savedata_type(options: *const Tox_Options) -> SavedataType; 277 | pub fn tox_options_set_savedata_type(options: *mut Tox_Options, type_: SavedataType); 278 | pub fn tox_options_get_savedata_data(options: *const Tox_Options) -> *const u8; 279 | pub fn tox_options_set_savedata_data(options: *mut Tox_Options, data: *const u8, length: usize); 280 | pub fn tox_options_get_savedata_length(options: *const Tox_Options) -> usize; 281 | pub fn tox_options_set_savedata_length(options: *mut Tox_Options, length: usize); 282 | pub fn tox_options_get_log_callback(options: *const Tox_Options) -> tox_log_cb; 283 | pub fn tox_options_set_log_callback(options: *mut Tox_Options, callback: tox_log_cb); 284 | pub fn tox_options_get_log_user_data( 285 | options: *const Tox_Options, 286 | ) -> *mut ::std::os::raw::c_void; 287 | pub fn tox_options_set_log_user_data( 288 | options: *mut Tox_Options, 289 | user_data: *mut ::std::os::raw::c_void, 290 | ); 291 | pub fn tox_options_default(options: *mut Tox_Options); 292 | } 293 | 294 | #[repr(u32)] 295 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 296 | pub enum TOX_ERR_OPTIONS_NEW { 297 | TOX_ERR_OPTIONS_NEW_OK = 0, 298 | TOX_ERR_OPTIONS_NEW_MALLOC = 1, 299 | } 300 | 301 | extern "C" { 302 | pub fn tox_options_new(error: *mut TOX_ERR_OPTIONS_NEW) -> *mut Tox_Options; 303 | pub fn tox_options_free(options: *mut Tox_Options); 304 | } 305 | 306 | extern "C" { 307 | pub fn tox_new(options: *const Tox_Options, error: *mut InitError) -> *mut Tox; 308 | pub fn tox_kill(tox: *mut Tox); 309 | pub fn tox_get_savedata_size(tox: *const Tox) -> usize; 310 | pub fn tox_get_savedata(tox: *const Tox, savedata: *mut u8); 311 | } 312 | extern "C" { 313 | pub fn tox_bootstrap( 314 | tox: *mut Tox, 315 | host: *const ::std::os::raw::c_char, 316 | port: u16, 317 | public_key: *const u8, 318 | error: *mut BootstrapError, 319 | ) -> bool; 320 | pub fn tox_add_tcp_relay( 321 | tox: *mut Tox, 322 | host: *const ::std::os::raw::c_char, 323 | port: u16, 324 | public_key: *const u8, 325 | error: *mut BootstrapError, 326 | ) -> bool; 327 | } 328 | 329 | extern "C" { 330 | pub fn tox_self_get_connection_status(tox: *const Tox) -> Connection; 331 | } 332 | 333 | pub type tox_self_connection_status_cb = ::std::option::Option< 334 | unsafe extern "C" fn( 335 | tox: *mut Tox, 336 | connection_status: Connection, 337 | user_data: *mut ::std::os::raw::c_void, 338 | ), 339 | >; 340 | 341 | extern "C" { 342 | pub fn tox_callback_self_connection_status( 343 | tox: *mut Tox, 344 | callback: tox_self_connection_status_cb, 345 | ); 346 | pub fn tox_iteration_interval(tox: *const Tox) -> u32; 347 | pub fn tox_iterate(tox: *mut Tox, user_data: *mut ::std::os::raw::c_void); 348 | pub fn tox_self_get_address(tox: *const Tox, address: *mut u8); 349 | pub fn tox_self_set_nospam(tox: *mut Tox, nospam: u32); 350 | pub fn tox_self_get_nospam(tox: *const Tox) -> u32; 351 | pub fn tox_self_get_public_key(tox: *const Tox, public_key: *mut u8); 352 | pub fn tox_self_get_secret_key(tox: *const Tox, secret_key: *mut u8); 353 | } 354 | 355 | extern "C" { 356 | pub fn tox_self_set_name( 357 | tox: *mut Tox, 358 | name: *const u8, 359 | length: usize, 360 | error: *mut SetInfoError, 361 | ) -> bool; 362 | pub fn tox_self_get_name_size(tox: *const Tox) -> usize; 363 | pub fn tox_self_get_name(tox: *const Tox, name: *mut u8); 364 | pub fn tox_self_set_status_message( 365 | tox: *mut Tox, 366 | status_message: *const u8, 367 | length: usize, 368 | error: *mut SetInfoError, 369 | ) -> bool; 370 | pub fn tox_self_get_status_message_size(tox: *const Tox) -> usize; 371 | pub fn tox_self_get_status_message(tox: *const Tox, status_message: *mut u8); 372 | pub fn tox_self_set_status(tox: *mut Tox, status: UserStatus); 373 | pub fn tox_self_get_status(tox: *const Tox) -> UserStatus; 374 | } 375 | 376 | extern "C" { 377 | pub fn tox_friend_add( 378 | tox: *mut Tox, 379 | address: *const u8, 380 | message: *const u8, 381 | length: usize, 382 | error: *mut FriendAddError, 383 | ) -> u32; 384 | pub fn tox_friend_add_norequest( 385 | tox: *mut Tox, 386 | public_key: *const u8, 387 | error: *mut FriendAddError, 388 | ) -> u32; 389 | } 390 | 391 | #[repr(u32)] 392 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 393 | pub enum TOX_ERR_FRIEND_DELETE { 394 | TOX_ERR_FRIEND_DELETE_OK = 0, 395 | TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND = 1, 396 | } 397 | 398 | extern "C" { 399 | pub fn tox_friend_delete( 400 | tox: *mut Tox, 401 | friend_number: u32, 402 | error: *mut TOX_ERR_FRIEND_DELETE, 403 | ) -> bool; 404 | } 405 | 406 | #[repr(u32)] 407 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 408 | pub enum TOX_ERR_FRIEND_BY_PUBLIC_KEY { 409 | TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK = 0, 410 | TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL = 1, 411 | TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND = 2, 412 | } 413 | 414 | extern "C" { 415 | pub fn tox_friend_by_public_key( 416 | tox: *const Tox, 417 | public_key: *const u8, 418 | error: *mut TOX_ERR_FRIEND_BY_PUBLIC_KEY, 419 | ) -> u32; 420 | pub fn tox_friend_exists(tox: *const Tox, friend_number: u32) -> bool; 421 | pub fn tox_self_get_friend_list_size(tox: *const Tox) -> usize; 422 | pub fn tox_self_get_friend_list(tox: *const Tox, friend_list: *mut u32); 423 | } 424 | 425 | #[repr(u32)] 426 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 427 | pub enum TOX_ERR_FRIEND_GET_PUBLIC_KEY { 428 | TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK = 0, 429 | TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND = 1, 430 | } 431 | 432 | extern "C" { 433 | pub fn tox_friend_get_public_key( 434 | tox: *const Tox, 435 | friend_number: u32, 436 | public_key: *mut u8, 437 | error: *mut TOX_ERR_FRIEND_GET_PUBLIC_KEY, 438 | ) -> bool; 439 | } 440 | 441 | #[repr(u32)] 442 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 443 | pub enum TOX_ERR_FRIEND_GET_LAST_ONLINE { 444 | TOX_ERR_FRIEND_GET_LAST_ONLINE_OK = 0, 445 | TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND = 1, 446 | } 447 | 448 | extern "C" { 449 | pub fn tox_friend_get_last_online( 450 | tox: *const Tox, 451 | friend_number: u32, 452 | error: *mut TOX_ERR_FRIEND_GET_LAST_ONLINE, 453 | ) -> u64; 454 | } 455 | 456 | #[repr(u32)] 457 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 458 | pub enum TOX_ERR_FRIEND_QUERY { 459 | TOX_ERR_FRIEND_QUERY_OK = 0, 460 | TOX_ERR_FRIEND_QUERY_NULL = 1, 461 | TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND = 2, 462 | } 463 | 464 | extern "C" { 465 | pub fn tox_friend_get_name_size( 466 | tox: *const Tox, 467 | friend_number: u32, 468 | error: *mut TOX_ERR_FRIEND_QUERY, 469 | ) -> usize; 470 | pub fn tox_friend_get_name( 471 | tox: *const Tox, 472 | friend_number: u32, 473 | name: *mut u8, 474 | error: *mut TOX_ERR_FRIEND_QUERY, 475 | ) -> bool; 476 | } 477 | 478 | pub type tox_friend_name_cb = ::std::option::Option< 479 | unsafe extern "C" fn( 480 | tox: *mut Tox, 481 | friend_number: u32, 482 | name: *const u8, 483 | length: usize, 484 | user_data: *mut ::std::os::raw::c_void, 485 | ), 486 | >; 487 | 488 | extern "C" { 489 | pub fn tox_callback_friend_name(tox: *mut Tox, callback: tox_friend_name_cb); 490 | pub fn tox_friend_get_status_message_size( 491 | tox: *const Tox, 492 | friend_number: u32, 493 | error: *mut TOX_ERR_FRIEND_QUERY, 494 | ) -> usize; 495 | pub fn tox_friend_get_status_message( 496 | tox: *const Tox, 497 | friend_number: u32, 498 | status_message: *mut u8, 499 | error: *mut TOX_ERR_FRIEND_QUERY, 500 | ) -> bool; 501 | } 502 | 503 | pub type tox_friend_status_message_cb = ::std::option::Option< 504 | unsafe extern "C" fn( 505 | tox: *mut Tox, 506 | friend_number: u32, 507 | message: *const u8, 508 | length: usize, 509 | user_data: *mut ::std::os::raw::c_void, 510 | ), 511 | >; 512 | 513 | extern "C" { 514 | pub fn tox_callback_friend_status_message( 515 | tox: *mut Tox, 516 | callback: tox_friend_status_message_cb, 517 | ); 518 | pub fn tox_friend_get_status( 519 | tox: *const Tox, 520 | friend_number: u32, 521 | error: *mut TOX_ERR_FRIEND_QUERY, 522 | ) -> UserStatus; 523 | } 524 | 525 | pub type tox_friend_status_cb = ::std::option::Option< 526 | unsafe extern "C" fn( 527 | tox: *mut Tox, 528 | friend_number: u32, 529 | status: UserStatus, 530 | user_data: *mut ::std::os::raw::c_void, 531 | ), 532 | >; 533 | 534 | extern "C" { 535 | pub fn tox_callback_friend_status(tox: *mut Tox, callback: tox_friend_status_cb); 536 | pub fn tox_friend_get_connection_status( 537 | tox: *const Tox, 538 | friend_number: u32, 539 | error: *mut TOX_ERR_FRIEND_QUERY, 540 | ) -> Connection; 541 | } 542 | 543 | pub type tox_friend_connection_status_cb = ::std::option::Option< 544 | unsafe extern "C" fn( 545 | tox: *mut Tox, 546 | friend_number: u32, 547 | connection_status: Connection, 548 | user_data: *mut ::std::os::raw::c_void, 549 | ), 550 | >; 551 | 552 | extern "C" { 553 | pub fn tox_callback_friend_connection_status( 554 | tox: *mut Tox, 555 | callback: tox_friend_connection_status_cb, 556 | ); 557 | pub fn tox_friend_get_typing( 558 | tox: *const Tox, 559 | friend_number: u32, 560 | error: *mut TOX_ERR_FRIEND_QUERY, 561 | ) -> bool; 562 | } 563 | 564 | pub type tox_friend_typing_cb = ::std::option::Option< 565 | unsafe extern "C" fn( 566 | tox: *mut Tox, 567 | friend_number: u32, 568 | is_typing: bool, 569 | user_data: *mut ::std::os::raw::c_void, 570 | ), 571 | >; 572 | 573 | extern "C" { 574 | pub fn tox_callback_friend_typing(tox: *mut Tox, callback: tox_friend_typing_cb); 575 | } 576 | 577 | #[repr(u32)] 578 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 579 | pub enum TOX_ERR_SET_TYPING { 580 | TOX_ERR_SET_TYPING_OK = 0, 581 | TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND = 1, 582 | } 583 | 584 | extern "C" { 585 | pub fn tox_self_set_typing( 586 | tox: *mut Tox, 587 | friend_number: u32, 588 | typing: bool, 589 | error: *mut TOX_ERR_SET_TYPING, 590 | ) -> bool; 591 | } 592 | 593 | extern "C" { 594 | pub fn tox_friend_send_message( 595 | tox: *mut Tox, 596 | friend_number: u32, 597 | type_: MessageType, 598 | message: *const u8, 599 | length: usize, 600 | error: *mut FriendSendMessageError, 601 | ) -> u32; 602 | } 603 | 604 | pub type tox_friend_read_receipt_cb = ::std::option::Option< 605 | unsafe extern "C" fn( 606 | tox: *mut Tox, 607 | friend_number: u32, 608 | message_id: u32, 609 | user_data: *mut ::std::os::raw::c_void, 610 | ), 611 | >; 612 | 613 | extern "C" { 614 | pub fn tox_callback_friend_read_receipt(tox: *mut Tox, callback: tox_friend_read_receipt_cb); 615 | } 616 | 617 | pub type tox_friend_request_cb = ::std::option::Option< 618 | unsafe extern "C" fn( 619 | tox: *mut Tox, 620 | public_key: *const u8, 621 | message: *const u8, 622 | length: usize, 623 | user_data: *mut ::std::os::raw::c_void, 624 | ), 625 | >; 626 | 627 | extern "C" { 628 | pub fn tox_callback_friend_request(tox: *mut Tox, callback: tox_friend_request_cb); 629 | } 630 | 631 | pub type tox_friend_message_cb = ::std::option::Option< 632 | unsafe extern "C" fn( 633 | tox: *mut Tox, 634 | friend_number: u32, 635 | type_: MessageType, 636 | message: *const u8, 637 | length: usize, 638 | user_data: *mut ::std::os::raw::c_void, 639 | ), 640 | >; 641 | 642 | extern "C" { 643 | pub fn tox_callback_friend_message(tox: *mut Tox, callback: tox_friend_message_cb); 644 | pub fn tox_hash(hash: *mut u8, data: *const u8, length: usize) -> bool; 645 | } 646 | 647 | extern "C" { 648 | pub fn tox_file_control( 649 | tox: *mut Tox, 650 | friend_number: u32, 651 | file_number: u32, 652 | control: FileControl, 653 | error: *mut FileControlError, 654 | ) -> bool; 655 | } 656 | 657 | pub type tox_file_recv_control_cb = ::std::option::Option< 658 | unsafe extern "C" fn( 659 | tox: *mut Tox, 660 | friend_number: u32, 661 | file_number: u32, 662 | control: FileControl, 663 | user_data: *mut ::std::os::raw::c_void, 664 | ), 665 | >; 666 | 667 | extern "C" { 668 | pub fn tox_callback_file_recv_control(tox: *mut Tox, callback: tox_file_recv_control_cb); 669 | } 670 | 671 | extern "C" { 672 | pub fn tox_file_seek( 673 | tox: *mut Tox, 674 | friend_number: u32, 675 | file_number: u32, 676 | position: u64, 677 | error: *mut FileSeekError, 678 | ) -> bool; 679 | } 680 | 681 | extern "C" { 682 | pub fn tox_file_get_file_id( 683 | tox: *const Tox, 684 | friend_number: u32, 685 | file_number: u32, 686 | file_id: *mut u8, 687 | error: *mut FileGetError, 688 | ) -> bool; 689 | } 690 | 691 | extern "C" { 692 | pub fn tox_file_send( 693 | tox: *mut Tox, 694 | friend_number: u32, 695 | kind: u32, 696 | file_size: u64, 697 | file_id: *const u8, 698 | filename: *const u8, 699 | filename_length: usize, 700 | error: *mut FileSendError, 701 | ) -> u32; 702 | } 703 | 704 | extern "C" { 705 | pub fn tox_file_send_chunk( 706 | tox: *mut Tox, 707 | friend_number: u32, 708 | file_number: u32, 709 | position: u64, 710 | data: *const u8, 711 | length: usize, 712 | error: *mut FileSendChunkError, 713 | ) -> bool; 714 | } 715 | 716 | pub type tox_file_chunk_request_cb = ::std::option::Option< 717 | unsafe extern "C" fn( 718 | tox: *mut Tox, 719 | friend_number: u32, 720 | file_number: u32, 721 | position: u64, 722 | length: usize, 723 | user_data: *mut ::std::os::raw::c_void, 724 | ), 725 | >; 726 | 727 | extern "C" { 728 | pub fn tox_callback_file_chunk_request(tox: *mut Tox, callback: tox_file_chunk_request_cb); 729 | } 730 | 731 | pub type tox_file_recv_cb = ::std::option::Option< 732 | unsafe extern "C" fn( 733 | tox: *mut Tox, 734 | friend_number: u32, 735 | file_number: u32, 736 | kind: u32, 737 | file_size: u64, 738 | filename: *const u8, 739 | filename_length: usize, 740 | user_data: *mut ::std::os::raw::c_void, 741 | ), 742 | >; 743 | 744 | extern "C" { 745 | pub fn tox_callback_file_recv(tox: *mut Tox, callback: tox_file_recv_cb); 746 | } 747 | 748 | pub type tox_file_recv_chunk_cb = ::std::option::Option< 749 | unsafe extern "C" fn( 750 | tox: *mut Tox, 751 | friend_number: u32, 752 | file_number: u32, 753 | position: u64, 754 | data: *const u8, 755 | length: usize, 756 | user_data: *mut ::std::os::raw::c_void, 757 | ), 758 | >; 759 | 760 | extern "C" { 761 | pub fn tox_callback_file_recv_chunk(tox: *mut Tox, callback: tox_file_recv_chunk_cb); 762 | } 763 | 764 | pub type tox_conference_invite_cb = ::std::option::Option< 765 | unsafe extern "C" fn( 766 | tox: *mut Tox, 767 | friend_number: u32, 768 | type_: ConferenceType, 769 | cookie: *const u8, 770 | length: usize, 771 | user_data: *mut ::std::os::raw::c_void, 772 | ), 773 | >; 774 | 775 | extern "C" { 776 | pub fn tox_callback_conference_invite(tox: *mut Tox, callback: tox_conference_invite_cb); 777 | } 778 | 779 | pub type tox_conference_connected_cb = ::std::option::Option< 780 | unsafe extern "C" fn( 781 | tox: *mut Tox, 782 | conference_number: u32, 783 | user_data: *mut ::std::os::raw::c_void, 784 | ), 785 | >; 786 | 787 | extern "C" { 788 | pub fn tox_callback_conference_connected(tox: *mut Tox, callback: tox_conference_connected_cb); 789 | } 790 | 791 | pub type tox_conference_message_cb = ::std::option::Option< 792 | unsafe extern "C" fn( 793 | tox: *mut Tox, 794 | conference_number: u32, 795 | peer_number: u32, 796 | type_: MessageType, 797 | message: *const u8, 798 | length: usize, 799 | user_data: *mut ::std::os::raw::c_void, 800 | ), 801 | >; 802 | 803 | extern "C" { 804 | pub fn tox_callback_conference_message(tox: *mut Tox, callback: tox_conference_message_cb); 805 | } 806 | 807 | pub type tox_conference_title_cb = ::std::option::Option< 808 | unsafe extern "C" fn( 809 | tox: *mut Tox, 810 | conference_number: u32, 811 | peer_number: u32, 812 | title: *const u8, 813 | length: usize, 814 | user_data: *mut ::std::os::raw::c_void, 815 | ), 816 | >; 817 | 818 | extern "C" { 819 | pub fn tox_callback_conference_title(tox: *mut Tox, callback: tox_conference_title_cb); 820 | } 821 | 822 | pub type tox_conference_peer_name_cb = ::std::option::Option< 823 | unsafe extern "C" fn( 824 | tox: *mut Tox, 825 | conference_number: u32, 826 | peer_number: u32, 827 | name: *const u8, 828 | length: usize, 829 | user_data: *mut ::std::os::raw::c_void, 830 | ), 831 | >; 832 | 833 | extern "C" { 834 | pub fn tox_callback_conference_peer_name(tox: *mut Tox, callback: tox_conference_peer_name_cb); 835 | } 836 | 837 | pub type tox_conference_peer_list_changed_cb = ::std::option::Option< 838 | unsafe extern "C" fn( 839 | tox: *mut Tox, 840 | conference_number: u32, 841 | user_data: *mut ::std::os::raw::c_void, 842 | ), 843 | >; 844 | 845 | extern "C" { 846 | pub fn tox_callback_conference_peer_list_changed( 847 | tox: *mut Tox, 848 | callback: tox_conference_peer_list_changed_cb, 849 | ); 850 | } 851 | 852 | #[repr(u32)] 853 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 854 | pub enum TOX_ERR_CONFERENCE_NEW { 855 | TOX_ERR_CONFERENCE_NEW_OK = 0, 856 | TOX_ERR_CONFERENCE_NEW_INIT = 1, 857 | } 858 | 859 | #[repr(u32)] 860 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 861 | pub enum TOX_ERR_CONFERENCE_DELETE { 862 | TOX_ERR_CONFERENCE_DELETE_OK = 0, 863 | TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND = 1, 864 | } 865 | 866 | extern "C" { 867 | pub fn tox_conference_new(tox: *mut Tox, error: *mut TOX_ERR_CONFERENCE_NEW) -> u32; 868 | pub fn tox_conference_delete( 869 | tox: *mut Tox, 870 | conference_number: u32, 871 | error: *mut TOX_ERR_CONFERENCE_DELETE, 872 | ) -> bool; 873 | pub fn tox_conference_peer_count( 874 | tox: *const Tox, 875 | conference_number: u32, 876 | error: *mut ConferencePeerQueryError, 877 | ) -> u32; 878 | pub fn tox_conference_peer_get_name_size( 879 | tox: *const Tox, 880 | conference_number: u32, 881 | peer_number: u32, 882 | error: *mut ConferencePeerQueryError, 883 | ) -> usize; 884 | pub fn tox_conference_peer_get_name( 885 | tox: *const Tox, 886 | conference_number: u32, 887 | peer_number: u32, 888 | name: *mut u8, 889 | error: *mut ConferencePeerQueryError, 890 | ) -> bool; 891 | pub fn tox_conference_peer_get_public_key( 892 | tox: *const Tox, 893 | conference_number: u32, 894 | peer_number: u32, 895 | public_key: *mut u8, 896 | error: *mut ConferencePeerQueryError, 897 | ) -> bool; 898 | pub fn tox_conference_peer_number_is_ours( 899 | tox: *const Tox, 900 | conference_number: u32, 901 | peer_number: u32, 902 | error: *mut ConferencePeerQueryError, 903 | ) -> bool; 904 | pub fn tox_conference_offline_peer_count( 905 | tox: *const Tox, 906 | conference_number: u32, 907 | error: *mut ConferencePeerQueryError, 908 | ) -> u32; 909 | pub fn tox_conference_offline_peer_get_name_size( 910 | tox: *const Tox, 911 | conference_number: u32, 912 | offline_peer_number: u32, 913 | error: *mut ConferencePeerQueryError, 914 | ) -> usize; 915 | pub fn tox_conference_offline_peer_get_name( 916 | tox: *const Tox, 917 | conference_number: u32, 918 | offline_peer_number: u32, 919 | name: *mut u8, 920 | error: *mut ConferencePeerQueryError, 921 | ) -> bool; 922 | pub fn tox_conference_offline_peer_get_public_key( 923 | tox: *const Tox, 924 | conference_number: u32, 925 | offline_peer_number: u32, 926 | public_key: *mut u8, 927 | error: *mut ConferencePeerQueryError, 928 | ) -> bool; 929 | pub fn tox_conference_offline_peer_get_last_active( 930 | tox: *const Tox, 931 | conference_number: u32, 932 | offline_peer_number: u32, 933 | error: *mut ConferencePeerQueryError, 934 | ) -> u64; 935 | pub fn tox_conference_invite( 936 | tox: *mut Tox, 937 | friend_number: u32, 938 | conference_number: u32, 939 | error: *mut ConferenceInviteError, 940 | ) -> bool; 941 | pub fn tox_conference_join( 942 | tox: *mut Tox, 943 | friend_number: u32, 944 | cookie: *const u8, 945 | length: usize, 946 | error: *mut ConferenceJoinError, 947 | ) -> u32; 948 | pub fn tox_conference_send_message( 949 | tox: *mut Tox, 950 | conference_number: u32, 951 | type_: MessageType, 952 | message: *const u8, 953 | length: usize, 954 | error: *mut ConferenceSendError, 955 | ) -> bool; 956 | pub fn tox_conference_get_title_size( 957 | tox: *const Tox, 958 | conference_number: u32, 959 | error: *mut ConferenceTitleError, 960 | ) -> usize; 961 | pub fn tox_conference_get_title( 962 | tox: *const Tox, 963 | conference_number: u32, 964 | title: *mut u8, 965 | error: *mut ConferenceTitleError, 966 | ) -> bool; 967 | pub fn tox_conference_set_title( 968 | tox: *mut Tox, 969 | conference_number: u32, 970 | title: *const u8, 971 | length: usize, 972 | error: *mut ConferenceTitleError, 973 | ) -> bool; 974 | pub fn tox_conference_get_chatlist_size(tox: *const Tox) -> usize; 975 | pub fn tox_conference_get_chatlist(tox: *const Tox, chatlist: *mut u32); 976 | } 977 | 978 | #[repr(u32)] 979 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 980 | pub enum TOX_ERR_CONFERENCE_GET_TYPE { 981 | TOX_ERR_CONFERENCE_GET_TYPE_OK = 0, 982 | TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND = 1, 983 | } 984 | 985 | extern "C" { 986 | pub fn tox_conference_get_type( 987 | tox: *const Tox, 988 | conference_number: u32, 989 | error: *mut TOX_ERR_CONFERENCE_GET_TYPE, 990 | ) -> ConferenceType; 991 | pub fn tox_conference_get_id( 992 | tox: *const Tox, 993 | conference_number: u32, 994 | id: *mut u8 995 | ) -> bool; 996 | } 997 | 998 | #[repr(u32)] 999 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 1000 | pub enum TOX_ERR_CONFERENCE_BY_ID { 1001 | TOX_ERR_CONFERENCE_BY_ID_OK = 0, 1002 | TOX_ERR_CONFERENCE_BY_ID_NULL = 1, 1003 | TOX_ERR_CONFERENCE_BY_ID_NOT_FOUND = 2, 1004 | } 1005 | 1006 | extern "C" { 1007 | pub fn tox_conference_by_id( 1008 | tox: *const Tox, 1009 | id: *const u8, 1010 | error: *mut TOX_ERR_CONFERENCE_BY_ID, 1011 | ) -> u32; 1012 | pub fn tox_conference_get_uid(tox: *const Tox, conference_number: u32, uid: *mut u8) -> bool; 1013 | } 1014 | 1015 | #[repr(u32)] 1016 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 1017 | pub enum TOX_ERR_CONFERENCE_BY_UID { 1018 | TOX_ERR_CONFERENCE_BY_UID_OK = 0, 1019 | TOX_ERR_CONFERENCE_BY_UID_NULL = 1, 1020 | TOX_ERR_CONFERENCE_BY_UID_NOT_FOUND = 2, 1021 | } 1022 | 1023 | extern "C" { 1024 | pub fn tox_conference_by_uid( 1025 | tox: *const Tox, 1026 | uid: *const u8, 1027 | error: *mut TOX_ERR_CONFERENCE_BY_UID, 1028 | ) -> u32; 1029 | } 1030 | 1031 | extern "C" { 1032 | pub fn tox_friend_send_lossy_packet( 1033 | tox: *mut Tox, 1034 | friend_number: u32, 1035 | data: *const u8, 1036 | length: usize, 1037 | error: *mut FriendCustomPacketError, 1038 | ) -> bool; 1039 | pub fn tox_friend_send_lossless_packet( 1040 | tox: *mut Tox, 1041 | friend_number: u32, 1042 | data: *const u8, 1043 | length: usize, 1044 | error: *mut FriendCustomPacketError, 1045 | ) -> bool; 1046 | } 1047 | 1048 | pub type tox_friend_lossy_packet_cb = ::std::option::Option< 1049 | unsafe extern "C" fn( 1050 | tox: *mut Tox, 1051 | friend_number: u32, 1052 | data: *const u8, 1053 | length: usize, 1054 | user_data: *mut ::std::os::raw::c_void, 1055 | ), 1056 | >; 1057 | 1058 | extern "C" { 1059 | pub fn tox_callback_friend_lossy_packet(tox: *mut Tox, callback: tox_friend_lossy_packet_cb); 1060 | } 1061 | 1062 | pub type tox_friend_lossless_packet_cb = ::std::option::Option< 1063 | unsafe extern "C" fn( 1064 | tox: *mut Tox, 1065 | friend_number: u32, 1066 | data: *const u8, 1067 | length: usize, 1068 | user_data: *mut ::std::os::raw::c_void, 1069 | ), 1070 | >; 1071 | 1072 | extern "C" { 1073 | pub fn tox_callback_friend_lossless_packet( 1074 | tox: *mut Tox, 1075 | callback: tox_friend_lossless_packet_cb, 1076 | ); 1077 | } 1078 | 1079 | extern "C" { 1080 | pub fn tox_self_get_dht_id(tox: *const Tox, dht_id: *mut u8); 1081 | } 1082 | 1083 | #[repr(u32)] 1084 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 1085 | pub enum TOX_ERR_GET_PORT { 1086 | TOX_ERR_GET_PORT_OK = 0, 1087 | TOX_ERR_GET_PORT_NOT_BOUND = 1, 1088 | } 1089 | 1090 | extern "C" { 1091 | pub fn tox_self_get_udp_port(tox: *const Tox, error: *mut TOX_ERR_GET_PORT) -> u16; 1092 | } 1093 | 1094 | extern "C" { 1095 | pub fn tox_self_get_tcp_port(tox: *const Tox, error: *mut TOX_ERR_GET_PORT) -> u16; 1096 | } 1097 | -------------------------------------------------------------------------------- /src/encryptsave.rs: -------------------------------------------------------------------------------- 1 | mod ll; 2 | pub mod errors; 3 | 4 | 5 | /// if $fun is true return Ok($res), or else Err($err). 6 | /// return Result<$res, $err>. 7 | macro_rules! tox_res { 8 | ( $res:ident <- $rexpr:expr, $err:ident, $fun:expr ) => { 9 | unsafe { 10 | let mut $res = $rexpr; 11 | let mut $err = ::std::mem::uninitialized(); 12 | if $fun { 13 | Ok($res) 14 | } else { 15 | Err($err) 16 | } 17 | } 18 | }; 19 | ( $res:ident, $err:ident, $fun:expr ) => { 20 | tox_res!( 21 | $res <- ::std::mem::uninitialized(), 22 | $err, 23 | $fun 24 | ) 25 | } 26 | } 27 | 28 | pub const PASS_ENCRYPTION_EXTRA_LENGTH: usize = 80; 29 | 30 | /// Determine whether the data has been encrypted. 31 | pub fn is_encrypted(data: &[u8]) -> bool { 32 | unsafe { ll::tox_is_data_encrypted(data.as_ptr()) } 33 | } 34 | 35 | #[repr(C)] 36 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 37 | pub struct ToxPassKey { 38 | passkey: ll::Tox_PassKey 39 | } 40 | 41 | /// ToxPassKey, Symmetric encryption local files. 42 | /// 43 | /// # Examples 44 | /// 45 | /// ``` 46 | /// use rstox::encryptsave::ToxPassKey; 47 | /// 48 | /// let passphrase = b"rstox is good"; 49 | /// let data = b"rstox is a Rust wrapper for toxcore."; 50 | /// 51 | /// let ciphertext = ToxPassKey::new(passphrase).ok().unwrap() 52 | /// .encrypt(data).ok().unwrap(); 53 | /// let plaintext = ToxPassKey::from(passphrase, &ciphertext).ok().unwrap() 54 | /// .decrypt(&ciphertext).ok().unwrap(); 55 | /// 56 | /// assert_eq!( 57 | /// String::from_utf8_lossy(data), 58 | /// String::from_utf8_lossy(&plaintext) 59 | /// ); 60 | /// ``` 61 | #[allow(unused_mut)] 62 | impl ToxPassKey { 63 | /// Generate ToxPassKey, using a random salt. 64 | pub fn new(passphrase: &[u8]) -> Result { 65 | let passkey = tox_res!( 66 | passkey, 67 | err, 68 | ll::tox_derive_key_from_pass( 69 | passphrase.as_ptr(), 70 | passphrase.len(), 71 | &mut passkey, 72 | &mut err 73 | ) 74 | )?; 75 | 76 | Ok(ToxPassKey { passkey: passkey }) 77 | } 78 | 79 | /// Generate Tox PassKey, read salt from the data. 80 | pub fn from(passphrase: &[u8], data: &[u8]) -> Result { 81 | ToxPassKey::with(passphrase, unsafe { 82 | let mut salt = Vec::with_capacity(ll::PASS_SALT_LENGTH); 83 | salt.set_len(ll::PASS_SALT_LENGTH); 84 | ll::tox_get_salt(data.as_ptr(), salt.as_mut_ptr()); 85 | salt 86 | }) 87 | } 88 | 89 | /// Generate ToxPassKey, using the specified salt. 90 | pub fn with(passphrase: &[u8], salt: Vec) -> Result { 91 | let passkey = tox_res!( 92 | passkey, 93 | err, 94 | ll::tox_derive_key_with_salt( 95 | passphrase.as_ptr(), 96 | passphrase.len(), 97 | salt.as_ptr(), 98 | &mut passkey, 99 | &mut err 100 | ) 101 | )?; 102 | 103 | Ok(ToxPassKey { passkey: passkey }) 104 | } 105 | 106 | /// encryption 107 | pub fn encrypt(&self, data: &[u8]) -> Result, errors::EncryptionError> { 108 | tox_res!( 109 | out <- { 110 | let len = data.len() + PASS_ENCRYPTION_EXTRA_LENGTH; 111 | let mut out = Vec::with_capacity(len); 112 | out.set_len(len); 113 | out 114 | }, 115 | err, 116 | ll::tox_pass_key_encrypt( 117 | data.as_ptr(), 118 | data.len(), 119 | &self.passkey, 120 | out.as_mut_ptr(), 121 | &mut err 122 | ) 123 | ) 124 | } 125 | 126 | /// decryption 127 | pub fn decrypt(&self, data: &[u8]) -> Result, errors::DecryptionError> { 128 | tox_res!( 129 | out <- { 130 | let len = data.len() - PASS_ENCRYPTION_EXTRA_LENGTH; 131 | let mut out = Vec::with_capacity(len); 132 | out.set_len(len); 133 | out 134 | }, 135 | err, 136 | ll::tox_pass_key_decrypt( 137 | data.as_ptr(), 138 | data.len(), 139 | &self.passkey, 140 | out.as_mut_ptr(), 141 | &mut err 142 | ) 143 | ) 144 | } 145 | } 146 | 147 | /// use passphrase encryption 148 | pub fn pass_encrypt(passphrase: &[u8], data: &[u8]) -> Result, errors::EncryptionError> { 149 | tox_res!( 150 | out <- { 151 | let len = data.len() + PASS_ENCRYPTION_EXTRA_LENGTH; 152 | let mut out = Vec::with_capacity(len); 153 | out.set_len(len); 154 | out 155 | }, 156 | err, 157 | ll::tox_pass_encrypt( 158 | data.as_ptr(), 159 | data.len(), 160 | passphrase.as_ptr(), 161 | passphrase.len(), 162 | out.as_mut_ptr(), 163 | &mut err 164 | ) 165 | ) 166 | } 167 | 168 | /// use passphrase decryption 169 | pub fn pass_decrypt(passphrase: &[u8], data: &[u8]) -> Result, errors::DecryptionError> { 170 | tox_res!( 171 | out <- { 172 | let len = data.len() - PASS_ENCRYPTION_EXTRA_LENGTH; 173 | let mut out = Vec::with_capacity(len); 174 | out.set_len(len); 175 | out 176 | }, 177 | err, 178 | ll::tox_pass_decrypt( 179 | data.as_ptr(), 180 | data.len(), 181 | passphrase.as_ptr(), 182 | passphrase.len(), 183 | out.as_mut_ptr(), 184 | &mut err 185 | ) 186 | ) 187 | } 188 | -------------------------------------------------------------------------------- /src/encryptsave/errors.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 3 | pub enum KeyDerivationError { 4 | #[doc(hidden)] NoError = 0, 5 | NullError = 1, 6 | Failed 7 | } 8 | 9 | #[repr(C)] 10 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 11 | pub enum EncryptionError { 12 | #[doc(hidden)] NoError = 0, 13 | NullError = 1, 14 | KeyDerivationFailed, 15 | Failed 16 | } 17 | 18 | #[repr(C)] 19 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 20 | pub enum DecryptionError { 21 | #[doc(hidden)] NoError = 0, 22 | NullError = 1, 23 | InvalidLength, 24 | BadFormat, 25 | KeyDerivationFailed, 26 | Failed 27 | } 28 | -------------------------------------------------------------------------------- /src/encryptsave/ll.rs: -------------------------------------------------------------------------------- 1 | use crate::encryptsave::errors; 2 | 3 | 4 | pub const PASS_SALT_LENGTH: usize = 32; 5 | pub const PASS_KEY_LENGTH: usize = 32; 6 | 7 | #[repr(C)] 8 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 9 | pub struct Tox_PassKey { 10 | salt: [u8; PASS_SALT_LENGTH], 11 | key: [u8; PASS_KEY_LENGTH] 12 | } 13 | 14 | #[link(name = "toxencryptsave")] 15 | extern "C" { 16 | pub fn tox_get_salt(data: *const u8, salt: *mut u8) -> bool; 17 | pub fn tox_derive_key_from_pass( 18 | passphrase: *const u8, 19 | pplength: usize, 20 | out_key: *mut Tox_PassKey, 21 | error: *mut errors::KeyDerivationError 22 | ) -> bool; 23 | pub fn tox_derive_key_with_salt( 24 | passphrase: *const u8, 25 | pplength: usize, 26 | salt: *const u8, 27 | out_key: *mut Tox_PassKey, 28 | error: *mut errors::KeyDerivationError 29 | ) -> bool; 30 | pub fn tox_pass_key_encrypt( 31 | data: *const u8, 32 | data_len: usize, 33 | key: *const Tox_PassKey, 34 | out: *mut u8, 35 | error: *mut errors::EncryptionError 36 | ) -> bool; 37 | pub fn tox_pass_encrypt( 38 | data: *const u8, 39 | data_len: usize, 40 | passphrase: *const u8, 41 | pplength: usize, 42 | out: *mut u8, 43 | error: *mut errors::EncryptionError 44 | ) -> bool; 45 | pub fn tox_pass_key_decrypt( 46 | data: *const u8, 47 | length: usize, 48 | key: *const Tox_PassKey, 49 | out: *mut u8, 50 | error: *mut errors::DecryptionError 51 | ) -> bool; 52 | pub fn tox_pass_decrypt( 53 | data: *const u8, 54 | length: usize, 55 | passphrase: *const u8, 56 | pplength: usize, 57 | out: *mut u8, 58 | error: *mut errors::DecryptionError 59 | ) -> bool; 60 | pub fn tox_is_data_encrypted(data: *const u8) -> bool; 61 | } 62 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | extern crate libc; 5 | 6 | pub mod core; 7 | // pub mod av; 8 | // pub mod encryptsave; 9 | --------------------------------------------------------------------------------