├── .gitmodules ├── LICENSE ├── README.md ├── circle.yml ├── tox_tcp_relay ├── avatar.png ├── loop_services.sh ├── tox-bootstrapd.conf ├── tox_tcp_relay.c └── update_from_ci.sh └── toxstatus.png /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "c-toxcore"] 2 | path = c-toxcore 3 | url = https://github.com/TokTok/c-toxcore 4 | [submodule "libsodium"] 5 | path = libsodium 6 | url = https://github.com/jedisct1/libsodium 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tox TCP-Relay Node 2 | 3 | run a TCP-Relay/Bootstrap Node for Tox 4 | 5 | ### Build Status 6 | 7 | **CircleCI:** [![CircleCI](https://circleci.com/gh/zoff99/ToxTCP-RelayNode/tree/master.png?style=badge)](https://circleci.com/gh/zoff99/ToxTCP-RelayNode) 8 | 9 | ### Installation (Linux) 10 | ``` 11 | git clone https://github.com/zoff99/ToxTCP-RelayNode 12 | cd ToxTCP-RelayNode 13 | cd tox_tcp_relay 14 | chmod a+rwx *.sh tox-bootstrapd* 15 | ./update_from_ci.sh 16 | chmod a+rwx *.sh tox-bootstrapd* 17 | ``` 18 | 19 | ### Operation (Linux) 20 | ``` 21 | cd ToxTCP-RelayNode 22 | cd tox_tcp_relay 23 | ./loop_services.sh & 24 | sleep 3 25 | cat tox-bootstrapd.log | grep 'Public Key:' # !to see the publickey! 26 | ``` 27 | 28 | 29 | 30 | test if your node is working on this webpage: 31 | https://nodes.tox.chat/test 32 | 33 | ``` 34 | Public key --> the Public key from the logfile (see above) 35 | IP:Port --> the public external IP address of your Server, the Port=33447 (for TCP) and Port=33446 (for UDP) 36 | UDP / TCP --> select the Protocol you want to Test (both should work) 37 | ``` 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | timezone: 3 | Europe/Berlin 4 | environment: 5 | MAKEFLAGS: "" 6 | ## ----------- RASPI cross compile ---------------- 7 | RASPI_PATH: "/home/ubuntu/cc/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin:$PATH" 8 | RASPI_SYSROOT_: "/home/ubuntu/cc/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot" 9 | RASPI_TOOL_PREFIX: arm-linux-gnueabihf 10 | RASPI_INSTALL_DEST: "/home/ubuntu/installdest/" 11 | RASPI_TARGET_: arm-linux-gnueabi 12 | RASPI_HOST_: arm-linux-gnueabi 13 | RASPI_CXX: $RASPI_TOOL_PREFIX-g++ 14 | RASPI_AR: $RASPI_TOOL_PREFIX-ar 15 | RASPI_RANLIB: $RASPI_TOOL_PREFIX-ranlib 16 | RASPI_CC: $RASPI_TOOL_PREFIX-gcc 17 | RASPI_LD: $RASPI_TOOL_PREFIX-ld 18 | RASPI_PKG_CONFIG_PATH: "/home/ubuntu/cc/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot/usr/lib/pkgconfig" 19 | RASPI_s_: "/home/ubuntu/src/" 20 | RASPI_PKGSDIR: "/home/ubuntu/pkgs/" 21 | ## ----------- RASPI cross compile ---------------- 22 | # --------------------------------------------------- 23 | # v0.1.10 mtweaks2 d4c11ecbc45faf0e66fbe8c4df59b8087d22f409 24 | # v0.1.10 mobtweaks f73b345c21fae0e0e56fae86dc82f63188a00aca 25 | # c-toxcore v0.1.9 a429ef4a28a5e5e0ad010efffb76d2abc3ada0af 26 | # c-toxcore v0.1.8 f6db9333e2d1262e7ba3846563c30f63c98ffa38 27 | # c-toxcore v0.1.7 48c86e942d487a8856cbd25797b320bfb1879ddc 28 | # c-toxcore v0.1.6 895de7ef26e7617769f2271345e414545c2581f8 29 | # c-toxcore v0.1.5 995578f1038842288c1ff552fd796ab2377db6e1 30 | # c-toxcore v0.1.4 27a97a8280813ec05a5209811c40ab23203bb292 31 | # c-toxcore v0.1.3 fdb46f6cf216a866d29402ae991be9c43282dde6 32 | # c-toxcore v0.1.2 a096c71db867ac83fc3e01e0fbe98573d20f9286 33 | # --------------------------------------------------- 34 | # c-toxcore v0.1.9 35 | CTOXCORE_VERSION_HASH: "zoff99/_0.1.10_2017_video_fix_07a" 36 | # c-toxcore repo url 37 | # CTOXCORE_URL: "https://github.com/TokTok/c-toxcore" 38 | CTOXCORE_URL: "https://github.com/zoff99/c-toxcore" 39 | LIBSODIUM_VERSION: "tags/1.0.13" 40 | LIBSODIUM_BRANCH: "1.0.13" 41 | RASPBERRRY_TOOLS_HASH: d820ab9c21969013b4e56c7e9cba25518afcdd44 42 | 43 | dependencies: 44 | pre: 45 | # ----------------------------------- 46 | - sudo /etc/init.d/mysql stop ; exit 0 47 | - sudo /etc/init.d/postgresql stop ; exit 0 48 | # ----------------------------------- 49 | - sudo apt-get update 50 | - sudo apt-get install cmake 51 | - aptitude search 4l|grep -i convert ; exit 0 52 | - aptitude search 4l|grep -i v4l ; exit 0 53 | - sudo apt-get install build-essential libtool autotools-dev automake checkinstall check git yasm libv4lconvert0 libv4l-dev 54 | - sudo apt-get install libopus-dev libvpx-dev pkg-config 55 | - sudo apt-get install libasound2-dev 56 | - sudo apt-get install linux-generic 57 | - sudo apt-get install libjpeg-dev 58 | - sudo apt-get install libpulse-dev 59 | - sudo apt-get install libconfig-dev 60 | 61 | - sudo bash -c "echo '::1 localhost ipv6-localhost ipv6-loopback' >> /etc/hosts" # ipv6 localhost entry 62 | 63 | - gcc --version ; exit 0 64 | - clang --version ; exit 0 65 | 66 | ### submodules ---------------- 67 | - git submodule add --force https://github.com/TokTok/c-toxcore c-toxcore ; echo ok 68 | - git submodule add --force https://github.com/jedisct1/libsodium libsodium ; echo ok 69 | - git submodule init ; git submodule update ; echo ok 70 | # -- sometimes submodule can't find commit hash, whatever ------ 71 | - rm -Rf c-toxcore ; git clone "$CTOXCORE_URL" 72 | # -- sometimes submodule can't find commit hash, whatever ------ 73 | - cd c-toxcore/ ; git checkout $CTOXCORE_VERSION_HASH 74 | - cd libsodium/ ; git checkout $LIBSODIUM_VERSION 75 | ### submodules ---------------- 76 | 77 | ### ------- compile and install libsodium ------- 78 | - cd libsodium/ ; ./autogen.sh 79 | - cd libsodium/ ; ./configure && make check 80 | - cd libsodium/ ; sudo bash -c "printf 'y\naa\n\n' | checkinstall --install --pkgname libsodium --pkgversion 1.0.0 --nodoc --deldesc=no --pkglicense='GPL2'" 81 | - cd libsodium/ ; sudo ldconfig 82 | - cd libsodium ; sudo ldconfig -v 2>/dev/null | grep sodium 83 | ## --- now again to save the artefact --- 84 | - cd libsodium ; export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; rm -Rf "$INSTALL_DEST" 85 | - cd libsodium ; export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; mkdir -p "$INSTALL_DEST"/usr ; ./configure --prefix="$INSTALL_DEST"/usr 86 | - cd libsodium ; export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; make install ; ls -alR "$INSTALL_DEST"/usr 87 | - mkdir -p $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries 88 | - export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; cd "$INSTALL_DEST" ; tar -czvf $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/pkg_libsodium.tar.gz * 89 | ## --- now again to save the artefact --- 90 | ### ------- compile and install libsodium ------- 91 | 92 | ### ------------ compile and install c-toxcore ------------ 93 | - cd c-toxcore ; cmake -DWARNINGS=OFF . 94 | - cd c-toxcore ; make 95 | - cd c-toxcore ; sudo make install 96 | - cd c-toxcore ; sudo ldconfig -v 2>/dev/null | grep toxcore 97 | ## --- now again to save the artefact --- 98 | - cd c-toxcore ; export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; rm -Rf "$INSTALL_DEST" 99 | - cd c-toxcore ; export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; mkdir -p "$INSTALL_DEST"/usr ; autoreconf -fi ; ./configure --enable-logging --disable-soname-versions --prefix="$INSTALL_DEST"/usr 100 | - cd c-toxcore ; export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; make install ; ls -alR "$INSTALL_DEST"/usr 101 | - mkdir -p $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries 102 | - cp -av c-toxcore/other/bootstrap_daemon/tox-bootstrapd.conf $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/ 103 | - cp -av c-toxcore/tox-bootstrapd $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/ 104 | - cd c-toxcore/ ; /usr/bin/cc -std=c99 -pedantic -isystem /usr/local/include -isystem /usr/include/opus -pthread 105 | CMakeFiles/tox-bootstrapd.dir/other/bootstrap_daemon/src/command_line_arguments.c.o 106 | CMakeFiles/tox-bootstrapd.dir/other/bootstrap_daemon/src/config.c.o 107 | CMakeFiles/tox-bootstrapd.dir/other/bootstrap_daemon/src/log.c.o 108 | CMakeFiles/tox-bootstrapd.dir/other/bootstrap_daemon/src/log_backend_stdout.c.o 109 | CMakeFiles/tox-bootstrapd.dir/other/bootstrap_daemon/src/log_backend_syslog.c.o 110 | CMakeFiles/tox-bootstrapd.dir/other/bootstrap_daemon/src/tox-bootstrapd.c.o 111 | CMakeFiles/tox-bootstrapd.dir/other/bootstrap_node_packets.c.o 112 | -o tox-bootstrapd_static 113 | -L/usr/local/lib -rdynamic -static --static libtoxnetcrypto.a 114 | -lconfig libtoxdht.a libtoxnetwork.a 115 | libtoxcrypto.a -lsodium -lpthread -lrt 116 | -Wl,-rpath,/home/ubuntu/ToxTCP-RelayNode/c-toxcore:/usr/local/lib 117 | - cd c-toxcore/ ; cp -av tox-bootstrapd_static $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/ 118 | - cd c-toxcore/ ; ldd tox-bootstrapd_static ; exit 0 119 | - export INSTALL_DEST=/home/ubuntu/installdest_linux/ ; cd "$INSTALL_DEST" ; tar -czvf $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/pkg_c-toxcore.tar.gz * 120 | ## --- now again to save the artefact --- 121 | ### ------------ run tests 122 | # - cd c-toxcore ; make test ARGS="-V" ; ex1=$? ; if [ $ex1 -ne 0 ]; then sleep 60; make test ARGS="-V" ; exit $? ; fi 123 | ### ------------ compile and install c-toxcore ------------ 124 | 125 | 126 | 127 | ## ----------- RASPI cross compile ---------------- 128 | ## ----------- set architecture ------------------- 129 | ## ----------- set architecture ------------------- 130 | - ARCH="RASPI";printf '#! /bin/bash\nexport CUR_ARCH_="'"$ARCH"'"\n' > ~/glo 131 | - chmod a+rx ~/glo 132 | - cat ~/glo 133 | ## ----------- set architecture ------------------- 134 | ## ----------- set architecture ------------------- 135 | 136 | - mkdir ~/cc/ 137 | - cd ~/cc ; git clone https://github.com/raspberrypi/tools 138 | - cd ~/cc/tools/ ; git checkout $RASPBERRRY_TOOLS_HASH 139 | 140 | - . ~/glo;a=${CUR_ARCH_}_PKG_CONFIG_PATH;mkdir -p "${!a}" 141 | - . ~/glo;a=${CUR_ARCH_}_PKGSDIR;mkdir -p "${!a}" 142 | - . ~/glo;a=${CUR_ARCH_}_SYSROOT_;ls -al "${!a}" 143 | - . ~/glo;a=${CUR_ARCH_}_s_;mkdir -p "${!a}" 144 | - . ~/glo;a=${CUR_ARCH_}_PKGSDIR;mkdir -p "${!a}" 145 | 146 | - . ~/glo;echo 'export PKGSDIR="$'"${CUR_ARCH_}"'_PKGSDIR";export INSTALL_DEST="$'"${CUR_ARCH_}"'_INSTALL_DEST";export PKG_CONFIG_PATH="$'"${CUR_ARCH_}"'_PKG_CONFIG_PATH";export PATH="$'"${CUR_ARCH_}"'_PATH";export CC="$'"${CUR_ARCH_}"'_CC";export CXX="$'"${CUR_ARCH_}"'_CXX";export AR="$'"${CUR_ARCH_}"'_AR";export RANLIB="$'"${CUR_ARCH_}"'_RANLIB";export _s_="$'"${CUR_ARCH_}"'_s_";export _SYSROOT_="$'"${CUR_ARCH_}"'_SYSROOT_";export _HOST_="$'"${CUR_ARCH_}"'_HOST_";export _TARGET_="$'"${CUR_ARCH_}"'_TARGET_";export _TOOL_PREFIX="$'"${CUR_ARCH_}"'_TOOL_PREFIX";export CUR_ARCH_="'"${CUR_ARCH_}"'";export LD="$'"${CUR_ARCH_}"'_LD"' > ~/pp 147 | - chmod u+x ~/pp 148 | - cat ~/pp 149 | 150 | - . ~/glo;printf '#! /bin/bash\n. ~/pp;rm -Rf ~/build/\nmkdir -p ~/build/\narg1_="$1";shift;cd ~/build/;$'"${CUR_ARCH_}"'_s_/"$arg1_"/configure $* && make && make install\n' > ~/do_compile.sh 151 | - chmod a+rx ~/do_compile.sh 152 | - cat ~/do_compile.sh 153 | 154 | - . ~/glo;printf '#! /bin/bash\n. ~/pp;rm -Rf ~/build/\nmkdir -p ~/build/\nrm -Rf "$INSTALL_DEST"\narg1_="$1";shift;cd ~/build/;$_s_/"$arg1_"/configure $* && make && make install && cd "$INSTALL_DEST" && tar -czvf "$PKGSDIR""/"pkg_"$arg1_".tar.gz * && rm -Rf "$INSTALL_DEST" \n' > ~/do_package.sh 155 | - chmod a+rx ~/do_package.sh 156 | - cat ~/do_package.sh 157 | 158 | 159 | - . ~/pp;cd $_s_;git clone --depth=1 --branch=v1.3.0 https://github.com/yasm/yasm.git 160 | - . ~/pp;cd $_s_/yasm/;autoreconf -fi 161 | - . ~/pp;~/do_compile.sh "yasm" --prefix="$_SYSROOT_"/usr --disable-shared --disable-soname-versions --with-sysroot="$_SYSROOT_" --host="$_HOST_" --target="$_TARGET_" 162 | 163 | - . ~/pp;cd $_s_;git clone --depth=1 --branch=v1.6.1 https://github.com/webmproject/libvpx.git 164 | - . ~/pp;export CROSS="arm-linux-gnueabihf-" ; ~/do_compile.sh "libvpx" --prefix="$_SYSROOT_"/usr --disable-examples --disable-unit-tests --target=generic-gnu --extra-cflags="--sysroot=$_SYSROOT_" 165 | - . ~/pp;export CROSS="arm-linux-gnueabihf-" ; ~/do_package.sh "libvpx" --prefix="$INSTALL_DEST"/usr --disable-examples --disable-unit-tests --target=generic-gnu --extra-cflags="--sysroot=$_SYSROOT_" 166 | 167 | - . ~/pp;cd $_s_;git clone --depth=1 --branch=v1.2.1 https://github.com/xiph/opus.git 168 | - . ~/pp;cd $_s_/opus/;autoreconf -fi 169 | - . ~/pp;~/do_compile.sh "opus" --prefix="$_SYSROOT_"/usr --disable-shared --disable-soname-versions --target="$_TOOL_PREFIX" --with-sysroot="$_SYSROOT_" --host="$_TOOL_PREFIX" 170 | - . ~/pp;~/do_package.sh "opus" --prefix="$INSTALL_DEST"/usr --disable-shared --disable-soname-versions --target="$_TOOL_PREFIX" --with-sysroot="$_SYSROOT_" --host="$_TOOL_PREFIX" 171 | 172 | - . ~/pp;cd $_s_;git clone --depth=1 --branch=$LIBSODIUM_BRANCH https://github.com/jedisct1/libsodium.git 173 | - . ~/pp;cd $_s_/libsodium/;autoreconf -fi 174 | - . ~/pp;~/do_compile.sh "libsodium" --prefix="$_SYSROOT_"/usr --disable-shared --disable-soname-versions --target="$_TOOL_PREFIX" --with-sysroot="$_SYSROOT_" --host="$_TOOL_PREFIX" --enable-minimal --disable-pie 175 | - . ~/pp;~/do_package.sh "libsodium" --prefix="$INSTALL_DEST"/usr --disable-shared --disable-soname-versions --target="$_TOOL_PREFIX" --with-sysroot="$_SYSROOT_" --host="$_TOOL_PREFIX" --enable-minimal --disable-pie 176 | 177 | # install raspi binary pkgs ------------------------- 178 | - wget 'https://github.com/zoff99/raspi_cross_compile/raw/master/bin_packages/libv4l-dev.tgz' -O ~/pkg2.tgz 179 | - . ~/pp;cd "$_SYSROOT_" ; tar -xzvf ~/pkg2.tgz 180 | - wget 'https://github.com/zoff99/raspi_cross_compile/raw/master/bin_packages/libv4lconvert0.tgz' -O ~/pkg3.tgz 181 | - . ~/pp;cd "$_SYSROOT_" ; tar -xzvf ~/pkg3.tgz 182 | - wget 'https://github.com/zoff99/raspi_cross_compile/raw/master/bin_packages/libjpeg62-turbo.tgz' -O ~/pkg4.tgz 183 | - . ~/pp;cd "$_SYSROOT_" ; tar -xzvf ~/pkg4.tgz 184 | - wget 'https://github.com/zoff99/raspi_cross_compile/raw/master/bin_packages/libjpeg62-turbo-dev.tgz' -O ~/pkg1.tgz 185 | - . ~/pp;cd "$_SYSROOT_" ; tar -xzvf ~/pkg1.tgz 186 | - wget 'https://github.com/zoff99/raspi_cross_compile/raw/master/bin_packages/libconfig-dev.tgz' -O ~/pkg1.tgz 187 | - . ~/pp;cd "$_SYSROOT_" ; tar -xzvf ~/pkg1.tgz 188 | # install raspi binary pkgs ------------------------- 189 | 190 | - . ~/pp;cd $_s_;git clone "$CTOXCORE_URL" 191 | - . ~/pp;cd $_s_/c-toxcore/;git checkout $CTOXCORE_VERSION_HASH 192 | - . ~/pp;cd $_s_/c-toxcore/;autoreconf -fi 193 | - . ~/pp;~/do_compile.sh "c-toxcore" --prefix="$_SYSROOT_"/usr --enable-logging --disable-soname-versions --host="$_TOOL_PREFIX" --with-sysroot="$_SYSROOT_" --disable-testing --disable-rt 194 | - . ~/pp;~/do_package.sh "c-toxcore" --prefix="$INSTALL_DEST"/usr --enable-logging --disable-soname-versions --host="$_TOOL_PREFIX" --with-sysroot="$_SYSROOT_" --disable-testing --disable-rt 195 | 196 | # --- toxbootstrapd for RASPI ---- 197 | - . ~/pp;~/do_compile.sh "c-toxcore" --prefix="$_SYSROOT_"/usr --enable-logging --enable-daemon --disable-soname-versions --host="$_TOOL_PREFIX" --with-sysroot="$_SYSROOT_" --disable-testing --disable-rt ; exit 0 # this will fail 198 | - . ~/pp; cd /home/ubuntu/build/build ; export V=3 ; /bin/bash ../libtool --tag=CC --mode=link $CC -std=gnu99 -I/home/ubuntu/src//c-toxcore/other/bootstrap_daemon -I"$_SYSROOT_"/usr/include -g -O2 -o tox-bootstrapd ../other/bootstrap_daemon/src/tox_bootstrapd-command_line_arguments.o ../other/bootstrap_daemon/src/tox_bootstrapd-config.o ../other/bootstrap_daemon/src/tox_bootstrapd-log.o ../other/bootstrap_daemon/src/tox_bootstrapd-tox-bootstrapd.o ../other/tox_bootstrapd-bootstrap_node_packets.o libtoxcore.la -L"$_SYSROOT_"/usr/lib -L"$_SYSROOT_"/usr/lib/arm-linux-gnueabihf -lconfig -lsodium ; exit 0 199 | - ls -al /home/ubuntu/build/build/.libs/tox-bootstrapd ; exit 0 200 | 201 | # -- move some lib files for ldd to correctly show output -- 202 | - cd ../ ; cd /home/ubuntu/build/build ; . ~/pp ; sed -i -e 's#ld_library_path="/lib:/usr/lib"#ld_library_path="/lib:/usr/lib:/lib/arm-linux-gnueabihf"#' /home/ubuntu/cc/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-ldd ; exit 0 203 | - cd ../ ; cd /home/ubuntu/build/build ; . ~/pp ; export CT_XLDD_VERBOSE=""; arm-linux-gnueabihf-ldd -s --root $_SYSROOT_ /home/ubuntu/build/build/.libs/tox-bootstrapd ; exit 0 204 | # -- move some lib files for ldd to correctly show output -- 205 | 206 | 207 | 208 | - file /home/ubuntu/build/build/.libs/tox-bootstrapd ; exit 0 209 | # --- toxbootstrapd for RASPI ---- 210 | 211 | - . ~/pp;mkdir -p $CIRCLE_ARTIFACTS/"${CUR_ARCH_}"/ 212 | - . ~/pp;cp -av "$PKGSDIR"/* $CIRCLE_ARTIFACTS/"${CUR_ARCH_}"/ 213 | 214 | # --- toxbootstrapd for RASPI ---- 215 | - . ~/pp;cp -av /home/ubuntu/build/build/.libs/tox-bootstrapd $CIRCLE_ARTIFACTS/"${CUR_ARCH_}"/ ; exit 0 216 | # --- toxbootstrapd for RASPI ---- 217 | 218 | - cd tox_tcp_relay ; rm -fv tox_tcp_relay tox_tcp_relay_static 219 | - cd tox_tcp_relay ; . ~/pp ; $CC -O2 -fPIC -o tox_tcp_relay tox_tcp_relay.c -std=gnu99 -I"$_SYSROOT_"/usr/local/include/ -L"$_SYSROOT_"/usr/lib/arm-linux-gnueabihf/ -lsodium -ltoxcore -ltoxav -lpthread -lvpx -ljpeg -lv4lconvert 220 | - cd tox_tcp_relay ; ldd tox_tcp_relay ; exit 0 221 | - cd tox_tcp_relay ; find . -name '*tox_tcp_relay*' -exec ls -al {} \; 2> /dev/null ; exit 0 222 | - cd tox_tcp_relay ; . ~/pp ; $CC -O2 -Wall -Wextra -Wpedantic -o tox_tcp_relay_static tox_tcp_relay.c -static -std=gnu99 -L"$_SYSROOT_"/usr/lib/arm-linux-gnueabihf/ -I"$_SYSROOT_"/usr/lib/arm-linux-gnueabihf/ -lsodium -ltoxcore -ltoxav -lsodium -lpthread -static-libgcc -static-libstdc++ -lopus -lvpx -lm -lpthread -lv4lconvert -ljpeg -lm -lrt 223 | - cd tox_tcp_relay ; ls -al tox_tcp_relay tox_tcp_relay_static 224 | - cd tox_tcp_relay ;. ~/pp ; cp -av ./tox_tcp_relay $CIRCLE_ARTIFACTS/"${CUR_ARCH_}"/ 225 | - cd tox_tcp_relay ;. ~/pp ; cp -av ./tox_tcp_relay_static $CIRCLE_ARTIFACTS/"${CUR_ARCH_}"/ 226 | 227 | ## ----------- RASPI cross compile ---------------- 228 | 229 | 230 | test: 231 | override: 232 | - cd tox_tcp_relay ; rm -fv tox_tcp_relay tox_tcp_relay_static 233 | - cd tox_tcp_relay ; gcc -O2 -fPIC -o tox_tcp_relay tox_tcp_relay.c -std=gnu99 -lsodium -I/usr/local/include/ -ltoxcore -ltoxav -lpthread -lvpx -lv4lconvert 234 | - cd tox_tcp_relay ; ldd tox_tcp_relay ; exit 0 235 | - find / -name '*libjpeg*' 2> /dev/null ; exit 0 236 | - cd tox_tcp_relay ; gcc -O2 -Wall -Wextra -Wpedantic -o tox_tcp_relay_static tox_tcp_relay.c -static -std=gnu99 -L/usr/local/lib -I/usr/local/include/ -lsodium -ltoxcore -ltoxav -ltoxgroup -ltoxmessenger -ltoxfriends -ltoxnetcrypto -ltoxdht -ltoxnetwork -ltoxcrypto -lsodium -lpthread -static-libgcc -static-libstdc++ -lopus -lvpx -lm -lpthread -lv4lconvert -ljpeg -lm -lrt 237 | - cd tox_tcp_relay ; ls -al tox_tcp_relay tox_tcp_relay_static 238 | - mkdir -p $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/ 239 | - cp -av tox_tcp_relay/tox_tcp_relay $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/ 240 | - cp -av tox_tcp_relay/tox_tcp_relay_static $CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/ 241 | - cd tox_tcp_relay ; ./tox_tcp_relay_static : 242 | background: true 243 | - sleep 10 244 | - cd tox_tcp_relay ; cat ./tox_tcp_relay.log 245 | - cd tox_tcp_relay ; cat ./tox_tcp_relay.log | grep '\-\-MyToxID\-\-:' | cut -d':' -f 3 246 | - sleep 10 247 | #- sleep 240 248 | - cd tox_tcp_relay ; cat ./tox_tcp_relay.log 249 | -------------------------------------------------------------------------------- /tox_tcp_relay/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoff99/ToxTCP-RelayNode/7fc1ef4ef96d5d2b96cd021e97be4f820b70300c/tox_tcp_relay/avatar.png -------------------------------------------------------------------------------- /tox_tcp_relay/loop_services.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | cd $(dirname "$0") 4 | 5 | while [ 1 == 1 ]; do 6 | ./tox-bootstrapd_static --foreground --log-backend=stdout --config=tox-bootstrapd.conf >> ./tox-bootstrapd.log 2>&1 7 | sleep 10 8 | done 9 | -------------------------------------------------------------------------------- /tox_tcp_relay/tox-bootstrapd.conf: -------------------------------------------------------------------------------- 1 | // Tox DHT bootstrap daemon configuration file. 2 | 3 | // Listening port (UDP). 4 | port = 33446 5 | 6 | // A key file is like a password, so keep it where no one can read it. 7 | // If there is no key file, a new one will be generated. 8 | // The daemon should have permission to read/write it. 9 | keys_file_path = "./keys" 10 | 11 | // The PID file written to by the daemon. 12 | // Make sure that the user that daemon runs as has permissions to write to the 13 | // PID file. 14 | pid_file_path = "./tox-bootstrapd.pid" 15 | 16 | // Enable IPv6. 17 | enable_ipv6 = false 18 | 19 | // Fallback to IPv4 in case IPv6 fails. 20 | enable_ipv4_fallback = true 21 | 22 | // Automatically bootstrap with nodes on local area network. 23 | enable_lan_discovery = true 24 | 25 | enable_tcp_relay = true 26 | 27 | // While Tox uses 33445 port by default, 443 (https) and 3389 (rdp) ports are very 28 | // common among nodes, so it's encouraged to keep them in place. 29 | tcp_relay_ports = [33447] 30 | 31 | // Reply to MOTD (Message Of The Day) requests. 32 | enable_motd = true 33 | 34 | // Just a message that is sent when someone requests MOTD. 35 | // Put anything you want, but note that it will be trimmed to fit into 255 bytes. 36 | motd = "tox-bootstrapd" 37 | 38 | // Any number of nodes the daemon will bootstrap itself off. 39 | // 40 | // Remember to replace the provided example with your own node list. 41 | // There is a maintained list of bootstrap nodes on Tox's wiki, if you need it 42 | // (https://wiki.tox.chat/doku.php?id=users:nodes). 43 | // 44 | // You may leave the list empty or remove "bootstrap_nodes" completely, 45 | // in both cases this will be interpreted as if you don't want to bootstrap 46 | // from anyone. 47 | // 48 | // address = any IPv4 or IPv6 address and also any US-ASCII domain name. 49 | bootstrap_nodes = ( 50 | ### tox.0x10k.com/bootstrapd-conf/ 51 | 52 | { 53 | #1 [DE] - sonOfRa 54 | address = "144.76.60.215" 55 | port = 33445 56 | public_key = "04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F" 57 | }, 58 | { 59 | #2 [US] - stal 60 | address = "23.226.230.47" 61 | port = 33445 62 | public_key = "A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074" 63 | }, 64 | { 65 | #3 [FR] - Munrek 66 | address = "195.154.119.113" 67 | port = 33445 68 | public_key = "E398A69646B8CEACA9F0B84F553726C1C49270558C57DF5F3C368F05A7D71354" 69 | }, 70 | { 71 | #4 [US] - nurupo (nurupo.contributions@gmail.com) 72 | address = "198.46.138.44" 73 | port = 33445 74 | public_key = "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67" 75 | }, 76 | { 77 | #5 [DE] - Martin Schröder 78 | address = "46.38.239.179" 79 | port = 33445 80 | public_key = "F5A1A38EFB6BD3C2C8AF8B10D85F0F89E931704D349F1D0720C3C4059AF2440A" 81 | }, 82 | { 83 | #6 [NL] - Impyy 84 | address = "178.62.250.138" 85 | port = 33445 86 | public_key = "788236D34978D1D5BD822F0A5BEBD2C53C64CC31CD3149350EE27D4D9A2F9B6B" 87 | }, 88 | { 89 | #7 [DE] - Manolis 90 | address = "130.133.110.14" 91 | port = 33445 92 | public_key = "461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F" 93 | }, 94 | { 95 | #8 [CA] - noisykeyboard 96 | address = "104.167.101.29" 97 | port = 33445 98 | public_key = "5918AC3C06955962A75AD7DF4F80A5D7C34F7DB9E1498D2E0495DE35B3FE8A57" 99 | }, 100 | { 101 | #9 [US] - Busindre 102 | address = "205.185.116.116" 103 | port = 33445 104 | public_key = "A179B09749AC826FF01F37A9613F6B57118AE014D4196A0E1105A98F93A54702" 105 | }, 106 | { 107 | #10 [US] - Busindre 108 | address = "198.98.51.198" 109 | port = 33445 110 | public_key = "1D5A5F2F5D6233058BF0259B09622FB40B482E4FA0931EB8FD3AB8E7BF7DAF6F" 111 | }, 112 | { 113 | #11 [LV] - fUNKIAM 114 | address = "80.232.246.79" 115 | port = 33445 116 | public_key = "CF6CECA0A14A31717CC8501DA51BE27742B70746956E6676FF423A529F91ED5D" 117 | }, 118 | { 119 | #12 [NL] - ray65536 120 | address = "108.61.165.198" 121 | port = 33445 122 | public_key = "8E7D0B859922EF569298B4D261A8CCB5FEA14FB91ED412A7603A585A25698832" 123 | }, 124 | { 125 | #13 [GB] - Kr9r0x 126 | address = "212.71.252.109" 127 | port = 33445 128 | public_key = "C4CEB8C7AC607C6B374E2E782B3C00EA3A63B80D4910B8649CCACDD19F260819" 129 | }, 130 | { 131 | #14 [SI] - fluke571 132 | address = "194.249.212.109" 133 | port = 33445 134 | public_key = "3CEE1F054081E7A011234883BC4FC39F661A55B73637A5AC293DDF1251D9432B" 135 | }, 136 | { 137 | #15 [UA] - MAH69K 138 | address = "185.25.116.107" 139 | port = 33445 140 | public_key = "DA4E4ED4B697F2E9B000EEFE3A34B554ACD3F45F5C96EAEA2516DD7FF9AF7B43" 141 | }, 142 | { 143 | #16 [CA] - WIeschie 144 | address = "192.99.168.140" 145 | port = 33445 146 | public_key = "6A4D0607A296838434A6A7DDF99F50EF9D60A2C510BBF31FE538A25CB6B4652F" 147 | }, 148 | { 149 | #17 [DE] - clearmartin 150 | address = "46.101.197.175" 151 | port = 443 152 | public_key = "CD133B521159541FB1D326DE9850F5E56A6C724B5B8E5EB5CD8D950408E95707" 153 | }, 154 | { 155 | #18 [SE] - Rotkaermota 156 | address = "95.215.46.114" 157 | port = 33445 158 | public_key = "5823FB947FF24CF83DDFAC3F3BAA18F96EA2018B16CC08429CB97FA502F40C23" 159 | }, 160 | { 161 | #19 [DE] - tastytea 162 | address = "5.189.176.217" 163 | port = 5190 164 | public_key = "2B2137E094F743AC8BD44652C55F41DFACC502F125E99E4FE24D40537489E32F" 165 | }, 166 | { 167 | #20 [FR] - pucetox (1D1C0B992DEB6D7F18561176F7F5E572BCC7F2BA5CFA7E9E437B9134122CE96D906A6119F9D2) 168 | address = "217.182.143.254" 169 | port = 2306 170 | public_key = "7AED21F94D82B05774F697B209628CD5A9AD17E0C073D9329076A4C28ED28147" 171 | }, 172 | { 173 | #21 [US] - ru_maniac (EBD2A7B649ABB10ED9F47E5113F04000F39D46F087CEB62FCCE1069471FD6915256D197F2A97) 174 | address = "104.223.122.15" 175 | port = 33445 176 | public_key = "0FB96EEBFB1650DDB52E70CF773DDFCABE25A95CC3BB50FC251082E4B63EF82A" 177 | }, 178 | { 179 | #22 [DE] - Deliran 180 | address = "78.47.114.252" 181 | port = 33445 182 | public_key = "1C5293AEF2114717547B39DA8EA6F1E331E5E358B35F9B6B5F19317911C5F976" 183 | }, 184 | { 185 | #23 [RU] - D4rk4 (35EDC07AEB18B163E07EE33F6CDDA63969F394FF6A617CEAB22A7EBBEAAAF854C0EDFBD46898) 186 | address = "83.137.53.211" 187 | port = 1813 188 | public_key = "53737F6D47FA6BD2808F378E339AF45BF86F39B64E79D6D491C53A1D522E7039" 189 | }, 190 | { 191 | #24 [NL] - tibietigni (D36CC0B702621F48FDBC540A57124A744E5133C932E65ACCEBCABF2586A02455171717175989) 192 | address = "81.4.110.149" 193 | port = 33445 194 | public_key = "9E7BD4793FFECA7F32238FA2361040C09025ED3333744483CA6F3039BFF0211E" 195 | }, 196 | { 197 | #25 [RU] - Igor Novgorodov 198 | address = "95.31.20.151" 199 | port = 33445 200 | public_key = "9CA69BB74DE7C056D1CC6B16AB8A0A38725C0349D187D8996766958584D39340" 201 | }, 202 | { 203 | #26 [CA] - wildermesser 204 | address = "104.233.104.126" 205 | port = 33445 206 | public_key = "EDEE8F2E839A57820DE3DA4156D88350E53D4161447068A3457EE8F59F362414" 207 | }, 208 | { 209 | #27 [FR] - a68366 210 | address = "51.254.84.212" 211 | port = 33445 212 | public_key = "AEC204B9A4501412D5F0BB67D9C81B5DB3EE6ADA64122D32A3E9B093D544327D" 213 | }, 214 | { 215 | #28 [BR] - umgeher 216 | address = "179.35.206.22" 217 | port = 33445 218 | public_key = "188E072676404ED833A4E947DC1D223DF8EFEBE5F5258573A236573688FB9761" 219 | }, 220 | { 221 | #29 [FR] - Skey 222 | address = "5.135.59.163" 223 | port = 33445 224 | public_key = "2D320F971EF2CA18004416C2AAE7BA52BF7949DB34EA8E2E21AF67BD367BE211" 225 | }, 226 | { 227 | #30 [RU] - ru_maniac (EBD2A7B649ABB10ED9F47E5113F04000F39D46F087CEB62FCCE1069471FD6915256D197F2A97) 228 | address = "185.58.206.164" 229 | port = 33445 230 | public_key = "24156472041E5F220D1FA11D9DF32F7AD697D59845701CDD7BE7D1785EB9DB39" 231 | }, 232 | { 233 | #31 [RU] - gem 234 | address = "188.244.38.183" 235 | port = 33445 236 | public_key = "15A0F9684E2423F9F46CFA5A50B562AE42525580D840CC50E518192BF333EE38" 237 | }, 238 | { 239 | #32 [GB] - mrflibble 240 | address = "185.64.89.42" 241 | port = 33445 242 | public_key = "FAAB17014F42F7F20949F61E55F66A73C230876812A9737F5F6D2DCE4D9E4207" 243 | }, 244 | { 245 | #33 [RU] - Net.Verified 246 | address = "82.211.31.116" 247 | port = 33445 248 | public_key = "AF97B76392A6474AF2FD269220FDCF4127D86A42EF3A242DF53A40A268A2CD7C" 249 | }, 250 | { 251 | #34 [SG] - wiiaam 252 | address = "128.199.199.197" 253 | port = 33445 254 | public_key = "B05C8869DBB4EDDD308F43C1A974A20A725A36EACCA123862FDE9945BF9D3E09" 255 | }, 256 | { 257 | #35 [AU] - AssPirate 258 | address = "103.230.156.174" 259 | port = 33445 260 | public_key = "5C4C7A60183D668E5BD8B3780D1288203E2F1BAE4EEF03278019E21F86174C1D" 261 | }, 262 | { 263 | #36 [FR] - h4nt3r (3BC3C6875508A2EC86BE3E35E4FA9155E444CFA96671AE7D7D0D2585A0A5FA38E071A5E463E5) 264 | address = "91.121.66.124" 265 | port = 33445 266 | public_key = "4E3F7D37295664BBD0741B6DBCB6431D6CD77FC4105338C2FC31567BF5C8224A" 267 | }, 268 | { 269 | #37 [RU] - t3mp 270 | address = "92.54.84.70" 271 | port = 33445 272 | public_key = "5625A62618CB4FCA70E147A71B29695F38CC65FF0CBD68AD46254585BE564802" 273 | }, 274 | { 275 | #38 [US] - PrivacyDragon 276 | address = "45.58.44.190" 277 | port = 33445 278 | public_key = "31910C0497D347FF160D6F3A6C0E317BAFA71E8E03BC4CBB2A185C9D4FB8B31E" 279 | }, 280 | { 281 | #39 [UA] - strngr 282 | address = "195.93.190.6" 283 | port = 33445 284 | public_key = "FB4CE0DDEFEED45F26917053E5D24BDDA0FA0A3D83A672A9DA2375928B37023D" 285 | }, 286 | { 287 | #40 [US] - AbacusAvenger 288 | address = "104.152.107.143" 289 | port = 33445 290 | public_key = "1A56EA3EDF5DF4C0AEABBF3C2E4E603890F87E983CAC8A0D532A335F2C6E3E1F" 291 | }, 292 | { 293 | #41 [NL] - ZaWertun 294 | address = "185.52.0.229" 295 | port = 33445 296 | public_key = "5521952892FBD5C185DF7180DB4DEF69D7844DEEE79B1F75A634ED9DF656756E" 297 | }, 298 | { 299 | #42 [ES] - _kinka_ 300 | address = "87.98.168.93" 301 | port = 33445 302 | public_key = "C3F6C06A624FAE086DA94604A7838DB495769807EC055FADA36EBF2D4484FB33" 303 | }, 304 | { 305 | #43 [RU] - MAXL-SPB (06B8B5F3DAED44EDE619E44CCA532D9463EDD2779ADC397E239EDCE9E3474413055FF791700C) 306 | address = "185.61.253.189" 307 | port = 33445 308 | public_key = "73EEBCB4CBBE56BF0E0F01881DDD88C6B250BAE92CF487BE3FBE02FD830CE200" 309 | }, 310 | { 311 | #44 [AR] - nek 312 | address = "109.75.40.105" 313 | port = 33445 314 | public_key = "2B9CD794424FD579044EC2FC5252B23DF8B4AAF239C25074F70B1090C3F8C83A" 315 | }, 316 | { 317 | #45 [UA] - Phsm 318 | address = "89.184.82.218" 319 | port = 33445 320 | public_key = "20965721D32CE50C3E837DD75B33908B33037E6225110BFF209277AEAF3F9639" 321 | }, 322 | { 323 | #46 [SW] - HooinKyoma 324 | address = "95.215.44.78" 325 | port = 33445 326 | public_key = "672DBE27B4ADB9D5FB105A6BB648B2F8FDB89B3323486A7A21968316E012023C" 327 | }, 328 | { 329 | #47 [FR] - Ricin.im 330 | address = "81.64.83.32" 331 | port = 1337 332 | public_key = "3651DAB570D7F60381F87B19D6935EE7F5FE01308DCE71C4B69993150C6A903C" 333 | }, 334 | { 335 | #48 [GB] - Kostik 336 | address = "185.120.34.64" 337 | port = 33445 338 | public_key = "728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854" 339 | }, 340 | { 341 | #49 [RU] - abbat 342 | address = "193.124.186.120" 343 | port = 33445 344 | public_key = "80EF8660D9C5ACE1577BAB031375A0F08284CBFD9F810A857955DCC87377FC4D" 345 | }, 346 | { 347 | #50 [NL] - LittleVulpix 348 | address = "146.185.136.123" 349 | port = 33445 350 | public_key = "09993FAF174DFFDC515B398A2EFC5639C4E6D7B736FC864F89786B50EAF88C1A" 351 | }, 352 | { 353 | #51 [FR] - LittleVulpix 354 | address = "163.172.136.118" 355 | port = 33445 356 | public_key = "2C289F9F37C20D09DA83565588BF496FAB3764853FA38141817A72E3F18ACA0B" 357 | }, 358 | { 359 | #52 [DE] - Sorunome 360 | address = "144.76.31.180" 361 | port = 33445 362 | public_key = "02807CF4F8BB8FB390CC3794BDF1E8449E9A8392C5D3F2200019DA9F1E812E46" 363 | }, 364 | { 365 | #53 [NL] - Yani 366 | address = "37.97.185.116" 367 | port = 33445 368 | public_key = "E59A0E71ADA20D35BD1B0957059D7EF7E7792B3D680AE25C6F4DBBA09114D165" 369 | }, 370 | { 371 | #54 [RU] - Cactus 372 | address = "193.124.186.205" 373 | port = 5228 374 | public_key = "9906D65F2A4751068A59D30505C5FC8AE1A95E0843AE9372EAFA3BAB6AC16C2C" 375 | }, 376 | { 377 | #55 [RU] - linxon 378 | address = "80.87.193.193" 379 | port = 33445 380 | public_key = "B38255EE4B054924F6D79A5E6E5889EC94B6ADF6FE9906F97A3D01E3D083223A" 381 | }, 382 | { 383 | #56 [TW] - initramfs 384 | address = "61.230.104.51" 385 | port = 33445 386 | public_key = "3F0A45A268367C1BEA652F258C85F4A66DA76BCAA667A49E770BCC4917AB6A25" 387 | }, 388 | { 389 | #57 [US] - brandon 390 | address = "138.68.2.139" 391 | port = 33445 392 | public_key = "49183DBF0E865713154069D1C7C7A2732ED78CF32C4D76AF5304FE31C5FEB81A" 393 | }, 394 | { 395 | #58 [US] - EveNeko (tox-bootstrapd@hibiki.eve.moe) 396 | address = "107.150.46.124" 397 | port = 33445 398 | public_key = "D3EB45181B343C2C222A5BCF72B760638E15ED87904625AAD351C594EEFAE03E" 399 | }, 400 | { 401 | #59 [GB] - EveNeko (tox-bootstrapd@hibiki.eve.moe) 402 | address = "185.133.194.202" 403 | port = 33445 404 | public_key = "1A480A53FAF2CBBFCC382D786C43E69EEE23F22C7C23A7CFEB6180A373E23E54" 405 | }, 406 | { 407 | #60 [DE] - DeadTeam 408 | address = "144.76.163.109" 409 | port = 33445 410 | public_key = "C7D284129E83877D63591F14B3F658D77FF9BA9BA7293AEB2BDFBFE1A803AF47" 411 | }, 412 | { 413 | #61 [RU] - Prototik 414 | address = "164.132.51.92" 415 | port = 33445 416 | public_key = "69C3FEBB977687B64FA0213BDEB89A43463BB48DED288150CFFB6429EFF82436" 417 | }, 418 | { 419 | #62 [UA] - Stranger 420 | address = "46.229.52.198 " 421 | port = 33445 422 | public_key = "813C8F4187833EF0655B10F7752141A352248462A567529A38B6BBF73E979307" 423 | }, 424 | { 425 | #63 [DE] - Prototik 426 | address = "95.188.83.80" 427 | port = 33445 428 | public_key = "B75583B6D967DB8AD7C6D3B6F9318194BCC79B2FEF18F69E2DF275B779E7AA30" 429 | }, 430 | { 431 | #64 [DE] - sys0p 432 | address = "138.201.172.228" 433 | port = 33445 434 | public_key = "1B08FC930EE60429B63273CE39068D46316E79A3F7DDAFAD9C8CA65E50047B7A" 435 | }, 436 | { 437 | #65 [DE] - Nolz 438 | address = "78.46.81.229" 439 | port = 33445 440 | public_key = "A856243058D1DE633379508ADCAFCF944E40E1672FF402750EF712E30C42012A" 441 | }, 442 | { 443 | #66 [CA] - velusip 444 | address = "144.217.86.39" 445 | port = 33445 446 | public_key = "7E5668E0EE09E19F320AD47902419331FFEE147BB3606769CFBE921A2A2FD34C" 447 | }, 448 | { 449 | #67 [RU] - Madji 450 | address = "77.37.160.178" 451 | port = 33440 452 | public_key = "CE678DEAFA29182EFD1B0C5B9BC6999E5A20B50A1A6EC18B91C8EBB591712416" 453 | }, 454 | { 455 | #68 [RU] - ps 456 | address = "77.37.142.179" 457 | port = 33445 458 | public_key = "98F5830A426C6BF165F895F04B897AFC4F57331B4BE0561F583C9F323194227B" 459 | }, 460 | { 461 | #69 [RU] - himura (EB8E9FFB08DC3C31F8450521A884B478A1B4452BBB4C86BDC7E2AD3CC681C146FF77CBEA21EA) 462 | address = "85.21.144.224" 463 | port = 33445 464 | public_key = "8F738BBC8FA9394670BCAB146C67A507B9907C8E564E28C2B59BEBB2FF68711B" 465 | }, 466 | { 467 | #70 [DE] - post-factum (tox.natalenko.name, 8218DB335926393789859EDF2D79AC4CC805ADF73472D08165FEA51555502A58AE84FCE7C3D4) 468 | address = "104.207.131.136" 469 | port = 33445 470 | public_key = "1CB6EBFD9D85448FA70D3CAE1220B76BF6FCE911B46ACDCF88054C190589650B" 471 | }, 472 | { 473 | #71 [FR] - dolohow 474 | address = "37.187.122.30" 475 | port = 33445 476 | public_key = "BEB71F97ED9C99C04B8489BB75579EB4DC6AB6F441B603D63533122F1858B51D" 477 | }, 478 | { 479 | #72 [NZ] - ws 480 | address = "202.36.75.162" 481 | port = 33445 482 | public_key = "F202E0936ABEE09067F55B0955C3FF6A84ABEED3C750A9EB930D926D03248F4C" 483 | }, 484 | { 485 | #73 [RU] - bax 486 | address = "94.19.12.244" 487 | port = 33445 488 | public_key = "92E139CCD0006AF84241A38629E77E73BCF2F98602DCC136E8D5F089E5196D46" 489 | }, 490 | { 491 | #74 [SI] - nnnn20430 (plfgr.eu.org) 492 | address = "213.161.5.12" 493 | port = 33445 494 | public_key = "F5A2E533EC720927FA970F508D949D5958F37889F039F50C905010244842656E" 495 | }, 496 | { 497 | #75 [FR] - SillyPeruvian (completelyunoriginal.moe) 498 | address = "46.105.30.235" 499 | port = 33445 500 | public_key = "FBC7DED0B0B662D81094D91CC312D6CDF12A7B16C7FFB93817143116B510C13E" 501 | }, 502 | { 503 | #76 [DE] - CeBe (tox@cebe.cc , 7F50119368DC8FD3B1ECAF5D18E3F8854F0484CEC5BBF625D420B8E38638733C02486E387AF8) 504 | address = "136.243.141.187" 505 | port = 443 506 | public_key = "6EE1FADE9F55CC7938234CC07C864081FC606D8FE7B751EDA217F268F1078A39" 507 | } 508 | ) 509 | -------------------------------------------------------------------------------- /tox_tcp_relay/tox_tcp_relay.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Zoff 4 | * in 2017 5 | * 6 | * dirty hack (echobot and toxic were used as blueprint) 7 | * 8 | * 9 | * compile on linux (dynamic): 10 | * gcc -O2 -fPIC -Wall -Wextra -Wpedantic -o toxdoorspy toxdoorspy.c -std=gnu99 -lsodium -I/usr/local/include/ -ltoxcore -ltoxav -lpthread -lvpx -lv4lconvert 11 | * compile for debugging (dynamic): 12 | * gcc -O0 -g -fPIC -Wall -Wextra -Wpedantic -o toxdoorspy toxdoorspy.c -std=gnu99 -lsodium -I/usr/local/include/ -ltoxcore -ltoxav -lpthread -lvpx -lv4lconvert 13 | * 14 | * compile on linux (static): 15 | * gcc -O2 -Wall -Wextra -Wpedantic -o toxdoorspy_static toxdoorspy.c -static -std=gnu99 -L/usr/local/lib -I/usr/local/include/ \ 16 | -lsodium -ltoxcore -ltoxav -ltoxgroup -ltoxmessenger -ltoxfriends -ltoxnetcrypto \ 17 | -ltoxdht -ltoxnetwork -ltoxcrypto -lsodium -lpthread -static-libgcc -static-libstdc++ \ 18 | -lopus -lvpx -lm -lpthread -lv4lconvert 19 | * 20 | 21 | * 22 | * 23 | */ 24 | 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | #include 51 | #include 52 | #include 53 | 54 | #define V4LCONVERT 1 55 | // #define HAVE_SOUND 1 56 | 57 | #ifdef HAVE_SOUND 58 | #include 59 | #endif 60 | 61 | 62 | 63 | #ifdef V4LCONVERT 64 | #include 65 | #endif 66 | 67 | #ifdef V4LCONVERT 68 | static struct v4lconvert_data *v4lconvert_data; 69 | #endif 70 | 71 | 72 | // ----------- version ----------- 73 | // ----------- version ----------- 74 | #define VERSION_MAJOR 0 75 | #define VERSION_MINOR 99 76 | #define VERSION_PATCH 1 77 | static const char global_version_string[] = "0.99.1"; 78 | // ----------- version ----------- 79 | // ----------- version ----------- 80 | 81 | typedef struct DHT_node { 82 | const char *ip; 83 | uint16_t port; 84 | const char key_hex[TOX_PUBLIC_KEY_SIZE*2 + 1]; 85 | unsigned char key_bin[TOX_PUBLIC_KEY_SIZE]; 86 | } DHT_node; 87 | 88 | 89 | 90 | #define MAX_AVATAR_FILE_SIZE 65536 91 | #define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */ 92 | #define TIME_STR_SIZE 32 93 | #define MAX_STR_SIZE 200 94 | 95 | #define CURRENT_LOG_LEVEL 9 // 0 -> error, 1 -> warn, 2 -> info, 9 -> debug 96 | 97 | #define KiB 1024 98 | #define MiB 1048576 /* 1024^2 */ 99 | #define GiB 1073741824 /* 1024^3 */ 100 | 101 | #define seconds_since_last_mod 1 // how long to wait before we process image files in seconds 102 | #define MAX_FILES 6 // how many filetransfers to/from 1 friend at the same time? 103 | #define MAX_RESEND_FILE_BEFORE_ASK 6 104 | #define AUTO_RESEND_SECONDS 60*5 // resend for this much seconds before asking again [5 min] 105 | #define VIDEO_BUFFER_COUNT 3 106 | uint32_t DEFAULT_GLOBAL_VID_BITRATE = 5000; // kbit/sec 107 | #define DEFAULT_GLOBAL_AUD_BITRATE 6 // kbit/sec 108 | #define DEFAULT_GLOBAL_MIN_VID_BITRATE 1000 // kbit/sec 109 | #define DEFAULT_GLOBAL_MIN_AUD_BITRATE 6 // kbit/sec 110 | #define DEFAULT_FPS_SLEEP_MS 250 // 250=4fps, 500=2fps, 160=6fps // default video fps (sleep in msecs.) 111 | 112 | #define CLEAR(x) memset(&(x), 0, sizeof(x)) 113 | #define c_sleep(x) usleep(1000*x) 114 | 115 | typedef enum FILE_TRANSFER_STATE { 116 | FILE_TRANSFER_INACTIVE, // == 0 , this is important 117 | FILE_TRANSFER_PAUSED, 118 | FILE_TRANSFER_PENDING, 119 | FILE_TRANSFER_STARTED, 120 | } FILE_TRANSFER_STATE; 121 | 122 | typedef enum FILE_TRANSFER_DIRECTION { 123 | FILE_TRANSFER_SEND, 124 | FILE_TRANSFER_RECV 125 | } FILE_TRANSFER_DIRECTION; 126 | 127 | struct FileTransfer { 128 | FILE *file; 129 | FILE_TRANSFER_STATE state; 130 | FILE_TRANSFER_DIRECTION direction; 131 | uint8_t file_type; 132 | char file_name[TOX_MAX_FILENAME_LENGTH + 1]; 133 | char file_path[PATH_MAX + 1]; /* Not used by senders */ 134 | double bps; 135 | uint32_t filenum; 136 | uint32_t friendnum; 137 | size_t index; 138 | uint64_t file_size; 139 | uint64_t position; 140 | time_t last_keep_alive; /* The last time we sent or received data */ 141 | uint32_t line_id; 142 | uint8_t file_id[TOX_FILE_ID_LENGTH]; 143 | }; 144 | 145 | 146 | struct LastOnline { 147 | uint64_t last_on; 148 | struct tm tm; 149 | char hour_min_str[TIME_STR_SIZE]; /* holds 24-hour time string e.g. "15:43:24" */ 150 | }; 151 | 152 | struct GroupChatInvite { 153 | char *key; 154 | uint16_t length; 155 | uint8_t type; 156 | bool pending; 157 | }; 158 | 159 | typedef struct { 160 | char name[TOXIC_MAX_NAME_LENGTH + 1]; 161 | int namelength; 162 | char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1]; 163 | size_t statusmsg_len; 164 | char pub_key[TOX_PUBLIC_KEY_SIZE]; 165 | char pubkey_string[(TOX_ADDRESS_SIZE * 2 + 1)]; 166 | char worksubdir[MAX_STR_SIZE]; 167 | uint32_t num; 168 | bool active; 169 | TOX_CONNECTION connection_status; 170 | bool is_typing; 171 | uint8_t status; 172 | struct LastOnline last_online; 173 | int have_resumed_fts; // wait with new FTs until all old FTs have been started (to resume) including avatars! 174 | struct FileTransfer file_receiver[MAX_FILES]; 175 | struct FileTransfer file_sender[MAX_FILES]; 176 | char last_answer[100]; 177 | int waiting_for_answer; // 0 -> no, 1 -> waiting for answer, 2 -> got answer 178 | time_t auto_resend_start_time; 179 | // mz_zip_archive zip_archive; 180 | } ToxicFriend; 181 | 182 | typedef struct { 183 | char name[TOXIC_MAX_NAME_LENGTH + 1]; 184 | int namelength; 185 | char pub_key[TOX_PUBLIC_KEY_SIZE]; 186 | uint32_t num; 187 | bool active; 188 | uint64_t last_on; 189 | } BlockedFriend; 190 | 191 | typedef struct { 192 | int num_selected; 193 | size_t num_friends; 194 | size_t num_online; 195 | size_t max_idx; /* 1 + the index of the last friend in list */ 196 | uint32_t *index; 197 | ToxicFriend *list; 198 | } FriendsList; 199 | 200 | 201 | static struct Avatar { 202 | char name[TOX_MAX_FILENAME_LENGTH + 1]; 203 | size_t name_len; 204 | char path[PATH_MAX + 1]; 205 | size_t path_len; 206 | off_t size; 207 | } Avatar; 208 | 209 | typedef struct { 210 | bool incoming; 211 | uint32_t state; 212 | uint32_t audio_bit_rate; 213 | uint32_t video_bit_rate; 214 | pthread_mutex_t arb_mutex[1]; 215 | } CallControl; 216 | 217 | 218 | struct buffer { 219 | void * start; 220 | size_t length; 221 | }; 222 | 223 | typedef struct TOXCAM_AV_VIDEO_FRAME { 224 | uint16_t w, h; 225 | uint8_t *y, *u, *v; 226 | // uint8_t bit_depth; 227 | } toxcam_av_video_frame; 228 | 229 | 230 | 231 | void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length); 232 | int avatar_send(Tox *m, uint32_t friendnum); 233 | struct FileTransfer *new_file_transfer(uint32_t friendnum, uint32_t filenum, FILE_TRANSFER_DIRECTION direction, uint8_t type); 234 | void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum); 235 | int has_reached_max_file_transfer_for_friend(uint32_t num); 236 | static int find_friend_in_friendlist(uint32_t friendnum); 237 | int is_friend_online(Tox *tox, uint32_t num); 238 | void av_local_disconnect(ToxAV *av, uint32_t num); 239 | void run_cmd_return_output(const char *command, char* output, int lastline); 240 | void save_resumable_fts(Tox *m, uint32_t friendnum); 241 | void resume_resumable_fts(Tox *m, uint32_t friendnum); 242 | void left_top_bar_into_yuv_frame(int bar_start_x_pix, int bar_start_y_pix, int bar_w_pix, int bar_h_pix, uint8_t r, uint8_t g, uint8_t b); 243 | void print_font_char(int start_x_pix, int start_y_pix, int font_char_num, uint8_t col_value); 244 | void text_on_yuf_frame_xy(int start_x_pix, int start_y_pix, const char* text); 245 | void blinking_dot_on_frame_xy(int start_x_pix, int start_y_pix, int* state); 246 | void black_yuf_frame_xy(); 247 | void rbg_to_yuv(uint8_t r, uint8_t g, uint8_t b, uint8_t *y, uint8_t *u, uint8_t *v); 248 | void set_color_in_yuv_frame_xy(uint8_t *yuv_frame, int px_x, int px_y, int frame_w, int frame_h, uint8_t r, uint8_t g, uint8_t b); 249 | 250 | 251 | const char *savedata_filename = "savedata.tox"; 252 | const char *savedata_tmp_filename = "savedata.tox.tmp"; 253 | const char *log_filename = "tox_tcp_relay.log"; 254 | const char *my_avatar_filename = "avatar.png"; 255 | 256 | char *v4l2_device; // video device filename 257 | 258 | const char *shell_cmd__single_shot = "./scripts/single_shot.sh 2> /dev/null"; 259 | const char *shell_cmd__get_cpu_temp = "./scripts/get_cpu_temp.sh 2> /dev/null"; 260 | const char *shell_cmd__get_gpu_temp = "./scripts/get_gpu_temp.sh 2> /dev/null"; 261 | const char *shell_cmd__get_my_number_of_open_files = "cat /proc/sys/fs/file-nr 2> /dev/null"; 262 | int global_want_restart = 0; 263 | const char *global_timestamp_format = "%H:%M:%S"; 264 | const char *global_long_timestamp_format = "%Y-%m-%d %H:%M:%S"; 265 | const char *global_overlay_timestamp_format = "%Y-%m-%d %H:%M:%S"; 266 | uint64_t global_start_time; 267 | int global_cam_device_fd = 0; 268 | uint32_t n_buffers; 269 | struct buffer *buffers = NULL; 270 | uint16_t video_width = 0; 271 | uint16_t video_height = 0; 272 | struct v4l2_format format; 273 | struct v4l2_format dest_format; 274 | toxcam_av_video_frame av_video_frame; 275 | vpx_image_t input; 276 | int global_video_active = 0; 277 | int global_send_first_frame = 0; 278 | int switch_nodelist_2 = 0; 279 | int video_high = 0; 280 | int switch_tcponly = 0; 281 | 282 | 283 | uint32_t global_audio_bit_rate; 284 | uint32_t global_video_bit_rate; 285 | ToxAV *mytox_av = NULL; 286 | int tox_loop_running = 1; 287 | int global_blink_state = 0; 288 | 289 | int toxav_video_thread_stop = 0; 290 | int toxav_iterate_thread_stop = 0; 291 | 292 | // -- hardcoded -- 293 | // -- hardcoded -- 294 | // -- hardcoded -- 295 | uint32_t friend_to_send_video_to = -1; 296 | // -- hardcoded -- 297 | // -- hardcoded -- 298 | // -- hardcoded -- 299 | 300 | int video_call_enabled = 0; 301 | 302 | TOX_CONNECTION my_connection_status = TOX_CONNECTION_NONE; 303 | FILE *logfile = NULL; 304 | FriendsList Friends; 305 | 306 | void dbg(int level, const char *fmt, ...) 307 | { 308 | char *level_and_format = NULL; 309 | char *fmt_copy = NULL; 310 | 311 | if (fmt == NULL) 312 | { 313 | return; 314 | } 315 | 316 | if (strlen(fmt) < 1) 317 | { 318 | return; 319 | } 320 | 321 | if (!logfile) 322 | { 323 | return; 324 | } 325 | 326 | if ((level < 0) || (level > 9)) 327 | { 328 | level = 0; 329 | } 330 | 331 | level_and_format = malloc(strlen(fmt) + 3); 332 | 333 | if (!level_and_format) 334 | { 335 | // fprintf(stderr, "free:000a\n"); 336 | return; 337 | } 338 | 339 | fmt_copy = level_and_format + 2; 340 | strcpy(fmt_copy, fmt); 341 | level_and_format[1] = ':'; 342 | if (level == 0) 343 | { 344 | level_and_format[0] = 'E'; 345 | } 346 | else if (level == 1) 347 | { 348 | level_and_format[0] = 'W'; 349 | } 350 | else if (level == 2) 351 | { 352 | level_and_format[0] = 'I'; 353 | } 354 | else 355 | { 356 | level_and_format[0] = 'D'; 357 | } 358 | 359 | if (level <= CURRENT_LOG_LEVEL) 360 | { 361 | va_list ap; 362 | va_start(ap, fmt); 363 | vfprintf(logfile, level_and_format, ap); 364 | va_end(ap); 365 | } 366 | 367 | // fprintf(stderr, "free:001\n"); 368 | if (level_and_format) 369 | { 370 | // fprintf(stderr, "free:001.a\n"); 371 | free(level_and_format); 372 | } 373 | // fprintf(stderr, "free:002\n"); 374 | } 375 | 376 | 377 | 378 | 379 | 380 | 381 | // linked list ---------- 382 | typedef struct ll_node { 383 | void* val; 384 | struct ll_node* next; 385 | } ll_node_t; 386 | 387 | 388 | void ll_fill_val(void **val, size_t data_size, void* data) 389 | { 390 | if (*val != NULL) 391 | { 392 | free(*val); 393 | *val = NULL; 394 | } 395 | 396 | *val = malloc(data_size); 397 | memcpy(*val, data, data_size); 398 | } 399 | 400 | 401 | // add to the beginning of the list 402 | void ll_push(ll_node_t** head, size_t data_size, void* data) 403 | { 404 | ll_node_t* new_node; 405 | new_node = calloc(1, sizeof(ll_node_t)); 406 | ll_fill_val(&(new_node->val), data_size, data); 407 | new_node->next = *head; 408 | *head = new_node; 409 | } 410 | 411 | void* ll_pop(ll_node_t** head) 412 | { 413 | void* retval = NULL; 414 | ll_node_t* next_node = NULL; 415 | 416 | if (*head == NULL) 417 | { 418 | return NULL; 419 | } 420 | 421 | next_node = (*head)->next; 422 | retval = (*head)->val; 423 | free(*head); 424 | *head = next_node; 425 | 426 | return retval; 427 | } 428 | 429 | void ll_free_val(void* val) 430 | { 431 | if (val != NULL) 432 | { 433 | free(val); 434 | val = NULL; 435 | } 436 | } 437 | 438 | void* ll_remove_by_index(ll_node_t** head, int n) 439 | { 440 | int i = 0; 441 | void* retval = NULL; 442 | ll_node_t* current = *head; 443 | ll_node_t* temp_node = NULL; 444 | 445 | if (n == 0) 446 | { 447 | return ll_pop(head); 448 | } 449 | 450 | for (i = 0; i < n-1; i++) 451 | { 452 | if (current->next == NULL) 453 | { 454 | return NULL; 455 | } 456 | current = current->next; 457 | } 458 | 459 | temp_node = current->next; 460 | if (temp_node != NULL) 461 | { 462 | retval = temp_node->val; 463 | current->next = temp_node->next; 464 | free(temp_node); 465 | } 466 | 467 | return retval; 468 | } 469 | 470 | #if 0 471 | void ll_print_list(ll_node_t* head) 472 | { 473 | ll_node_t* current = head; 474 | int i = 0; 475 | 476 | while (current != NULL) 477 | { 478 | dbg(9, "element #%d=%p\n", i, current->val); 479 | i++; 480 | current = current->next; 481 | } 482 | } 483 | #endif 484 | 485 | ll_node_t* resumable_filetransfers = NULL; 486 | 487 | // linked list ---------- 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | time_t get_unix_time(void) 498 | { 499 | return time(NULL); 500 | } 501 | 502 | void yieldcpu(uint32_t ms) 503 | { 504 | usleep(1000 * ms); 505 | } 506 | 507 | 508 | void tox_log_cb__custom(Tox *tox, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func, const char *message, void *user_data) 509 | { 510 | dbg(9, "%d:%s:%d:%s:%s\n", (int)level, file, (int)line, func, message); 511 | } 512 | 513 | 514 | Tox *create_tox() 515 | { 516 | Tox *tox; 517 | struct Tox_Options options; 518 | 519 | /* 520 | TOX_ERR_OPTIONS_NEW err_options; 521 | struct Tox_Options options = tox_options_new(&err_options); 522 | if (err_options != TOX_ERR_OPTIONS_NEW_OK) 523 | { 524 | dbg(0, "tox_options_new error\n"); 525 | } 526 | */ 527 | 528 | tox_options_default(&options); 529 | 530 | // ---------------------------------------------- 531 | uint16_t tcp_port = 33447; // act as TCP relay 532 | dbg(0, "TCP relay port: 33447\n"); 533 | // uint16_t tcp_port = 0; // DON'T act as TCP relay 534 | // ---------------------------------------------- 535 | 536 | // ---------------------------------------------- 537 | if (switch_tcponly == 0) 538 | { 539 | options.udp_enabled = true; // UDP mode 540 | dbg(0, "setting UDP mode\n"); 541 | } 542 | else 543 | { 544 | options.udp_enabled = false; // TCP mode 545 | dbg(0, "setting TCP mode\n"); 546 | } 547 | // ---------------------------------------------- 548 | 549 | options.ipv6_enabled = false; 550 | options.local_discovery_enabled = true; 551 | options.hole_punching_enabled = true; 552 | options.tcp_port = tcp_port; 553 | 554 | // ------------------------------------------------------------ 555 | // set our own handler for c-toxcore logging messages!! 556 | options.log_callback = tox_log_cb__custom; 557 | // ------------------------------------------------------------ 558 | 559 | 560 | FILE *f = fopen(savedata_filename, "rb"); 561 | if (f) 562 | { 563 | fseek(f, 0, SEEK_END); 564 | long fsize = ftell(f); 565 | fseek(f, 0, SEEK_SET); 566 | 567 | uint8_t *savedata = malloc(fsize); 568 | 569 | size_t dummy = fread(savedata, fsize, 1, f); 570 | if (dummy < 1) 571 | { 572 | dbg(0, "reading savedata failed\n"); 573 | } 574 | fclose(f); 575 | 576 | options.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE; 577 | options.savedata_data = savedata; 578 | options.savedata_length = fsize; 579 | 580 | TOX_ERR_NEW error; 581 | tox = tox_new(&options, &error); 582 | dbg(9, "tox_new1:TOX_ERR_NEW = %d\n", (int)error); 583 | 584 | free((void *)savedata); 585 | } 586 | else 587 | { 588 | TOX_ERR_NEW error; 589 | tox = tox_new(&options, &error); 590 | dbg(9, "tox_new2:TOX_ERR_NEW = %d\n", (int)error); 591 | } 592 | 593 | bool local_discovery_enabled = tox_options_get_local_discovery_enabled(&options); 594 | dbg(9, "local discovery enabled = %d\n", (int)local_discovery_enabled); 595 | 596 | dbg(9, "tox = %p\n", tox); 597 | return tox; 598 | } 599 | 600 | void replace_bad_char_from_string(char *str, const char replace_with) 601 | { 602 | // win32: '\ / : * ? " < > |' 603 | char bad_chars[] = "/:*?<>|\""; 604 | int i; 605 | int j; 606 | 607 | if ((str) && (strlen(str) > 0)) 608 | { 609 | for(i = 0; (int)i < (int)strlen(str) ;i++) 610 | { 611 | for(j = 0; (int)j < (int)strlen(bad_chars); j++) 612 | if (str[i] == bad_chars[j]) 613 | { 614 | str[i] = replace_with; 615 | } 616 | } 617 | } 618 | } 619 | 620 | 621 | void update_savedata_file(const Tox *tox) 622 | { 623 | size_t size = tox_get_savedata_size(tox); 624 | char *savedata = malloc(size); 625 | tox_get_savedata(tox, (uint8_t *)savedata); 626 | 627 | FILE *f = fopen(savedata_tmp_filename, "wb"); 628 | fwrite(savedata, size, 1, f); 629 | fclose(f); 630 | 631 | rename(savedata_tmp_filename, savedata_filename); 632 | 633 | free(savedata); 634 | } 635 | 636 | off_t file_size(const char *path) 637 | { 638 | struct stat st; 639 | 640 | if (stat(path, &st) == -1) 641 | { 642 | return 0; 643 | } 644 | 645 | return st.st_size; 646 | } 647 | 648 | int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size) 649 | { 650 | if (bin_id_size != TOX_ADDRESS_SIZE || output_size < (TOX_ADDRESS_SIZE * 2 + 1)) 651 | { 652 | return -1; 653 | } 654 | 655 | size_t i; 656 | for (i = 0; i < TOX_ADDRESS_SIZE; ++i) 657 | { 658 | snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff); 659 | } 660 | 661 | return 0; 662 | } 663 | 664 | void random_char(char *output, int len) 665 | { 666 | int i; 667 | srandom(time(NULL)); 668 | 669 | for (i = 0; i < len - 1; i++) 670 | { 671 | output[i] = (unsigned char) (rand() % 255 + 1); 672 | } 673 | output[len - 1] = '\0'; 674 | } 675 | 676 | void bin_id_to_string_all(const char *bin_id, size_t bin_id_size, char *output, size_t output_size) 677 | { 678 | if (bin_id) 679 | { 680 | size_t i; 681 | for (i = 0; i < bin_id_size; ++i) 682 | { 683 | snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff); 684 | } 685 | } 686 | } 687 | 688 | 689 | size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname) 690 | { 691 | int len = strlen(pathname) - 1; 692 | char *path = strdup(pathname); 693 | 694 | if (path == NULL) 695 | { 696 | // TODO 697 | } 698 | 699 | while (len >= 0 && pathname[len] == '/') 700 | { 701 | path[len--] = '\0'; 702 | } 703 | 704 | char *finalname = strdup(path); 705 | 706 | if (finalname == NULL) 707 | { 708 | // TODO 709 | } 710 | 711 | const char *basenm = strrchr(path, '/'); 712 | if (basenm != NULL) 713 | { 714 | if (basenm[1]) 715 | { 716 | strcpy(finalname, &basenm[1]); 717 | } 718 | } 719 | 720 | snprintf(namebuf, bufsize, "%s", finalname); 721 | free(finalname); 722 | free(path); 723 | 724 | return strlen(namebuf); 725 | } 726 | 727 | void bootstap_nodes(Tox *tox, DHT_node nodes[], int number_of_nodes, int add_as_tcp_relay) 728 | { 729 | 730 | bool res = 0; 731 | for (size_t i = 0; (int)i < (int)number_of_nodes; i ++) 732 | { 733 | res = sodium_hex2bin(nodes[i].key_bin, sizeof(nodes[i].key_bin), 734 | nodes[i].key_hex, sizeof(nodes[i].key_hex)-1, NULL, NULL, NULL); 735 | // dbg(9, "sodium_hex2bin:res=%d\n", res); 736 | 737 | TOX_ERR_BOOTSTRAP error; 738 | res = tox_bootstrap(tox, nodes[i].ip, nodes[i].port, nodes[i].key_bin, &error); 739 | if (res != true) 740 | { 741 | if (error == TOX_ERR_BOOTSTRAP_OK) 742 | { 743 | // dbg(9, "bootstrap:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_OK\n", nodes[i].ip, nodes[i].port); 744 | } 745 | else if (error == TOX_ERR_BOOTSTRAP_NULL) 746 | { 747 | // dbg(9, "bootstrap:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_NULL\n", nodes[i].ip, nodes[i].port); 748 | } 749 | else if (error == TOX_ERR_BOOTSTRAP_BAD_HOST) 750 | { 751 | // dbg(9, "bootstrap:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_BAD_HOST\n", nodes[i].ip, nodes[i].port); 752 | } 753 | else if (error == TOX_ERR_BOOTSTRAP_BAD_PORT) 754 | { 755 | // dbg(9, "bootstrap:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_BAD_PORT\n", nodes[i].ip, nodes[i].port); 756 | } 757 | } 758 | else 759 | { 760 | // dbg(9, "bootstrap:%s %d [TRUE]res=%d\n", nodes[i].ip, nodes[i].port, res); 761 | } 762 | 763 | if (add_as_tcp_relay == 1) 764 | { 765 | res = tox_add_tcp_relay(tox, nodes[i].ip, nodes[i].port, nodes[i].key_bin, &error); // use also as TCP relay 766 | if (res != true) 767 | { 768 | if (error == TOX_ERR_BOOTSTRAP_OK) 769 | { 770 | // dbg(9, "add_tcp_relay:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_OK\n", nodes[i].ip, nodes[i].port); 771 | } 772 | else if (error == TOX_ERR_BOOTSTRAP_NULL) 773 | { 774 | // dbg(9, "add_tcp_relay:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_NULL\n", nodes[i].ip, nodes[i].port); 775 | } 776 | else if (error == TOX_ERR_BOOTSTRAP_BAD_HOST) 777 | { 778 | // dbg(9, "add_tcp_relay:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_BAD_HOST\n", nodes[i].ip, nodes[i].port); 779 | } 780 | else if (error == TOX_ERR_BOOTSTRAP_BAD_PORT) 781 | { 782 | // dbg(9, "add_tcp_relay:%s %d [FALSE]res=TOX_ERR_BOOTSTRAP_BAD_PORT\n", nodes[i].ip, nodes[i].port); 783 | } 784 | } 785 | else 786 | { 787 | // dbg(9, "add_tcp_relay:%s %d [TRUE]res=%d\n", nodes[i].ip, nodes[i].port, res); 788 | } 789 | } 790 | else 791 | { 792 | dbg(2, "Not adding any TCP relays\n"); 793 | } 794 | } 795 | } 796 | 797 | 798 | void bootstrap(Tox *tox) 799 | { 800 | 801 | // these nodes seem to be faster!! 802 | DHT_node nodes1[] = 803 | { 804 | {"178.62.250.138", 33445, "788236D34978D1D5BD822F0A5BEBD2C53C64CC31CD3149350EE27D4D9A2F9B6B", {0}}, 805 | {"51.15.37.145", 33445, "6FC41E2BD381D37E9748FC0E0328CE086AF9598BECC8FEB7DDF2E440475F300E", {0}}, 806 | {"130.133.110.14", 33445, "461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F", {0}}, 807 | {"23.226.230.47", 33445, "A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074", {0}}, 808 | {"163.172.136.118", 33445, "2C289F9F37C20D09DA83565588BF496FAB3764853FA38141817A72E3F18ACA0B", {0}}, 809 | {"217.182.143.254", 443, "7AED21F94D82B05774F697B209628CD5A9AD17E0C073D9329076A4C28ED28147", {0}}, 810 | {"185.14.30.213", 443, "2555763C8C460495B14157D234DD56B86300A2395554BCAE4621AC345B8C1B1B", {0}}, 811 | {"136.243.141.187", 443, "6EE1FADE9F55CC7938234CC07C864081FC606D8FE7B751EDA217F268F1078A39", {0}}, 812 | {"128.199.199.197", 33445, "B05C8869DBB4EDDD308F43C1A974A20A725A36EACCA123862FDE9945BF9D3E09", {0}}, 813 | {"198.46.138.44", 33445, "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67", {0}} 814 | }; 815 | 816 | 817 | // more nodes here, but maybe some issues 818 | DHT_node nodes2[] = 819 | { 820 | {"178.62.250.138", 33445, "788236D34978D1D5BD822F0A5BEBD2C53C64CC31CD3149350EE27D4D9A2F9B6B", {0}}, 821 | {"136.243.141.187", 443, "6EE1FADE9F55CC7938234CC07C864081FC606D8FE7B751EDA217F268F1078A39", {0}}, 822 | {"185.14.30.213", 443, "2555763C8C460495B14157D234DD56B86300A2395554BCAE4621AC345B8C1B1B", {0}}, 823 | {"198.46.138.44",33445,"F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67", {0}}, 824 | {"51.15.37.145",33445,"6FC41E2BD381D37E9748FC0E0328CE086AF9598BECC8FEB7DDF2E440475F300E", {0}}, 825 | {"130.133.110.14",33445,"461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F", {0}}, 826 | {"205.185.116.116",33445,"A179B09749AC826FF01F37A9613F6B57118AE014D4196A0E1105A98F93A54702", {0}}, 827 | {"198.98.51.198",33445,"1D5A5F2F5D6233058BF0259B09622FB40B482E4FA0931EB8FD3AB8E7BF7DAF6F", {0}}, 828 | {"108.61.165.198",33445,"8E7D0B859922EF569298B4D261A8CCB5FEA14FB91ED412A7603A585A25698832", {0}}, 829 | {"194.249.212.109",33445,"3CEE1F054081E7A011234883BC4FC39F661A55B73637A5AC293DDF1251D9432B", {0}}, 830 | {"185.25.116.107",33445,"DA4E4ED4B697F2E9B000EEFE3A34B554ACD3F45F5C96EAEA2516DD7FF9AF7B43", {0}}, 831 | {"5.189.176.217",5190,"2B2137E094F743AC8BD44652C55F41DFACC502F125E99E4FE24D40537489E32F", {0}}, 832 | {"217.182.143.254",2306,"7AED21F94D82B05774F697B209628CD5A9AD17E0C073D9329076A4C28ED28147", {0}}, 833 | {"104.223.122.15",33445,"0FB96EEBFB1650DDB52E70CF773DDFCABE25A95CC3BB50FC251082E4B63EF82A", {0}}, 834 | {"tox.verdict.gg",33445,"1C5293AEF2114717547B39DA8EA6F1E331E5E358B35F9B6B5F19317911C5F976", {0}}, 835 | {"d4rk4.ru",1813,"53737F6D47FA6BD2808F378E339AF45BF86F39B64E79D6D491C53A1D522E7039", {0}}, 836 | {"104.233.104.126",33445,"EDEE8F2E839A57820DE3DA4156D88350E53D4161447068A3457EE8F59F362414", {0}}, 837 | {"51.254.84.212",33445,"AEC204B9A4501412D5F0BB67D9C81B5DB3EE6ADA64122D32A3E9B093D544327D", {0}}, 838 | {"88.99.133.52",33445,"2D320F971EF2CA18004416C2AAE7BA52BF7949DB34EA8E2E21AF67BD367BE211", {0}}, 839 | {"185.58.206.164",33445,"24156472041E5F220D1FA11D9DF32F7AD697D59845701CDD7BE7D1785EB9DB39", {0}}, 840 | {"92.54.84.70",33445,"5625A62618CB4FCA70E147A71B29695F38CC65FF0CBD68AD46254585BE564802", {0}}, 841 | {"195.93.190.6",33445,"FB4CE0DDEFEED45F26917053E5D24BDDA0FA0A3D83A672A9DA2375928B37023D", {0}}, 842 | {"tox.uplinklabs.net",33445,"1A56EA3EDF5DF4C0AEABBF3C2E4E603890F87E983CAC8A0D532A335F2C6E3E1F", {0}}, 843 | {"toxnode.nek0.net",33445,"20965721D32CE50C3E837DD75B33908B33037E6225110BFF209277AEAF3F9639", {0}}, 844 | {"95.215.44.78",33445,"672DBE27B4ADB9D5FB105A6BB648B2F8FDB89B3323486A7A21968316E012023C", {0}}, 845 | {"163.172.136.118",33445,"2C289F9F37C20D09DA83565588BF496FAB3764853FA38141817A72E3F18ACA0B", {0}}, 846 | {"sorunome.de",33445,"02807CF4F8BB8FB390CC3794BDF1E8449E9A8392C5D3F2200019DA9F1E812E46", {0}}, 847 | {"37.97.185.116",33445,"E59A0E71ADA20D35BD1B0957059D7EF7E7792B3D680AE25C6F4DBBA09114D165", {0}}, 848 | {"193.124.186.205",5228,"9906D65F2A4751068A59D30505C5FC8AE1A95E0843AE9372EAFA3BAB6AC16C2C", {0}}, 849 | {"80.87.193.193",33445,"B38255EE4B054924F6D79A5E6E5889EC94B6ADF6FE9906F97A3D01E3D083223A", {0}}, 850 | {"initramfs.io",33445,"3F0A45A268367C1BEA652F258C85F4A66DA76BCAA667A49E770BCC4917AB6A25", {0}}, 851 | {"hibiki.eve.moe",33445,"D3EB45181B343C2C222A5BCF72B760638E15ED87904625AAD351C594EEFAE03E", {0}}, 852 | {"tox.deadteam.org",33445,"C7D284129E83877D63591F14B3F658D77FF9BA9BA7293AEB2BDFBFE1A803AF47", {0}}, 853 | {"46.229.52.198",33445,"813C8F4187833EF0655B10F7752141A352248462A567529A38B6BBF73E979307", {0}}, 854 | {"node.tox.ngc.network",33445,"A856243058D1DE633379508ADCAFCF944E40E1672FF402750EF712E30C42012A", {0}}, 855 | {"144.217.86.39",33445,"7E5668E0EE09E19F320AD47902419331FFEE147BB3606769CFBE921A2A2FD34C", {0}}, 856 | {"185.14.30.213",443,"2555763C8C460495B14157D234DD56B86300A2395554BCAE4621AC345B8C1B1B", {0}}, 857 | {"77.37.160.178",33440,"CE678DEAFA29182EFD1B0C5B9BC6999E5A20B50A1A6EC18B91C8EBB591712416", {0}}, 858 | {"85.21.144.224",33445,"8F738BBC8FA9394670BCAB146C67A507B9907C8E564E28C2B59BEBB2FF68711B", {0}}, 859 | {"tox.natalenko.name",33445,"1CB6EBFD9D85448FA70D3CAE1220B76BF6FCE911B46ACDCF88054C190589650B", {0}}, 860 | {"37.187.122.30",33445,"BEB71F97ED9C99C04B8489BB75579EB4DC6AB6F441B603D63533122F1858B51D", {0}}, 861 | {"completelyunoriginal.moe",33445,"FBC7DED0B0B662D81094D91CC312D6CDF12A7B16C7FFB93817143116B510C13E", {0}}, 862 | {"136.243.141.187",443,"6EE1FADE9F55CC7938234CC07C864081FC606D8FE7B751EDA217F268F1078A39", {0}}, 863 | {"tox.abilinski.com",33445,"0E9D7FEE2AA4B42A4C18FE81C038E32FFD8D907AAA7896F05AA76C8D31A20065", {0}}, 864 | {"95.215.46.114",33445,"5823FB947FF24CF83DDFAC3F3BAA18F96EA2018B16CC08429CB97FA502F40C23", {0}}, 865 | {"51.15.54.207",33445,"1E64DBA45EC810C0BF3A96327DC8A9D441AB262C14E57FCE11ECBCE355305239", {0}} 866 | }; 867 | 868 | // only nodes.tox.chat 869 | DHT_node nodes3[] = 870 | { 871 | {"51.15.37.145", 33445, "6FC41E2BD381D37E9748FC0E0328CE086AF9598BECC8FEB7DDF2E440475F300E", {0}} 872 | }; 873 | 874 | 875 | if (switch_nodelist_2 == 0) 876 | { 877 | dbg(9, "nodeslist:1\n"); 878 | bootstap_nodes(tox, &nodes1, (int)(sizeof(nodes1)/sizeof(DHT_node)), 1); 879 | } 880 | else if (switch_nodelist_2 == 2) 881 | { 882 | dbg(9, "nodeslist:3\n"); 883 | bootstap_nodes(tox, &nodes3, (int)(sizeof(nodes3)/sizeof(DHT_node)), 0); 884 | } 885 | else // (switch_nodelist_2 == 1) 886 | { 887 | dbg(9, "nodeslist:2\n"); 888 | bootstap_nodes(tox, &nodes2, (int)(sizeof(nodes2)/sizeof(DHT_node)), 1); 889 | } 890 | } 891 | 892 | 893 | // fill string with toxid in upper case hex. 894 | // size of toxid_str needs to be: [TOX_ADDRESS_SIZE*2 + 1] !! 895 | void get_my_toxid(Tox *tox, char *toxid_str) 896 | { 897 | uint8_t tox_id_bin[TOX_ADDRESS_SIZE]; 898 | tox_self_get_address(tox, tox_id_bin); 899 | 900 | char tox_id_hex_local[TOX_ADDRESS_SIZE*2 + 1]; 901 | sodium_bin2hex(tox_id_hex_local, sizeof(tox_id_hex_local), tox_id_bin, sizeof(tox_id_bin)); 902 | 903 | for (size_t i = 0; i < sizeof(tox_id_hex_local)-1; i ++) 904 | { 905 | tox_id_hex_local[i] = toupper(tox_id_hex_local[i]); 906 | } 907 | 908 | snprintf(toxid_str, (size_t)(TOX_ADDRESS_SIZE*2 + 1), "%s", (const char*)tox_id_hex_local); 909 | } 910 | 911 | void print_tox_id(Tox *tox) 912 | { 913 | char tox_id_hex[TOX_ADDRESS_SIZE*2 + 1]; 914 | get_my_toxid(tox, tox_id_hex); 915 | 916 | if (logfile) 917 | { 918 | dbg(2, "--MyToxID--:%s\n", tox_id_hex); 919 | int fd = fileno(logfile); 920 | fsync(fd); 921 | } 922 | } 923 | 924 | int is_friend_online(Tox *tox, uint32_t num) 925 | { 926 | int j = find_friend_in_friendlist(num); 927 | switch (Friends.list[j].connection_status) 928 | { 929 | case TOX_CONNECTION_NONE: 930 | return 0; 931 | break; 932 | case TOX_CONNECTION_TCP: 933 | return 1; 934 | break; 935 | case TOX_CONNECTION_UDP: 936 | return 1; 937 | break; 938 | default: 939 | return 0; 940 | break; 941 | } 942 | } 943 | 944 | static int find_friend_in_friendlist(uint32_t friendnum) 945 | { 946 | int i; 947 | 948 | for (i = 0; i <= Friends.max_idx; ++i) 949 | { 950 | if (Friends.list[i].num == friendnum) 951 | { 952 | return i; 953 | } 954 | } 955 | 956 | return -1; 957 | } 958 | 959 | static void update_friend_last_online(uint32_t num, time_t timestamp) 960 | { 961 | int friendlistnum = find_friend_in_friendlist(num); 962 | 963 | Friends.list[friendlistnum].last_online.last_on = timestamp; 964 | Friends.list[friendlistnum].last_online.tm = *localtime((const time_t *)×tamp); 965 | 966 | /* if the format changes make sure TIME_STR_SIZE is the correct size !! */ 967 | strftime(Friends.list[friendlistnum].last_online.hour_min_str, TIME_STR_SIZE, global_timestamp_format, &Friends.list[friendlistnum].last_online.tm); 968 | } 969 | 970 | void send_file_to_friend_real(Tox *m, uint32_t num, const char* filename, int resume, uint8_t* fileid_resume) 971 | { 972 | // ------- hack to send file -------- 973 | // ------- hack to send file -------- 974 | const char *errmsg = NULL; 975 | char path[MAX_STR_SIZE]; 976 | 977 | snprintf(path, sizeof(path), "%s", filename); 978 | dbg(2, "send_file_to_friend_real:path=%s\n", path); 979 | 980 | FILE *file_to_send = fopen(path, "r"); 981 | 982 | if (file_to_send == NULL) 983 | { 984 | dbg(0, "send_file_to_friend_real:error opening file\n"); 985 | return; 986 | } 987 | 988 | off_t filesize = file_size(path); 989 | 990 | if (filesize == 0) 991 | { 992 | dbg(0, "send_file_to_friend_real:filesize 0\n"); 993 | fclose(file_to_send); 994 | return; 995 | } 996 | 997 | char file_name[TOX_MAX_FILENAME_LENGTH]; 998 | size_t namelen = get_file_name(file_name, sizeof(file_name), path); 999 | 1000 | TOX_ERR_FILE_SEND err; 1001 | 1002 | char *o = calloc(1, (size_t)TOX_FILE_ID_LENGTH); 1003 | uint32_t filenum = -1; 1004 | if (resume == 0) 1005 | { 1006 | dbg(9, "resume == 0\n"); 1007 | random_char(o, (int)TOX_FILE_ID_LENGTH); 1008 | 1009 | filenum = tox_file_send(m, num, TOX_FILE_KIND_DATA, (uint64_t)filesize, (uint8_t*)o, 1010 | (uint8_t *)file_name, namelen, &err); 1011 | } 1012 | else 1013 | { 1014 | dbg(9, "resume == 1\n"); 1015 | 1016 | filenum = tox_file_send(m, num, TOX_FILE_KIND_DATA, (uint64_t)filesize, fileid_resume, 1017 | (uint8_t *)file_name, namelen, &err); 1018 | } 1019 | dbg(2, "send_file_to_friend:tox_file_send=%s filenum=%d\n", file_name, (int)filenum); 1020 | 1021 | if (err != TOX_ERR_FILE_SEND_OK) 1022 | { 1023 | dbg(0, "send_file_to_friend_real: ! TOX_ERR_FILE_SEND_OK\n"); 1024 | goto on_send_error; 1025 | } 1026 | 1027 | dbg(2, "send_file_to_friend_real(1):tox_file_send=%s filenum=%d\n", file_name, (int)filenum); 1028 | struct FileTransfer *ft = new_file_transfer(num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA); 1029 | dbg(2, "send_file_to_friend_real(2):tox_file_send=%s filenum=%d\n", file_name, (int)filenum); 1030 | 1031 | if (!ft) 1032 | { 1033 | dbg(0, "send_file_to_friend_real:ft=NULL\n"); 1034 | err = TOX_ERR_FILE_SEND_TOO_MANY; 1035 | goto on_send_error; 1036 | } 1037 | 1038 | memcpy(ft->file_name, file_name, namelen + 1); 1039 | ft->file = file_to_send; 1040 | ft->file_size = filesize; 1041 | 1042 | if (resume == 0) 1043 | { 1044 | dbg(9, "resume == 0\n"); 1045 | memcpy(ft->file_id, o, (size_t)TOX_FILE_ID_LENGTH); 1046 | } 1047 | else 1048 | { 1049 | dbg(9, "resume == 1\n"); 1050 | memcpy(ft->file_id, fileid_resume, (size_t)TOX_FILE_ID_LENGTH); 1051 | } 1052 | 1053 | dbg(0, "send_file_to_friend_real:tox_file_get_file_id num=%d filenum=%d\n", (int)num, (int)filenum); 1054 | dbg(0, "send_file_to_friend_real:file_id_resume=%d ft->file_id=%d\n", (int)fileid_resume, (int)ft->file_id); 1055 | dbg(0, "send_file_to_friend_real:o=%d ft->file_id=%d\n", (int)o, (int)ft->file_id); 1056 | 1057 | char file_id_str[TOX_FILE_ID_LENGTH * 2 + 1]; 1058 | bin_id_to_string_all((char*)ft->file_id, (size_t)TOX_FILE_ID_LENGTH, file_id_str, (size_t)(TOX_FILE_ID_LENGTH * 2 + 1)); 1059 | dbg(2, "send_file_to_friend_real:file_id=%s\n", file_id_str); 1060 | bin_id_to_string_all((char*)fileid_resume, (size_t)TOX_FILE_ID_LENGTH, file_id_str, (size_t)(TOX_FILE_ID_LENGTH * 2 + 1)); 1061 | dbg(2, "send_file_to_friend_real:fileid_resume=%s\n", file_id_str); 1062 | bin_id_to_string_all((char*)o, (size_t)TOX_FILE_ID_LENGTH, file_id_str, (size_t)(TOX_FILE_ID_LENGTH * 2 + 1)); 1063 | dbg(2, "send_file_to_friend_real:o=%s\n", file_id_str); 1064 | 1065 | free(o); 1066 | o = NULL; 1067 | 1068 | return; 1069 | 1070 | on_send_error: 1071 | 1072 | free(o); 1073 | o = NULL; 1074 | 1075 | switch (err) 1076 | { 1077 | case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: 1078 | errmsg = "File transfer failed: Invalid friend."; 1079 | break; 1080 | 1081 | case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED: 1082 | errmsg = "File transfer failed: Friend is offline."; 1083 | 1084 | break; 1085 | 1086 | case TOX_ERR_FILE_SEND_NAME_TOO_LONG: 1087 | errmsg = "File transfer failed: Filename is too long."; 1088 | break; 1089 | 1090 | case TOX_ERR_FILE_SEND_TOO_MANY: 1091 | errmsg = "File transfer failed: Too many concurrent file transfers."; 1092 | 1093 | break; 1094 | 1095 | default: 1096 | errmsg = "File transfer failed."; 1097 | break; 1098 | } 1099 | 1100 | dbg(0, "send_file_to_friend_real:ft error=%s\n", errmsg); 1101 | tox_file_control(m, num, filenum, TOX_FILE_CONTROL_CANCEL, NULL); 1102 | fclose(file_to_send); 1103 | 1104 | // ------- hack to send file -------- 1105 | // ------- hack to send file -------- 1106 | } 1107 | 1108 | void resume_file_to_friend(Tox *m, uint32_t num, struct FileTransfer* ft) 1109 | { 1110 | char *file_name_incl_full_path = NULL; 1111 | int j = find_friend_in_friendlist(ft->friendnum); 1112 | 1113 | if (j > -1) 1114 | { 1115 | file_name_incl_full_path = malloc(300); 1116 | snprintf(file_name_incl_full_path, 299, "%s/%s", (const char*)Friends.list[j].worksubdir, ft->file_name); 1117 | dbg(2, "resume_file_to_friend:full path=%s\n", file_name_incl_full_path); 1118 | char file_id_str[TOX_FILE_ID_LENGTH * 2 + 1]; 1119 | bin_id_to_string_all((char*)ft->file_id, (size_t)TOX_FILE_ID_LENGTH, file_id_str, (size_t)(TOX_FILE_ID_LENGTH * 2 + 1)); 1120 | dbg(2, "resume_file_to_friend:file_id=%d file_id_bin=%d\n", (int)file_id_str, (int)ft->file_id); 1121 | dbg(2, "resume_file_to_friend:file_id=%s\n", file_id_str); 1122 | 1123 | dbg(2, "resume_file_to_friend:path=%s friendnum=%d filenum=%d\n", file_name_incl_full_path, (int)ft->friendnum, (int)ft->filenum); 1124 | send_file_to_friend_real(m, ft->friendnum, file_name_incl_full_path, 1, ft->file_id); 1125 | } 1126 | else 1127 | { 1128 | dbg(0, "resume_file_to_friend:friend %d not found in friendlist\n", (int)ft->friendnum); 1129 | } 1130 | } 1131 | 1132 | void send_file_to_friend(Tox *m, uint32_t num, const char* filename) 1133 | { 1134 | send_file_to_friend_real(m, num, filename, 0, NULL); 1135 | } 1136 | 1137 | 1138 | int copy_file(const char *from, const char *to) 1139 | { 1140 | int fd_to, fd_from; 1141 | char buf[4096]; 1142 | ssize_t nread; 1143 | int saved_errno; 1144 | 1145 | fd_from = open(from, O_RDONLY); 1146 | 1147 | if (fd_from < 0) 1148 | { 1149 | dbg(0, "copy_file:002\n"); 1150 | return -1; 1151 | } 1152 | 1153 | fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666); 1154 | if (fd_to < 0) 1155 | { 1156 | dbg(0, "copy_file:003\n"); 1157 | goto out_error; 1158 | } 1159 | 1160 | while (nread = read(fd_from, buf, sizeof buf), nread > 0) 1161 | { 1162 | char *out_ptr = buf; 1163 | ssize_t nwritten; 1164 | 1165 | do 1166 | { 1167 | nwritten = write(fd_to, out_ptr, nread); 1168 | 1169 | if (nwritten >= 0) 1170 | { 1171 | nread -= nwritten; 1172 | out_ptr += nwritten; 1173 | } 1174 | else if (errno != EINTR) 1175 | { 1176 | dbg(0, "copy_file:004\n"); 1177 | goto out_error; 1178 | } 1179 | 1180 | } while (nread > 0); 1181 | } 1182 | 1183 | if (nread == 0) 1184 | { 1185 | if (close(fd_to) < 0) 1186 | { 1187 | fd_to = -1; 1188 | dbg(0, "copy_file:005\n"); 1189 | goto out_error; 1190 | } 1191 | 1192 | close(fd_from); 1193 | 1194 | /* Success! */ 1195 | return 0; 1196 | } 1197 | 1198 | 1199 | out_error: 1200 | saved_errno = errno; 1201 | 1202 | close(fd_from); 1203 | if (fd_to >= 0) 1204 | { 1205 | close(fd_to); 1206 | } 1207 | 1208 | dbg(0, "copy_file:009\n"); 1209 | 1210 | errno = saved_errno; 1211 | return -1; 1212 | } 1213 | 1214 | 1215 | 1216 | char* copy_file_to_friend_subdir(int friendlistnum, const char* file_with_path, const char* filename) 1217 | { 1218 | } 1219 | 1220 | int have_resumed_fts_friend(uint32_t friendnum) 1221 | { 1222 | int j = find_friend_in_friendlist(friendnum); 1223 | 1224 | if (Friends.list[j].have_resumed_fts == 1) 1225 | { 1226 | return 1; 1227 | } 1228 | else 1229 | { 1230 | return 0; 1231 | } 1232 | } 1233 | 1234 | void send_file_to_all_friends(Tox *m, const char* file_with_path, const char* filename) 1235 | { 1236 | } 1237 | 1238 | void on_tox_friend_status(Tox *tox, uint32_t friend_number, TOX_USER_STATUS status, void *user_data) 1239 | { 1240 | dbg(2, "on_tox_friend_status:friendnum=%d status=%d\n", (int)friend_number, (int)status); 1241 | } 1242 | 1243 | void friendlist_onConnectionChange(Tox *m, uint32_t num, TOX_CONNECTION connection_status, void *user_data) 1244 | { 1245 | int friendlistnum = find_friend_in_friendlist(num); 1246 | dbg(2, "friendlist_onConnectionChange:*ENTER*:friendnum=%d %d\n", (int)num, (int)connection_status); 1247 | 1248 | Friends.list[friendlistnum].connection_status = connection_status; 1249 | update_friend_last_online(num, get_unix_time()); 1250 | 1251 | if (is_friend_online(m, num) == 1) 1252 | { 1253 | dbg(0, "friend %d just got online\n", num); 1254 | 1255 | resume_resumable_fts(m, num); 1256 | 1257 | if (avatar_send(m, num) == -1) 1258 | { 1259 | dbg(0, "avatar_send failed for friend %d\n", num); 1260 | } 1261 | } 1262 | else 1263 | { 1264 | dbg(0, "friend %d went *OFFLINE*\n", num); 1265 | 1266 | // save all resumeable FTs 1267 | save_resumable_fts(m, num); 1268 | // friend went offline -> cancel all filetransfers 1269 | kill_all_file_transfers_friend(m, num); 1270 | // friend went offline -> hang up on all calls 1271 | av_local_disconnect(mytox_av, num); 1272 | } 1273 | 1274 | dbg(2, "friendlist_onConnectionChange:*READY*:friendnum=%d %d\n", (int)num, (int)connection_status); 1275 | 1276 | } 1277 | 1278 | void friendlist_onFriendAdded(Tox *m, uint32_t num, bool sort) 1279 | { 1280 | // dbg(9, "friendlist_onFriendAdded:001\n"); 1281 | 1282 | if (Friends.max_idx == 0) 1283 | { 1284 | // dbg(9, "friendlist_onFriendAdded:001.a malloc 1 friend struct, max_id=%d, num=%d\n", (int)Friends.max_idx, (int)num); 1285 | Friends.list = malloc(sizeof(ToxicFriend)); 1286 | } 1287 | else 1288 | { 1289 | // dbg(9, "friendlist_onFriendAdded:001.b realloc %d friend struct, max_id=%d, num=%d\n", (int)(Friends.max_idx + 1), (int)Friends.max_idx, (int)num); 1290 | Friends.list = realloc(Friends.list, ((Friends.max_idx + 1) * sizeof(ToxicFriend))); 1291 | } 1292 | 1293 | // dbg(9, "friendlist_onFriendAdded:001.c set friend to all 0 values\n"); 1294 | memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend)); // fill friend with "0" bytes 1295 | 1296 | 1297 | // dbg(2, "friendlist_onFriendAdded:003:%d\n", (int)Friends.max_idx); 1298 | Friends.list[Friends.max_idx].num = num; 1299 | Friends.list[Friends.max_idx].active = true; 1300 | Friends.list[Friends.max_idx].connection_status = TOX_CONNECTION_NONE; 1301 | Friends.list[Friends.max_idx].status = TOX_USER_STATUS_NONE; 1302 | Friends.list[Friends.max_idx].waiting_for_answer = 0; 1303 | Friends.list[Friends.max_idx].auto_resend_start_time = 0; 1304 | Friends.list[Friends.max_idx].have_resumed_fts = 0; 1305 | 1306 | TOX_ERR_FRIEND_GET_PUBLIC_KEY pkerr; 1307 | tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[Friends.max_idx].pub_key, &pkerr); 1308 | 1309 | if (pkerr != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK) 1310 | { 1311 | dbg(0, "tox_friend_get_public_key failed (error %d)\n", pkerr); 1312 | } 1313 | 1314 | bin_id_to_string(Friends.list[Friends.max_idx].pub_key, (size_t) TOX_ADDRESS_SIZE, Friends.list[Friends.max_idx].pubkey_string, (size_t) (TOX_ADDRESS_SIZE * 2 + 1)); 1315 | // dbg(2, "friend pubkey=%s\n", Friends.list[Friends.max_idx].pubkey_string); 1316 | 1317 | TOX_ERR_FRIEND_GET_LAST_ONLINE loerr; 1318 | time_t t = tox_friend_get_last_online(m, num, &loerr); 1319 | 1320 | if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK) 1321 | { 1322 | t = 0; 1323 | } 1324 | 1325 | update_friend_last_online(num, t); 1326 | 1327 | Friends.max_idx++; 1328 | 1329 | } 1330 | 1331 | // after you are finished call free_friendlist_nums ! 1332 | uint32_t* load_friendlist_nums(Tox *m) 1333 | { 1334 | size_t numfriends = tox_self_get_friend_list_size(m); 1335 | uint32_t *friend_list = malloc(numfriends * sizeof(uint32_t)); 1336 | tox_self_get_friend_list(m, friend_list); 1337 | 1338 | return friend_list; 1339 | } 1340 | 1341 | void free_friendlist_nums(void* friend_list) 1342 | { 1343 | if (friend_list) 1344 | { 1345 | free(friend_list); 1346 | friend_list = NULL; 1347 | } 1348 | } 1349 | 1350 | static void load_friendlist(Tox *m) 1351 | { 1352 | size_t i; 1353 | // TODO 1354 | size_t numfriends = tox_self_get_friend_list_size(m); 1355 | uint32_t* friend_lookup_list = load_friendlist_nums(m); 1356 | 1357 | for (i = 0; i < numfriends; ++i) 1358 | { 1359 | friendlist_onFriendAdded(m, friend_lookup_list[i], false); 1360 | dbg(2, "loading friend num:%d pubkey=%s\n", (int)friend_lookup_list[i], Friends.list[Friends.max_idx - 1].pubkey_string); 1361 | } 1362 | 1363 | free_friendlist_nums((void*) friend_lookup_list); 1364 | } 1365 | 1366 | 1367 | 1368 | 1369 | void close_file_transfer(Tox *m, struct FileTransfer *ft, int CTRL) 1370 | { 1371 | dbg(9, "close_file_transfer:001\n"); 1372 | 1373 | if (!ft) 1374 | { 1375 | return; 1376 | } 1377 | 1378 | if (ft->state == FILE_TRANSFER_INACTIVE) 1379 | { 1380 | return; 1381 | } 1382 | 1383 | if (ft->file) 1384 | { 1385 | fclose(ft->file); 1386 | } 1387 | 1388 | if (CTRL >= 0) 1389 | { 1390 | tox_file_control(m, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) CTRL, NULL); 1391 | } 1392 | 1393 | memset(ft, 0, sizeof(struct FileTransfer)); 1394 | ft->state = FILE_TRANSFER_INACTIVE; // == 0 1395 | 1396 | } 1397 | 1398 | int has_reached_max_file_transfer_for_friend(uint32_t num) 1399 | { 1400 | int active_ft = 0; 1401 | int friendlistnum = find_friend_in_friendlist(num); 1402 | int i; 1403 | 1404 | for (i = 0; i < MAX_FILES; ++i) 1405 | { 1406 | struct FileTransfer *ft_send = &Friends.list[friendlistnum].file_sender[i]; 1407 | 1408 | if (ft_send->state != FILE_TRANSFER_INACTIVE) 1409 | { 1410 | if (ft_send->file_name != NULL) 1411 | { 1412 | active_ft++; 1413 | } 1414 | } 1415 | } 1416 | 1417 | if (active_ft < MAX_FILES) 1418 | { 1419 | return 0; 1420 | } 1421 | else 1422 | { 1423 | // have reached max filetransfers already 1424 | return 1; 1425 | } 1426 | } 1427 | 1428 | struct FileTransfer *get_file_transfer_from_filename_struct(int friendlistnum, const char* filename) 1429 | { 1430 | size_t i; 1431 | 1432 | for (i = 0; i < MAX_FILES; ++i) 1433 | { 1434 | struct FileTransfer *ft_send = &Friends.list[friendlistnum].file_sender[i]; 1435 | 1436 | if (ft_send->state != FILE_TRANSFER_INACTIVE) 1437 | { 1438 | if (ft_send->file_name != NULL) 1439 | { 1440 | if ((strlen(ft_send->file_name) > 0) && (filename != NULL) && (strlen(filename) > 0)) 1441 | { 1442 | if (strncmp((char*)ft_send->file_name, filename, strlen(ft_send->file_name)) == 0) 1443 | { 1444 | // dbg(9, "found ft by filename:%s\n", ft_send->file_name); 1445 | return ft_send; 1446 | } 1447 | } 1448 | } 1449 | } 1450 | } 1451 | 1452 | return NULL; 1453 | } 1454 | 1455 | 1456 | struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum) 1457 | { 1458 | size_t i; 1459 | 1460 | int friendlistnum = find_friend_in_friendlist(friendnum); 1461 | 1462 | for (i = 0; i < MAX_FILES; ++i) 1463 | { 1464 | struct FileTransfer *ft_send = &Friends.list[friendlistnum].file_sender[i]; 1465 | 1466 | if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum) 1467 | { 1468 | return ft_send; 1469 | } 1470 | 1471 | struct FileTransfer *ft_recv = &Friends.list[friendlistnum].file_receiver[i]; 1472 | 1473 | if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum) 1474 | { 1475 | return ft_recv; 1476 | } 1477 | } 1478 | 1479 | return NULL; 1480 | } 1481 | 1482 | // 1483 | // cut message at 999 chars length !! 1484 | // 1485 | void send_text_message_to_friend(Tox *tox, uint32_t friend_number, const char *fmt, ...) 1486 | { 1487 | char msg2[1000]; 1488 | size_t length = 0; 1489 | 1490 | if (fmt == NULL) 1491 | { 1492 | dbg(9, "send_text_message_to_friend:no message to send\n"); 1493 | return; 1494 | } 1495 | 1496 | va_list ap; 1497 | va_start(ap, fmt); 1498 | vsnprintf(msg2, 999, fmt, ap); 1499 | va_end(ap); 1500 | 1501 | length = (size_t)strlen(msg2); 1502 | tox_friend_send_message(tox, friend_number, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *)msg2, length, NULL); 1503 | } 1504 | 1505 | 1506 | void friend_request_cb(Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length, 1507 | void *user_data) 1508 | { 1509 | uint32_t friendnum = tox_friend_add_norequest(tox, public_key, NULL); 1510 | dbg(2, "add friend:002:friendnum=%d max_id=%d\n", friendnum, (int)Friends.max_idx); 1511 | friendlist_onFriendAdded(tox, friendnum, 0); 1512 | 1513 | update_savedata_file(tox); 1514 | } 1515 | 1516 | /* ssssshhh I stole this from ToxBot, don't tell anyone.. */ 1517 | /* ssssshhh and I stole this from EchoBot, don't tell anyone.. */ 1518 | static void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs) 1519 | { 1520 | long unsigned int minutes = (secs % 3600) / 60; 1521 | long unsigned int hours = (secs / 3600) % 24; 1522 | long unsigned int days = (secs / 3600) / 24; 1523 | 1524 | snprintf(buf, bufsize, "%lud %luh %lum", days, hours, minutes); 1525 | } 1526 | 1527 | // 1528 | // lastline param ignored for now!! 1529 | // 1530 | void run_cmd_return_output(const char *command, char* output, int lastline) 1531 | { 1532 | FILE *fp = NULL; 1533 | char path[1035]; 1534 | char *pos = NULL; 1535 | 1536 | if (!output) 1537 | { 1538 | return; 1539 | } 1540 | 1541 | /* Open the command for reading. */ 1542 | fp = popen(command, "r"); 1543 | if (fp == NULL) 1544 | { 1545 | dbg(0, "Failed to run command: %s errno=%d error=%s\n", command, errno, strerror(errno)); 1546 | output[0] = '\0'; 1547 | return; 1548 | } 1549 | 1550 | /* Read the output a line at a time - output it. */ 1551 | while (fgets(path, sizeof(path)-1, fp) != NULL) 1552 | { 1553 | snprintf(output, 299, "%s", (const char*)path); 1554 | } 1555 | 1556 | if (strlen(output) > 1) 1557 | { 1558 | if ((pos = strchr(output, '\n')) != NULL) 1559 | { 1560 | *pos = '\0'; 1561 | } 1562 | } 1563 | 1564 | /* close */ 1565 | pclose(fp); 1566 | } 1567 | 1568 | void remove_friend(Tox *tox, uint32_t friend_number) 1569 | { 1570 | TOX_ERR_FRIEND_DELETE error; 1571 | tox_friend_delete(tox, friend_number, &error); 1572 | } 1573 | 1574 | void cmd_delfriend(Tox *tox, uint32_t friend_number, const char* message) 1575 | { 1576 | uint32_t del_friend_number = -1; 1577 | if (friend_number != del_friend_number) 1578 | { 1579 | // remove_friend(tox, del_friend_number); 1580 | } 1581 | } 1582 | 1583 | void cmd_stats(Tox *tox, uint32_t friend_number) 1584 | { 1585 | switch (my_connection_status) 1586 | { 1587 | case TOX_CONNECTION_NONE: 1588 | send_text_message_to_friend(tox, friend_number, "tox_tcp_relay status:offline"); 1589 | break; 1590 | case TOX_CONNECTION_TCP: 1591 | send_text_message_to_friend(tox, friend_number, "tox_tcp_relay status:Online, using TCP"); 1592 | break; 1593 | case TOX_CONNECTION_UDP: 1594 | send_text_message_to_friend(tox, friend_number, "tox_tcp_relay status:Online, using UDP"); 1595 | break; 1596 | default: 1597 | send_text_message_to_friend(tox, friend_number, "tox_tcp_relay status:*unknown*"); 1598 | break; 1599 | } 1600 | 1601 | // ----- uptime ----- 1602 | char time_str[200]; 1603 | uint64_t cur_time = time(NULL); 1604 | get_elapsed_time_str(time_str, sizeof(time_str), cur_time - global_start_time); 1605 | send_text_message_to_friend(tox, friend_number, "Uptime: %s", time_str); 1606 | // ----- uptime ----- 1607 | 1608 | char output_str[1000]; 1609 | run_cmd_return_output(shell_cmd__get_my_number_of_open_files, output_str, 1); 1610 | if (strlen(output_str) > 0) 1611 | { 1612 | send_text_message_to_friend(tox, friend_number, "toxcam open files:%s", output_str); 1613 | } 1614 | else 1615 | { 1616 | send_text_message_to_friend(tox, friend_number, "ERROR getting open files"); 1617 | } 1618 | 1619 | // --- temp --- 1620 | run_cmd_return_output(shell_cmd__get_cpu_temp, output_str, 1); 1621 | if (strlen(output_str) > 0) 1622 | { 1623 | send_text_message_to_friend(tox, friend_number, "toxcam Cpu temp:%s\xC2\xB0%s", output_str, "C"); 1624 | } 1625 | else 1626 | { 1627 | send_text_message_to_friend(tox, friend_number, "ERROR getting Cpu temp"); 1628 | } 1629 | 1630 | run_cmd_return_output(shell_cmd__get_gpu_temp, output_str, 1); 1631 | if (strlen(output_str) > 0) 1632 | { 1633 | send_text_message_to_friend(tox, friend_number, "toxcam GPU temp:%s\xC2\xB0%s", output_str, "C"); 1634 | } 1635 | else 1636 | { 1637 | send_text_message_to_friend(tox, friend_number, "ERROR getting GPU temp"); 1638 | } 1639 | // --- temp --- 1640 | 1641 | char tox_id_hex[TOX_ADDRESS_SIZE*2 + 1]; 1642 | get_my_toxid(tox, tox_id_hex); 1643 | 1644 | send_text_message_to_friend(tox, friend_number, "tox:%s", tox_id_hex); 1645 | } 1646 | 1647 | void cmd_kamft(Tox *tox, uint32_t friend_number) 1648 | { 1649 | send_text_message_to_friend(tox, friend_number, "killing all filetransfers to you ..."); 1650 | kill_all_file_transfers_friend(tox, friend_number); 1651 | } 1652 | 1653 | void cmd_snap(Tox *tox, uint32_t friend_number) 1654 | { 1655 | send_text_message_to_friend(tox, friend_number, "*Feature DISABLED*"); 1656 | 1657 | if (1 == 1 + 1) 1658 | { 1659 | send_text_message_to_friend(tox, friend_number, "capture single shot, and send to all friends ..."); 1660 | 1661 | char output_str[1000]; 1662 | run_cmd_return_output(shell_cmd__single_shot, output_str, 1); 1663 | 1664 | #if 0 1665 | if (strlen(output_str) > 0) 1666 | { 1667 | // send_text_message_to_friend(tox, friend_number, "toxcam:%s", output_str); 1668 | } 1669 | else 1670 | { 1671 | send_text_message_to_friend(tox, friend_number, "ERROR running snap command"); 1672 | } 1673 | #endif 1674 | 1675 | send_text_message_to_friend(tox, friend_number, "... capture single shot, ready!"); 1676 | 1677 | } 1678 | } 1679 | 1680 | void cmd_friends(Tox *tox, uint32_t friend_number) 1681 | { 1682 | size_t i; 1683 | // TODO 1684 | size_t numfriends = tox_self_get_friend_list_size(tox); 1685 | int j = -1; 1686 | 1687 | for (i = 0; i < numfriends; ++i) 1688 | { 1689 | j = find_friend_in_friendlist((uint32_t) i); 1690 | if (j > -1) 1691 | { 1692 | send_text_message_to_friend(tox, friend_number, "%d:friend", j); 1693 | send_text_message_to_friend(tox, friend_number, "%d tox:%s", j, (const char*)Friends.list[j].pubkey_string); 1694 | send_text_message_to_friend(tox, friend_number, "%d:last online (in client local time):%s", j, (const char*)Friends.list[j].last_online.hour_min_str); 1695 | 1696 | switch (Friends.list[j].connection_status) 1697 | { 1698 | case TOX_CONNECTION_NONE: 1699 | send_text_message_to_friend(tox, friend_number, "%d:%s", j, "status:offline"); 1700 | break; 1701 | case TOX_CONNECTION_TCP: 1702 | send_text_message_to_friend(tox, friend_number, "%d:%s", j, "status:Online, using TCP"); 1703 | break; 1704 | case TOX_CONNECTION_UDP: 1705 | send_text_message_to_friend(tox, friend_number, "%d:%s", j, "status:Online, using UDP"); 1706 | break; 1707 | default: 1708 | send_text_message_to_friend(tox, friend_number, "%d:%s", j, "status:*unknown*"); 1709 | break; 1710 | } 1711 | } 1712 | } 1713 | } 1714 | 1715 | void cmd_restart(Tox *tox, uint32_t friend_number) 1716 | { 1717 | send_text_message_to_friend(tox, friend_number, "toxcam services will restart ..."); 1718 | 1719 | global_want_restart = 1; 1720 | } 1721 | 1722 | 1723 | void cmd_vcm(Tox *tox, uint32_t friend_number) 1724 | { 1725 | // send_text_message_to_friend(tox, friend_number, "video-call-me not yet implemented!"); 1726 | 1727 | dbg(9, "cmd_vcm:001\n"); 1728 | 1729 | if (global_video_active == 1) 1730 | { 1731 | send_text_message_to_friend(tox, friend_number, "there is already a video session active"); 1732 | } 1733 | else 1734 | { 1735 | send_text_message_to_friend(tox, friend_number, "i am trying to send my video ..."); 1736 | 1737 | if (mytox_av != NULL) 1738 | { 1739 | dbg(9, "cmd_vcm:003\n"); 1740 | global_video_bit_rate = DEFAULT_GLOBAL_VID_BITRATE; 1741 | friend_to_send_video_to = friend_number; 1742 | dbg(9, "cmd_vcm:004\n"); 1743 | 1744 | TOXAV_ERR_CALL error = 0; 1745 | toxav_call(mytox_av, friend_number, global_audio_bit_rate, global_video_bit_rate, &error); 1746 | // toxav_call(mytox_av, friend_number, 0, 40, &error); 1747 | dbg(9, "cmd_vcm:005\n"); 1748 | 1749 | if (error != TOXAV_ERR_CALL_OK) 1750 | { 1751 | switch (error) 1752 | { 1753 | case TOXAV_ERR_CALL_MALLOC: 1754 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_MALLOC\n"); 1755 | break; 1756 | 1757 | case TOXAV_ERR_CALL_SYNC: 1758 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_SYNC\n"); 1759 | break; 1760 | 1761 | case TOXAV_ERR_CALL_FRIEND_NOT_FOUND: 1762 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_FRIEND_NOT_FOUND\n"); 1763 | break; 1764 | 1765 | case TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED: 1766 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED\n"); 1767 | break; 1768 | 1769 | case TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL: 1770 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL\n"); 1771 | break; 1772 | 1773 | case TOXAV_ERR_CALL_INVALID_BIT_RATE: 1774 | dbg(0, "toxav_call (1):TOXAV_ERR_CALL_INVALID_BIT_RATE\n"); 1775 | break; 1776 | 1777 | default: 1778 | dbg(0, "toxav_call (1):*unknown error*\n"); 1779 | break; 1780 | } 1781 | } 1782 | } 1783 | else 1784 | { 1785 | dbg(9, "cmd_vcm:006\n"); 1786 | send_text_message_to_friend(tox, friend_number, "sending video failed:toxav==NULL"); 1787 | } 1788 | } 1789 | 1790 | dbg(9, "cmd_vcm:099\n"); 1791 | } 1792 | 1793 | void send_help_to_friend(Tox *tox, uint32_t friend_number) 1794 | { 1795 | send_text_message_to_friend(tox, friend_number, "=========================\nToxCam version:%s\n=========================", global_version_string); 1796 | // send_text_message_to_friend(tox, friend_number, " commands are:"); 1797 | send_text_message_to_friend(tox, friend_number, " .stats --> show ToxCam status"); 1798 | send_text_message_to_friend(tox, friend_number, " .friends --> show ToxCam Friends"); 1799 | send_text_message_to_friend(tox, friend_number, " .snap --> snap a single still image"); 1800 | send_text_message_to_friend(tox, friend_number, " .restart --> restart ToxCam system"); 1801 | send_text_message_to_friend(tox, friend_number, " .vcm --> videocall me"); 1802 | } 1803 | 1804 | //void start_zipfile(mz_zip_archive *pZip, size_t size_pZip, const char* zip_file_full_path) 1805 | //{ 1806 | //} 1807 | //void add_file_to_zipfile(mz_zip_archive *pZip, const char* file_to_add_full_path, const char* filename_in_zipfile) 1808 | //{ 1809 | //} 1810 | //void finish_zipfile(mz_zip_archive *pZip) 1811 | //{ 1812 | //} 1813 | 1814 | void friend_message_cb(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message, 1815 | size_t length, void *user_data) 1816 | { 1817 | int j; 1818 | int send_back = 0; 1819 | 1820 | if (type == TOX_MESSAGE_TYPE_NORMAL) 1821 | { 1822 | if (message != NULL) 1823 | { 1824 | j = find_friend_in_friendlist(friend_number); 1825 | dbg(2, "message from friend:%d msg:%s\n", (int)friend_number, (char*)message); 1826 | 1827 | if (strncmp((char*)message, ".help", strlen((char*)".help")) == 0) 1828 | { 1829 | send_help_to_friend(tox, friend_number); 1830 | } 1831 | else if (strncmp((char*)message, ".stats", strlen((char*)".stats")) == 0) 1832 | { 1833 | cmd_stats(tox, friend_number); 1834 | } 1835 | else if (strncmp((char*)message, ".friends", strlen((char*)".friends")) == 0) 1836 | { 1837 | cmd_friends(tox, friend_number); 1838 | } 1839 | else if (strncmp((char*)message, ".snap", strlen((char*)".snap")) == 0) 1840 | { 1841 | cmd_snap(tox, friend_number); 1842 | } 1843 | else if (strncmp((char*)message, ".restart", strlen((char*)".restart")) == 0) // restart toxcam processes (no reboot) 1844 | { 1845 | cmd_restart(tox, friend_number); 1846 | } 1847 | else if (strncmp((char*)message, ".vcm", strlen((char*)".vcm")) == 0) // video call me! 1848 | { 1849 | cmd_vcm(tox, friend_number); 1850 | } 1851 | else 1852 | { 1853 | if (Friends.list[j].waiting_for_answer == 1) 1854 | { 1855 | // we want to get user feedback 1856 | snprintf(Friends.list[j].last_answer, 99, (char*)message); 1857 | Friends.list[j].waiting_for_answer = 2; 1858 | 1859 | if (Friends.list[j].last_answer) 1860 | { 1861 | dbg(2, "got answer from friend:%d answer:%s\n", (int)friend_number, Friends.list[j].last_answer); 1862 | } 1863 | else 1864 | { 1865 | dbg(2, "got answer from friend:%d answer:NULL\n", (int)friend_number); 1866 | } 1867 | } 1868 | else 1869 | { 1870 | // send_back = 1; 1871 | // unknown command, just send "help / usage" 1872 | send_help_to_friend(tox, friend_number); 1873 | } 1874 | } 1875 | } 1876 | else 1877 | { 1878 | dbg(2, "message from friend:%d msg:NULL\n", (int)friend_number); 1879 | } 1880 | } 1881 | else 1882 | { 1883 | dbg(2, "message from friend:%d\n", (int)friend_number); 1884 | } 1885 | 1886 | if (send_back == 1) 1887 | { 1888 | tox_friend_send_message(tox, friend_number, type, message, length, NULL); 1889 | } 1890 | } 1891 | 1892 | 1893 | 1894 | void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, 1895 | const uint8_t *data, size_t length, void *user_data) 1896 | { 1897 | struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber); 1898 | 1899 | if (!ft) 1900 | { 1901 | return; 1902 | } 1903 | } 1904 | 1905 | 1906 | void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size, 1907 | const uint8_t *filename, size_t filename_length, void *userdata) 1908 | { 1909 | /* We don't care about receiving avatars */ 1910 | if (kind != TOX_FILE_KIND_DATA) 1911 | { 1912 | tox_file_control(m, friendnumber, filenumber, TOX_FILE_CONTROL_CANCEL, NULL); 1913 | dbg(9, "on_file_recv:002:cancel incoming avatar\n"); 1914 | return; 1915 | } 1916 | else 1917 | { 1918 | // cancel all filetransfers. we don't want to receive files 1919 | tox_file_control(m, friendnumber, filenumber, TOX_FILE_CONTROL_CANCEL, NULL); 1920 | dbg(9, "on_file_recv:003:cancel incoming file\n"); 1921 | return; 1922 | } 1923 | } 1924 | 1925 | void save_resumable_fts(Tox *m, uint32_t friendnum) 1926 | { 1927 | size_t i; 1928 | int friendlistnum = find_friend_in_friendlist(friendnum); 1929 | for (i = 0; i < MAX_FILES; ++i) 1930 | { 1931 | // for now save only sending FTs 1932 | struct FileTransfer *ft = &Friends.list[friendlistnum].file_sender[i]; 1933 | if (ft->state != FILE_TRANSFER_INACTIVE) 1934 | { 1935 | dbg(9, "save_resumable_fts:saving sender FT i=%d ftnum=%d for friendnum:#%d pos=%d filesize=%d\n", i, (int)ft->filenum, (int)friendnum, (int)ft->position, (int)ft->file_size); 1936 | ll_push(&resumable_filetransfers, sizeof(struct FileTransfer), ft); 1937 | dbg(9, "save_resumable_fts:pushed struct=%p\n", resumable_filetransfers->val); 1938 | } 1939 | } 1940 | 1941 | Friends.list[friendlistnum].have_resumed_fts = 0; 1942 | } 1943 | 1944 | 1945 | 1946 | void resume_resumable_fts(Tox *m, uint32_t friendnum) 1947 | { 1948 | dbg(9, "resume_resumable_fts:001\n"); 1949 | 1950 | ll_node_t* saved_ft_list = resumable_filetransfers; 1951 | int i = 0; 1952 | while (saved_ft_list != NULL) 1953 | { 1954 | dbg(9, "resume_resumable_fts:element #%d=%p\n", i, saved_ft_list->val); 1955 | if (saved_ft_list->val != NULL) 1956 | { 1957 | struct FileTransfer *ft = (struct FileTransfer*)saved_ft_list->val; 1958 | if (ft->friendnum == friendnum) 1959 | { 1960 | dbg(9, "resume_resumable_fts:**found element #%d=%p\n", i, saved_ft_list->val); 1961 | resume_file_to_friend(m, ft->filenum, ft); 1962 | // now remove element, and start loop again 1963 | ll_remove_by_index(&resumable_filetransfers, i); 1964 | saved_ft_list = resumable_filetransfers; 1965 | i = 0; 1966 | continue; 1967 | } 1968 | } 1969 | 1970 | i++; 1971 | saved_ft_list = saved_ft_list->next; 1972 | } 1973 | 1974 | int j = find_friend_in_friendlist(friendnum); 1975 | if (j > -1) 1976 | { 1977 | Friends.list[j].have_resumed_fts = 1; 1978 | } 1979 | } 1980 | 1981 | 1982 | 1983 | void on_file_chunk_request(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, 1984 | size_t length, void *userdata) 1985 | { 1986 | // dbg(9, "on_file_chunk_request:001:friendnum=%d filenum=%d position=%ld len=%d\n", (int)friendnumber, (int)filenumber, (long)position, (int)length); 1987 | struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber); 1988 | 1989 | if (!ft) 1990 | { 1991 | dbg(0, "on_file_chunk_request:003 ft=NULL\n"); 1992 | return; 1993 | } 1994 | 1995 | if (ft->file_type == TOX_FILE_KIND_AVATAR) 1996 | { 1997 | on_avatar_chunk_request(tox, ft, position, length); 1998 | return; 1999 | } 2000 | 2001 | 2002 | if (ft->state != FILE_TRANSFER_STARTED) 2003 | { 2004 | dbg(0, "on_file_chunk_request:005 !FILE_TRANSFER_STARTED\n"); 2005 | return; 2006 | } 2007 | 2008 | if (length == 0) 2009 | { 2010 | dbg(2, "File '%s' successfully sent, ft->state=%d\n", ft->file_name, (int)ft->state); 2011 | 2012 | char origname[300]; 2013 | snprintf(origname, 299, "%s", (const char*)ft->file_name); 2014 | 2015 | close_file_transfer(tox, ft, -1); 2016 | // also remove the file from disk 2017 | 2018 | int friendlist_num = find_friend_in_friendlist(friendnumber); 2019 | char longname[300]; 2020 | snprintf(longname, 299, "%s/%s", (const char*)Friends.list[friendlist_num].worksubdir, origname); 2021 | dbg(2, "delete file %s\n", longname); 2022 | unlink(longname); 2023 | 2024 | return; 2025 | } 2026 | 2027 | if (ft->file == NULL) 2028 | { 2029 | dbg(0, "File transfer for '%s' failed: Null file pointer\n", ft->file_name); 2030 | close_file_transfer(tox, ft, TOX_FILE_CONTROL_CANCEL); 2031 | return; 2032 | } 2033 | 2034 | if (ft->position != position) 2035 | { 2036 | if (fseek(ft->file, position, SEEK_SET) == -1) 2037 | { 2038 | dbg(0, "File transfer for '%s' failed: Seek fail\n", ft->file_name); 2039 | close_file_transfer(tox, ft, TOX_FILE_CONTROL_CANCEL); 2040 | return; 2041 | } 2042 | 2043 | ft->position = position; 2044 | } 2045 | 2046 | uint8_t send_data[length]; 2047 | size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file); 2048 | 2049 | if (send_length != length) 2050 | { 2051 | dbg(0, "File transfer for '%s' failed: Read fail\n", ft->file_name); 2052 | close_file_transfer(tox, ft, TOX_FILE_CONTROL_CANCEL); 2053 | return; 2054 | } 2055 | 2056 | TOX_ERR_FILE_SEND_CHUNK err; 2057 | tox_file_send_chunk(tox, friendnumber, filenumber, position, send_data, send_length, &err); 2058 | 2059 | if (err != TOX_ERR_FILE_SEND_CHUNK_OK) 2060 | { 2061 | dbg(0, "tox_file_send_chunk failed in chat callback (error %d)\n", err); 2062 | } 2063 | 2064 | ft->position += send_length; 2065 | ft->bps += send_length; 2066 | ft->last_keep_alive = get_unix_time(); 2067 | 2068 | } 2069 | 2070 | 2071 | void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL control) 2072 | { 2073 | switch (control) 2074 | { 2075 | case TOX_FILE_CONTROL_RESUME: 2076 | if (ft->state == FILE_TRANSFER_PENDING) 2077 | { 2078 | ft->state = FILE_TRANSFER_STARTED; 2079 | } 2080 | else if (ft->state == FILE_TRANSFER_PAUSED) 2081 | { 2082 | ft->state = FILE_TRANSFER_STARTED; 2083 | } 2084 | 2085 | break; 2086 | 2087 | case TOX_FILE_CONTROL_PAUSE: 2088 | ft->state = FILE_TRANSFER_PAUSED; 2089 | break; 2090 | 2091 | case TOX_FILE_CONTROL_CANCEL: 2092 | close_file_transfer(m, ft, -1); 2093 | break; 2094 | } 2095 | } 2096 | 2097 | 2098 | void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, 2099 | void *userdata) 2100 | { 2101 | struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber); 2102 | 2103 | if (!ft) 2104 | { 2105 | return; 2106 | } 2107 | 2108 | if (ft->file_type == TOX_FILE_KIND_AVATAR) 2109 | { 2110 | on_avatar_file_control(m, ft, control); 2111 | return; 2112 | } 2113 | 2114 | dbg(9, "on_file_control:002:file in/out\n"); 2115 | 2116 | 2117 | 2118 | switch (control) 2119 | { 2120 | case TOX_FILE_CONTROL_RESUME: 2121 | { 2122 | dbg(9, "on_file_control:003:TOX_FILE_CONTROL_RESUME\n"); 2123 | 2124 | ft->last_keep_alive = get_unix_time(); 2125 | 2126 | /* transfer is accepted */ 2127 | if (ft->state == FILE_TRANSFER_PENDING) 2128 | { 2129 | ft->state = FILE_TRANSFER_STARTED; 2130 | dbg(9, "on_file_control:004:pending -> started\n"); 2131 | } 2132 | else if (ft->state == FILE_TRANSFER_PAUSED) 2133 | { /* transfer is resumed */ 2134 | ft->state = FILE_TRANSFER_STARTED; 2135 | dbg(9, "on_file_control:005:paused -> started\n"); 2136 | } 2137 | 2138 | break; 2139 | } 2140 | 2141 | case TOX_FILE_CONTROL_PAUSE: 2142 | { 2143 | dbg(9, "on_file_control:006:TOX_FILE_CONTROL_PAUSE\n"); 2144 | ft->state = FILE_TRANSFER_PAUSED; 2145 | break; 2146 | } 2147 | 2148 | case TOX_FILE_CONTROL_CANCEL: 2149 | { 2150 | dbg(1, "File transfer for '%s' was aborted\n", ft->file_name); 2151 | close_file_transfer(m, ft, -1); 2152 | break; 2153 | } 2154 | } 2155 | 2156 | } 2157 | 2158 | 2159 | 2160 | void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length) 2161 | { 2162 | dbg(9, "on_avatar_chunk_request:001\n"); 2163 | 2164 | if (ft->state != FILE_TRANSFER_STARTED) 2165 | { 2166 | dbg(0, "on_avatar_chunk_request:001a:!FILE_TRANSFER_STARTED\n"); 2167 | return; 2168 | } 2169 | 2170 | if (length == 0) 2171 | { 2172 | close_file_transfer(m, ft, -1); 2173 | return; 2174 | } 2175 | 2176 | if (ft->file == NULL) 2177 | { 2178 | close_file_transfer(m, ft, TOX_FILE_CONTROL_CANCEL); 2179 | return; 2180 | } 2181 | 2182 | if (ft->position != position) 2183 | { 2184 | if (fseek(ft->file, position, SEEK_SET) == -1) 2185 | { 2186 | close_file_transfer(m, ft, TOX_FILE_CONTROL_CANCEL); 2187 | return; 2188 | } 2189 | 2190 | ft->position = position; 2191 | } 2192 | 2193 | uint8_t send_data[length]; 2194 | size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file); 2195 | 2196 | if (send_length != length) 2197 | { 2198 | close_file_transfer(m, ft, TOX_FILE_CONTROL_CANCEL); 2199 | return; 2200 | } 2201 | 2202 | TOX_ERR_FILE_SEND_CHUNK err; 2203 | tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err); 2204 | 2205 | if (err != TOX_ERR_FILE_SEND_CHUNK_OK) 2206 | { 2207 | dbg(0, "tox_file_send_chunk failed in avatar callback (error %d)\n", err); 2208 | } 2209 | 2210 | ft->position += send_length; 2211 | ft->last_keep_alive = get_unix_time(); 2212 | } 2213 | 2214 | 2215 | void self_connection_status_cb(Tox *tox, TOX_CONNECTION connection_status, void *user_data) 2216 | { 2217 | switch (connection_status) 2218 | { 2219 | case TOX_CONNECTION_NONE: 2220 | dbg(2, "Offline\n"); 2221 | my_connection_status = TOX_CONNECTION_NONE; 2222 | break; 2223 | case TOX_CONNECTION_TCP: 2224 | dbg(2, "Online, using TCP\n"); 2225 | my_connection_status = TOX_CONNECTION_TCP; 2226 | break; 2227 | case TOX_CONNECTION_UDP: 2228 | dbg(2, "Online, using UDP\n"); 2229 | my_connection_status = TOX_CONNECTION_UDP; 2230 | break; 2231 | } 2232 | } 2233 | 2234 | 2235 | static struct FileTransfer *new_file_sender(uint32_t friendnum, uint32_t filenum, uint8_t type) 2236 | { 2237 | size_t i; 2238 | 2239 | dbg(9, "new_file_sender:001 friendnum=%d filenum=%d type=%d\n", (int)friendnum, (int) filenum, (int) type); 2240 | int friendlistnum = find_friend_in_friendlist(friendnum); 2241 | 2242 | for (i = 0; i < MAX_FILES; ++i) 2243 | { 2244 | struct FileTransfer *ft = &Friends.list[friendlistnum].file_sender[i]; 2245 | dbg(9, "new_file_sender:002 i=%d\n", (int)i); 2246 | 2247 | if (ft->state == FILE_TRANSFER_INACTIVE) 2248 | { 2249 | dbg(9, "new_file_sender:003:reusing sender i=%d\n", (int)i); 2250 | 2251 | memset(ft, 0, sizeof(struct FileTransfer)); 2252 | // ft->state = FILE_TRANSFER_INACTIVE; // == 0 2253 | 2254 | ft->index = i; 2255 | ft->friendnum = friendnum; 2256 | ft->filenum = filenum; 2257 | ft->file_type = type; 2258 | ft->last_keep_alive = get_unix_time(); 2259 | ft->state = FILE_TRANSFER_PENDING; 2260 | ft->direction = FILE_TRANSFER_SEND; 2261 | 2262 | dbg(9, "new_file_sender:003 i=%d\n", (int)i); 2263 | 2264 | return ft; 2265 | } 2266 | } 2267 | 2268 | return NULL; 2269 | } 2270 | 2271 | 2272 | 2273 | static struct FileTransfer *new_file_receiver(uint32_t friendnum, uint32_t filenum, uint8_t type) 2274 | { 2275 | size_t i; 2276 | int friendlistnum = find_friend_in_friendlist(friendnum); 2277 | 2278 | for (i = 0; i < MAX_FILES; ++i) 2279 | { 2280 | struct FileTransfer *ft = &Friends.list[friendlistnum].file_receiver[i]; 2281 | 2282 | if (ft->state == FILE_TRANSFER_INACTIVE) { 2283 | memset(ft, 0, sizeof(struct FileTransfer)); 2284 | // ft->state = FILE_TRANSFER_INACTIVE; // == 0 2285 | 2286 | ft->index = i; 2287 | ft->friendnum = friendnum; 2288 | ft->filenum = filenum; 2289 | ft->file_type = type; 2290 | ft->last_keep_alive = get_unix_time(); 2291 | ft->state = FILE_TRANSFER_PENDING; 2292 | ft->direction = FILE_TRANSFER_RECV; 2293 | return ft; 2294 | } 2295 | } 2296 | 2297 | return NULL; 2298 | } 2299 | 2300 | 2301 | struct FileTransfer *new_file_transfer(uint32_t friendnum, uint32_t filenum, 2302 | FILE_TRANSFER_DIRECTION direction, uint8_t type) 2303 | { 2304 | if (direction == FILE_TRANSFER_RECV) 2305 | { 2306 | return new_file_receiver(friendnum, filenum, type); 2307 | } 2308 | 2309 | if (direction == FILE_TRANSFER_SEND) 2310 | { 2311 | return new_file_sender(friendnum, filenum, type); 2312 | } 2313 | 2314 | return NULL; 2315 | } 2316 | 2317 | 2318 | int avatar_send(Tox *m, uint32_t friendnum) 2319 | { 2320 | dbg(2, "avatar_send:001 friendnum=%d\n", (int)friendnum); 2321 | dbg(2, "avatar_send:002 %d %s %d\n", (int)Avatar.size, Avatar.name, (int)Avatar.name_len); 2322 | 2323 | TOX_ERR_FILE_SEND err; 2324 | uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size, 2325 | NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err); 2326 | dbg(2, "avatar_send:tox_file_send=%s filenum=%d\n", (const char*)Avatar.name, (int)filenum); 2327 | 2328 | if (Avatar.size == 0) 2329 | { 2330 | return 0; 2331 | } 2332 | 2333 | if (err != TOX_ERR_FILE_SEND_OK) 2334 | { 2335 | dbg(0, "avatar_send:tox_file_send failed for _friendnumber %d (error %d)\n", friendnum, err); 2336 | return -1; 2337 | } 2338 | 2339 | dbg(2, "avatar_send(1):tox_file_send=%s filenum=%d\n", (const char*)Avatar.name, (int)filenum); 2340 | struct FileTransfer *ft = new_file_transfer(friendnum, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR); 2341 | dbg(2, "avatar_send(2):tox_file_send=%s filenum=%d\n", (const char*)Avatar.name, (int)filenum); 2342 | 2343 | if (!ft) 2344 | { 2345 | dbg(0, "avatar_send:003:ft=NULL\n"); 2346 | return -1; 2347 | } 2348 | 2349 | ft->file = fopen(Avatar.path, "r"); 2350 | 2351 | if (ft->file == NULL) 2352 | { 2353 | dbg(0, "avatar_send:004:ft->file=NULL\n"); 2354 | return -1; 2355 | } 2356 | 2357 | snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name); 2358 | ft->file_size = Avatar.size; 2359 | 2360 | return 0; 2361 | } 2362 | 2363 | 2364 | int check_file_signature(const char *signature, size_t size, FILE *fp) 2365 | { 2366 | char buf[size]; 2367 | if (fread(buf, size, 1, fp) != 1) 2368 | { 2369 | return -1; 2370 | } 2371 | int ret = memcmp(signature, buf, size); 2372 | if (fseek(fp, 0L, SEEK_SET) == -1) 2373 | { 2374 | return -1; 2375 | } 2376 | return ret == 0 ? 0 : 1; 2377 | } 2378 | 2379 | 2380 | void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum) 2381 | { 2382 | } 2383 | void kill_all_file_transfers(Tox *m) 2384 | { 2385 | } 2386 | 2387 | 2388 | int avatar_set(Tox *m, const char *path, size_t path_len) 2389 | { 2390 | dbg(2, "avatar_set:001\n"); 2391 | 2392 | if (path_len == 0 || path_len >= sizeof(Avatar.path)) 2393 | { 2394 | return -1; 2395 | } 2396 | 2397 | dbg(9, "avatar_set:002\n"); 2398 | FILE *fp = fopen(path, "rb"); 2399 | 2400 | if (fp == NULL) 2401 | { 2402 | return -1; 2403 | } 2404 | 2405 | char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; 2406 | 2407 | if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) 2408 | { 2409 | fclose(fp); 2410 | return -1; 2411 | } 2412 | fclose(fp); 2413 | 2414 | dbg(9, "avatar_set:003\n"); 2415 | 2416 | off_t size = file_size(path); 2417 | 2418 | if (size == 0 || size > MAX_AVATAR_FILE_SIZE) 2419 | { 2420 | return -1; 2421 | } 2422 | 2423 | dbg(9, "avatar_set:004\n"); 2424 | 2425 | get_file_name(Avatar.name, sizeof(Avatar.name), path); 2426 | Avatar.name_len = strlen(Avatar.name); 2427 | snprintf(Avatar.path, sizeof(Avatar.path), "%s", path); 2428 | Avatar.path_len = path_len; 2429 | Avatar.size = size; 2430 | 2431 | dbg(9, "avatar_set:099\n"); 2432 | 2433 | return 0; 2434 | } 2435 | 2436 | static void avatar_clear(void) 2437 | { 2438 | memset(&Avatar, 0, sizeof(struct Avatar)); 2439 | } 2440 | 2441 | void avatar_unset(Tox *m) 2442 | { 2443 | avatar_clear(); 2444 | } 2445 | 2446 | int check_number_of_files_to_resend_to_friend(Tox *m, uint32_t friendnum, int friendlistnum) 2447 | { 2448 | } 2449 | void resend_zip_files_and_send(Tox *m, uint32_t friendnum, int friendlistnum) 2450 | { 2451 | } 2452 | void process_friends_dir(Tox *m, uint32_t friendnum, int friendlistnum) 2453 | { 2454 | } 2455 | void check_friends_dir(Tox *m) 2456 | { 2457 | } 2458 | void check_dir(Tox *m) 2459 | { 2460 | } 2461 | 2462 | 2463 | char* get_current_time_date_formatted() 2464 | { 2465 | time_t t; 2466 | struct tm *tm = NULL; 2467 | const int max_size_datetime_str = 100; 2468 | char *str_date_time = malloc(max_size_datetime_str); 2469 | 2470 | memset(str_date_time, 0, 100); 2471 | t = time(NULL); 2472 | tm = localtime(&t); 2473 | 2474 | strftime(str_date_time, max_size_datetime_str, global_overlay_timestamp_format, tm); 2475 | 2476 | // dbg(9, "str_date_time=%s\n", str_date_time); 2477 | 2478 | return str_date_time; 2479 | } 2480 | 2481 | 2482 | // ------------------- V4L2 stuff --------------------- 2483 | // ------------------- V4L2 stuff --------------------- 2484 | // ------------------- V4L2 stuff --------------------- 2485 | 2486 | 2487 | static int xioctl(int fh, unsigned long request, void *arg) 2488 | { 2489 | int r; 2490 | 2491 | do 2492 | { 2493 | r = ioctl(fh, request, arg); 2494 | } while (-1 == r && EINTR == errno); 2495 | 2496 | return r; 2497 | } 2498 | 2499 | 2500 | 2501 | int init_cam() 2502 | { 2503 | int video_dev_open_error = 0; 2504 | int fd; 2505 | 2506 | if ((fd = open(v4l2_device, O_RDWR)) < 0) 2507 | { 2508 | dbg(0, "error opening video device[1]\n"); 2509 | video_dev_open_error = 1; 2510 | } 2511 | 2512 | if (video_dev_open_error == 1) 2513 | { 2514 | sleep(20); // sleep 20 seconds 2515 | 2516 | if ((fd = open(v4l2_device, O_RDWR)) < 0) 2517 | { 2518 | dbg(0, "error opening video device[2]\n"); 2519 | video_dev_open_error = 1; 2520 | } 2521 | else 2522 | { 2523 | video_dev_open_error = 0; 2524 | } 2525 | } 2526 | 2527 | struct v4l2_capability cap; 2528 | struct v4l2_cropcap cropcap; 2529 | // struct v4l2_crop crop; 2530 | 2531 | if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) 2532 | { 2533 | dbg(0, "VIDIOC_QUERYCAP\n"); 2534 | } 2535 | 2536 | if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) 2537 | { 2538 | dbg(0, "The device does not handle single-planar video capture.\n"); 2539 | } 2540 | 2541 | if (!(cap.capabilities & V4L2_CAP_STREAMING)) 2542 | { 2543 | dbg(0, "The device does not support streaming i/o.\n"); 2544 | } 2545 | 2546 | 2547 | /* Select video input, video standard and tune here. */ 2548 | CLEAR(cropcap); 2549 | 2550 | cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2551 | 2552 | if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) 2553 | { 2554 | #if 0 2555 | crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2556 | crop.c = cropcap.defrect; /* reset to full area */ 2557 | /* Scale the width and height to 50 % of their original size and center the output. */ 2558 | crop.c.width = crop.c.width / 2; 2559 | crop.c.height = crop.c.height / 2; 2560 | crop.c.left = crop.c.left + crop.c.width / 2; 2561 | crop.c.top = crop.c.top + crop.c.height / 2; 2562 | 2563 | if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) 2564 | { 2565 | switch (errno) 2566 | { 2567 | case EINVAL: 2568 | dbg(0, "Cropping not supported (1)\n"); 2569 | break; 2570 | default: 2571 | dbg(0, "some error on croping setup\n"); 2572 | break; 2573 | } 2574 | } 2575 | #endif 2576 | } 2577 | else 2578 | { 2579 | dbg(0, "Cropping not supported (2)\n"); 2580 | } 2581 | 2582 | 2583 | #ifdef V4LCONVERT 2584 | v4lconvert_data = v4lconvert_create(fd); 2585 | #endif 2586 | 2587 | CLEAR(format); 2588 | CLEAR(dest_format); 2589 | 2590 | format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2591 | format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; 2592 | 2593 | format.fmt.pix.width = 1920; 2594 | format.fmt.pix.height = 1080; 2595 | 2596 | dest_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2597 | dest_format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; 2598 | 2599 | dest_format.fmt.pix.width = format.fmt.pix.width; 2600 | dest_format.fmt.pix.height = format.fmt.pix.height; 2601 | 2602 | if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) 2603 | { 2604 | dbg(2, "Video format(wanted): V4L2_PIX_FMT_YUV420\n"); 2605 | } 2606 | else if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) 2607 | { 2608 | dbg(2, "Video format(wanted): V4L2_PIX_FMT_MJPEG\n"); 2609 | } 2610 | else 2611 | { 2612 | dbg(2, "Video format(wanted): %u\n", format.fmt.pix.pixelformat); 2613 | } 2614 | 2615 | // Get <-> Set ?? 2616 | if (-1 == xioctl(fd, VIDIOC_G_FMT, &format)) 2617 | { 2618 | dbg(0, "VIDIOC_G_FMT\n"); 2619 | } 2620 | 2621 | if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) 2622 | { 2623 | dbg(2, "Video format(got): V4L2_PIX_FMT_YUV420\n"); 2624 | } 2625 | else if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) 2626 | { 2627 | dbg(2, "Video format(got): V4L2_PIX_FMT_MJPEG\n"); 2628 | } 2629 | else 2630 | { 2631 | dbg(2, "Video format(got): %u\n", format.fmt.pix.pixelformat); 2632 | } 2633 | 2634 | if (video_high == 1) 2635 | { 2636 | format.fmt.pix.width = 1280; 2637 | format.fmt.pix.height = 720; 2638 | } 2639 | else 2640 | { 2641 | format.fmt.pix.width = 640; 2642 | format.fmt.pix.height = 480; 2643 | } 2644 | 2645 | video_width = format.fmt.pix.width; 2646 | video_height = format.fmt.pix.height; 2647 | dbg(2, "Video size(wanted): %u %u\n", video_width, video_height); 2648 | 2649 | if (-1 == xioctl(fd, VIDIOC_S_FMT, &format)) 2650 | { 2651 | dbg(0, "VIDIOC_S_FMT\n"); 2652 | } 2653 | 2654 | if (-1 == xioctl(fd, VIDIOC_G_FMT, &format)) 2655 | { 2656 | dbg(0, "VIDIOC_G_FMT\n"); 2657 | } 2658 | 2659 | video_width = format.fmt.pix.width; 2660 | video_height = format.fmt.pix.height; 2661 | dbg(2, "Video size(got): %u %u\n", video_width, video_height); 2662 | 2663 | dest_format.fmt.pix.width = format.fmt.pix.width; 2664 | dest_format.fmt.pix.height = format.fmt.pix.height; 2665 | 2666 | 2667 | /* Buggy driver paranoia. */ 2668 | /* 2669 | min = fmt.fmt.pix.width * 2; 2670 | if (fmt.fmt.pix.bytesperline < min) 2671 | fmt.fmt.pix.bytesperline = min; 2672 | min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; 2673 | if (fmt.fmt.pix.sizeimage < min) 2674 | fmt.fmt.pix.sizeimage = min; 2675 | */ 2676 | 2677 | 2678 | struct v4l2_requestbuffers bufrequest; 2679 | 2680 | CLEAR(bufrequest); 2681 | 2682 | bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2683 | bufrequest.memory = V4L2_MEMORY_MMAP; 2684 | bufrequest.count = VIDEO_BUFFER_COUNT; 2685 | 2686 | dbg(0, "VIDIOC_REQBUFS want type=%d\n", (int)bufrequest.type); 2687 | 2688 | if (-1 == xioctl(fd, VIDIOC_REQBUFS, &bufrequest)) 2689 | { 2690 | if (EINVAL == errno) 2691 | { 2692 | dbg(0, "%s does not support x i/o\n", v4l2_device); 2693 | } 2694 | else 2695 | { 2696 | // dbg(0, "VIDIOC_REQBUFS error %d, %s\n", errno, strerror(errno)); 2697 | // try again ... 2698 | if (-1 == xioctl(fd, VIDIOC_REQBUFS, &bufrequest)) 2699 | { 2700 | if (EINVAL == errno) 2701 | { 2702 | dbg(0, "[2nd] %s does not support x i/o\n", v4l2_device); 2703 | } 2704 | else 2705 | { 2706 | dbg(0, "[2nd] VIDIOC_REQBUFS error %d, %s\n", errno, strerror(errno)); 2707 | } 2708 | } 2709 | } 2710 | } 2711 | 2712 | dbg(0, "VIDIOC_REQBUFS got type=%d\n", (int)bufrequest.type); 2713 | 2714 | if (bufrequest.count < 2) 2715 | { 2716 | dbg(0, "Insufficient buffer memory on %s\n", v4l2_device); 2717 | } 2718 | 2719 | 2720 | buffers = calloc(bufrequest.count, sizeof(*buffers)); 2721 | 2722 | for (n_buffers = 0; n_buffers < bufrequest.count; ++n_buffers) 2723 | { 2724 | struct v4l2_buffer bufferinfo; 2725 | 2726 | CLEAR(bufferinfo); 2727 | 2728 | bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2729 | bufferinfo.memory = V4L2_MEMORY_MMAP; 2730 | bufferinfo.index = n_buffers; 2731 | 2732 | if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &bufferinfo)) 2733 | { 2734 | dbg(9, "VIDIOC_QUERYBUF (2) error %d, %s\n", errno, strerror(errno)); 2735 | } 2736 | 2737 | /* 2738 | if (ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0) 2739 | { 2740 | dbg(0, "VIDIOC_QUERYBUF %d %s\n", errno, strerror(errno)); 2741 | } 2742 | */ 2743 | 2744 | buffers[n_buffers].length = bufferinfo.length; 2745 | buffers[n_buffers].start = mmap(NULL /* start anywhere */, bufferinfo.length, PROT_READ | PROT_WRITE /* required */, 2746 | MAP_SHARED /* recommended */, fd, bufferinfo.m.offset); 2747 | 2748 | if (MAP_FAILED == buffers[n_buffers].start) 2749 | { 2750 | dbg(0, "mmap error %d, %s\n", errno, strerror(errno)); 2751 | } 2752 | 2753 | } 2754 | 2755 | return fd; 2756 | } 2757 | 2758 | 2759 | int v4l_startread() 2760 | { 2761 | dbg(9, "start cam\n"); 2762 | size_t i; 2763 | enum v4l2_buf_type type; 2764 | 2765 | for (i = 0; i < n_buffers; ++i) 2766 | { 2767 | struct v4l2_buffer buf; 2768 | 2769 | dbg(9, "buffer (1) %d of %d\n", i, n_buffers); 2770 | 2771 | CLEAR(buf); 2772 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2773 | buf.memory = V4L2_MEMORY_MMAP; 2774 | buf.index = i; 2775 | 2776 | if (-1 == xioctl(global_cam_device_fd, VIDIOC_QBUF, &buf)) 2777 | { 2778 | dbg(9, "VIDIOC_QBUF (3) error %d, %s\n", errno, strerror(errno)); 2779 | return 0; 2780 | } 2781 | } 2782 | 2783 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2784 | if (-1 == xioctl(global_cam_device_fd, VIDIOC_STREAMON, &type)) 2785 | { 2786 | dbg(9, "VIDIOC_STREAMON error %d, %s\n", errno, strerror(errno)); 2787 | return 0; 2788 | } 2789 | 2790 | return 1; 2791 | } 2792 | 2793 | 2794 | int v4l_endread() 2795 | { 2796 | dbg(9, "stop webcam\n"); 2797 | enum v4l2_buf_type type; 2798 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2799 | if (-1 == xioctl(global_cam_device_fd, VIDIOC_STREAMOFF, &type)) 2800 | { 2801 | dbg(9, "VIDIOC_STREAMOFF error %d, %s\n", errno, strerror(errno)); 2802 | return 0; 2803 | } 2804 | 2805 | return 1; 2806 | } 2807 | 2808 | 2809 | void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *input, uint16_t width, uint16_t height) 2810 | { 2811 | uint8_t *end = input + width * height * 2; 2812 | while (input != end) 2813 | { 2814 | uint8_t *line_end = input + width * 2; 2815 | while (input != line_end) 2816 | { 2817 | *plane_y++ = *input++; 2818 | *plane_v++ = *input++; 2819 | *plane_y++ = *input++; 2820 | *plane_u++ = *input++; 2821 | } 2822 | 2823 | line_end = input + width * 2; 2824 | while (input != line_end) 2825 | { 2826 | *plane_y++ = *input++; 2827 | input++; // u 2828 | *plane_y++ = *input++; 2829 | input++; // v 2830 | } 2831 | } 2832 | } 2833 | 2834 | 2835 | int v4l_getframe(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t width, uint16_t height) 2836 | { 2837 | if (width != video_width || height != video_height) 2838 | { 2839 | dbg(9, "V4L:\twidth/height mismatch %u %u != %u %u\n", width, height, video_width, video_height); 2840 | return 0; 2841 | } 2842 | 2843 | struct v4l2_buffer buf; 2844 | 2845 | CLEAR(buf); 2846 | 2847 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2848 | buf.memory = V4L2_MEMORY_MMAP; // V4L2_MEMORY_USERPTR; 2849 | 2850 | if (-1 == ioctl(global_cam_device_fd, VIDIOC_DQBUF, &buf)) 2851 | { 2852 | switch (errno) 2853 | { 2854 | case EINTR: 2855 | case EAGAIN: return 0; 2856 | 2857 | case EIO: 2858 | /* Could ignore EIO, see spec. */ 2859 | 2860 | /* fall through */ 2861 | 2862 | default: dbg(9, "VIDIOC_DQBUF error %d, %s\n", errno, strerror(errno)); return -1; 2863 | 2864 | } 2865 | } 2866 | 2867 | /*for (i = 0; i < n_buffers; ++i) 2868 | if (buf.m.userptr == (unsigned long)buffers[i].start 2869 | && buf.length == buffers[i].length) 2870 | break; 2871 | 2872 | if(i >= n_buffers) { 2873 | dbg(9, "fatal error\n"); 2874 | return 0; 2875 | }*/ 2876 | 2877 | // dbg(9, "buf.index=%d\n", (int)buf.index); 2878 | 2879 | void *data = (void *)buffers[buf.index].start; // length = buf.bytesused //(void*)buf.m.userptr 2880 | 2881 | /* assumes planes are continuous memory */ 2882 | #ifdef V4LCONVERT 2883 | // dbg(9, "V4LCONVERT\n"); 2884 | int result = v4lconvert_convert(v4lconvert_data, &format, &dest_format, data, buf.bytesused, y, 2885 | (video_width * video_height * 3) / 2); 2886 | 2887 | if (result == -1) 2888 | { 2889 | dbg(0, "v4lconvert_convert error %s\n", v4lconvert_get_error_message(v4lconvert_data)); 2890 | } 2891 | #else 2892 | dbg(9, "convert2\n"); 2893 | if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) 2894 | { 2895 | dbg(9, "yuv422to420\n"); 2896 | yuv422to420(y, u, v, data, video_width, video_height); 2897 | } 2898 | else 2899 | { 2900 | } 2901 | #endif 2902 | 2903 | if (-1 == xioctl(global_cam_device_fd, VIDIOC_QBUF, &buf)) 2904 | { 2905 | dbg(9, "VIDIOC_QBUF (1) error %d, %s\n", errno, strerror(errno)); 2906 | } 2907 | 2908 | #ifdef V4LCONVERT 2909 | return (result == -1 ? 0 : 1); 2910 | #else 2911 | return 1; 2912 | #endif 2913 | } 2914 | 2915 | 2916 | void close_cam() 2917 | { 2918 | #ifdef V4LCONVERT 2919 | v4lconvert_destroy(v4lconvert_data); 2920 | #endif 2921 | 2922 | size_t i; 2923 | for (i = 0; i < n_buffers; ++i) 2924 | { 2925 | if (-1 == munmap(buffers[i].start, buffers[i].length)) 2926 | { 2927 | dbg(9, "munmap error\n"); 2928 | } 2929 | } 2930 | 2931 | close(global_cam_device_fd); 2932 | } 2933 | 2934 | // ------------------- V4L2 stuff --------------------- 2935 | // ------------------- V4L2 stuff --------------------- 2936 | // ------------------- V4L2 stuff --------------------- 2937 | 2938 | 2939 | 2940 | // ------------------ Tox AV stuff -------------------- 2941 | // ------------------ Tox AV stuff -------------------- 2942 | // ------------------ Tox AV stuff -------------------- 2943 | 2944 | static void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data) 2945 | { 2946 | if (global_video_active == 1) 2947 | { 2948 | dbg(9, "Call already active\n"); 2949 | } 2950 | else 2951 | { 2952 | dbg(9, "Handling CALL callback friendnum=%d audio_enabled=%d video_enabled=%d\n", (int)friend_number, (int)audio_enabled, (int)video_enabled); 2953 | ((CallControl *)user_data)->incoming = true; 2954 | 2955 | TOXAV_ERR_ANSWER err; 2956 | global_video_bit_rate = DEFAULT_GLOBAL_VID_BITRATE; 2957 | int audio_bitrate = DEFAULT_GLOBAL_AUD_BITRATE; 2958 | int video_bitrate = global_video_bit_rate; 2959 | friend_to_send_video_to = friend_number; 2960 | global_video_active = 1; 2961 | global_send_first_frame = 2; 2962 | 2963 | dbg(9, "Handling CALL callback friendnum=%d audio_bitrate=%d video_bitrate=%d\n", (int)friend_number, (int)audio_bitrate, (int)video_bitrate); 2964 | 2965 | toxav_answer(av, friend_number, audio_bitrate, video_bitrate, &err); 2966 | } 2967 | } 2968 | 2969 | static void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data) 2970 | { 2971 | dbg(9, "Handling CALL STATE callback: %d friend_number=%d\n", state, (int)friend_number); 2972 | 2973 | ((CallControl *)user_data)->state = state; 2974 | 2975 | if (state & TOXAV_FRIEND_CALL_STATE_FINISHED) 2976 | { 2977 | dbg(9, "Call with friend %d finished\n", friend_number); 2978 | global_video_active = 0; 2979 | return; 2980 | } 2981 | else if (state & TOXAV_FRIEND_CALL_STATE_ERROR) 2982 | { 2983 | dbg(9, "Call with friend %d errored\n", friend_number); 2984 | global_video_active = 0; 2985 | return; 2986 | } 2987 | else if (state & TOXAV_FRIEND_CALL_STATE_SENDING_A) 2988 | { 2989 | dbg(9, "Call with friend state:TOXAV_FRIEND_CALL_STATE_SENDING_A\n"); 2990 | } 2991 | else if (state & TOXAV_FRIEND_CALL_STATE_SENDING_V) 2992 | { 2993 | dbg(9, "Call with friend state:TOXAV_FRIEND_CALL_STATE_SENDING_V\n"); 2994 | } 2995 | else if (state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A) 2996 | { 2997 | dbg(9, "Call with friend state:TOXAV_FRIEND_CALL_STATE_ACCEPTING_A\n"); 2998 | } 2999 | else if (state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V) 3000 | { 3001 | dbg(9, "Call with friend state:TOXAV_FRIEND_CALL_STATE_ACCEPTING_V\n"); 3002 | } 3003 | 3004 | dbg(9, "t_toxav_call_state_cb:002\n"); 3005 | int send_audio = (state & TOXAV_FRIEND_CALL_STATE_SENDING_A) && (state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A); 3006 | int send_video = state & TOXAV_FRIEND_CALL_STATE_SENDING_V && (state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V); 3007 | dbg(9, "t_toxav_call_state_cb:002a send_audio=%d send_video=%d global_video_bit_rate=%d\n", send_audio, send_video, (int)global_video_bit_rate); 3008 | TOXAV_ERR_BIT_RATE_SET bitrate_err = 0; 3009 | // ** // toxav_bit_rate_set(av, friend_number, 0, send_video ? global_video_bit_rate : 0, &bitrate_err); 3010 | dbg(9, "t_toxav_call_state_cb:004\n"); 3011 | 3012 | if (bitrate_err) 3013 | { 3014 | dbg(9, "ToxAV:Error setting/changing video bitrate\n"); 3015 | } 3016 | 3017 | if (send_video == 1) 3018 | { 3019 | dbg(9, "t_toxav_call_state_cb:004\n"); 3020 | global_video_active = 1; 3021 | global_send_first_frame = 2; 3022 | } 3023 | else 3024 | { 3025 | dbg(9, "t_toxav_call_state_cb:005\n"); 3026 | global_video_active = 0; 3027 | global_send_first_frame = 0; 3028 | } 3029 | 3030 | dbg(9, "Call state for friend %d changed to %d, audio=%d, video=%d\n", friend_number, state, send_audio, send_video); 3031 | } 3032 | 3033 | static void t_toxav_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, 3034 | uint32_t audio_bit_rate, uint32_t video_bit_rate, 3035 | void *user_data) 3036 | { 3037 | dbg(0, "t_toxav_bit_rate_status_cb:001 video_bit_rate=%d\n", (int)video_bit_rate); 3038 | dbg(0, "t_toxav_bit_rate_status_cb:001 audio_bit_rate=%d\n", (int)audio_bit_rate); 3039 | 3040 | TOXAV_ERR_BIT_RATE_SET error = 0; 3041 | 3042 | 3043 | uint32_t video_bit_rate_ = video_bit_rate; 3044 | 3045 | if (video_bit_rate < DEFAULT_GLOBAL_MIN_VID_BITRATE) 3046 | { 3047 | video_bit_rate_ = DEFAULT_GLOBAL_MIN_VID_BITRATE; 3048 | } 3049 | 3050 | toxav_bit_rate_set(av, friend_number, audio_bit_rate, video_bit_rate_, &error); 3051 | 3052 | if (error != 0) 3053 | { 3054 | dbg(0, "ToxAV:Setting new Video bitrate has failed with error #%u\n", error); 3055 | } 3056 | else 3057 | { 3058 | global_video_bit_rate = video_bit_rate_; 3059 | } 3060 | 3061 | dbg(2, "suggested bit rates: audio: %d video: %d\n", audio_bit_rate, video_bit_rate); 3062 | dbg(2, "actual bit rates: audio: %d video: %d\n", global_audio_bit_rate, global_video_bit_rate); 3063 | } 3064 | 3065 | 3066 | static void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, 3067 | int16_t const *pcm, 3068 | size_t sample_count, 3069 | uint8_t channels, 3070 | uint32_t sampling_rate, 3071 | void *user_data) 3072 | { 3073 | if (global_video_active == 1) 3074 | { 3075 | if (friend_to_send_video_to == friend_number) 3076 | { 3077 | } 3078 | else 3079 | { 3080 | // wrong friend 3081 | } 3082 | } 3083 | else 3084 | { 3085 | } 3086 | 3087 | // CallControl *cc = (CallControl *)user_data; 3088 | // frame *f = (frame *)malloc(sizeof(uint16_t) + sample_count * sizeof(int16_t) * channels); 3089 | // memcpy(f->data, pcm, sample_count * sizeof(int16_t) * channels); 3090 | // f->size = sample_count; 3091 | 3092 | // pthread_mutex_lock(cc->arb_mutex); 3093 | // free(rb_write(cc->arb, f)); 3094 | // pthread_mutex_unlock(cc->arb_mutex); 3095 | } 3096 | 3097 | 3098 | static void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number, 3099 | uint16_t width, uint16_t height, 3100 | uint8_t const *y, uint8_t const *u, uint8_t const *v, 3101 | int32_t ystride, int32_t ustride, int32_t vstride, 3102 | void *user_data) 3103 | { 3104 | 3105 | if (global_video_active == 1) 3106 | { 3107 | if (friend_to_send_video_to == friend_number) 3108 | { 3109 | } 3110 | else 3111 | { 3112 | // wrong friend 3113 | } 3114 | } 3115 | else 3116 | { 3117 | } 3118 | 3119 | 3120 | // ystride = abs(ystride); 3121 | // ustride = abs(ustride); 3122 | // vstride = abs(vstride); 3123 | 3124 | // uint16_t *img_data = (uint16_t *)malloc(height * width * 6); 3125 | 3126 | // unsigned long int i, j; 3127 | 3128 | // for (i = 0; i < height; ++i) 3129 | // { 3130 | // for (j = 0; j < width; ++j) 3131 | // { 3132 | // uint8_t *point = (uint8_t *) img_data + 3 * ((i * width) + j); 3133 | // int yx = y[(i * ystride) + j]; 3134 | // int ux = u[((i / 2) * ustride) + (j / 2)]; 3135 | // int vx = v[((i / 2) * vstride) + (j / 2)]; 3136 | 3137 | // point[0] = YUV2R(yx, ux, vx); 3138 | // point[1] = YUV2G(yx, ux, vx); 3139 | // point[2] = YUV2B(yx, ux, vx); 3140 | // } 3141 | // } 3142 | 3143 | 3144 | // CvMat mat = cvMat(height, width, CV_8UC3, img_data); 3145 | 3146 | // CvSize sz; 3147 | // sz.height = height; 3148 | // sz.width = width; 3149 | 3150 | // IplImage *header = cvCreateImageHeader(sz, 1, 3); 3151 | // IplImage *img = cvGetImage(&mat, header); 3152 | // cvShowImage(vdout, img); 3153 | // free(img_data); 3154 | } 3155 | 3156 | void set_av_video_frame() 3157 | { 3158 | vpx_img_alloc(&input, VPX_IMG_FMT_I420, video_width, video_height, 1); 3159 | av_video_frame.y = input.planes[0]; /**< Y (Luminance) plane and VPX_PLANE_PACKED */ 3160 | av_video_frame.u = input.planes[1]; /**< U (Chroma) plane */ 3161 | av_video_frame.v = input.planes[2]; /**< V (Chroma) plane */ 3162 | av_video_frame.w = input.d_w; 3163 | av_video_frame.h = input.d_h; 3164 | //av_video_frame.bit_depth = input.bit_depth; 3165 | 3166 | dbg(2,"ToxVideo:av_video_frame set\n"); 3167 | } 3168 | 3169 | void *thread_av(void *data) 3170 | { 3171 | ToxAV *av = (ToxAV *) data; 3172 | 3173 | pthread_t id = pthread_self(); 3174 | pthread_mutex_t av_thread_lock; 3175 | 3176 | if (pthread_mutex_init(&av_thread_lock, NULL) != 0) 3177 | { 3178 | dbg(0, "Error creating av_thread_lock\n"); 3179 | } 3180 | else 3181 | { 3182 | dbg(2, "av_thread_lock created successfully\n"); 3183 | } 3184 | 3185 | dbg(2, "AV Thread #%d: starting\n", (int) id); 3186 | 3187 | if (video_call_enabled == 1) 3188 | { 3189 | global_cam_device_fd = init_cam(); 3190 | dbg(2, "AV Thread #%d: init cam\n", (int) id); 3191 | set_av_video_frame(); 3192 | // start streaming 3193 | v4l_startread(); 3194 | } 3195 | 3196 | while (toxav_iterate_thread_stop != 1) 3197 | { 3198 | yieldcpu(1000); 3199 | } 3200 | 3201 | 3202 | if (video_call_enabled == 1) 3203 | { 3204 | // end streaming 3205 | v4l_endread(); 3206 | } 3207 | 3208 | dbg(2, "ToxVideo:Clean thread exit!\n"); 3209 | } 3210 | 3211 | 3212 | void *thread_video_av(void *data) 3213 | { 3214 | ToxAV *av = (ToxAV *) data; 3215 | 3216 | pthread_t id = pthread_self(); 3217 | pthread_mutex_t av_thread_lock; 3218 | 3219 | if (pthread_mutex_init(&av_thread_lock, NULL) != 0) 3220 | { 3221 | dbg(0, "Error creating video av_thread_lock\n"); 3222 | } 3223 | else 3224 | { 3225 | dbg(2, "av_thread_lock video created successfully\n"); 3226 | } 3227 | 3228 | dbg(2, "AV video Thread #%d: starting\n", (int) id); 3229 | 3230 | while (toxav_video_thread_stop != 1) 3231 | { 3232 | pthread_mutex_lock(&av_thread_lock); 3233 | toxav_iterate(av); 3234 | // dbg(9, "AV video Thread #%d running ...", (int) id); 3235 | pthread_mutex_unlock(&av_thread_lock); 3236 | usleep(toxav_iteration_interval(av) * 1000); 3237 | } 3238 | 3239 | dbg(2, "ToxVideo:Clean video thread exit!\n"); 3240 | } 3241 | 3242 | 3243 | void av_local_disconnect(ToxAV *av, uint32_t num) 3244 | { 3245 | dbg(9, "av_local_disconnect\n"); 3246 | TOXAV_ERR_CALL_CONTROL error = 0; 3247 | toxav_call_control(av, num, TOXAV_CALL_CONTROL_CANCEL, &error); 3248 | global_video_active = 0; 3249 | global_send_first_frame = 0; 3250 | friend_to_send_video_to = -1; 3251 | } 3252 | 3253 | 3254 | // ------------------ Tox AV stuff -------------------- 3255 | // ------------------ Tox AV stuff -------------------- 3256 | // ------------------ Tox AV stuff -------------------- 3257 | 3258 | 3259 | 3260 | // ------------------ YUV420 overlay hack ------------- 3261 | // ------------------ YUV420 overlay hack ------------- 3262 | // ------------------ YUV420 overlay hack ------------- 3263 | 3264 | 3265 | 3266 | 3267 | /** 3268 | * 8x8 monochrome bitmap fonts for rendering 3269 | * Author: Daniel Hepper 3270 | * 3271 | * License: Public Domain 3272 | * 3273 | * Based on: 3274 | * // Summary: font8x8.h 3275 | * // 8x8 monochrome bitmap fonts for rendering 3276 | * // 3277 | * // Author: 3278 | * // Marcel Sondaar 3279 | * // International Business Machines (public domain VGA fonts) 3280 | * // 3281 | * // License: 3282 | * // Public Domain 3283 | * 3284 | * Fetched from: http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm 3285 | **/ 3286 | 3287 | // Constant: font8x8_basic 3288 | // Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin) 3289 | char font8x8_basic[128][8] = { 3290 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) 3291 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001 3292 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002 3293 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003 3294 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004 3295 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005 3296 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006 3297 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007 3298 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008 3299 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009 3300 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A 3301 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B 3302 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C 3303 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D 3304 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E 3305 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F 3306 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010 3307 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011 3308 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012 3309 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013 3310 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 3311 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015 3312 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016 3313 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017 3314 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018 3315 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019 3316 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A 3317 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B 3318 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C 3319 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D 3320 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E 3321 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F 3322 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) 3323 | { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) 3324 | { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") 3325 | { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) 3326 | { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) 3327 | { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) 3328 | { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) 3329 | { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') 3330 | { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() 3331 | { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) 3332 | { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) 3333 | { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) 3334 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) 3335 | { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) 3336 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) 3337 | { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) 3338 | { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) 3339 | { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) 3340 | { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) 3341 | { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) 3342 | { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) 3343 | { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) 3344 | { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) 3345 | { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) 3346 | { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) 3347 | { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) 3348 | { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) 3349 | { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (//) 3350 | { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) 3351 | { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) 3352 | { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) 3353 | { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) 3354 | { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) 3355 | { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) 3356 | { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) 3357 | { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) 3358 | { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) 3359 | { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) 3360 | { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) 3361 | { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) 3362 | { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) 3363 | { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) 3364 | { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) 3365 | { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) 3366 | { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) 3367 | { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) 3368 | { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) 3369 | { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) 3370 | { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) 3371 | { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) 3372 | { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) 3373 | { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) 3374 | { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) 3375 | { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) 3376 | { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) 3377 | { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) 3378 | { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) 3379 | { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) 3380 | { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) 3381 | { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) 3382 | { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) 3383 | { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) 3384 | { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) 3385 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) 3386 | { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) 3387 | { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) 3388 | { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) 3389 | { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) 3390 | { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) 3391 | { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) 3392 | { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) 3393 | { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) 3394 | { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) 3395 | { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) 3396 | { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) 3397 | { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) 3398 | { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) 3399 | { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) 3400 | { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) 3401 | { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) 3402 | { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) 3403 | { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) 3404 | { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) 3405 | { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) 3406 | { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) 3407 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) 3408 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) 3409 | { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) 3410 | { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) 3411 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) 3412 | { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) 3413 | { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) 3414 | { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) 3415 | { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) 3416 | { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) 3417 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F 3418 | }; 3419 | 3420 | 3421 | 3422 | // "0" -> [48] 3423 | // "9" -> [57] 3424 | // ":" -> [58] 3425 | 3426 | 3427 | void print_font_char(int start_x_pix, int start_y_pix, int font_char_num, uint8_t col_value) 3428 | { 3429 | int font_w = 8; 3430 | int font_h = 8; 3431 | 3432 | uint8_t *y_plane = av_video_frame.y; 3433 | // uint8_t col_value = 0; // black 3434 | char *bitmap = font8x8_basic[font_char_num]; 3435 | 3436 | int k; 3437 | int j; 3438 | int offset = 0; 3439 | int set = 0; 3440 | 3441 | for (k=0;k 255 ? 255 : (X) < 0 ? 0 : X) 3517 | 3518 | // RGB -> YUV 3519 | #define RGB2Y(R, G, B) CLIP(( ( 66 * (R) + 129 * (G) + 25 * (B) + 128) >> 8) + 16) 3520 | #define RGB2U(R, G, B) CLIP(( ( -38 * (R) - 74 * (G) + 112 * (B) + 128) >> 8) + 128) 3521 | #define RGB2V(R, G, B) CLIP(( ( 112 * (R) - 94 * (G) - 18 * (B) + 128) >> 8) + 128) 3522 | 3523 | // YUV -> RGB 3524 | #define C(Y) ( (Y) - 16 ) 3525 | #define D(U) ( (U) - 128 ) 3526 | #define E(V) ( (V) - 128 ) 3527 | 3528 | #define YUV2R(Y, U, V) CLIP(( 298 * C(Y) + 409 * E(V) + 128) >> 8) 3529 | #define YUV2G(Y, U, V) CLIP(( 298 * C(Y) - 100 * D(U) - 208 * E(V) + 128) >> 8) 3530 | #define YUV2B(Y, U, V) CLIP(( 298 * C(Y) + 516 * D(U) + 128) >> 8) 3531 | 3532 | void rbg_to_yuv(uint8_t r, uint8_t g, uint8_t b, uint8_t *y, uint8_t *u, uint8_t *v) 3533 | { 3534 | *y = RGB2Y(r, g, b); 3535 | *u = RGB2U(r, g, b); 3536 | *v = RGB2V(r, g, b); 3537 | } 3538 | 3539 | void text_on_yuf_frame_xy(int start_x_pix, int start_y_pix, const char* text) 3540 | { 3541 | int carriage = 0; 3542 | const int letter_width = 8; 3543 | const int letter_spacing = 1; 3544 | 3545 | int block_needed_width = 2 + 2 + (strlen(text) * (letter_width + letter_spacing)); 3546 | left_top_bar_into_yuv_frame(start_x_pix, start_y_pix, block_needed_width, 12, 255, 255, 255); 3547 | 3548 | int looper; 3549 | 3550 | for(looper=0;(int)looper < (int)strlen(text);looper++) 3551 | { 3552 | uint8_t c = text[looper]; 3553 | if ((c > 0) && (c < 127)) 3554 | { 3555 | print_font_char((12 + ((letter_width + letter_spacing) * carriage)), 12, c, 0); 3556 | } 3557 | else 3558 | { 3559 | // leave a blank 3560 | } 3561 | carriage++; 3562 | } 3563 | } 3564 | 3565 | void left_top_bar_into_yuv_frame(int bar_start_x_pix, int bar_start_y_pix, int bar_w_pix, int bar_h_pix, uint8_t r, uint8_t g, uint8_t b) 3566 | { 3567 | // int bar_width = bar_w_pix; // 150; // should be mulitple of 2 !! 3568 | // int bar_height = bar_h_pix; // 20; // should be mulitple of 2 !! 3569 | // int bar_start_x = bar_start_x_pix; // 10; // should be mulitple of 2 !! (zero is also ok) 3570 | // int bar_start_y = bar_start_y_pix; // 10; // should be mulitple of 2 !! (zero is also ok) 3571 | 3572 | // uint8_t *y_plane = av_video_frame.y; 3573 | 3574 | int k; 3575 | int j; 3576 | // int offset = 0; 3577 | 3578 | for (k=0;k mono, 2 -> stereo 3679 | if ((err = snd_pcm_hw_params_set_channels (audio_capture_handle, hw_params, 1)) < 0) { 3680 | dbg(9, "cannot set channel count (%s)\n", 3681 | snd_strerror (err)); 3682 | //exit (1); 3683 | } 3684 | 3685 | if ((err = snd_pcm_hw_params (audio_capture_handle, hw_params)) < 0) { 3686 | dbg(9, "cannot set parameters (%s)\n", 3687 | snd_strerror (err)); 3688 | //exit (1); 3689 | } 3690 | 3691 | snd_pcm_hw_params_free (hw_params); 3692 | 3693 | if ((err = snd_pcm_prepare (audio_capture_handle)) < 0) { 3694 | dbg(9, "cannot prepare audio interface for use (%s)\n", 3695 | snd_strerror (err)); 3696 | //exit (1); 3697 | } 3698 | } 3699 | 3700 | #endif 3701 | 3702 | // ------------------ alsa recording ------------------ 3703 | // ------------------ alsa recording ------------------ 3704 | // ------------------ alsa recording ------------------ 3705 | 3706 | 3707 | void sigint_handler(int signo) 3708 | { 3709 | if (signo == SIGINT) 3710 | { 3711 | printf("received SIGINT, pid=%d\n", getpid()); 3712 | tox_loop_running = 0; 3713 | } 3714 | } 3715 | 3716 | int main(int argc, char *argv[]) 3717 | { 3718 | global_want_restart = 0; 3719 | global_video_active = 0; 3720 | global_send_first_frame = 0; 3721 | 3722 | // valid audio bitrates: [ bit_rate < 6 || bit_rate > 510 ] 3723 | global_audio_bit_rate = DEFAULT_GLOBAL_AUD_BITRATE; 3724 | global_video_bit_rate = DEFAULT_GLOBAL_VID_BITRATE; 3725 | 3726 | video_high = 0; 3727 | 3728 | logfile = fopen(log_filename, "wb"); 3729 | setvbuf(logfile, NULL, _IONBF, 0); 3730 | 3731 | v4l2_device = malloc(400); 3732 | memset(v4l2_device, 0, 400); 3733 | snprintf(v4l2_device, 399, "%s", "/dev/video0"); 3734 | 3735 | int aflag = 0; 3736 | char *cvalue = NULL; 3737 | int index; 3738 | int opt; 3739 | 3740 | const char *short_opt = "hvd:t23b:f"; 3741 | struct option long_opt[] = 3742 | { 3743 | {"help", no_argument, NULL, 'h'}, 3744 | {"version", no_argument, NULL, 'v'}, 3745 | {"videodevice", required_argument, NULL, 'd'}, 3746 | {NULL, 0, NULL, 0 } 3747 | }; 3748 | 3749 | while((opt = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1) 3750 | { 3751 | switch (opt) 3752 | { 3753 | case -1: /* no more arguments */ 3754 | case 0: /* long options toggles */ 3755 | break; 3756 | case 'a': 3757 | aflag = 1; 3758 | break; 3759 | case '2': 3760 | switch_nodelist_2 = 1; 3761 | break; 3762 | case '3': 3763 | switch_nodelist_2 = 2; 3764 | break; 3765 | case 't': 3766 | switch_tcponly = 1; 3767 | break; 3768 | case 'f': 3769 | video_high = 1; 3770 | break; 3771 | case 'd': 3772 | snprintf(v4l2_device, 399, "%s", optarg); 3773 | // printf("Using Videodevice: %s\n", v4l2_device); 3774 | dbg(3, "Using Videodevice: %s\n", v4l2_device); 3775 | break; 3776 | case 'b': 3777 | DEFAULT_GLOBAL_VID_BITRATE = (uint32_t)atoi(optarg); 3778 | dbg(3, "Using Videobitrate: %d\n", (int)DEFAULT_GLOBAL_VID_BITRATE); 3779 | global_video_bit_rate = DEFAULT_GLOBAL_VID_BITRATE; 3780 | break; 3781 | case 'v': 3782 | printf("Tox TCP-Relay version: %s\n", global_version_string); 3783 | if (logfile) 3784 | { 3785 | fclose(logfile); 3786 | logfile = NULL; 3787 | } 3788 | return(0); 3789 | break; 3790 | 3791 | case 'h': 3792 | printf("Usage: %s [OPTIONS]\n", argv[0]); 3793 | printf(" -d, --videodevice devicefile file\n"); 3794 | printf(" -b bitrate video bitrate in kbit/s\n"); 3795 | printf(" -f use 720p video mode\n"); 3796 | printf(" -t, tcp only mode\n"); 3797 | printf(" -2, use alternate bootnode list\n"); 3798 | printf(" -3, use only nodes.tox.chat as bootnode\n"); 3799 | printf(" -v, --version show version\n"); 3800 | printf(" -h, --help print this help and exit\n"); 3801 | printf("\n"); 3802 | if (logfile) 3803 | { 3804 | fclose(logfile); 3805 | logfile = NULL; 3806 | } 3807 | return(0); 3808 | 3809 | case ':': 3810 | case '?': 3811 | fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); 3812 | if (logfile) 3813 | { 3814 | fclose(logfile); 3815 | logfile = NULL; 3816 | } 3817 | return(-2); 3818 | 3819 | default: 3820 | fprintf(stderr, "%s: invalid option -- %c\n", argv[0], opt); 3821 | fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); 3822 | if (logfile) 3823 | { 3824 | fclose(logfile); 3825 | logfile = NULL; 3826 | } 3827 | return(-2); 3828 | } 3829 | } 3830 | 3831 | 3832 | Tox *tox = create_tox(); 3833 | global_start_time = time(NULL); 3834 | 3835 | const char *name = "ToxTCP-Relay"; 3836 | tox_self_set_name(tox, (uint8_t *)name, strlen(name), NULL); 3837 | 3838 | const char *status_message = "Tox TCP Relay Node"; 3839 | tox_self_set_status_message(tox, (uint8_t *)status_message, strlen(status_message), NULL); 3840 | 3841 | Friends.max_idx = 0; 3842 | 3843 | 3844 | bootstrap(tox); 3845 | 3846 | 3847 | print_tox_id(tox); 3848 | 3849 | // init callbacks ---------------------------------- 3850 | // tox_callback_friend_request(tox, friend_request_cb); 3851 | // tox_callback_friend_message(tox, friend_message_cb); 3852 | // tox_callback_friend_connection_status(tox, friendlist_onConnectionChange); 3853 | // tox_callback_friend_status(tox, on_tox_friend_status); 3854 | 3855 | // tox_callback_self_connection_status(tox, self_connection_status_cb); 3856 | 3857 | // tox_callback_file_chunk_request(tox, on_file_chunk_request); 3858 | // tox_callback_file_recv_control(tox, on_file_control); 3859 | // tox_callback_file_recv(tox, on_file_recv); 3860 | // tox_callback_file_recv_chunk(tox, on_file_recv_chunk); 3861 | // init callbacks ---------------------------------- 3862 | 3863 | 3864 | update_savedata_file(tox); 3865 | load_friendlist(tox); 3866 | 3867 | char path[300]; 3868 | snprintf(path, sizeof(path), "%s", my_avatar_filename); 3869 | int len = strlen(path) - 1; 3870 | avatar_set(tox, path, len); 3871 | 3872 | long long unsigned int cur_time = time(NULL); 3873 | uint8_t off = 1; 3874 | long long loop_counter = 0; 3875 | while (1) 3876 | { 3877 | tox_iterate(tox, NULL); 3878 | usleep(tox_iteration_interval(tox) * 1000); 3879 | if (tox_self_get_connection_status(tox) && off) 3880 | { 3881 | dbg(2, "Tox online, took %llu seconds\n", time(NULL) - cur_time); 3882 | off = 0; 3883 | break; 3884 | } 3885 | c_sleep(20); 3886 | loop_counter++; 3887 | 3888 | if (loop_counter > (50 * 20)) 3889 | { 3890 | loop_counter = 0; 3891 | // if not yet online, bootstrap every 20 seconds 3892 | dbg(2, "Tox NOT online yet, bootstrapping again\n"); 3893 | bootstrap(tox); 3894 | } 3895 | } 3896 | 3897 | 3898 | TOXAV_ERR_NEW rc; 3899 | dbg(2, "new Tox AV\n"); 3900 | mytox_av = toxav_new(tox, &rc); 3901 | if (rc != TOXAV_ERR_NEW_OK) 3902 | { 3903 | dbg(0, "Error at toxav_new: %d\n", rc); 3904 | } 3905 | 3906 | CallControl mytox_CC; 3907 | memset(&mytox_CC, 0, sizeof(CallControl)); 3908 | 3909 | // init AV callbacks ------------------------------- 3910 | // toxav_callback_call(mytox_av, t_toxav_call_cb, &mytox_CC); 3911 | // toxav_callback_call_state(mytox_av, t_toxav_call_state_cb, &mytox_CC); 3912 | // toxav_callback_bit_rate_status(mytox_av, t_toxav_bit_rate_status_cb, &mytox_CC); 3913 | // toxav_callback_video_receive_frame(mytox_av, t_toxav_receive_video_frame_cb, &mytox_CC); 3914 | // toxav_callback_audio_receive_frame(mytox_av, t_toxav_receive_audio_frame_cb, &mytox_CC); 3915 | // init AV callbacks ------------------------------- 3916 | 3917 | 3918 | // start toxav thread ------------------------------ 3919 | pthread_t tid[2]; // 0 -> toxav_iterate thread, 1 -> video send thread 3920 | 3921 | 3922 | // start toxav thread ------------------------------ 3923 | toxav_iterate_thread_stop = 0; 3924 | if (pthread_create(&(tid[0]), NULL, thread_av, (void *)mytox_av) != 0) 3925 | { 3926 | dbg(0, "AV iterate Thread create failed"); 3927 | } 3928 | else 3929 | { 3930 | dbg(2, "AV iterate Thread successfully created"); 3931 | } 3932 | 3933 | toxav_video_thread_stop = 0; 3934 | if (pthread_create(&(tid[1]), NULL, thread_video_av, (void *)mytox_av) != 0) 3935 | { 3936 | dbg(0, "AV video Thread create failed"); 3937 | } 3938 | else 3939 | { 3940 | dbg(2, "AV video Thread successfully created"); 3941 | } 3942 | // start toxav thread ------------------------------ 3943 | 3944 | 3945 | 3946 | // start audio recoding stuff ---------------------- 3947 | #ifdef HAVE_SOUND 3948 | init_sound_device(); 3949 | record_from_sound_device(); 3950 | close_sound_device(); 3951 | #endif 3952 | // start audio recoding stuff ---------------------- 3953 | 3954 | 3955 | 3956 | tox_loop_running = 1; 3957 | signal(SIGINT, sigint_handler); 3958 | 3959 | while (tox_loop_running) 3960 | { 3961 | tox_iterate(tox, NULL); 3962 | usleep(tox_iteration_interval(tox) * 1000); 3963 | 3964 | if (global_want_restart == 1) 3965 | { 3966 | // need to restart me! 3967 | break; 3968 | } 3969 | else 3970 | { 3971 | check_dir(tox); 3972 | check_friends_dir(tox); 3973 | } 3974 | } 3975 | 3976 | 3977 | kill_all_file_transfers(tox); 3978 | close_cam(); 3979 | toxav_kill(mytox_av); 3980 | tox_kill(tox); 3981 | 3982 | if (logfile) 3983 | { 3984 | fclose(logfile); 3985 | logfile = NULL; 3986 | } 3987 | 3988 | return 0; 3989 | } 3990 | 3991 | -------------------------------------------------------------------------------- /tox_tcp_relay/update_from_ci.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | ##################################################### 4 | # update binary from Circle CI (master branch) 5 | ##################################################### 6 | 7 | cd $(dirname "$0") 8 | 9 | pkill tox-bootstrapd_static # will stop bootstrapd 10 | cp -av tox-bootstrapd_static tox-bootstrapd_static__BACKUP 11 | wget -O tox-bootstrapd_static 'https://circleci.com/api/v1/project/zoff99/ToxTCP-RelayNode/latest/artifacts/0/$CIRCLE_ARTIFACTS/ubuntu_14_04_binaries/tox-bootstrapd_static?filter=successful&branch=master' 12 | chmod u+rwx tox-bootstrapd_static 13 | 14 | -------------------------------------------------------------------------------- /toxstatus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zoff99/ToxTCP-RelayNode/7fc1ef4ef96d5d2b96cd021e97be4f820b70300c/toxstatus.png --------------------------------------------------------------------------------