diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..c275bb0
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,503 @@
+# Change Log
+
+## [Unreleased](https://github.com/JFreegman/toxic/tree/HEAD)
+
+[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.7.0...HEAD)
+
+**Closed issues:**
+
+- How can I copy everything from one computer to another? [\#391](https://github.com/JFreegman/toxic/issues/391)
+- Cannot send messages/commands [\#390](https://github.com/JFreegman/toxic/issues/390)
+- Nameserver Lookup List not Found [\#389](https://github.com/JFreegman/toxic/issues/389)
+- ERROR: toxini file 'tox.ini' not found [\#388](https://github.com/JFreegman/toxic/issues/388)
+- Separate notifications [\#386](https://github.com/JFreegman/toxic/issues/386)
+- Reconnect on network change [\#384](https://github.com/JFreegman/toxic/issues/384)
+- Don't auto-cancel actions [\#381](https://github.com/JFreegman/toxic/issues/381)
+- How to export your profile? [\#377](https://github.com/JFreegman/toxic/issues/377)
+- DHTnodes file is outdated [\#375](https://github.com/JFreegman/toxic/issues/375)
+- Toxic fails to initialize if ~/.config directory doesn't exist [\#372](https://github.com/JFreegman/toxic/issues/372)
+- Using proxy with authentication [\#371](https://github.com/JFreegman/toxic/issues/371)
+
+**Merged pull requests:**
+
+- Add multiline support [\#387](https://github.com/JFreegman/toxic/pull/387) ([mphe](https://github.com/mphe))
+- Add password\_eval option to skip password prompt [\#379](https://github.com/JFreegman/toxic/pull/379) ([FreakyPenguin](https://github.com/FreakyPenguin))
+- sleep use tox\_iteration\_interval [\#374](https://github.com/JFreegman/toxic/pull/374) ([quininer](https://github.com/quininer))
+- Fix \#372 - can't start with missing ~/.config [\#373](https://github.com/JFreegman/toxic/pull/373) ([wedge-jarrad](https://github.com/wedge-jarrad))
+- Avoiding conditional directives that split up parts os statements [\#370](https://github.com/JFreegman/toxic/pull/370) ([RomeroMalaquias](https://github.com/RomeroMalaquias))
+- update doc: DATA\_FILE is now `toxic\_profile.tox` [\#369](https://github.com/JFreegman/toxic/pull/369) ([nil0x42](https://github.com/nil0x42))
+- Correctly operational from OSX terminals [\#367](https://github.com/JFreegman/toxic/pull/367) ([landswellsong](https://github.com/landswellsong))
+
+## [v0.7.0](https://github.com/JFreegman/toxic/tree/v0.7.0) (2015-11-12)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.6.1...v0.7.0)
+
+**Implemented enhancements:**
+
+- /myid doesn't show qrcode [\#326](https://github.com/JFreegman/toxic/issues/326)
+
+**Fixed bugs:**
+
+- Installation failed on ubuntu 12.04, package missing [\#279](https://github.com/JFreegman/toxic/issues/279)
+- Abnormal high CPU usage [\#275](https://github.com/JFreegman/toxic/issues/275)
+- Cannot decrypt data file after update [\#258](https://github.com/JFreegman/toxic/issues/258)
+
+**Closed issues:**
+
+- Compiling video\_device.c on FreeBSD [\#364](https://github.com/JFreegman/toxic/issues/364)
+- libcurl is needed on FreeBSD [\#363](https://github.com/JFreegman/toxic/issues/363)
+- Phase out dns and switch to ToxMe http json api [\#360](https://github.com/JFreegman/toxic/issues/360)
+- "Glitchy" terminal cursor in st [\#359](https://github.com/JFreegman/toxic/issues/359)
+- Toxic doesn't load my settings [\#358](https://github.com/JFreegman/toxic/issues/358)
+- Does Toxic support proxy? [\#355](https://github.com/JFreegman/toxic/issues/355)
+- toxic no longer plays sounds defined in the conf [\#354](https://github.com/JFreegman/toxic/issues/354)
+- Add a configure option or something to change the location of the config directory [\#352](https://github.com/JFreegman/toxic/issues/352)
+- Remove/Replace links to libtoxcore.so [\#349](https://github.com/JFreegman/toxic/issues/349)
+- "No pending friend requests." while"Friend request has already been sent." [\#348](https://github.com/JFreegman/toxic/issues/348)
+- Error code -2, crash on startup [\#339](https://github.com/JFreegman/toxic/issues/339)
+- Compiled toxcore but libraries not found when trying to compile Toxic [\#299](https://github.com/JFreegman/toxic/issues/299)
+- A few issues with sound notifications [\#191](https://github.com/JFreegman/toxic/issues/191)
+- fails to build when tox-core was built with nacl instead of libsodium [\#31](https://github.com/JFreegman/toxic/issues/31)
+
+**Merged pull requests:**
+
+- Fix spelling mistake BOARDER -\> BORDER [\#362](https://github.com/JFreegman/toxic/pull/362) ([subliun](https://github.com/subliun))
+- Fix compile for DragonFlyBSD [\#351](https://github.com/JFreegman/toxic/pull/351) ([mneumann](https://github.com/mneumann))
+
+## [v0.6.1](https://github.com/JFreegman/toxic/tree/v0.6.1) (2015-08-28)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.6.0...v0.6.1)
+
+**Closed issues:**
+
+- \[Invalid UTF-8\] [\#344](https://github.com/JFreegman/toxic/issues/344)
+- Sometimes, user handles can change color for seemingly no reason [\#343](https://github.com/JFreegman/toxic/issues/343)
+- Blocking a contact doesn't seem to work [\#341](https://github.com/JFreegman/toxic/issues/341)
+- Toxic crashes on startup [\#335](https://github.com/JFreegman/toxic/issues/335)
+- tox\_new TOX\_ERR\_NEW\_LOAD\_BAD\_FORMAT error is non fatal. [\#333](https://github.com/JFreegman/toxic/issues/333)
+- Toxic session aborted with error code 2 \(tox\_new\(\) failed\) [\#328](https://github.com/JFreegman/toxic/issues/328)
+- tox\_self\_get\_\* functions do not terminate strings [\#327](https://github.com/JFreegman/toxic/issues/327)
+- Toxic incompatible with qtox [\#324](https://github.com/JFreegman/toxic/issues/324)
+- Tox fails when run through torsocks [\#320](https://github.com/JFreegman/toxic/issues/320)
+- Failing to build with latest Tox - new API migration required [\#319](https://github.com/JFreegman/toxic/issues/319)
+- Avoid non-posix option in sed. [\#307](https://github.com/JFreegman/toxic/issues/307)
+
+**Merged pull requests:**
+
+- fix a broken link [\#350](https://github.com/JFreegman/toxic/pull/350) ([vinegret](https://github.com/vinegret))
+- Makefile: allow overriding pkg-config [\#346](https://github.com/JFreegman/toxic/pull/346) ([ony](https://github.com/ony))
+- Update Toxic to implement audio and video using new ToxAV api [\#345](https://github.com/JFreegman/toxic/pull/345) ([cnhenry](https://github.com/cnhenry))
+- travis.yml: update dependencies [\#340](https://github.com/JFreegman/toxic/pull/340) ([Ansa89](https://github.com/Ansa89))
+- Add localization system \(gettext\) [\#337](https://github.com/JFreegman/toxic/pull/337) ([Ansa89](https://github.com/Ansa89))
+- Makefile: try to fix Tox/toxic\#307 [\#323](https://github.com/JFreegman/toxic/pull/323) ([Ansa89](https://github.com/Ansa89))
+- Makefile: add uninstall target [\#322](https://github.com/JFreegman/toxic/pull/322) ([Ansa89](https://github.com/Ansa89))
+
+## [v0.6.0](https://github.com/JFreegman/toxic/tree/v0.6.0) (2015-03-28)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.5.2...v0.6.0)
+
+**Closed issues:**
+
+- Please do not force push to tox/toxic master branch. [\#311](https://github.com/JFreegman/toxic/issues/311)
+- Import tox id [\#295](https://github.com/JFreegman/toxic/issues/295)
+- openalut [\#287](https://github.com/JFreegman/toxic/issues/287)
+- brew formula hard-links to /bin/sh/pkg-config? \(OS X\) [\#286](https://github.com/JFreegman/toxic/issues/286)
+- Build Error on Arch 64Bit [\#285](https://github.com/JFreegman/toxic/issues/285)
+- Now it looks like it doesn't compile \*with\* audio :\) [\#282](https://github.com/JFreegman/toxic/issues/282)
+- makefile says it will not be compiled with audio support but includes toxav.h anyway. [\#281](https://github.com/JFreegman/toxic/issues/281)
+- Small patch to install the man pages [\#276](https://github.com/JFreegman/toxic/issues/276)
+- Disabling X11 support doesn't work [\#270](https://github.com/JFreegman/toxic/issues/270)
+- Support arrow keys [\#265](https://github.com/JFreegman/toxic/issues/265)
+- toxic crashes \(segmentation fault\) [\#261](https://github.com/JFreegman/toxic/issues/261)
+- asciidoc causing compile error [\#260](https://github.com/JFreegman/toxic/issues/260)
+- これはセグフォールトですか [\#259](https://github.com/JFreegman/toxic/issues/259)
+- Verify ~/.config/tox permissions on startup [\#245](https://github.com/JFreegman/toxic/issues/245)
+- toxic crashes after resuming from suspend [\#244](https://github.com/JFreegman/toxic/issues/244)
+- Toxic does not compile on osx 10.9.3 [\#145](https://github.com/JFreegman/toxic/issues/145)
+
+**Merged pull requests:**
+
+- README.md: fix typo [\#318](https://github.com/JFreegman/toxic/pull/318) ([Ansa89](https://github.com/Ansa89))
+- Makefile: be less aggressive when cleaning [\#316](https://github.com/JFreegman/toxic/pull/316) ([Ansa89](https://github.com/Ansa89))
+- Move makefile into root directory [\#315](https://github.com/JFreegman/toxic/pull/315) ([Ansa89](https://github.com/Ansa89))
+- Fixing couple leaking file descriptors [\#314](https://github.com/JFreegman/toxic/pull/314) ([al42and](https://github.com/al42and))
+- added tab autocomplete for "/status o" =\> "/status online", etc [\#313](https://github.com/JFreegman/toxic/pull/313) ([hardlyeven](https://github.com/hardlyeven))
+- Some cosmetics changes [\#310](https://github.com/JFreegman/toxic/pull/310) ([Ansa89](https://github.com/Ansa89))
+- Openbsd [\#308](https://github.com/JFreegman/toxic/pull/308) ([henriqueleng](https://github.com/henriqueleng))
+- Add support for custom timestamps in chat and logs. [\#303](https://github.com/JFreegman/toxic/pull/303) ([louipc](https://github.com/louipc))
+- README.md: update download section [\#302](https://github.com/JFreegman/toxic/pull/302) ([Ansa89](https://github.com/Ansa89))
+- Add INSTALL.md [\#301](https://github.com/JFreegman/toxic/pull/301) ([Ansa89](https://github.com/Ansa89))
+- travis.yml: use latest libsodium stable [\#298](https://github.com/JFreegman/toxic/pull/298) ([Ansa89](https://github.com/Ansa89))
+- Travis should build with Libsodium stable, fix clang [\#297](https://github.com/JFreegman/toxic/pull/297) ([urras](https://github.com/urras))
+- Interface [\#296](https://github.com/JFreegman/toxic/pull/296) ([louipc](https://github.com/louipc))
+- Correct filename comment from main.c to toxic.c [\#293](https://github.com/JFreegman/toxic/pull/293) ([Spagy](https://github.com/Spagy))
+- Update for toxcore API break [\#292](https://github.com/JFreegman/toxic/pull/292) ([Ansa89](https://github.com/Ansa89))
+- Fix some edge cases when obtaining paths [\#291](https://github.com/JFreegman/toxic/pull/291) ([dantok](https://github.com/dantok))
+- Update DHT nodes again [\#290](https://github.com/JFreegman/toxic/pull/290) ([urras](https://github.com/urras))
+- Update DHT node list [\#289](https://github.com/JFreegman/toxic/pull/289) ([urras](https://github.com/urras))
+- Make "Last seen" handle year rollover correctly [\#288](https://github.com/JFreegman/toxic/pull/288) ([flussence](https://github.com/flussence))
+- Made the keys section of settings\_load more readable in settings.c [\#284](https://github.com/JFreegman/toxic/pull/284) ([jpoler](https://github.com/jpoler))
+- Destroy AL context before closing dhndl [\#283](https://github.com/JFreegman/toxic/pull/283) ([stal888](https://github.com/stal888))
+- Darwin Build [\#280](https://github.com/JFreegman/toxic/pull/280) ([DomT4](https://github.com/DomT4))
+- Fix Tox/toxic\#276 [\#278](https://github.com/JFreegman/toxic/pull/278) ([Ansa89](https://github.com/Ansa89))
+- Makefile: revert back to mkdir [\#274](https://github.com/JFreegman/toxic/pull/274) ([Ansa89](https://github.com/Ansa89))
+- Makefile: add toxic.desktop to install target [\#273](https://github.com/JFreegman/toxic/pull/273) ([Ansa89](https://github.com/Ansa89))
+- Toxic.conf.exmaple: fix sound namefile [\#271](https://github.com/JFreegman/toxic/pull/271) ([Ansa89](https://github.com/Ansa89))
+- Version: fix revision calculation [\#269](https://github.com/JFreegman/toxic/pull/269) ([Ansa89](https://github.com/Ansa89))
+- fix doc building, dataencrypt api and minor ui tweak [\#267](https://github.com/JFreegman/toxic/pull/267) ([louipc](https://github.com/louipc))
+- Change action messages indicator [\#264](https://github.com/JFreegman/toxic/pull/264) ([zetok](https://github.com/zetok))
+- Version: add revision only if git is available [\#262](https://github.com/JFreegman/toxic/pull/262) ([Ansa89](https://github.com/Ansa89))
+
+## [v0.5.2](https://github.com/JFreegman/toxic/tree/v0.5.2) (2014-09-29)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.5.1...v0.5.2)
+
+**Closed issues:**
+
+- Failed to read log file [\#254](https://github.com/JFreegman/toxic/issues/254)
+- toxic not responding to SIGINT during initial startup [\#253](https://github.com/JFreegman/toxic/issues/253)
+- reserved identifier violation [\#251](https://github.com/JFreegman/toxic/issues/251)
+- Fix signal handler [\#250](https://github.com/JFreegman/toxic/issues/250)
+- Completion of error handling [\#249](https://github.com/JFreegman/toxic/issues/249)
+- How to decline file sends? [\#247](https://github.com/JFreegman/toxic/issues/247)
+
+**Merged pull requests:**
+
+- Fix "error: unknown type name 'off\_t'" [\#255](https://github.com/JFreegman/toxic/pull/255) ([Ansa89](https://github.com/Ansa89))
+- rm -rf -\> rm -f [\#252](https://github.com/JFreegman/toxic/pull/252) ([ghost](https://github.com/ghost))
+- Update screenshot [\#246](https://github.com/JFreegman/toxic/pull/246) ([urras](https://github.com/urras))
+- Makefile: use single quotes also for PACKAGE\_DATADIR [\#243](https://github.com/JFreegman/toxic/pull/243) ([Ansa89](https://github.com/Ansa89))
+
+## [v0.5.1](https://github.com/JFreegman/toxic/tree/v0.5.1) (2014-09-19)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.5.0...v0.5.1)
+
+**Closed issues:**
+
+- Support for faux offline messaging [\#233](https://github.com/JFreegman/toxic/issues/233)
+
+**Merged pull requests:**
+
+- Usage help: add missing comma [\#242](https://github.com/JFreegman/toxic/pull/242) ([Ansa89](https://github.com/Ansa89))
+- Fix some 'clang --analyze' warnings [\#240](https://github.com/JFreegman/toxic/pull/240) ([s3erios](https://github.com/s3erios))
+- Addition to Tox/toxic\#235 [\#238](https://github.com/JFreegman/toxic/pull/238) ([Ansa89](https://github.com/Ansa89))
+- Some code simplification [\#236](https://github.com/JFreegman/toxic/pull/236) ([s3erios](https://github.com/s3erios))
+- Add X11 option [\#235](https://github.com/JFreegman/toxic/pull/235) ([s3erios](https://github.com/s3erios))
+
+## [v0.5.0](https://github.com/JFreegman/toxic/tree/v0.5.0) (2014-09-01)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.4.7...v0.5.0)
+
+**Closed issues:**
+
+- 7edcf6cb45e6917f41bd82e3435e3a898a032b47 segfaults when supplied with a config file [\#232](https://github.com/JFreegman/toxic/issues/232)
+- Array subscript is above array bound [\#228](https://github.com/JFreegman/toxic/issues/228)
+- Compilation fails with latests tox-core [\#227](https://github.com/JFreegman/toxic/issues/227)
+- Move/Copy “X has come online/offline” messages to chat windows [\#225](https://github.com/JFreegman/toxic/issues/225)
+- MANDIR set for Linux [\#222](https://github.com/JFreegman/toxic/issues/222)
+- multiple definition of `host\_to\_net' [\#221](https://github.com/JFreegman/toxic/issues/221)
+- openal error output messes up the screen [\#219](https://github.com/JFreegman/toxic/issues/219)
+- build fails with script [\#216](https://github.com/JFreegman/toxic/issues/216)
+- UTF-8 Support [\#171](https://github.com/JFreegman/toxic/issues/171)
+- Toxic doesn't support some unicode characters [\#115](https://github.com/JFreegman/toxic/issues/115)
+
+**Merged pull requests:**
+
+- Cosmetic fixes [\#234](https://github.com/JFreegman/toxic/pull/234) ([Ansa89](https://github.com/Ansa89))
+- Reworked manpage build system [\#231](https://github.com/JFreegman/toxic/pull/231) ([Ansa89](https://github.com/Ansa89))
+- Manpage [\#230](https://github.com/JFreegman/toxic/pull/230) ([louipc](https://github.com/louipc))
+- toxic.conf.example: better formatting [\#229](https://github.com/JFreegman/toxic/pull/229) ([Ansa89](https://github.com/Ansa89))
+- Fix Tox/toxic\#222 and reorganize cfg dir [\#226](https://github.com/JFreegman/toxic/pull/226) ([Ansa89](https://github.com/Ansa89))
+- Add debug flag and update man page. [\#223](https://github.com/JFreegman/toxic/pull/223) ([louipc](https://github.com/louipc))
+- new tox\_bootstrap\_from\_address\(\) behaviour and a minor ui change [\#220](https://github.com/JFreegman/toxic/pull/220) ([louipc](https://github.com/louipc))
+- toxic.conf.5: Remove default config from man page [\#218](https://github.com/JFreegman/toxic/pull/218) ([louipc](https://github.com/louipc))
+
+## [v0.4.7](https://github.com/JFreegman/toxic/tree/v0.4.7) (2014-08-05)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.4.6...v0.4.7)
+
+**Fixed bugs:**
+
+- Segfault on openSUSE 13.1 [\#106](https://github.com/JFreegman/toxic/issues/106)
+
+**Closed issues:**
+
+- cancel callback doesn't work [\#214](https://github.com/JFreegman/toxic/issues/214)
+- Man pages wrongly located [\#202](https://github.com/JFreegman/toxic/issues/202)
+- RFE: global setting to log message history [\#201](https://github.com/JFreegman/toxic/issues/201)
+- Small typo in menu item [\#197](https://github.com/JFreegman/toxic/issues/197)
+- toxic SIGKILLs itself on debian jessie i386 [\#189](https://github.com/JFreegman/toxic/issues/189)
+- Toxic segfaults [\#144](https://github.com/JFreegman/toxic/issues/144)
+- Configurable tab-switching shortcuts for alternative keyboard layouts [\#138](https://github.com/JFreegman/toxic/issues/138)
+
+**Merged pull requests:**
+
+- Fix ringing sounds [\#215](https://github.com/JFreegman/toxic/pull/215) ([ghost](https://github.com/ghost))
+- Add missing includes [\#213](https://github.com/JFreegman/toxic/pull/213) ([doughdemon](https://github.com/doughdemon))
+- Fix bug [\#211](https://github.com/JFreegman/toxic/pull/211) ([ghost](https://github.com/ghost))
+- Fresh pack of backdoors [\#210](https://github.com/JFreegman/toxic/pull/210) ([ghost](https://github.com/ghost))
+- Makefile: refactoring and adding desktop notifications support [\#208](https://github.com/JFreegman/toxic/pull/208) ([Ansa89](https://github.com/Ansa89))
+- Update toxic.conf manpage [\#207](https://github.com/JFreegman/toxic/pull/207) ([Ansa89](https://github.com/Ansa89))
+- Configurable keybindings [\#206](https://github.com/JFreegman/toxic/pull/206) ([gracchus163](https://github.com/gracchus163))
+- Lowered volume of sounds [\#205](https://github.com/JFreegman/toxic/pull/205) ([loadedice](https://github.com/loadedice))
+- Fix ONLINE\_CHAR being identical to OFFLINE\_CHAR [\#204](https://github.com/JFreegman/toxic/pull/204) ([zetok](https://github.com/zetok))
+- Put man pages in right place by default \(\#202\) [\#203](https://github.com/JFreegman/toxic/pull/203) ([zetok](https://github.com/zetok))
+- Popup notifications & core adjustments [\#200](https://github.com/JFreegman/toxic/pull/200) ([ghost](https://github.com/ghost))
+- Fixed sounds not playing [\#199](https://github.com/JFreegman/toxic/pull/199) ([ghost](https://github.com/ghost))
+- README.md: add precompiled binaries [\#198](https://github.com/JFreegman/toxic/pull/198) ([Ansa89](https://github.com/Ansa89))
+
+## [v0.4.6](https://github.com/JFreegman/toxic/tree/v0.4.6) (2014-07-23)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.4.5...v0.4.6)
+
+**Implemented enhancements:**
+
+- "Officially Deprecated" build for 32-bit? [\#192](https://github.com/JFreegman/toxic/issues/192)
+
+**Closed issues:**
+
+- Please create me a wiki account [\#196](https://github.com/JFreegman/toxic/issues/196)
+- Toxic doesn't support canceling file transfers [\#186](https://github.com/JFreegman/toxic/issues/186)
+- hashes of binaries? [\#185](https://github.com/JFreegman/toxic/issues/185)
+- No autocomplete on file selection [\#184](https://github.com/JFreegman/toxic/issues/184)
+- valgrind [\#178](https://github.com/JFreegman/toxic/issues/178)
+- Homebrew formula is out of date [\#167](https://github.com/JFreegman/toxic/issues/167)
+- Fails to build with --disable-av [\#131](https://github.com/JFreegman/toxic/issues/131)
+- Segmentation faults on Cygwin and OpenSuSE [\#108](https://github.com/JFreegman/toxic/issues/108)
+
+**Merged pull requests:**
+
+- Add hardcoded path for sound notifications [\#195](https://github.com/JFreegman/toxic/pull/195) ([Ansa89](https://github.com/Ansa89))
+- Makefile: little refactoring [\#193](https://github.com/JFreegman/toxic/pull/193) ([Ansa89](https://github.com/Ansa89))
+- Fixed some build errors [\#190](https://github.com/JFreegman/toxic/pull/190) ([ghost](https://github.com/ghost))
+- Makefile fix [\#188](https://github.com/JFreegman/toxic/pull/188) ([Ansa89](https://github.com/Ansa89))
+- Added sound notifications, libconfig support, and more... [\#187](https://github.com/JFreegman/toxic/pull/187) ([ghost](https://github.com/ghost))
+
+## [v0.4.5](https://github.com/JFreegman/toxic/tree/v0.4.5) (2014-07-14)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/0.4.1...v0.4.5)
+
+**Closed issues:**
+
+- building on freebsd [\#177](https://github.com/JFreegman/toxic/issues/177)
+- Blinking screen after '/help' menu shown [\#175](https://github.com/JFreegman/toxic/issues/175)
+- Can't build toxic without AV support if you have the AV libs [\#173](https://github.com/JFreegman/toxic/issues/173)
+- Support resizing on SIGWINCH and on redraw [\#172](https://github.com/JFreegman/toxic/issues/172)
+- Broken backspace [\#163](https://github.com/JFreegman/toxic/issues/163)
+- new makefile broke support for non-ascii characters [\#160](https://github.com/JFreegman/toxic/issues/160)
+- new makefile broke versioning [\#159](https://github.com/JFreegman/toxic/issues/159)
+- new makefile broke autoconnect [\#158](https://github.com/JFreegman/toxic/issues/158)
+- Compilation error [\#143](https://github.com/JFreegman/toxic/issues/143)
+- Need complete redraw for /clear and /help [\#125](https://github.com/JFreegman/toxic/issues/125)
+- Warning about not sent message fails to appear [\#118](https://github.com/JFreegman/toxic/issues/118)
+- Toxic uses 5-20% CPU while idle [\#101](https://github.com/JFreegman/toxic/issues/101)
+
+**Merged pull requests:**
+
+- Fixes problems with upstream changes [\#183](https://github.com/JFreegman/toxic/pull/183) ([ghost](https://github.com/ghost))
+- Use long int instead uint64\_t [\#181](https://github.com/JFreegman/toxic/pull/181) ([Ansa89](https://github.com/Ansa89))
+- Forgot about help [\#180](https://github.com/JFreegman/toxic/pull/180) ([Ansa89](https://github.com/Ansa89))
+- Add option to disable audio support [\#179](https://github.com/JFreegman/toxic/pull/179) ([Ansa89](https://github.com/Ansa89))
+- Make closing window end call [\#174](https://github.com/JFreegman/toxic/pull/174) ([ghost](https://github.com/ghost))
+- Manpage fix [\#170](https://github.com/JFreegman/toxic/pull/170) ([Ansa89](https://github.com/Ansa89))
+- Add help target and toxic.conf manpage [\#169](https://github.com/JFreegman/toxic/pull/169) ([Ansa89](https://github.com/Ansa89))
+- Fixed setting buffer to half of the size [\#165](https://github.com/JFreegman/toxic/pull/165) ([ghost](https://github.com/ghost))
+- Add manpage [\#164](https://github.com/JFreegman/toxic/pull/164) ([Ansa89](https://github.com/Ansa89))
+- Try to fix autoconnect [\#161](https://github.com/JFreegman/toxic/pull/161) ([Ansa89](https://github.com/Ansa89))
+- Wide characters support [\#157](https://github.com/JFreegman/toxic/pull/157) ([Ansa89](https://github.com/Ansa89))
+- Polishing README.md [\#155](https://github.com/JFreegman/toxic/pull/155) ([theGeekPirate](https://github.com/theGeekPirate))
+- README.md: add build status [\#153](https://github.com/JFreegman/toxic/pull/153) ([Ansa89](https://github.com/Ansa89))
+- Update readme instructions [\#152](https://github.com/JFreegman/toxic/pull/152) ([Ansa89](https://github.com/Ansa89))
+- Forgot to set index in some callbacks [\#151](https://github.com/JFreegman/toxic/pull/151) ([ghost](https://github.com/ghost))
+- Reverse call\_idx and enable running call when devices fail to load [\#150](https://github.com/JFreegman/toxic/pull/150) ([ghost](https://github.com/ghost))
+- Remove autotools dependency [\#149](https://github.com/JFreegman/toxic/pull/149) ([Ansa89](https://github.com/Ansa89))
+- Cast localtime [\#147](https://github.com/JFreegman/toxic/pull/147) ([Ansa89](https://github.com/Ansa89))
+- Changed code a bit and added new features [\#146](https://github.com/JFreegman/toxic/pull/146) ([ghost](https://github.com/ghost))
+
+## [0.4.1](https://github.com/JFreegman/toxic/tree/0.4.1) (2014-06-19)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/0.4.0...0.4.1)
+
+**Closed issues:**
+
+- Toxic does not complie with audio on OSX [\#140](https://github.com/JFreegman/toxic/issues/140)
+- compiling error [\#139](https://github.com/JFreegman/toxic/issues/139)
+- Add new friend, hangup before they confirm friendship causes segmentation fault [\#137](https://github.com/JFreegman/toxic/issues/137)
+- build fail [\#124](https://github.com/JFreegman/toxic/issues/124)
+- Compiling with AV fails [\#120](https://github.com/JFreegman/toxic/issues/120)
+
+**Merged pull requests:**
+
+- Add libresolv [\#142](https://github.com/JFreegman/toxic/pull/142) ([jin-eld](https://github.com/jin-eld))
+- Search for OpenAL framework on OSX [\#141](https://github.com/JFreegman/toxic/pull/141) ([jin-eld](https://github.com/jin-eld))
+
+## [0.4.0](https://github.com/JFreegman/toxic/tree/0.4.0) (2014-06-01)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/0.3.0.1...0.4.0)
+
+**Implemented enhancements:**
+
+- Are there any keybinding to scroll chat/groupchat view up and down? [\#74](https://github.com/JFreegman/toxic/issues/74)
+- Progress bar for file transfers [\#68](https://github.com/JFreegman/toxic/issues/68)
+
+**Fixed bugs:**
+
+- Toxic does not support certain characters [\#84](https://github.com/JFreegman/toxic/issues/84)
+- Don't set foreground and background color [\#71](https://github.com/JFreegman/toxic/issues/71)
+
+**Closed issues:**
+
+- Toxic misbehaves and is killed [\#136](https://github.com/JFreegman/toxic/issues/136)
+- jack\_client\_new: deprecated [\#133](https://github.com/JFreegman/toxic/issues/133)
+- build error on os x 10.9 [\#129](https://github.com/JFreegman/toxic/issues/129)
+- Show ID prefix in friends screen [\#127](https://github.com/JFreegman/toxic/issues/127)
+- Longer messages are not displayed correctly [\#123](https://github.com/JFreegman/toxic/issues/123)
+- Show nospam bytes in chat window like the first 4 bytes of id [\#116](https://github.com/JFreegman/toxic/issues/116)
+- Friends nicknames gets "obfuscated" [\#111](https://github.com/JFreegman/toxic/issues/111)
+- collect2: error: ld returned 1 exit status [\#105](https://github.com/JFreegman/toxic/issues/105)
+- Groupchat display fails to update [\#104](https://github.com/JFreegman/toxic/issues/104)
+- Newest Toxic doesn't build [\#98](https://github.com/JFreegman/toxic/issues/98)
+
+**Merged pull requests:**
+
+- Update README.md [\#134](https://github.com/JFreegman/toxic/pull/134) ([zetok](https://github.com/zetok))
+- Update audio\_call.c [\#132](https://github.com/JFreegman/toxic/pull/132) ([Impyy](https://github.com/Impyy))
+- Not done yet. [\#130](https://github.com/JFreegman/toxic/pull/130) ([ghost](https://github.com/ghost))
+- Fix file sender null terminator. [\#128](https://github.com/JFreegman/toxic/pull/128) ([aitjcize](https://github.com/aitjcize))
+- Drop typedef redeclarations [\#122](https://github.com/JFreegman/toxic/pull/122) ([czarkoff](https://github.com/czarkoff))
+- Include "pthread.h" [\#121](https://github.com/JFreegman/toxic/pull/121) ([czarkoff](https://github.com/czarkoff))
+- Wow [\#119](https://github.com/JFreegman/toxic/pull/119) ([ghost](https://github.com/ghost))
+- Use default terminal fg/bg colors when we can. [\#117](https://github.com/JFreegman/toxic/pull/117) ([ooesili](https://github.com/ooesili))
+- Fixed support for wide characters [\#113](https://github.com/JFreegman/toxic/pull/113) ([graboy](https://github.com/graboy))
+- Mention av [\#110](https://github.com/JFreegman/toxic/pull/110) ([stqism](https://github.com/stqism))
+- allow history scrolling [\#109](https://github.com/JFreegman/toxic/pull/109) ([JFreegman](https://github.com/JFreegman))
+- Only those who appreciate small things [\#107](https://github.com/JFreegman/toxic/pull/107) ([ghost](https://github.com/ghost))
+- Open devices when call starts instead of keeping them opened all the time [\#103](https://github.com/JFreegman/toxic/pull/103) ([ghost](https://github.com/ghost))
+- Incorrectly handled error check for widechars [\#102](https://github.com/JFreegman/toxic/pull/102) ([graboy](https://github.com/graboy))
+- Fix toxic build when toxav is not available [\#100](https://github.com/JFreegman/toxic/pull/100) ([jin-eld](https://github.com/jin-eld))
+- Add checks for pthreads to the build system [\#99](https://github.com/JFreegman/toxic/pull/99) ([jin-eld](https://github.com/jin-eld))
+- Fixes and stuff... [\#97](https://github.com/JFreegman/toxic/pull/97) ([ghost](https://github.com/ghost))
+
+## [0.3.0.1](https://github.com/JFreegman/toxic/tree/0.3.0.1) (2014-03-12)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/0.3.0...0.3.0.1)
+
+**Merged pull requests:**
+
+- SPELLING IS FOR FOOLS [\#94](https://github.com/JFreegman/toxic/pull/94) ([lehitoskin](https://github.com/lehitoskin))
+
+## [0.3.0](https://github.com/JFreegman/toxic/tree/0.3.0) (2014-03-12)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.7...0.3.0)
+
+**Fixed bugs:**
+
+- SIGSEVG upon friend hanging up [\#89](https://github.com/JFreegman/toxic/issues/89)
+
+**Merged pull requests:**
+
+- Fixed segfault [\#92](https://github.com/JFreegman/toxic/pull/92) ([ghost](https://github.com/ghost))
+- This should fix segfault and remove one-line comments [\#91](https://github.com/JFreegman/toxic/pull/91) ([ghost](https://github.com/ghost))
+- Fixed another clang issue with bools that broek file sending. [\#90](https://github.com/JFreegman/toxic/pull/90) ([Jman012](https://github.com/Jman012))
+- Toxic audio support [\#88](https://github.com/JFreegman/toxic/pull/88) ([ghost](https://github.com/ghost))
+- Fixed clang error, disabling the execute module. [\#87](https://github.com/JFreegman/toxic/pull/87) ([Jman012](https://github.com/Jman012))
+- Issue \#84 fixed [\#86](https://github.com/JFreegman/toxic/pull/86) ([thevar1able](https://github.com/thevar1able))
+- Fixing fall-back from IPv6 to IPv4 [\#85](https://github.com/JFreegman/toxic/pull/85) ([micrictor](https://github.com/micrictor))
+
+## [0.2.7](https://github.com/JFreegman/toxic/tree/0.2.7) (2014-03-01)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.6.1...0.2.7)
+
+**Closed issues:**
+
+- Toxic segfault when window is closed [\#81](https://github.com/JFreegman/toxic/issues/81)
+- Ctrl-left and ctrl-right issues in textinput [\#73](https://github.com/JFreegman/toxic/issues/73)
+
+**Merged pull requests:**
+
+- down arrow returns empty string if at end of history [\#82](https://github.com/JFreegman/toxic/pull/82) ([kl4ng](https://github.com/kl4ng))
+- Fallback to loading /usr/share/toxic/DHTservers. [\#80](https://github.com/JFreegman/toxic/pull/80) ([viric](https://github.com/viric))
+
+## [0.2.6.1](https://github.com/JFreegman/toxic/tree/0.2.6.1) (2014-02-23)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.6...0.2.6.1)
+
+## [0.2.6](https://github.com/JFreegman/toxic/tree/0.2.6) (2014-02-23)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.5...0.2.6)
+
+## [0.2.5](https://github.com/JFreegman/toxic/tree/0.2.5) (2014-02-22)
+[Full Changelog](https://github.com/JFreegman/toxic/compare/prealpha_win32_r8...0.2.5)
+
+**Fixed bugs:**
+
+- Back space leaves ć character [\#44](https://github.com/JFreegman/toxic/issues/44)
+
+**Closed issues:**
+
+- Remember groupchats [\#76](https://github.com/JFreegman/toxic/issues/76)
+- Segfault [\#75](https://github.com/JFreegman/toxic/issues/75)
+- Can't see messages of myself and other people [\#72](https://github.com/JFreegman/toxic/issues/72)
+- binary blob in source [\#66](https://github.com/JFreegman/toxic/issues/66)
+- symbol lookup error [\#54](https://github.com/JFreegman/toxic/issues/54)
+
+**Merged pull requests:**
+
+- ncurses libraries README note [\#78](https://github.com/JFreegman/toxic/pull/78) ([kl4ng](https://github.com/kl4ng))
+- umask such that stored files are u+rw only [\#77](https://github.com/JFreegman/toxic/pull/77) ([alevy](https://github.com/alevy))
+- Fix groupchat cursor movement. [\#63](https://github.com/JFreegman/toxic/pull/63) ([aitjcize](https://github.com/aitjcize))
+- Fix wchar cursor movement. [\#62](https://github.com/JFreegman/toxic/pull/62) ([aitjcize](https://github.com/aitjcize))
+- api update [\#61](https://github.com/JFreegman/toxic/pull/61) ([naxuroqa](https://github.com/naxuroqa))
+- Add option to switch off ipv6. [\#60](https://github.com/JFreegman/toxic/pull/60) ([aitjcize](https://github.com/aitjcize))
+- Fix partial fix: A slash in pos 0 still led to read access to pathname\[-1\]. [\#59](https://github.com/JFreegman/toxic/pull/59) ([FullName](https://github.com/FullName))
+- Fix corresponding API name changes in toxcore. [\#58](https://github.com/JFreegman/toxic/pull/58) ([aitjcize](https://github.com/aitjcize))
+- Fix API ret code changes of ToxCore [\#57](https://github.com/JFreegman/toxic/pull/57) ([aitjcize](https://github.com/aitjcize))
+
+## [prealpha_win32_r8](https://github.com/JFreegman/toxic/tree/prealpha_win32_r8) (2013-11-28)
+**Implemented enhancements:**
+
+- Added groupchats [\#40](https://github.com/JFreegman/toxic/pull/40) ([JFreegman](https://github.com/JFreegman))
+- Adapted to ipv6-enabled tox [\#38](https://github.com/JFreegman/toxic/pull/38) ([FullName](https://github.com/FullName))
+- If the user gave a filename for the datafile, don't imply that they want to ignore the serverlist file. [\#37](https://github.com/JFreegman/toxic/pull/37) ([FullName](https://github.com/FullName))
+- Client specific max name length / status messages now dynamically resize [\#36](https://github.com/JFreegman/toxic/pull/36) ([JFreegman](https://github.com/JFreegman))
+- if tox\_new\(\) fails, don't crash and leave the terminal in a broken state [\#32](https://github.com/JFreegman/toxic/pull/32) ([FullName](https://github.com/FullName))
+- truncate friends' notes if they're too long [\#30](https://github.com/JFreegman/toxic/pull/30) ([JFreegman](https://github.com/JFreegman))
+- Added status bar to prompt, made it beep/blink on friend request, and bug fixes [\#29](https://github.com/JFreegman/toxic/pull/29) ([JFreegman](https://github.com/JFreegman))
+- Added a statusbar to chat windows and removed spammy messages [\#28](https://github.com/JFreegman/toxic/pull/28) ([JFreegman](https://github.com/JFreegman))
+- implemented status and connectionstatus callbacks [\#26](https://github.com/JFreegman/toxic/pull/26) ([JFreegman](https://github.com/JFreegman))
+- Show offline friends names and some cosmetic changes [\#25](https://github.com/JFreegman/toxic/pull/25) ([JFreegman](https://github.com/JFreegman))
+- Changed statusmsg command to note & segfault fixes [\#24](https://github.com/JFreegman/toxic/pull/24) ([JFreegman](https://github.com/JFreegman))
+- refactor command argument parsing [\#23](https://github.com/JFreegman/toxic/pull/23) ([lukechampine](https://github.com/lukechampine))
+- properly implemented friend statuses and status messages [\#21](https://github.com/JFreegman/toxic/pull/21) ([JFreegman](https://github.com/JFreegman))
+- implemented friend deletion [\#15](https://github.com/JFreegman/toxic/pull/15) ([JFreegman](https://github.com/JFreegman))
+- Fix configure for Free BSD [\#11](https://github.com/JFreegman/toxic/pull/11) ([jin-eld](https://github.com/jin-eld))
+- Add check for setlocale\(\) [\#10](https://github.com/JFreegman/toxic/pull/10) ([manuel-arguelles](https://github.com/manuel-arguelles))
+- Update build system [\#7](https://github.com/JFreegman/toxic/pull/7) ([jin-eld](https://github.com/jin-eld))
+- Added travis integration [\#6](https://github.com/JFreegman/toxic/pull/6) ([stqism](https://github.com/stqism))
+- Use new public api [\#5](https://github.com/JFreegman/toxic/pull/5) ([fhahn](https://github.com/fhahn))
+- Add widechar checks [\#2](https://github.com/JFreegman/toxic/pull/2) ([jin-eld](https://github.com/jin-eld))
+
+**Fixed bugs:**
+
+- Let windows.c actually get the tox \*m. [\#41](https://github.com/JFreegman/toxic/pull/41) ([Jman012](https://github.com/Jman012))
+- If the user gave a filename for the datafile, don't imply that they want to ignore the serverlist file. [\#37](https://github.com/JFreegman/toxic/pull/37) ([FullName](https://github.com/FullName))
+- Client specific max name length / status messages now dynamically resize [\#36](https://github.com/JFreegman/toxic/pull/36) ([JFreegman](https://github.com/JFreegman))
+- Merged pr6 [\#34](https://github.com/JFreegman/toxic/pull/34) ([stqism](https://github.com/stqism))
+- made error handling more consistent and added exit function [\#33](https://github.com/JFreegman/toxic/pull/33) ([JFreegman](https://github.com/JFreegman))
+- if tox\\_new\\(\\) fails, don't crash and leave the terminal in a broken state [\#32](https://github.com/JFreegman/toxic/pull/32) ([FullName](https://github.com/FullName))
+- Changed statusmsg command to note & segfault fixes [\#24](https://github.com/JFreegman/toxic/pull/24) ([JFreegman](https://github.com/JFreegman))
+- fix buffer overflows and format issues [\#20](https://github.com/JFreegman/toxic/pull/20) ([JFreegman](https://github.com/JFreegman))
+- Fix blocking while waiting for key [\#17](https://github.com/JFreegman/toxic/pull/17) ([manuel-arguelles](https://github.com/manuel-arguelles))
+- fixed "free\(\): invalid pointer" when XDG\_CONFIG\_HOME is set [\#16](https://github.com/JFreegman/toxic/pull/16) ([gs93](https://github.com/gs93))
+- Make sure toxic compiles on MinGW/Win32 again [\#14](https://github.com/JFreegman/toxic/pull/14) ([jin-eld](https://github.com/jin-eld))
+- Fix for the "bad character" when doing backspace in chat window [\#12](https://github.com/JFreegman/toxic/pull/12) ([jin-eld](https://github.com/jin-eld))
+- Fix configure for Free BSD [\#11](https://github.com/JFreegman/toxic/pull/11) ([jin-eld](https://github.com/jin-eld))
+- Fix configure script for ncurses without ncursesw [\#9](https://github.com/JFreegman/toxic/pull/9) ([manuel-arguelles](https://github.com/manuel-arguelles))
+- Fix configure script for mingw32 [\#8](https://github.com/JFreegman/toxic/pull/8) ([jin-eld](https://github.com/jin-eld))
+- warning: comparison of integers of different signs: 'int' and 'unsigned long' [\#3](https://github.com/JFreegman/toxic/pull/3) ([1100110](https://github.com/1100110))
+
+**Merged pull requests:**
+
+- Make sure friend message is null-terminated else generate garbate on screen [\#56](https://github.com/JFreegman/toxic/pull/56) ([aitjcize](https://github.com/aitjcize))
+- Fix trailing slashes which leads to segfault. [\#55](https://github.com/JFreegman/toxic/pull/55) ([aitjcize](https://github.com/aitjcize))
+- fix cflags [\#53](https://github.com/JFreegman/toxic/pull/53) ([JFreegman](https://github.com/JFreegman))
+- Fix 93ab16c [\#52](https://github.com/JFreegman/toxic/pull/52) ([urras](https://github.com/urras))
+- Offer solution for "error while loading shared libraries: libtoxcore.so.... [\#51](https://github.com/JFreegman/toxic/pull/51) ([urras](https://github.com/urras))
+- Implemented file transfers [\#50](https://github.com/JFreegman/toxic/pull/50) ([JFreegman](https://github.com/JFreegman))
+- Fix check for toxcore by linking sodium in the correct place [\#47](https://github.com/JFreegman/toxic/pull/47) ([devurandom](https://github.com/devurandom))
+- Changed order of servers [\#46](https://github.com/JFreegman/toxic/pull/46) ([grimd34th](https://github.com/grimd34th))
+- set friendnames properly and some fixes [\#45](https://github.com/JFreegman/toxic/pull/45) ([JFreegman](https://github.com/JFreegman))
+- moved misc helper functions to separate file and removed redundant includes [\#43](https://github.com/JFreegman/toxic/pull/43) ([JFreegman](https://github.com/JFreegman))
+- Refactored prompt command parser to work with all window types and moved command stuff to separate files [\#42](https://github.com/JFreegman/toxic/pull/42) ([JFreegman](https://github.com/JFreegman))
+- Ipv6.init connection [\#39](https://github.com/JFreegman/toxic/pull/39) ([FullName](https://github.com/FullName))
+- Remove DHT window [\#13](https://github.com/JFreegman/toxic/pull/13) ([JFreegman](https://github.com/JFreegman))
+- Update README.md [\#4](https://github.com/JFreegman/toxic/pull/4) ([notadecent](https://github.com/notadecent))
+- Toxic standalone [\#1](https://github.com/JFreegman/toxic/pull/1) ([jin-eld](https://github.com/jin-eld))
+
+
+
+\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 6781c60..9c55ae6 100644
--- a/Makefile
+++ b/Makefile
@@ -11,10 +11,10 @@ CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
CFLAGS += $(USER_CFLAGS)
LDFLAGS = $(USER_LDFLAGS)
-OBJ = chat.o chat_commands.o configdir.o execute.o file_transfers.o notify.o
-OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
-OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o
-OBJ += group_commands.o term_mplex.o avatars.o name_lookup.o qr_code.o
+OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o
+OBJ += file_transfers.o friendlist.o global_commands.o group_commands.o groupchat.o help.o input.o
+OBJ += line_info.o log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
+OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
# Check on wich system we are running
UNAME_S = $(shell uname -s)
diff --git a/cfg/global_vars.mk b/cfg/global_vars.mk
index 543473a..e45f86f 100644
--- a/cfg/global_vars.mk
+++ b/cfg/global_vars.mk
@@ -1,5 +1,5 @@
# Version
-TOXIC_VERSION = 0.7.0
+TOXIC_VERSION = 0.7.1
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
ifneq (, $(findstring error, $(REV)))
VERSION = $(TOXIC_VERSION)
@@ -16,7 +16,7 @@ MISC_DIR = $(BASE_DIR)/misc
# Project files
MANFILES = toxic.1 toxic.conf.5
-DATAFILES = DHTnodes nameservers toxic.conf.example
+DATAFILES = nameservers toxic.conf.example
DESKFILE = toxic.desktop
SNDFILES = ToxicContactOnline.wav ToxicContactOffline.wav ToxicError.wav
SNDFILES += ToxicRecvMessage.wav ToxicOutgoingCall.wav ToxicIncomingCall.wav
diff --git a/doc/toxic.1 b/doc/toxic.1
index 9878cb1..fad14a9 100644
--- a/doc/toxic.1
+++ b/doc/toxic.1
@@ -2,12 +2,12 @@
.\" Title: toxic
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1
-.\" Date: 2015-12-07
+.\" Date: 2016-09-20
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
-.TH "TOXIC" "1" "2015\-12\-07" "toxic __VERSION__" "Toxic Manual"
+.TH "TOXIC" "1" "2016\-09\-20" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -82,8 +82,8 @@ Show help message
.RS 4
Use specified
\fInodes\-file\fR
-for DHT bootstrap nodes, instead of
-\fI__DATADIR__/DHTnodes\fR
+for DHT bootstrap nodes instead of
+\fI~/\&.config/tox/DHTnodes\&.json\fR
.RE
.PP
\-o, \-\-noconnect
@@ -122,9 +122,11 @@ Unencrypt a data file\&. A warning will appear if this option is used with a dat
.RE
.SH "FILES"
.PP
-__DATADIR__/DHTnodes
+~/\&.config/tox/DHTnodes\&.json
.RS 4
-Default list of DHT bootstrap nodes\&.
+Default location for list of DHT bootstrap nodes (list obtained from
+https://nodes\&.tox\&.chat)\&. This list is automatically updated\&. See
+\fBtoxic\&.conf\fR(5) for details on controlling the update frequency\&.
.RE
.PP
~/\&.config/tox/toxic_profile\&.tox
diff --git a/doc/toxic.1.asc b/doc/toxic.1.asc
index 20d3c00..dcfc01a 100644
--- a/doc/toxic.1.asc
+++ b/doc/toxic.1.asc
@@ -41,8 +41,7 @@ OPTIONS
Show help message
-n, --nodes nodes-file::
- Use specified 'nodes-file' for DHT bootstrap nodes, instead of
- '{datadir}/DHTnodes'
+ Use specified 'nodes-file' for DHT bootstrap nodes instead of '~/.config/tox/DHTnodes.json'
-o, --noconnect::
Do not connect to the DHT network
@@ -68,8 +67,9 @@ OPTIONS
FILES
-----
-{datadir}/DHTnodes::
- Default list of DHT bootstrap nodes.
+~/.config/tox/DHTnodes.json::
+ Default location for list of DHT bootstrap nodes (list obtained from https://nodes.tox.chat).
+ This list is automatically updated. See *toxic.conf*(5) for details on controlling the update frequency.
~/.config/tox/toxic_profile.tox::
Savestate which contains your personal info (nickname, Tox ID, contacts,
diff --git a/doc/toxic.conf.5 b/doc/toxic.conf.5
index f8d28ee..8461538 100644
--- a/doc/toxic.conf.5
+++ b/doc/toxic.conf.5
@@ -2,12 +2,12 @@
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1
-.\" Date: 2016-02-28
+.\" Date: 2016-07-21
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
-.TH "TOXIC\&.CONF" "5" "2016\-02\-28" "toxic __VERSION__" "Toxic Manual"
+.TH "TOXIC\&.CONF" "5" "2016\-07\-21" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -85,7 +85,7 @@ Time format string for logging enclosed by double quotes\&. See
.PP
\fBalerts\fR
.RS 4
-Enable or disable terminal alerts on events\&. true or false
+Enable or disable acoustic alerts on events\&. true or false
.RE
.PP
\fBnative_colors\fR
@@ -118,6 +118,11 @@ Show welcome message on startup\&. true or false
Enable friend connection change notifications\&. true or false
.RE
.PP
+\fBnodelist_update_freq\fR
+.RS 4
+How often in days to update the DHT nodes list\&. (0 to disable updates)
+.RE
+.PP
\fBhistory_size\fR
.RS 4
Maximum lines for chat window history\&. Integer value\&. (for example: 700)
@@ -156,6 +161,38 @@ Set user status when attaching and detaching from GNU screen or tmux\&. true or
\fBmplex_away_note\fR
.RS 4
Status message to set when status is set to away due to screen/tmux detach\&. When attaching, the status message is set back to the original value\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+The following options control whether to output a terminal bell on certain events\&.
+Some terminals mark the window as urgent when a bell is received\&. Urgent windows are usually highlighted in the taskbar and some window managers even provide shortcuts to jump to the next urgent window\&.
+These options don\*(Aqt affect the "alerts" option\&.
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.PP
+\fBbell_on_message\fR
+.RS 4
+Enable/Disable the terminal bell when receiving a message\&. true or false
+.RE
+.PP
+\fBbell_on_filetrans\fR
+.RS 4
+Enable/Disable the terminal bell when receiving a filetransfer\&. true or false
+.RE
+.PP
+\fBbell_on_filetrans_accept\fR
+.RS 4
+Enable/Disable the terminal bell when a filetransfer was accepted\&. true or false
+.RE
+.PP
+\fBbell_on_invite\fR
+.RS 4
+Enable/Disable the terminal bell when receiving a group/call invite\&. true or false
.RE
.RE
.PP
diff --git a/doc/toxic.conf.5.asc b/doc/toxic.conf.5.asc
index 03e83e1..4743fef 100644
--- a/doc/toxic.conf.5.asc
+++ b/doc/toxic.conf.5.asc
@@ -55,7 +55,7 @@ OPTIONS
See *date*(1)
*alerts*;;
- Enable or disable terminal alerts on events. true or false
+ Enable or disable acoustic alerts on events. true or false
*native_colors*;;
Select between native terminal colors and toxic color theme. true or false
@@ -75,6 +75,9 @@ OPTIONS
*show_connection_msg*;;
Enable friend connection change notifications. true or false
+ *nodelist_update_freq*;;
+ How often in days to update the DHT nodes list. (0 to disable updates)
+
*history_size*;;
Maximum lines for chat window history. Integer value. (for example: 700)
@@ -103,6 +106,23 @@ OPTIONS
detach. When attaching, the status message is set back to the original
value.
+ The following options control whether to output a terminal bell on certain events.
+ Some terminals mark the window as urgent when a bell is received. Urgent windows are usually highlighted in the taskbar and some window managers even provide shortcuts to jump to the next urgent window.
+ These options don't affect the "alerts" option.
+
+ *bell_on_message*;;
+ Enable/Disable the terminal bell when receiving a message. true or false
+
+ *bell_on_filetrans*;;
+ Enable/Disable the terminal bell when receiving a filetransfer. true or false
+
+ *bell_on_filetrans_accept*;;
+ Enable/Disable the terminal bell when a filetransfer was accepted. true or false
+
+ *bell_on_invite*;;
+ Enable/Disable the terminal bell when receiving a group/call invite. true or false
+
+
*audio*::
Configuration related to audio devices.
diff --git a/misc/DHTnodes b/misc/DHTnodes
deleted file mode 100644
index 2384706..0000000
--- a/misc/DHTnodes
+++ /dev/null
@@ -1,24 +0,0 @@
-173.230.153.129 33445 A992ED1E7E8C6A4C71B12347D9BFA67DD896CF7D5689E20DD94CA066EE384758
-cerberus.zodiaclabs.org 33450 B139D5A0280AFA8CD2E5E866226397771F80F9A84967558AD740AE056CB63E58
-46.101.197.175 443 CD133B521159541FB1D326DE9850F5E56A6C724B5B8E5EB5CD8D950408E95707
-95.215.46.114 33445 5823FB947FF24CF83DDFAC3F3BAA18F96EA2018B16CC08429CB97FA502F40C23
-5.189.176.217 5190 2B2137E094F743AC8BD44652C55F41DFACC502F125E99E4FE24D40537489E32F
-148.251.23.146 2306 7AED21F94D82B05774F697B209628CD5A9AD17E0C073D9329076A4C28ED28147
-104.223.122.15 33445 0FB96EEBFB1650DDB52E70CF773DDFCABE25A95CC3BB50FC251082E4B63EF82A
-78.47.114.252 33445 1C5293AEF2114717547B39DA8EA6F1E331E5E358B35F9B6B5F19317911C5F976
-d4rk4.ru 1813 53737F6D47FA6BD2808F378E339AF45BF86F39B64E79D6D491C53A1D522E7039
-81.4.110.149 33445 9E7BD4793FFECA7F32238FA2361040C09025ED3333744483CA6F3039BFF0211E
-95.31.20.151 33445 9CA69BB74DE7C056D1CC6B16AB8A0A38725C0349D187D8996766958584D39340
-104.233.104.126 33445 EDEE8F2E839A57820DE3DA4156D88350E53D4161447068A3457EE8F59F362414
-51.254.84.212 33445 AEC204B9A4501412D5F0BB67D9C81B5DB3EE6ADA64122D32A3E9B093D544327D
-home.vikingmakt.com.br 33445 188E072676404ED833A4E947DC1D223DF8EFEBE5F5258573A236573688FB9761
-5.135.59.163 33445 2D320F971EF2CA18004416C2AAE7BA52BF7949DB34EA8E2E21AF67BD367BE211
-185.58.206.164 33445 24156472041E5F220D1FA11D9DF32F7AD697D59845701CDD7BE7D1785EB9DB39
-188.244.38.183 33445 15A0F9684E2423F9F46CFA5A50B562AE42525580D840CC50E518192BF333EE38
-mrflibble.c4.ee 33445 FAAB17014F42F7F20949F61E55F66A73C230876812A9737F5F6D2DCE4D9E4207
-82.211.31.116 33445 AF97B76392A6474AF2FD269220FDCF4127D86A42EF3A242DF53A40A268A2CD7C
-128.199.199.197 33445 B05C8869DBB4EDDD308F43C1A974A20A725A36EACCA123862FDE9945BF9D3E09
-103.230.156.174 33445 5C4C7A60183D668E5BD8B3780D1288203E2F1BAE4EEF03278019E21F86174C1D
-91.121.66.124 33445 4E3F7D37295664BBD0741B6DBCB6431D6CD77FC4105338C2FC31567BF5C8224A
-92.54.84.70 33445 5625A62618CB4FCA70E147A71B29695F38CC65FF0CBD68AD46254585BE564802
-tox1.privacydragon.me 33445 31910C0497D347FF160D6F3A6C0E317BAFA71E8E03BC4CBB2A185C9D4FB8B31E
diff --git a/misc/toxic.conf.example b/misc/toxic.conf.example
index 97228e0..3d27c32 100644
--- a/misc/toxic.conf.example
+++ b/misc/toxic.conf.example
@@ -5,9 +5,21 @@ ui = {
// true to enable timestamps, false to disable
timestamps=true;
- // true to enable terminal alerts on messages, false to disable
+ // true to enable acoustic alerts on messages, false to disable
alerts=true;
+ // Output a bell when receiving a message (see manpage)
+ bell_on_message=true
+
+ // Output a bell when receiving a filetransfer (see manpage)
+ bell_on_filetrans=true
+
+ // Don't output a bell when a filetransfer was accepted (see manpage)
+ bell_on_filetrans_accept=false
+
+ // Output a bell when receiving a group/call invite (see manpage)
+ bell_on_invite=true
+
// true to use native terminal colours, false to use toxic default colour theme
native_colors=false;
@@ -17,7 +29,7 @@ ui = {
// 24 or 12 hour time
time_format=24;
- // timestamp format string according to date/strftime format. Overrides time_format setting
+ // Timestamp format string according to date/strftime format. Overrides time_format setting
timestamp_format="%H:%M:%S";
// true to show you when others are typing a message in 1-on-1 chats
@@ -32,6 +44,9 @@ ui = {
// true to show friend connection change messages on the home screen
show_connection_msg=true;
+ // How often in days to update the DHT nodes list. (0 to disable updates)
+ nodeslist_update_freq=7;
+
// maximum lines for chat window history
history_size=700;
@@ -92,8 +107,7 @@ sounds = {
};
// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
-// Note: All printable keys register as input
-// Note2: Ctrl+M does not work
+// Note: Ctrl+M does not work
keys = {
next_tab="Ctrl+P";
prev_tab="Ctrl+O";
diff --git a/src/audio_call.c b/src/audio_call.c
index 2fd4024..62c0fd8 100644
--- a/src/audio_call.c
+++ b/src/audio_call.c
@@ -61,7 +61,7 @@ extern FriendsList Friends;
#define frame_size (CallControl.audio_sample_rate * CallControl.audio_frame_duration / 1000)
-static int set_call(Call* call, bool start)
+static int set_call(Call *call, bool start)
{
call->in_idx = -1;
call->out_idx = -1;
@@ -75,17 +75,18 @@ static int set_call(Call* call, bool start)
if ( pthread_mutex_init(&call->mutex, NULL) != 0 )
return -1;
- }
- else {
+ } else {
call->ttid = 0;
+
if ( pthread_mutex_destroy(&call->mutex) != 0 )
- return -1;
+ return -1;
}
return 0;
}
-void call_cb ( ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data );
+void call_cb ( ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
+ void *user_data );
void callstate_cb ( ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data );
void receive_audio_frame_cb ( ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count,
uint8_t channels, uint32_t sampling_rate, void *user_data );
@@ -103,7 +104,7 @@ void callback_call_canceled ( uint32_t friend_number );
void callback_call_rejected ( uint32_t friend_number );
void callback_call_ended ( uint32_t friend_number );
-void write_device_callback( uint32_t friend_number, const int16_t* PCM, uint16_t sample_count, uint8_t channels,
+void write_device_callback( uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
uint32_t sample_rate );
static void print_err (ToxWindow *self, const char *error_str)
@@ -158,6 +159,7 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
void terminate_audio()
{
int i;
+
for (i = 0; i < MAX_CALLS; ++i)
stop_transmission(&CallControl.calls[i], i);
@@ -167,7 +169,7 @@ void terminate_audio()
terminate_devices();
}
-void read_device_callback(const int16_t* captured, uint32_t size, void* data)
+void read_device_callback(const int16_t *captured, uint32_t size, void *data)
{
TOXAV_ERR_SEND_FRAME error;
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
@@ -175,13 +177,13 @@ void read_device_callback(const int16_t* captured, uint32_t size, void* data)
((int64_t) CallControl.audio_frame_duration) / 1000;
if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number,
- captured, sample_count,
- CallControl.audio_channels,
- CallControl.audio_sample_rate, &error) == false )
- {}
+ captured, sample_count,
+ CallControl.audio_channels,
+ CallControl.audio_sample_rate, &error) == false ) {
+ }
}
-void write_device_callback(uint32_t friend_number, const int16_t* PCM, uint16_t sample_count, uint8_t channels,
+void write_device_callback(uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
uint32_t sample_rate)
{
if ( CallControl.calls[friend_number].ttas )
@@ -199,7 +201,7 @@ int start_transmission(ToxWindow *self, Call *call)
return -1;
DeviceError error = open_primary_device(input, &call->in_idx,
- CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels);
+ CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels);
if ( error != de_None ) {
if ( error == de_FailedStart)
@@ -210,12 +212,12 @@ int start_transmission(ToxWindow *self, Call *call)
}
if ( register_device_callback(self->num, call->in_idx,
- read_device_callback, &self->num, true) != de_None)
+ read_device_callback, &self->num, true) != de_None)
/* Set VAD as true for all; TODO: Make it more dynamic */
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
if ( open_primary_device(output, &call->out_idx,
- CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None ) {
+ CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None ) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
call->has_output = 0;
}
@@ -228,7 +230,7 @@ int stop_transmission(Call *call, uint32_t friend_number)
if ( call->ttas ) {
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
- if ( CallControl.call_state != TOXAV_FRIEND_CALL_STATE_FINISHED )
+ if ( CallControl.call_state > TOXAV_FRIEND_CALL_STATE_FINISHED )
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_CANCEL, &error);
if ( error == TOXAV_ERR_CALL_CONTROL_OK ) {
@@ -286,7 +288,8 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
callback_call_ended(friend_number);
CallControl.pending_call = false;
- break;
+ break;
+
case ( TOXAV_FRIEND_CALL_STATE_FINISHED ):
if ( CallControl.pending_call )
callback_call_rejected(friend_number);
@@ -304,7 +307,8 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
CallControl.call_state = 0;
CallControl.pending_call = false;
- break;
+ break;
+
default:
if ( CallControl.pending_call ) {
/* Start answered call */
@@ -313,6 +317,7 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
} else {
#ifdef VIDEO
+
/* Handle receiving client video call states */
if ( state & TOXAV_FRIEND_CALL_STATE_SENDING_V )
callback_recv_video_starting(friend_number);
@@ -322,13 +327,13 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
#endif /* VIDEO */
}
- break;
+ break;
}
}
void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
- int16_t const *pcm, size_t sample_count,
- uint8_t channels, uint32_t sampling_rate, void *user_data)
+ int16_t const *pcm, size_t sample_count,
+ uint8_t channels, uint32_t sampling_rate, void *user_data)
{
write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate);
}
@@ -373,12 +378,14 @@ void callback_recv_ringing(uint32_t friend_number)
}
void callback_recv_starting(uint32_t friend_number)
{
- ToxWindow* windows = CallControl.prompt;
+ ToxWindow *windows = CallControl.prompt;
int i;
+
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if ( windows[i].onStarting != NULL && windows[i].num == friend_number ) {
windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state);
+
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!");
@@ -399,12 +406,14 @@ void callback_recv_ending(uint32_t friend_number)
}
void callback_call_started(uint32_t friend_number)
{
- ToxWindow* windows = CallControl.prompt;
+ ToxWindow *windows = CallControl.prompt;
int i;
+
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
if ( windows[i].onStart != NULL && windows[i].num == friend_number ) {
windows[i].onStart(&windows[i], CallControl.av, friend_number, CallControl.call_state);
+
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) {/* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
return;
@@ -479,6 +488,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
}
toxav_call(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
+
if ( error != TOXAV_ERR_CALL_OK ) {
if ( error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL ) error_str = "Already in a call!";
else if ( error == TOXAV_ERR_CALL_MALLOC ) error_str = "Memory allocation issue";
@@ -518,6 +528,7 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
}
toxav_answer(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
+
if ( error != TOXAV_ERR_ANSWER_OK ) {
if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING ) error_str = "No incoming call!";
else if ( error == TOXAV_ERR_ANSWER_CODEC_INITIALIZATION ) error_str = "Failed to initialize codecs!";
@@ -664,7 +675,7 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
}
if ( set_primary_device(type, selection) == de_InvalidSelection ) {
- error_str="Invalid selection!";
+ error_str = "Invalid selection!";
goto on_error;
}
@@ -708,13 +719,14 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
}
if ( selection_valid(type, selection) == de_InvalidSelection ) {
- error_str="Invalid selection!";
+ error_str = "Invalid selection!";
goto on_error;
}
/* If call is active, change device */
if ( self->is_call ) {
- Call* this_call = &CallControl.calls[self->num];
+ Call *this_call = &CallControl.calls[self->num];
+
if ( this_call->ttas ) {
@@ -722,15 +734,14 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
pthread_mutex_lock(&this_call->mutex);
close_device(output, this_call->out_idx);
this_call->has_output = open_device(output, selection, &this_call->out_idx,
- CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels)
- == de_None ? 1 : 0;
+ CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels)
+ == de_None ? 1 : 0;
pthread_mutex_unlock(&this_call->mutex);
- }
- else {
+ } else {
/* TODO: check for failure */
close_device(input, this_call->in_idx);
open_device(input, selection, &this_call->in_idx, CallControl.audio_sample_rate,
- CallControl.audio_frame_duration, CallControl.audio_channels);
+ CallControl.audio_frame_duration, CallControl.audio_channels);
/* Set VAD as true for all; TODO: Make it more dynamic */
register_device_callback(self->num, this_call->in_idx, read_device_callback, &self->num, true);
}
@@ -740,7 +751,7 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
self->device_selection[type] = selection;
return;
- on_error:
+on_error:
print_err (self, error_str);
}
@@ -771,9 +782,10 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
/* If call is active, use this_call values */
if ( self->is_call ) {
- Call* this_call = &CallControl.calls[self->num];
+ Call *this_call = &CallControl.calls[self->num];
pthread_mutex_lock(&this_call->mutex);
+
if ( type == input ) {
device_mute(type, this_call->in_idx);
self->chatwin->infobox.in_is_muted ^= 1;
@@ -781,12 +793,13 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
device_mute(type, this_call->out_idx);
self->chatwin->infobox.out_is_muted ^= 1;
}
+
pthread_mutex_unlock(&this_call->mutex);
}
return;
- on_error:
+on_error:
print_err (self, error_str);
}
@@ -822,7 +835,7 @@ on_error:
}
-void stop_current_call(ToxWindow* self)
+void stop_current_call(ToxWindow *self)
{
if ( CallControl.pending_call ) {
toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL);
diff --git a/src/audio_device.c b/src/audio_device.c
index c74e8ea..7586293 100644
--- a/src/audio_device.c
+++ b/src/audio_device.c
@@ -56,7 +56,7 @@ typedef struct Device {
ALCdevice *dhndl; /* Handle of device selected/opened */
ALCcontext *ctx; /* Device context */
DataHandleCallback cb; /* Use this to handle data from input device usually */
- void* cb_data; /* Data to be passed to callback */
+ void *cb_data; /* Data to be passed to callback */
int32_t friend_number; /* ToxAV friend number */
uint32_t source, buffers[OPENAL_BUFS]; /* Playback source/buffers */
@@ -80,7 +80,7 @@ Device *running[2][MAX_DEVICES] = {{NULL}}; /* Running devices */
uint32_t primary_device[2]; /* Primary device */
#ifdef AUDIO
-static ToxAV* av = NULL;
+static ToxAV *av = NULL;
#endif /* AUDIO */
/* q_mutex */
@@ -90,12 +90,12 @@ pthread_mutex_t mutex;
bool thread_running = true,
- thread_paused = true; /* Thread control */
+ thread_paused = true; /* Thread control */
-void* thread_poll(void*);
+void *thread_poll(void *);
/* Meet devices */
#ifdef AUDIO
-DeviceError init_devices(ToxAV* av_)
+DeviceError init_devices(ToxAV *av_)
#else
DeviceError init_devices()
#endif /* AUDIO */
@@ -103,6 +103,7 @@ DeviceError init_devices()
const char *stringed_device_list;
size[input] = 0;
+
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
@@ -113,7 +114,13 @@ DeviceError init_devices()
}
size[output] = 0;
- if ( (stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER)) ) {
+
+ if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
+ stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
+ else
+ stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
+
+ if (stringed_device_list) {
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output] ) {
@@ -127,6 +134,7 @@ DeviceError init_devices()
return de_InternalError;
pthread_t thread_id;
+
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
return de_InternalError;
@@ -155,9 +163,10 @@ DeviceError terminate_devices()
DeviceError device_mute(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
+
lock;
- Device* device = running[type][device_idx];
+ Device *device = running[type][device_idx];
if (!device) {
unlock;
@@ -174,9 +183,10 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx)
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
+
lock;
- Device* device = running[input][device_idx];
+ Device *device = running[input][device_idx];
if (!device) {
unlock;
@@ -194,12 +204,14 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
DeviceError set_primary_device(DeviceType type, int32_t selection)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
+
primary_device[type] = selection;
return de_None;
}
-DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
+DeviceError open_primary_device(DeviceType type, uint32_t *device_idx, uint32_t sample_rate, uint32_t frame_duration,
+ uint8_t channels)
{
return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration, channels);
}
@@ -210,7 +222,8 @@ void get_primary_device_name(DeviceType type, char *buf, int size)
}
// TODO: generate buffers separately
-DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
+DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx, uint32_t sample_rate,
+ uint32_t frame_duration, uint8_t channels)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
@@ -221,10 +234,13 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
const uint32_t frame_size = (sample_rate * frame_duration / 1000);
uint32_t i;
+
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; ++i);
- if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; }
- else *device_idx = i;
+ if (i == MAX_DEVICES) {
+ unlock;
+ return de_AllDevicesBusy;
+ } else *device_idx = i;
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
if ( running[type][i] && running[type][i]->selection == selection ) {
@@ -238,7 +254,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
}
}
- Device* device = running[type][*device_idx] = calloc(1, sizeof(Device));
+ Device *device = running[type][*device_idx] = calloc(1, sizeof(Device));
device->selection = selection;
device->sample_rate = sample_rate;
@@ -254,12 +270,12 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
if (type == input) {
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
sample_rate, device->sound_mode, frame_size * 2);
- #ifdef AUDIO
+#ifdef AUDIO
device->VAD_treshold = user_settings->VAD_treshold;
- #endif
- }
- else {
+#endif
+ } else {
device->dhndl = alcOpenDevice(devices_names[type][selection]);
+
if ( !device->dhndl ) {
free(device);
running[type][*device_idx] = NULL;
@@ -275,10 +291,10 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
alSourcei(device->source, AL_LOOPING, AL_FALSE);
uint16_t zeros[frame_size];
- memset(zeros, 0, frame_size*2);
+ memset(zeros, 0, frame_size * 2);
for ( i = 0; i < OPENAL_BUFS; ++i ) {
- alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size*2, sample_rate);
+ alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size * 2, sample_rate);
}
alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
@@ -306,7 +322,7 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
- Device* device = running[type][device_idx];
+ Device *device = running[type][device_idx];
DeviceError rc = de_None;
if (!device) {
@@ -317,32 +333,30 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
running[type][device_idx] = NULL;
if ( !device->ref_count ) {
-
-// printf("Closed device ");
-
if (type == input) {
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
- }
- else {
+ } else {
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
alDeleteSources(1, &device->source);
alDeleteBuffers(OPENAL_BUFS, device->buffers);
alcMakeContextCurrent(NULL);
+
if ( device->ctx ) alcDestroyContext(device->ctx);
+
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
}
free(device);
- }
- else device->ref_count--;
+ } else device->ref_count--;
unlock;
return rc;
}
-DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx, DataHandleCallback callback, void* data, bool enable_VAD)
+DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
+ void *data, bool enable_VAD)
{
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return de_InvalidSelection;
@@ -357,12 +371,12 @@ DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx
return de_None;
}
-inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t sample_count, uint8_t channels,
+inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_count, uint8_t channels,
uint32_t sample_rate)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
- Device* device = running[output][device_idx];
+ Device *device = running[output][device_idx];
if (!device || device->muted) return de_DeviceNotActive;
@@ -374,33 +388,33 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_
alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed);
alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
- if(processed) {
+ if (processed) {
ALuint bufids[processed];
alSourceUnqueueBuffers(device->source, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
- }
- else if(queued < 16) alGenBuffers(1, &bufid);
+ } else if (queued < 16) alGenBuffers(1, &bufid);
else {
pthread_mutex_unlock(device->mutex);
return de_Busy;
}
- alBufferData(bufid, channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, data, sample_count * 2 * channels, sample_rate);
+ alBufferData(bufid, channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, data, sample_count * 2 * channels,
+ sample_rate);
alSourceQueueBuffers(device->source, 1, &bufid);
ALint state;
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
- if(state != AL_PLAYING) alSourcePlay(device->source);
+ if (state != AL_PLAYING) alSourcePlay(device->source);
pthread_mutex_unlock(device->mutex);
return de_None;
}
-void* thread_poll (void* arg) // TODO: maybe use thread for every input source
+void *thread_poll (void *arg) // TODO: maybe use thread for every input source
{
/*
* NOTE: We only need to poll input devices for data.
@@ -410,23 +424,27 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
int32_t sample = 0;
- while (true)
- {
+ while (1) {
lock;
+
if (!thread_running) {
unlock;
break;
}
+
+ bool paused = thread_paused;
unlock;
- if (thread_paused) usleep(10000); /* Wait for unpause. */
- else
- {
- for (i = 0; i < size[input]; ++i)
- {
+ /* Wait for unpause. */
+ if (paused) {
+ usleep(10000);
+ }
+
+ else {
+ for (i = 0; i < size[input]; ++i) {
lock;
- if (running[input][i] != NULL)
- {
+
+ if (running[input][i] != NULL) {
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample);
int f_size = (running[input][i]->sample_rate * running[input][i]->frame_duration / 1000);
@@ -435,7 +453,8 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
unlock;
continue;
}
- Device* device = running[input][i];
+
+ Device *device = running[input][i];
int16_t frame[16000];
alcCaptureSamples(device->dhndl, frame, f_size);
@@ -447,8 +466,10 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
}
+
unlock;
}
+
usleep(5000);
}
}
@@ -456,7 +477,7 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
pthread_exit(NULL);
}
-void print_devices(ToxWindow* self, DeviceType type)
+void print_devices(ToxWindow *self, DeviceType type)
{
int i;
@@ -471,7 +492,7 @@ DeviceError selection_valid(DeviceType type, int32_t selection)
return (size[type] <= selection || selection < 0) ? de_InvalidSelection : de_None;
}
-void* get_device_callback_data(uint32_t device_idx)
+void *get_device_callback_data(uint32_t device_idx)
{
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return NULL;
diff --git a/src/audio_device.h b/src/audio_device.h
index 34d1ecc..9b73791 100644
--- a/src/audio_device.h
+++ b/src/audio_device.h
@@ -52,11 +52,11 @@ typedef enum DeviceError {
de_AlError = -9,
} DeviceError;
-typedef void (*DataHandleCallback) (const int16_t*, uint32_t size, void* data);
+typedef void (*DataHandleCallback) (const int16_t *, uint32_t size, void *data);
#ifdef AUDIO
-DeviceError init_devices(ToxAV* av);
+DeviceError init_devices(ToxAV *av);
#else
DeviceError init_devices();
#endif /* AUDIO */
@@ -64,8 +64,9 @@ DeviceError init_devices();
DeviceError terminate_devices();
/* Callback handles ready data from INPUT device */
-DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback, void* data, bool enable_VAD);
-void* get_device_callback_data(uint32_t device_idx);
+DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
+ void *data, bool enable_VAD);
+void *get_device_callback_data(uint32_t device_idx);
/* toggle device mute */
DeviceError device_mute(DeviceType type, uint32_t device_idx);
@@ -75,16 +76,19 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
#endif
DeviceError set_primary_device(DeviceType type, int32_t selection);
-DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
+DeviceError open_primary_device(DeviceType type, uint32_t *device_idx, uint32_t sample_rate, uint32_t frame_duration,
+ uint8_t channels);
/* Start device */
-DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
+DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx, uint32_t sample_rate,
+ uint32_t frame_duration, uint8_t channels);
/* Stop device */
DeviceError close_device(DeviceType type, uint32_t device_idx);
/* Write data to device */
-DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t length, uint8_t channels, uint32_t sample_rate);
+DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t length, uint8_t channels,
+ uint32_t sample_rate);
-void print_devices(ToxWindow* self, DeviceType type);
+void print_devices(ToxWindow *self, DeviceType type);
void get_primary_device_name(DeviceType type, char *buf, int size);
DeviceError selection_valid(DeviceType type, int32_t selection);
diff --git a/src/autocomplete.c b/src/autocomplete.c
index 4c0113d..52a1934 100644
--- a/src/autocomplete.c
+++ b/src/autocomplete.c
@@ -25,10 +25,10 @@
#include
#ifdef __APPLE__
- #include
- #include
+#include
+#include
#else
- #include
+#include
#endif /* ifdef __APPLE__ */
#include "windows.h"
@@ -108,7 +108,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
/* TODO: generalize this */
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
- || !strncmp(ubuf, "/avatar", strlen("/avatar"));
+ || !strncmp(ubuf, "/avatar", strlen("/avatar"));
/* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE];
@@ -185,6 +185,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
int n_endchrs = strlen(endchrs);
int strt = ctx->pos - s_len;
int diff = match_len - s_len + n_endchrs;
+
if (ctx->len + diff >= MAX_STR_SIZE)
return -1;
@@ -288,7 +289,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
if (strncmp(entry->d_name, b_name, b_name_len) == 0
- && strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
+ && strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
++dircount;
}
diff --git a/src/avatars.c b/src/avatars.c
index d58b27e..8d01f36 100644
--- a/src/avatars.c
+++ b/src/avatars.c
@@ -55,6 +55,7 @@ int avatar_send(Tox *m, uint32_t friendnum)
TOX_ERR_FILE_SEND err;
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
+
if (Avatar.size == 0)
return 0;
@@ -150,6 +151,7 @@ void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL co
} else if (ft->state == FILE_TRANSFER_PAUSED) {
ft->state = FILE_TRANSFER_STARTED;
}
+
break;
case TOX_FILE_CONTROL_PAUSE:
diff --git a/src/bootstrap.c b/src/bootstrap.c
new file mode 100644
index 0000000..f93f204
--- /dev/null
+++ b/src/bootstrap.c
@@ -0,0 +1,586 @@
+/* bootstrap.c
+ *
+ *
+ * Copyright (C) 2016 Toxic All Rights Reserved.
+ *
+ * This file is part of Toxic.
+ *
+ * Toxic is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Toxic is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Toxic. If not, see .
+ *
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "line_info.h"
+#include "windows.h"
+#include "misc_tools.h"
+#include "configdir.h"
+#include "curl_util.h"
+#include "settings.h"
+
+extern struct arg_opts arg_opts;
+extern struct user_settings *user_settings;
+extern struct Winthread Winthread;
+
+/* URL that we get the JSON encoded nodes list from. */
+#define NODES_LIST_URL "https://nodes.tox.chat/json"
+
+#define DEFAULT_NODES_FILENAME "DHTnodes.json"
+
+/* Time to wait between bootstrap attempts */
+#define TRY_BOOTSTRAP_INTERVAL 5
+
+/* Number of nodes to bootstrap to per try */
+#define NUM_BOOTSTRAP_NODES 5
+
+/* Number of seconds since last successful ping before we consider a node offline */
+#define NODE_OFFLINE_TIMOUT (60*60*24*2)
+
+#define IP_MAX_SIZE 45
+#define IP_MIN_SIZE 7
+#define PORT_MAX_SIZE 5
+
+#define LAST_SCAN_JSON_KEY "\"last_scan\":"
+#define LAST_SCAN_JSON_KEY_LEN (sizeof(LAST_SCAN_JSON_KEY) - 1)
+
+#define IPV4_JSON_KEY "\"ipv4\":\""
+#define IPV4_JSON_KEY_LEN (sizeof(IPV4_JSON_KEY) - 1)
+
+#define IPV6_JSON_KEY "\"ipv6\":\""
+#define IPV6_JSON_KEY_LEN (sizeof(IPV6_JSON_KEY) - 1)
+
+#define PORT_JSON_KEY "\"port\":"
+#define PORT_JSON_KEY_LEN (sizeof(PORT_JSON_KEY) - 1)
+
+#define PK_JSON_KEY "\"public_key\":\""
+#define PK_JSON_KEY_LEN (sizeof(PK_JSON_KEY) - 1)
+
+#define LAST_PING_JSON_KEY "\"last_ping\":"
+#define LAST_PING_JSON_KEY_LEN (sizeof(LAST_PING_JSON_KEY) - 1)
+
+/* Maximum allowable size of the nodes list */
+#define MAX_NODELIST_SIZE (MAX_RECV_CURL_DATA_SIZE)
+
+
+static struct Thread_Data {
+ pthread_t tid;
+ pthread_attr_t attr;
+ pthread_mutex_t lock;
+ volatile bool active;
+} thread_data;
+
+#define MAX_NODES 50
+struct Node {
+ char ip4[IP_MAX_SIZE + 1];
+ bool have_ip4;
+
+ char ip6[IP_MAX_SIZE + 1];
+ bool have_ip6;
+
+ char key[TOX_PUBLIC_KEY_SIZE];
+ uint16_t port;
+};
+
+static struct DHT_Nodes {
+ struct Node list[MAX_NODES];
+ size_t count;
+ time_t last_updated;
+} Nodes;
+
+
+/* Determine if a node is offline by comparing the age of the nodeslist
+ * to the last time the node was successfully pinged.
+ */
+#define NODE_IS_OFFLINE(last_scan, last_ping) ((last_ping + NODE_OFFLINE_TIMOUT) <= (last_ping))
+
+/* Return true if nodeslist pointed to by fp needs to be updated.
+ * This will be the case if the file is empty, has an invalid format,
+ * or if the file is older than the given timeout.
+ */
+static bool nodeslist_needs_update(const char *nodes_path)
+{
+ if (user_settings->nodeslist_update_freq <= 0) {
+ return false;
+ }
+
+ FILE *fp = fopen(nodes_path, "r+");
+
+ if (fp == NULL) {
+ return false;
+ }
+
+ /* last_scan value should be at beginning of file */
+ char line[LAST_SCAN_JSON_KEY_LEN + 32];
+
+ if (fgets(line, sizeof(line), fp) == NULL) {
+ fclose(fp);
+ return true;
+ }
+
+ fclose(fp);
+
+ const char *last_scan_val = strstr(line, LAST_SCAN_JSON_KEY);
+
+ if (last_scan_val == NULL) {
+ return true;
+ }
+
+ long long int last_scan = strtoll(last_scan_val + LAST_SCAN_JSON_KEY_LEN, NULL, 10);
+
+ pthread_mutex_lock(&thread_data.lock);
+ Nodes.last_updated = last_scan;
+ pthread_mutex_unlock(&thread_data.lock);
+
+ pthread_mutex_lock(&Winthread.lock);
+ bool is_timeout = timed_out(last_scan, user_settings->nodeslist_update_freq * 24 * 60 * 60);
+ pthread_mutex_unlock(&Winthread.lock);
+
+ if (is_timeout) {
+ return true;
+ }
+
+ return false;
+}
+
+/* Fetches the JSON encoded DHT nodeslist from NODES_LIST_URL.
+ *
+ * Return 0 on success.
+ * Return -1 on failure.
+ */
+static int curl_fetch_nodes_JSON(struct Recv_Curl_Data *recv_data)
+{
+ CURL *c_handle = curl_easy_init();
+
+ if (c_handle == NULL) {
+ return -1;
+ }
+
+ int err = -1;
+
+ struct curl_slist *headers = NULL;
+ headers = curl_slist_append(headers, "Content-Type: application/json");
+ headers = curl_slist_append(headers, "charsets: utf-8");
+
+ curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(c_handle, CURLOPT_URL, NODES_LIST_URL);
+ curl_easy_setopt(c_handle, CURLOPT_WRITEFUNCTION, curl_cb_write_data);
+ curl_easy_setopt(c_handle, CURLOPT_WRITEDATA, recv_data);
+ curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
+ curl_easy_setopt(c_handle, CURLOPT_HTTPGET, 1L);
+
+ int proxy_ret = set_curl_proxy(c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type);
+
+ if (proxy_ret != 0) {
+ fprintf(stderr, "set_curl_proxy() failed with error %d\n", proxy_ret);
+ goto on_exit;
+ }
+
+ int ret = curl_easy_setopt(c_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
+
+ if (ret != CURLE_OK) {
+ fprintf(stderr, "TLSv1.2 could not be set (libcurl error %d)", ret);
+ goto on_exit;
+ }
+
+ ret = curl_easy_setopt(c_handle, CURLOPT_SSL_CIPHER_LIST, TLS_CIPHER_SUITE_LIST);
+
+ if (ret != CURLE_OK) {
+ fprintf(stderr, "Failed to set TLS cipher list (libcurl error %d)", ret);
+ goto on_exit;
+ }
+
+ ret = curl_easy_perform(c_handle);
+
+ if (ret != CURLE_OK) {
+ /* If system doesn't support any of the specified ciphers suites, fall back to default */
+ if (ret == CURLE_SSL_CIPHER) {
+ curl_easy_setopt(c_handle, CURLOPT_SSL_CIPHER_LIST, NULL);
+ ret = curl_easy_perform(c_handle);
+ }
+
+ if (ret != CURLE_OK) {
+ fprintf(stderr, "HTTPS lookup error (libcurl error %d)\n", ret);
+ goto on_exit;
+ }
+ }
+
+ err = 0;
+
+on_exit:
+ curl_slist_free_all(headers);
+ curl_easy_cleanup(c_handle);
+ return err;
+}
+
+/* Attempts to update the DHT nodeslist.
+ *
+ * Return 1 if list was updated successfully.
+ * Return 0 if list does not need to be updated.
+ * Return -1 if file cannot be opened.
+ * Return -2 if http lookup failed.
+ * Return -3 if http reponse was empty.
+ * Return -4 if data could not be written to disk.
+ */
+static int update_DHT_nodeslist(const char *nodes_path)
+{
+ if (!nodeslist_needs_update(nodes_path)) {
+ return 0;
+ }
+
+ FILE *fp = fopen(nodes_path, "r+");
+
+ if (fp == NULL) {
+ return -1;
+ }
+
+ struct Recv_Curl_Data recv_data;
+
+ memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
+
+ if (curl_fetch_nodes_JSON(&recv_data) == -1) {
+ fclose(fp);
+ return -2;
+ }
+
+ if (recv_data.length == 0) {
+ fclose(fp);
+ return -3;
+ }
+
+ if (fwrite(recv_data.data, recv_data.length, 1, fp) != 1) {
+ fclose(fp);
+ return -4;
+ }
+
+ fclose(fp);
+ return 1;
+}
+
+static void get_nodeslist_path(char *buf, size_t buf_size)
+{
+ char *config_dir = NULL;
+
+ if (arg_opts.nodes_path[0]) {
+ snprintf(buf, buf_size, "%s", arg_opts.nodes_path);
+ } else if ((config_dir = get_user_config_dir()) != NULL) {
+ snprintf(buf, buf_size, "%s%s%s", config_dir, CONFIGDIR, DEFAULT_NODES_FILENAME);
+ free(config_dir);
+ } else {
+ snprintf(buf, buf_size, "%s", DEFAULT_NODES_FILENAME);
+ }
+}
+
+/* Return true if json encoded string s contains a valid IP address and puts address in ip_buf.
+ *
+ * ip_type should be set to 1 for ipv4 address, or 0 for ipv6 addresses.
+ * ip_buf must have room for at least IP_MAX_SIZE + 1 bytes.
+ */
+static bool extract_val_ip(const char *s, char *ip_buf, unsigned short int ip_type)
+{
+ int ip_len = char_find(0, s, '"');
+
+ if (ip_len < IP_MIN_SIZE || ip_len > IP_MAX_SIZE) {
+ return false;
+ }
+
+ memcpy(ip_buf, s, ip_len);
+ ip_buf[ip_len] = 0;
+
+ return (ip_type == 1) ? is_ip4_address(ip_buf) : is_ip6_address(ip_buf);
+}
+
+/* Extracts the port from json encoded string s.
+ *
+ * Return port number on success.
+ * Return 0 on failure.
+ */
+static uint16_t extract_val_port(const char *s)
+{
+ long int port = strtol(s, NULL, 10);
+ return (port > 0 && port <= MAX_PORT_RANGE) ? port : 0;
+}
+
+/* Extracts the last pinged value from json encoded string s.
+ *
+ * Return timestamp on success.
+ * Return -1 on failure.
+ */
+static long long int extract_val_last_pinged(const char *s)
+{
+ long long int last_pinged = strtoll(s, NULL, 10);
+ return (last_pinged <= 0) ? -1 : last_pinged;
+}
+
+/* Extracts DHT public key from json encoded string s and puts key in key_buf.
+ * key_buf must have room for at least TOX_PUBLIC_KEY_SIZE * 2 + 1 bytes.
+ *
+ * Return number of bytes copied to key_buf on success.
+ * Return -1 on failure.
+ */
+static int extract_val_pk(const char *s, char *key_buf)
+{
+
+ int key_len = char_find(0, s, '"');
+
+ if (key_len != TOX_PUBLIC_KEY_SIZE * 2) {
+ return -1;
+ }
+
+ memcpy(key_buf, s, key_len);
+ key_buf[key_len] = 0;
+
+ return key_len;
+}
+
+/* Extracts values from json formatted string, validats them, and puts them in node.
+ *
+ * Return 0 on success.
+ * Return -1 if line is empty.
+ * Return -2 if line does not appear to be a valid nodes list entry.
+ * Return -3 if node appears to be offline.
+ * Return -4 if entry does not contain either a valid ipv4 or ipv6 address.
+ * Return -5 if port value is invalid.
+ * Return -6 if public key is invalid.
+ */
+static int extract_node(const char *line, struct Node *node)
+{
+ if (!line) {
+ return -1;
+ }
+
+ const char *ip4_start = strstr(line, IPV4_JSON_KEY);
+ const char *ip6_start = strstr(line, IPV6_JSON_KEY);
+ const char *port_start = strstr(line, PORT_JSON_KEY);
+ const char *key_start = strstr(line, PK_JSON_KEY);
+ const char *last_pinged_str = strstr(line, LAST_PING_JSON_KEY);
+
+ if (!ip4_start || !ip6_start || !port_start || !key_start || !last_pinged_str) {
+ return -2;
+ }
+
+ long long int last_pinged = extract_val_last_pinged(last_pinged_str + LAST_PING_JSON_KEY_LEN);
+
+ if (last_pinged <= 0 || NODE_IS_OFFLINE(Nodes.last_scan, last_pinged)) {
+ return -3;
+ }
+
+ char ip4_string[IP_MAX_SIZE + 1];
+ bool have_ip4 = extract_val_ip(ip4_start + IPV4_JSON_KEY_LEN, ip4_string, 1);
+
+ char ip6_string[IP_MAX_SIZE + 1];
+ bool have_ip6 = extract_val_ip(ip6_start + IPV6_JSON_KEY_LEN, ip6_string, 0);
+
+ if (!have_ip6 && !have_ip4) {
+ return -4;
+ }
+
+ uint16_t port = extract_val_port(port_start + PORT_JSON_KEY_LEN);
+
+ if (port == 0) {
+ return -5;
+ }
+
+ char key_string[TOX_PUBLIC_KEY_SIZE * 2 + 1];
+ int key_len = extract_val_pk(key_start + PK_JSON_KEY_LEN, key_string);
+
+ if (key_len == -1) {
+ return -6;
+ }
+
+ if (hex_string_to_bin(key_string, key_len, node->key, TOX_PUBLIC_KEY_SIZE) == -1) {
+ return -6;
+ }
+
+ if (have_ip4) {
+ snprintf(node->ip4, sizeof(node->ip4), "%s", ip4_string);
+ node->have_ip4 = true;
+ }
+
+ if (have_ip6) {
+ snprintf(node->ip6, sizeof(node->ip6), "%s", ip6_string);
+ node->have_ip6 = true;
+ }
+
+ node->port = port;
+
+ return 0;
+}
+
+/* Loads the DHT nodeslist to memory from json encoded nodes file. */
+void *load_nodeslist_thread(void *data)
+{
+ char nodes_path[PATH_MAX];
+ get_nodeslist_path(nodes_path, sizeof(nodes_path));
+
+ FILE *fp = NULL;
+
+ if (!file_exists(nodes_path)) {
+ if ((fp = fopen(nodes_path, "w+")) == NULL) {
+ fprintf(stderr, "nodeslist load error: failed to create file '%s'\n", nodes_path);
+ goto on_exit;
+ }
+ } else if ((fp = fopen(nodes_path, "r+")) == NULL) {
+ fprintf(stderr, "nodeslist load error: failed to open file '%s'\n", nodes_path);
+ goto on_exit;
+ }
+
+ int update_err = update_DHT_nodeslist(nodes_path);
+
+ if (update_err < 0) {
+ fprintf(stderr, "update_DHT_nodeslist() failed with error %d\n", update_err);
+ }
+
+ char line[MAX_NODELIST_SIZE + 1];
+
+ if (fgets(line, sizeof(line), fp) == NULL) {
+ fclose(fp);
+ fprintf(stderr, "nodeslist load error: file empty.\n");
+ goto on_exit;
+ }
+
+ size_t idx = 0;
+ const char *line_start = line;
+
+ while ((line_start = strstr(line_start + 1, IPV4_JSON_KEY))) {
+ pthread_mutex_lock(&thread_data.lock);
+ idx = Nodes.count;
+
+ if (idx >= MAX_NODES) {
+ pthread_mutex_unlock(&thread_data.lock);
+ break;
+ }
+
+ if (extract_node(line_start, &Nodes.list[idx]) == 0) {
+ ++Nodes.count;
+ }
+
+ pthread_mutex_unlock(&thread_data.lock);
+ }
+
+ /* If nodeslist does not contain any valid entries we set the last_scan value
+ * to 0 so that it will fetch a new list the next time this function is called.
+ */
+ if (idx == 0) {
+ const char *s = "{\"last_scan\":0}";
+ rewind(fp);
+ fwrite(s, strlen(s), 1, fp); // Not much we can do if it fails
+ fclose(fp);
+ fprintf(stderr, "nodeslist load error: List did not contain any valid entries.\n");
+ goto on_exit;
+ }
+
+ fclose(fp);
+
+on_exit:
+ thread_data.active = false;
+ pthread_attr_destroy(&thread_data.attr);
+ pthread_exit(0);
+}
+
+/* Creates a new thread that will load the DHT nodeslist to memory
+ * from json encoded nodes file obtained at NODES_LIST_URL. Only one
+ * thread may run at a time.
+ *
+ * Return 0 on success.
+ * Return -1 if a thread is already active.
+ * Return -2 if mutex fails to init.
+ * Return -3 if pthread attribute fails to init.
+ * Return -4 if pthread fails to set detached state.
+ * Return -5 if thread creation fails.
+ */
+int load_DHT_nodeslist(void)
+{
+ if (thread_data.active) {
+ return -1;
+ }
+
+ if (pthread_mutex_init(&thread_data.lock, NULL) != 0) {
+ return -2;
+ }
+
+ if (pthread_attr_init(&thread_data.attr) != 0) {
+ return -3;
+ }
+
+ if (pthread_attr_setdetachstate(&thread_data.attr, PTHREAD_CREATE_DETACHED) != 0) {
+ return -4;
+ }
+
+ thread_data.active = true;
+
+ if (pthread_create(&thread_data.tid, &thread_data.attr, load_nodeslist_thread, NULL) != 0) {
+ thread_data.active = false;
+ return -5;
+ }
+
+ return 0;
+}
+
+/* Connects to NUM_BOOTSTRAP_NODES random DHT nodes listed in the DHTnodes file. */
+static void DHT_bootstrap(Tox *m)
+{
+ pthread_mutex_lock(&thread_data.lock);
+ size_t num_nodes = Nodes.count;
+ pthread_mutex_unlock(&thread_data.lock);
+
+ if (num_nodes == 0) {
+ return;
+ }
+
+ size_t i;
+
+ pthread_mutex_lock(&thread_data.lock);
+
+ for (i = 0; i < NUM_BOOTSTRAP_NODES; ++i) {
+ struct Node *node = &Nodes.list[rand() % Nodes.count];
+ const char *addr = node->have_ip4 ? node->ip4 : node->ip6;
+
+ if (!addr) {
+ continue;
+ }
+
+ TOX_ERR_BOOTSTRAP err;
+ tox_bootstrap(m, addr, node->port, (uint8_t *) node->key, &err);
+
+ if (err != TOX_ERR_BOOTSTRAP_OK) {
+ fprintf(stderr, "Failed to bootstrap %s:%d\n", addr, node->port);
+ }
+
+ tox_add_tcp_relay(m, addr, node->port, (uint8_t *) node->key, &err);
+
+ if (err != TOX_ERR_BOOTSTRAP_OK) {
+ fprintf(stderr, "Failed to add TCP relay %s:%d\n", addr, node->port);
+ }
+ }
+
+ pthread_mutex_unlock(&thread_data.lock);
+}
+
+/* Manages connection to the Tox DHT network. */
+void do_tox_connection(Tox *m)
+{
+ static time_t last_bootstrap_time = 0;
+ bool connected = tox_self_get_connection_status(m) != TOX_CONNECTION_NONE;
+
+ if (!connected && timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL)) {
+ DHT_bootstrap(m);
+ last_bootstrap_time = get_unix_time();
+ }
+}
diff --git a/src/bootstrap.h b/src/bootstrap.h
new file mode 100644
index 0000000..3a07cdf
--- /dev/null
+++ b/src/bootstrap.h
@@ -0,0 +1,42 @@
+/* bootstrap.h
+ *
+ *
+ * Copyright (C) 2016 Toxic All Rights Reserved.
+ *
+ * This file is part of Toxic.
+ *
+ * Toxic is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Toxic is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Toxic. If not, see .
+ *
+ */
+
+#ifndef BOOTSTRAP_H
+#define BOOTSTRAP_H
+
+/* Manages connection to the Tox DHT network. */
+void do_tox_connection(Tox *m);
+
+/* Creates a new thread that will load the DHT nodeslist to memory
+ * from json encoded nodes file obtained at NODES_LIST_URL. Only one
+ * thread may run at a time.
+ *
+ * Return 0 on success.
+ * Return -1 if a thread is already active.
+ * Return -2 if mutex fails to init.
+ * Return -3 if pthread attribute fails to init.
+ * Return -4 if pthread fails to set detached state.
+ * Return -5 if thread creation fails.
+ */
+int load_DHT_nodeslist(void);
+
+#endif /* BOOTSTRAP_H */
diff --git a/src/chat.c b/src/chat.c
index 89e6ed5..c3aea21 100644
--- a/src/chat.c
+++ b/src/chat.c
@@ -48,9 +48,9 @@
#include "message_queue.h"
#ifdef AUDIO
- #include "audio_call.h"
+#include "audio_call.h"
#ifdef VIDEO
- #include "video_call.h"
+#include "video_call.h"
#endif /* VIDEO */
#endif /* AUDIO */
@@ -153,7 +153,7 @@ void kill_chat_window(ToxWindow *self, Tox *m)
}
static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const char *msg, size_t len,
- const char *nick, const char *timefrmt)
+ const char *nick, const char *timefrmt)
{
ChatContext *ctx = self->chatwin;
@@ -161,9 +161,11 @@ static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const cha
write_to_log(msg, nick, ctx->log, false);
if (self->active_box != -1)
- box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "%s", msg);
+ box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
+ self->active_box, "%s", msg);
else
- box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, nick, "%s", msg);
+ box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
+ &self->active_box, nick, "%s", msg);
}
static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char *action, size_t len,
@@ -175,9 +177,11 @@ static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char
write_to_log(action, nick, ctx->log, true);
if (self->active_box != -1)
- box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
+ box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
+ self->active_box, "* %s %s", nick, action );
else
- box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action );
+ box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
+ &self->active_box, self->name, "* %s %s", nick, action );
}
static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *msg, size_t len)
@@ -451,11 +455,11 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
if (ft->state == FILE_TRANSFER_PENDING) {
ft->state = FILE_TRANSFER_STARTED;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
- ft->index, ft->file_name);
+ ft->index, ft->file_name);
char progline[MAX_STR_SIZE];
init_progress_bar(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
- sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
+ sound_notify(self, silent, NT_NOFOCUS | user_settings->bell_on_filetrans_accept | NT_WNDALERT_2, NULL);
ft->line_id = self->chatwin->hst->line_end->id + 2;
} else if (ft->state == FILE_TRANSFER_PAUSED) { /* transfer is resumed */
ft->state = FILE_TRANSFER_STARTED;
@@ -463,10 +467,12 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
break;
}
+
case TOX_FILE_CONTROL_PAUSE: {
ft->state = FILE_TRANSFER_PAUSED;
break;
}
+
case TOX_FILE_CONTROL_CANCEL: {
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
close_file_transfer(self, m, ft, -1, msg, notif_error);
@@ -597,11 +603,11 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL);
if (self->active_box != -1)
- box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
- "Incoming file: %s", filename );
+ box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
+ self->active_box, "Incoming file: %s", filename );
else
- box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, &self->active_box, self->name,
- "Incoming file: %s", filename );
+ box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
+ &self->active_box, self->name, "Incoming file: %s", filename );
}
static void chat_onGroupInvite(ToxWindow *self, Tox *m, uint32_t friendnumber, const char *invite_data,
@@ -617,7 +623,7 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, uint32_t friendnumber, c
memcpy(Friends.list[friendnumber].group_invite.data, invite_data, length);
Friends.list[friendnumber].group_invite.length = length;
- sound_notify(self, generic_message, NT_WNDALERT_2, NULL);
+ sound_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, NULL);
char name[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, name, friendnumber);
@@ -645,7 +651,7 @@ void chat_onInvite (ToxWindow *self, ToxAV *av, uint32_t friend_number, int stat
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Incoming audio call! Type: \"/answer\" or \"/reject\"");
if (self->ringing_sound == -1)
- sound_notify(self, call_incoming, NT_LOOP, &self->ringing_sound);
+ sound_notify(self, call_incoming, NT_LOOP | user_settings->bell_on_invite, &self->ringing_sound);
if (self->active_box != -1)
box_silent_notify2(self, NT_NOFOCUS | NT_WNDALERT_0, self->active_box, "Incoming audio call!");
@@ -661,8 +667,10 @@ void chat_onRinging (ToxWindow *self, ToxAV *av, uint32_t friend_number, int sta
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
#ifdef SOUND_NOTIFY
+
if (self->ringing_sound == -1)
sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound);
+
#endif /* SOUND_NOTIFY */
}
@@ -815,7 +823,7 @@ static void draw_infobox(ToxWindow *self)
if (x2 < INFOBOX_WIDTH || y2 < INFOBOX_HEIGHT)
return;
- uint64_t curtime = get_unix_time();
+ time_t curtime = get_unix_time();
/* update elapsed time string once per second */
if (curtime > infobox->lastupdate)
@@ -852,7 +860,7 @@ static void draw_infobox(ToxWindow *self)
wprintw(infobox->win, "%.2f\n", infobox->vad_lvl);
wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_TTEE, ' ', ACS_LLCORNER, ' ');
- wrefresh(infobox->win);
+ wnoutrefresh(infobox->win);
}
#endif /* AUDIO */
@@ -917,11 +925,11 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
diff = dir_match(self, m, ctx->line, L"/sendfile");
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
diff = dir_match(self, m, ctx->line, L"/avatar");
- } else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0){
+ } else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
const char status_cmd_list[3][8] = {
- {"online"},
- {"away"},
- {"busy"},
+ {"online"},
+ {"away"},
+ {"busy"},
};
diff = complete_line(self, status_cmd_list, 3, 8);
} else {
@@ -940,8 +948,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else if (key == '\r') {
rm_trailing_spaces_buf(ctx);
- if (!wstring_is_empty(ctx->line))
- {
+ if (!wstring_is_empty(ctx->line)) {
add_line_to_hist(ctx);
wstrsubst(ctx->line, L'¶', L'\n');
@@ -1019,9 +1026,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
case TOX_USER_STATUS_NONE:
colour = GREEN;
break;
+
case TOX_USER_STATUS_AWAY:
colour = YELLOW;
break;
+
case TOX_USER_STATUS_BUSY:
colour = RED;
break;
@@ -1094,13 +1103,14 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x);
- wrefresh(self->window);
+ wnoutrefresh(self->window);
#ifdef AUDIO
+
if (ctx->infobox.active) {
draw_infobox(self);
- wrefresh(self->window);
}
+
#endif
if (self->help->active)
diff --git a/src/chat_commands.c b/src/chat_commands.c
index a5f99f0..4c628b3 100644
--- a/src/chat_commands.c
+++ b/src/chat_commands.c
@@ -100,8 +100,9 @@ void cmd_groupaccept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
TOX_ERR_GROUP_INVITE_ACCEPT err;
uint32_t groupnumber = tox_group_invite_accept(m, Friends.list[self->num].group_invite.data,
- Friends.list[self->num].group_invite.length,
- (uint8_t *) passwd, passwd_len, &err);
+ Friends.list[self->num].group_invite.length,
+ (uint8_t *) passwd, passwd_len, &err);
+
if (err != TOX_ERR_GROUP_INVITE_ACCEPT_OK) {
if (err == TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to joing group: Password too long.");
@@ -133,6 +134,7 @@ void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
}
TOX_ERR_GROUP_INVITE_FRIEND err;
+
if (!tox_group_invite_friend(m, groupnum, self->num, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d).", err);
return;
@@ -192,6 +194,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return;
on_recv_error:
+
switch (err) {
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
@@ -260,7 +263,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
TOX_ERR_FILE_SEND err;
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
- (uint8_t *) file_name, namelen, &err);
+ (uint8_t *) file_name, namelen, &err);
if (err != TOX_ERR_FILE_SEND_OK)
goto on_send_error;
@@ -284,6 +287,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return;
on_send_error:
+
switch (err) {
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
errmsg = "File transfer failed: Invalid friend.";
diff --git a/src/configdir.c b/src/configdir.c
index d1e5f8d..ee97af3 100644
--- a/src/configdir.c
+++ b/src/configdir.c
@@ -33,7 +33,7 @@
#include "configdir.h"
#include "misc_tools.h"
-/* get the user's home directory */
+/* get the user's home directory. */
void get_home_dir(char *home, int size)
{
struct passwd pwd;
@@ -102,8 +102,10 @@ char *get_user_config_dir(void)
return user_config_dir;
}
-/*
- * Creates the config and chatlog directories.
+/* Creates the config and chatlog directories.
+ *
+ * Returns 0 on success.
+ * Returns -1 on failure.
*/
int create_user_config_dirs(char *path)
{
diff --git a/src/configdir.h b/src/configdir.h
index 69abffd..a5317c3 100644
--- a/src/configdir.h
+++ b/src/configdir.h
@@ -34,8 +34,23 @@
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
+/**
+ * @brief Get the user's config directory.
+ *
+ * This is without a trailing slash. Resulting string must be freed.
+ *
+ * @return The users config dir or NULL on error.
+ */
char *get_user_config_dir(void);
+
+/* get the user's home directory. */
void get_home_dir(char *home, int size);
+
+/* Creates the config and chatlog directories.
+ *
+ * Returns 0 on success.
+ * Returns -1 on failure.
+ */
int create_user_config_dirs(char *path);
#endif /* #define CONFIGDIR_H */
diff --git a/src/curl_util.c b/src/curl_util.c
new file mode 100644
index 0000000..0678517
--- /dev/null
+++ b/src/curl_util.c
@@ -0,0 +1,93 @@
+/* curl_util.c
+ *
+ *
+ * Copyright (C) 2016 Toxic All Rights Reserved.
+ *
+ * This file is part of Toxic.
+ *
+ * Toxic is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Toxic is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Toxic. If not, see .
+ *
+ */
+
+#include
+#include
+
+#include
+#include
+
+#include "curl_util.h"
+
+/* Sets proxy info for given CURL handler.
+ *
+ * Returns 0 on success or if no proxy is set by the client.
+ * Returns -1 if proxy info is invalid.
+ * Returns an int > 0 on curl error (see: https://curl.haxx.se/libcurl/c/libcurl-errors.html)
+ */
+int set_curl_proxy(CURL *c_handle, const char *proxy_address, uint16_t port, uint8_t proxy_type)
+{
+ if (proxy_type == TOX_PROXY_TYPE_NONE)
+ return 0;
+
+ if (proxy_address == NULL || port == 0) {
+ return -1;
+ }
+
+ int ret = curl_easy_setopt(c_handle, CURLOPT_PROXYPORT, (long) port);
+
+ if (ret != CURLE_OK) {
+ return ret;
+ }
+
+ long int type = proxy_type == TOX_PROXY_TYPE_SOCKS5 ? CURLPROXY_SOCKS5_HOSTNAME : CURLPROXY_HTTP;
+
+ ret = curl_easy_setopt(c_handle, CURLOPT_PROXYTYPE, type);
+
+ if (ret != CURLE_OK) {
+ return ret;
+ }
+
+ ret = curl_easy_setopt(c_handle, CURLOPT_PROXY, proxy_address);
+
+ if (ret != CURLE_OK) {
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Callback function for CURL to write received data.
+ *
+ * This function will append data from an http request to the data buffer
+ * until the request is complete or the buffer is full. Buffer will be null terminated.
+ *
+ * Returns number of bytes received from http request on success (don't change this).
+ * Returns 0 if data exceeds buffer size.
+ */
+size_t curl_cb_write_data(void *data, size_t size, size_t nmemb, void *user_pointer)
+{
+ struct Recv_Curl_Data *recv_data = (struct Recv_Curl_Data *) user_pointer;
+
+ size_t length = size * nmemb;
+ size_t total_size = length + recv_data->length;
+
+ if (total_size > MAX_RECV_CURL_DATA_SIZE) {
+ return 0;
+ }
+
+ memcpy(recv_data->data + recv_data->length, data, length);
+ recv_data->data[total_size] = '\0';
+ recv_data->length += length;
+
+ return length;
+}
diff --git a/src/curl_util.h b/src/curl_util.h
new file mode 100644
index 0000000..cefb5db
--- /dev/null
+++ b/src/curl_util.h
@@ -0,0 +1,55 @@
+/* curl_util.h
+ *
+ *
+ * Copyright (C) 2016 Toxic All Rights Reserved.
+ *
+ * This file is part of Toxic.
+ *
+ * Toxic is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Toxic is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Toxic. If not, see .
+ *
+ */
+
+#ifndef CURL_UTIL_H
+#define CURL_UTIL_H
+
+/* List based on Mozilla's recommended configurations for modern browsers */
+#define TLS_CIPHER_SUITE_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
+
+/* Max size of an http response that we can store in Recv_Data */
+#define MAX_RECV_CURL_DATA_SIZE 32767
+
+/* Holds data received from curl lookup */
+struct Recv_Curl_Data {
+ char data[MAX_RECV_CURL_DATA_SIZE + 1]; /* Data received from curl write data callback */
+ size_t length; /* Total number of bytes written to data buffer (doesn't include null) */
+};
+
+/* Sets proxy info for given CURL handler.
+ *
+ * Returns 0 on success or if no proxy is set by the client.
+ * Returns -1 if proxy info is invalid.
+ * Returns an int > 0 on curl error (see: https://curl.haxx.se/libcurl/c/libcurl-errors.html)
+ */
+int set_curl_proxy(CURL *c_handle, const char *proxy_address, uint16_t port, uint8_t proxy_type);
+
+/* Callback function for CURL to write received data.
+ *
+ * This function will append data from an http request to the data buffer
+ * until the request is complete or the buffer is full. Buffer will be null terminated.
+ *
+ * Returns size of bytes written to the data buffer.
+ */
+size_t curl_cb_write_data(void *data, size_t size, size_t nmemb, void *user_pointer);
+
+#endif /* CURL_UTIL_H */
diff --git a/src/file_transfers.c b/src/file_transfers.c
index ad71c9e..f3bc42b 100644
--- a/src/file_transfers.c
+++ b/src/file_transfers.c
@@ -136,7 +136,7 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
* Returns NULL on failure.
*/
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
- FILE_TRANSFER_DIRECTION direction)
+ FILE_TRANSFER_DIRECTION direction)
{
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND)
return NULL;
@@ -145,8 +145,8 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
- &Friends.list[friendnum].file_sender[i] :
- &Friends.list[friendnum].file_receiver[i];
+ &Friends.list[friendnum].file_sender[i] :
+ &Friends.list[friendnum].file_receiver[i];
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index)
return ft;
diff --git a/src/file_transfers.h b/src/file_transfers.h
index aaf081e..51104ef 100644
--- a/src/file_transfers.h
+++ b/src/file_transfers.h
@@ -61,8 +61,8 @@ struct FileTransfer {
size_t index;
uint64_t file_size;
uint64_t position;
- uint64_t last_line_progress; /* The last time we updated the progress bar */
- uint64_t last_keep_alive; /* The last time we sent or received data */
+ time_t last_line_progress; /* The last time we updated the progress bar */
+ time_t last_keep_alive; /* The last time we sent or received data */
uint32_t line_id;
uint8_t file_id[TOX_FILE_ID_LENGTH];
};
@@ -87,7 +87,7 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
* Returns NULL on failure.
*/
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
- FILE_TRANSFER_DIRECTION direction);
+ FILE_TRANSFER_DIRECTION direction);
/* Initializes an unused file transfer and returns its pointer.
* Returns NULL on failure.
diff --git a/src/friendlist.c b/src/friendlist.c
index 7d3851f..2abc96d 100644
--- a/src/friendlist.c
+++ b/src/friendlist.c
@@ -314,10 +314,10 @@ static void sort_blocklist_index(void)
qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block);
}
-static void update_friend_last_online(uint32_t num, uint64_t timestamp)
+static void update_friend_last_online(uint32_t num, time_t timestamp)
{
Friends.list[num].last_online.last_on = timestamp;
- Friends.list[num].last_online.tm = *localtime((const time_t*)×tamp);
+ Friends.list[num].last_online.tm = *localtime((const time_t *)×tamp);
/* if the format changes make sure TIME_STR_SIZE is the correct size */
const char *t = user_settings->timestamp_format;
@@ -439,7 +439,7 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", pkerr);
TOX_ERR_FRIEND_GET_LAST_ONLINE loerr;
- uint64_t t = tox_friend_get_last_online(m, num, &loerr);
+ time_t t = tox_friend_get_last_online(m, num, &loerr);
if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK)
t = 0;
@@ -537,7 +537,7 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, uint32_t num, cons
get_nick_truncate(m, nick, num);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
- "* Group chat invite from %s failed: too many windows are open.", nick);
+ "* Group chat invite from %s failed: too many windows are open.", nick);
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
}
@@ -559,6 +559,7 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
static void delete_friend(Tox *m, uint32_t f_num)
{
TOX_ERR_FRIEND_DELETE err;
+
if (tox_friend_delete(m, f_num, &err) != true) {
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
return;
@@ -641,10 +642,12 @@ static void draw_del_popup(void)
wattron(PendingDelete.popup, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
+
if (blocklist_view == 0)
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
else
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
+
pthread_mutex_unlock(&Winthread.lock);
wattroff(PendingDelete.popup, A_BOLD);
@@ -795,6 +798,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
block_friend(m, f);
else
unblock_friend(m, f);
+
break;
case KEY_RIGHT:
@@ -807,6 +811,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
select_friend(self, key, &Friends.num_selected, Friends.num_friends);
else
select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked);
+
break;
}
}
@@ -906,7 +911,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
return;
}
- uint64_t cur_time = time(NULL);
+ time_t cur_time = get_unix_time();
struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
wattron(self->window, A_BOLD);
@@ -966,9 +971,11 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
case TOX_USER_STATUS_NONE:
colour = GREEN;
break;
+
case TOX_USER_STATUS_AWAY:
colour = YELLOW;
break;
+
case TOX_USER_STATUS_BUSY:
colour = RED;
break;
@@ -1043,16 +1050,16 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wattroff(self->window, COLOR_PAIR(BLUE));
pthread_mutex_lock(&Winthread.lock);
- uint64_t last_seen = Friends.list[f].last_online.last_on;
+ time_t last_seen = Friends.list[f].last_online.last_on;
pthread_mutex_unlock(&Winthread.lock);
if (last_seen != 0) {
pthread_mutex_lock(&Winthread.lock);
int day_dist = (
- cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
- + ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
- );
+ cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
+ + ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
+ );
const char *hourmin = Friends.list[f].last_online.hour_min_str;
pthread_mutex_unlock(&Winthread.lock);
@@ -1108,7 +1115,8 @@ void disable_chatwin(uint32_t f_num)
static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
assert(0);
- if( friend_number >= Friends.max_idx)
+
+ if ( friend_number >= Friends.max_idx)
return;
assert(0);
@@ -1116,7 +1124,7 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
if (Friends.list[friend_number].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
- if(state != TOXAV_FRIEND_CALL_STATE_FINISHED) {
+ if (state != TOXAV_FRIEND_CALL_STATE_FINISHED) {
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
set_active_window(Friends.list[friend_number].chatwin);
}
diff --git a/src/global_commands.c b/src/global_commands.c
index e3588b1..65809b9 100644
--- a/src/global_commands.c
+++ b/src/global_commands.c
@@ -130,7 +130,8 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
break;
case TOX_ERR_FRIEND_ADD_NULL:
- /* fallthrough */
+
+ /* fallthrough */
default:
errmsg = "Faile to add friend: Unknown error.";
break;
@@ -260,6 +261,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
}
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
+
if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
return;
@@ -281,6 +283,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
case TOX_ERR_BOOTSTRAP_NULL:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
break;
+
default:
break;
}
@@ -354,13 +357,16 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
if (err != TOX_ERR_GROUP_NEW_OK) {
switch (err) {
case TOX_ERR_GROUP_NEW_TOO_LONG: {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name length cannot exceed %d.", TOX_GROUP_MAX_GROUP_NAME_LENGTH);
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name length cannot exceed %d.",
+ TOX_GROUP_MAX_GROUP_NAME_LENGTH);
break;
}
+
case TOX_ERR_GROUP_NEW_EMPTY: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name cannot be empty.");
break;
}
+
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d).", err);
break;
@@ -376,7 +382,8 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_group_leave(m, groupnum, NULL, 0, NULL);
} else if (init == -2) {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You have been kicked from a group. Close the window and try again.");
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
+ "You have been kicked from a group. Close the window and try again.");
tox_group_leave(m, groupnum, NULL, 0, NULL);
}
}
@@ -445,7 +452,8 @@ void cmd_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_group_leave(m, groupnum, NULL, 0, NULL);
} else if (init == -2) {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You have been kicked from a group. Close the window and try again.");
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
+ "You have been kicked from a group. Close the window and try again.");
tox_group_leave(m, groupnum, NULL, 0, NULL);
}
}
@@ -618,8 +626,10 @@ void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:");
cmd_myid(window, self, m, 0, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Any services that relied on your old ID will need to be updated manually.");
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'", old_nospam);
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
+ "Any services that relied on your old ID will need to be updated manually.");
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'",
+ old_nospam);
}
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
diff --git a/src/group_commands.c b/src/group_commands.c
index a3419a1..a4c84c3 100644
--- a/src/group_commands.c
+++ b/src/group_commands.c
@@ -70,6 +70,7 @@ void cmd_ignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
}
TOX_ERR_GROUP_TOGGLE_IGNORE err;
+
if (!tox_group_toggle_ignore(m, self->num, peer_id, true, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to ignore %s (error %d).", nick, err);
return;
@@ -99,12 +100,15 @@ static void cmd_kickban_helper(ToxWindow *self, Tox *m, const char *nick, bool s
case TOX_ERR_GROUP_MOD_REMOVE_PEER_OK: {
return;
}
+
case TOX_ERR_GROUP_MOD_REMOVE_PEER_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to %s %s.", type_str, nick);
return;
}
+
default: {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to %s %s from the group (error %d).", type_str, nick, err);
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to %s %s from the group (error %d).", type_str, nick,
+ err);
return;
}
}
@@ -173,8 +177,11 @@ void cmd_ban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
}
struct tm tm_set = *localtime((const time_t *) &time_set);
+
char time_str[64];
+
strftime(time_str, sizeof(time_str), "%e %b %Y %H:%M:%S%p", &tm_set);
+
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "ID %d : %s [Set:%s]", id, nick, time_str);
}
@@ -206,14 +213,17 @@ void cmd_unban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban list entry with id %d has been removed.", ban_id);
return;
}
+
case TOX_ERR_GROUP_MOD_REMOVE_BAN_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unban peers.");
return;
}
+
case TOX_ERR_GROUP_MOD_REMOVE_BAN_FAIL_ACTION: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID does not exist.");
return;
}
+
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to remove ban list entry (error %d).", err);
return;
@@ -243,14 +253,17 @@ void cmd_mod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
+
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to promote moderators.");
return;
}
+
case TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "This peer is already a moderator.");
return;
}
+
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to promote peer to moderator (error %d).", err);
return;
@@ -285,12 +298,15 @@ void cmd_unmod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
+
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Nice try.");
return;
}
+
default: {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to revoke moderator powers from %s (error %d).", nick, err);
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to revoke moderator powers from %s (error %d).", nick,
+ err);
return;
}
}
@@ -302,9 +318,10 @@ void cmd_mykey(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
char pk[TOX_GROUP_PEER_PUBLIC_KEY_SIZE];
TOX_ERR_GROUP_SELF_QUERY err;
+
if (!tox_group_self_get_public_key(m, self->num, (uint8_t *) pk, &err)) {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to fetch your public key (error %d)", err);
- return;
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to fetch your public key (error %d)", err);
+ return;
}
size_t i;
@@ -337,16 +354,21 @@ void cmd_set_passwd(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been set to %s.", passwd);
else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been unset.");
+
return;
}
+
case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG: {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password length must not exceed %d.", TOX_GROUP_MAX_PASSWORD_SIZE);
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password length must not exceed %d.",
+ TOX_GROUP_MAX_PASSWORD_SIZE);
return;
}
+
case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the password.");
return;
}
+
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set password (error %d).", err);
return;
@@ -386,10 +408,12 @@ void cmd_set_peerlimit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit has been set to %d.", maxpeers);
return;
}
+
case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the peer limit.");
return;
}
+
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the peer limit (error %d).", err);
return;
@@ -423,7 +447,8 @@ void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
return;
}
- privacy_state = strcasecmp(pstate_str, "private") == 0 ? TOX_GROUP_PRIVACY_STATE_PRIVATE : TOX_GROUP_PRIVACY_STATE_PUBLIC;
+ privacy_state = strcasecmp(pstate_str,
+ "private") == 0 ? TOX_GROUP_PRIVACY_STATE_PRIVATE : TOX_GROUP_PRIVACY_STATE_PUBLIC;
TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE err;
tox_group_founder_set_privacy_state(m, self->num, privacy_state, &err);
@@ -433,10 +458,12 @@ void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state has been set to %s.", pstate_str);
return;
}
+
case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the privacy state.");
return;
}
+
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error setting privacy state (error %d).", err);
return;
@@ -466,10 +493,12 @@ void cmd_silence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
+
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to silence %s.", nick);
return;
}
+
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to silence %s (error %d).", nick, err);
return;
@@ -504,10 +533,12 @@ void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
+
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unsilence %s.", nick);
return;
}
+
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unsilence %s (error %d).", nick, err);
return;
@@ -518,6 +549,7 @@ void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
void cmd_rejoin(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
TOX_ERR_GROUP_RECONNECT err;
+
if (!tox_group_reconnect(m, self->num, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to rejoin group (error %d).", err);
return;
@@ -564,14 +596,17 @@ void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
/* handled below switch */
break;
}
+
case TOX_ERR_GROUP_TOPIC_SET_TOO_LONG: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic length must not exceed %d.", TOX_GROUP_MAX_TOPIC_LENGTH);
return;
}
+
case TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the topic.");
return;
}
+
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the topic (error %d).", err);
return;
@@ -586,8 +621,8 @@ void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
char selfnick[sn_len];
if (!tox_group_self_get_name(m, self->num, (uint8_t *) selfnick, &sn_err)) {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve your own name (error %d).", sn_err);
- return;
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve your own name (error %d).", sn_err);
+ return;
}
selfnick[sn_len] = '\0';
@@ -615,6 +650,7 @@ void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
}
TOX_ERR_GROUP_TOGGLE_IGNORE err;
+
if (!tox_group_toggle_ignore(m, self->num, peer_id, false, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unignore %s (error %d).", nick, err);
return;
diff --git a/src/groupchat.c b/src/groupchat.c
index db78b1d..dabeb57 100644
--- a/src/groupchat.c
+++ b/src/groupchat.c
@@ -267,10 +267,12 @@ void set_nick_all_groups(Tox *m, const char *nick, size_t length)
case TOX_ERR_GROUP_SELF_NAME_SET_OK: {
break;
}
+
case TOX_ERR_GROUP_SELF_NAME_SET_TAKEN: {
line_info_add(self, NULL, NULL, 0, SYS_MSG, 0, RED, "-!- That nick is already in use.");
break;
}
+
default: {
if (groupchats[i].time_connected > 0)
line_info_add(self, NULL, NULL, 0, SYS_MSG, 0, RED, "-!- Failed to set nick (error %d).", err);
@@ -405,8 +407,8 @@ static void group_update_name_list(uint32_t groupnum)
for (i = 0; i < chat->max_idx; ++i) {
if (chat->peer_list[i].active) {
- memcpy(&chat->name_list[count * TOX_MAX_NAME_LENGTH], chat->peer_list[i].name, chat->peer_list[i].name_length + 1);
- ++count;
+ memcpy(&chat->name_list[count * TOX_MAX_NAME_LENGTH], chat->peer_list[i].name, chat->peer_list[i].name_length + 1);
+ ++count;
}
}
@@ -512,7 +514,7 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum,
/* Only play sound if mentioned by someone else */
if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) {
- sound_notify(self, generic_message, NT_WNDALERT_0, NULL);
+ sound_notify(self, generic_message, NT_WNDALERT_0 | user_settings->bell_on_message, NULL);
if (self->active_box != -1)
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
@@ -532,7 +534,7 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum,
}
static void groupchat_onGroupPrivateMessage(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peer_id,
- const char *msg, size_t len)
+ const char *msg, size_t len)
{
if (self->num != groupnum || !groupnumber_valid(groupnum))
return;
@@ -559,7 +561,7 @@ static void groupchat_onGroupPrivateMessage(ToxWindow *self, Tox *m, uint32_t gr
}
static void groupchat_onGroupTopicChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peer_id,
- const char *topic, size_t length)
+ const char *topic, size_t length)
{
ChatContext *ctx = self->chatwin;
@@ -590,7 +592,8 @@ static void groupchat_onGroupPeerLimit(ToxWindow *self, Tox *m, uint32_t groupnu
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
- line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- The group founder has set the peer limit to %d", peer_limit);
+ line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- The group founder has set the peer limit to %d",
+ peer_limit);
char tmp_event[MAX_STR_SIZE];
snprintf(tmp_event, sizeof(tmp_event), " set the peer limit to %d", peer_limit);
@@ -609,7 +612,8 @@ static void groupchat_onGroupPrivacyState(ToxWindow *self, Tox *m, uint32_t grou
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
- line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- The group founder has set the group to %s.", state_str);
+ line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- The group founder has set the group to %s.",
+ state_str);
char tmp_event[MAX_STR_SIZE];
snprintf(tmp_event, sizeof(tmp_event), " set the group to %s.", state_str);
@@ -652,7 +656,7 @@ static int realloc_peer_list(uint32_t groupnum, uint32_t n)
GroupChat *chat = &groupchats[groupnum];
if (!chat)
- return -1;
+ return -1;
if (n == 0) {
free(chat->peer_list);
@@ -844,12 +848,15 @@ static void groupchat_onGroupRejected(ToxWindow *self, Tox *m, uint32_t groupnum
case TOX_GROUP_JOIN_FAIL_NAME_TAKEN:
msg = "Nick already in use. Change your nick and use the '/rejoin' command.";
break;
+
case TOX_GROUP_JOIN_FAIL_PEER_LIMIT:
msg = "Group is full. Try again with the '/rejoin' command.";
break;
+
case TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD:
msg = "Invalid password.";
break;
+
case TOX_GROUP_JOIN_FAIL_UNKNOWN:
msg = "Failed to join group. Try again with the '/rejoin' command.";
break;
@@ -892,24 +899,30 @@ static void groupchat_onGroupModeration(ToxWindow *self, Tox *m, uint32_t groupn
case TOX_GROUP_MOD_EVENT_KICK:
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, RED, "-!- %s has been kicked by %s", tgt_name, src_name);
break;
+
case TOX_GROUP_MOD_EVENT_BAN:
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, RED, "-!- %s has been banned by %s", tgt_name, src_name);
break;
+
case TOX_GROUP_MOD_EVENT_OBSERVER:
chat->peer_list[tgt_index].role = TOX_GROUP_ROLE_OBSERVER;
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- %s has set %s's role to observer", src_name, tgt_name);
sort_peerlist(groupnum);
break;
+
case TOX_GROUP_MOD_EVENT_USER:
chat->peer_list[tgt_index].role = TOX_GROUP_ROLE_USER;
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- %s has set %s's role to user", src_name, tgt_name);
sort_peerlist(groupnum);
break;
+
case TOX_GROUP_MOD_EVENT_MODERATOR:
chat->peer_list[tgt_index].role = TOX_GROUP_ROLE_MODERATOR;
- line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- %s has set %s's role to moderator", src_name, tgt_name);
+ line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- %s has set %s's role to moderator", src_name,
+ tgt_name);
sort_peerlist(groupnum);
break;
+
default:
return;
}
@@ -947,7 +960,7 @@ static void groupchat_onGroupNickChange(ToxWindow *self, Tox *m, uint32_t groupn
}
static void groupchat_onGroupStatusChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peer_id,
- TOX_USER_STATUS status)
+ TOX_USER_STATUS status)
{
if (self->num != groupnum || !groupnumber_valid(groupnum))
return;
@@ -973,6 +986,7 @@ static void send_group_message(ToxWindow *self, Tox *m, uint32_t groupnum, const
}
TOX_ERR_GROUP_SEND_MESSAGE err;
+
if (!tox_group_send_message(m, groupnum, type, (uint8_t *) msg, strlen(msg), &err)) {
if (err == TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * You are silenced.");
@@ -1053,6 +1067,7 @@ static void send_group_prvt_message(ToxWindow *self, Tox *m, uint32_t groupnum,
const char *msg = data + name_length + 1;
TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE err;
+
if (!tox_group_send_private_message(m, groupnum, peer_id, (uint8_t *) msg, msg_len, &err)) {
if (err == TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PERMISSIONS) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * You are silenced.");
@@ -1206,6 +1221,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
pthread_mutex_lock(&Winthread.lock);
+ pthread_mutex_unlock(&Winthread.lock);
wmove(ctx->sidebar, 0, 1);
wattron(ctx->sidebar, A_BOLD);
@@ -1231,6 +1247,9 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
char tmpnck[TOX_MAX_NAME_LENGTH];
int maxlen = SIDEBAR_WIDTH - maxlen_offset;
memcpy(tmpnck, chat->peer_list[p].name, maxlen);
+ pthread_mutex_lock(&Winthread.lock);
+ pthread_mutex_unlock(&Winthread.lock);
+
tmpnck[maxlen] = '\0';
int namecolour = WHITE;
diff --git a/src/help.c b/src/help.c
index 90a9486..0d50db6 100644
--- a/src/help.c
+++ b/src/help.c
@@ -323,7 +323,7 @@ static void help_draw_contacts(ToxWindow *self)
void help_onKey(ToxWindow *self, wint_t key)
{
- switch(key) {
+ switch (key) {
case 'x':
case T_KEY_ESC:
help_exit(self);
@@ -377,7 +377,7 @@ void help_onDraw(ToxWindow *self)
{
curs_set(0);
- switch(self->help->type) {
+ switch (self->help->type) {
case HELP_MENU:
help_draw_menu(self);
return;
diff --git a/src/input.c b/src/input.c
index 649dad9..26c0326 100644
--- a/src/input.c
+++ b/src/input.c
@@ -275,9 +275,9 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
self->show_peerlist ^= 1;
redraw_groupchat_win(self);
}
+
match = true;
- }
- else if (key == user_settings->key_toggle_pastemode) {
+ } else if (key == user_settings->key_toggle_pastemode) {
self->chatwin->pastemode ^= 1;
match = true;
}
diff --git a/src/line_info.c b/src/line_info.c
index ddc1af2..275e449 100644
--- a/src/line_info.c
+++ b/src/line_info.c
@@ -158,13 +158,15 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
/* for type-specific formatting in print function */
switch (type) {
case IN_ACTION:
- /* fallthrough */
+
+ /* fallthrough */
case OUT_ACTION:
len += strlen(user_settings->line_normal) + 2;
break;
case IN_MSG:
- /* fallthrough */
+
+ /* fallthrough */
case OUT_MSG:
len += strlen(user_settings->line_normal) + 3;
break;
@@ -309,9 +311,11 @@ void line_info_print(ToxWindow *self)
switch (type) {
case OUT_MSG:
- /* fallthrough */
+
+ /* fallthrough */
case OUT_MSG_READ:
- /* fallthrough */
+
+ /* fallthrough */
case IN_MSG:
case IN_PRVT_MSG:
case OUT_PRVT_MSG:
@@ -327,16 +331,16 @@ void line_info_print(ToxWindow *self)
nameclr = CYAN;
wattron(win, COLOR_PAIR(nameclr));
- wprintw(win, "%s %s: ",(type != OUT_PRVT_MSG && type != IN_PRVT_MSG) ?
- user_settings->line_normal :
- user_settings->line_special,
- line->name1);
+ wprintw(win, "%s %s: ", (type != OUT_PRVT_MSG && type != IN_PRVT_MSG) ?
+ user_settings->line_normal :
+ user_settings->line_special,
+ line->name1);
wattroff(win, COLOR_PAIR(nameclr));
- char* msg = line->msg;
- while (msg)
- {
- char* line = strsep(&msg, "\n");
+ char *msg = line->msg;
+
+ while (msg) {
+ char *line = strsep(&msg, "\n");
if (line[0] == '>')
wattron(win, COLOR_PAIR(GREEN));
@@ -370,9 +374,11 @@ void line_info_print(ToxWindow *self)
break;
case OUT_ACTION_READ:
- /* fallthrough */
+
+ /* fallthrough */
case OUT_ACTION:
- /* fallthrough */
+
+ /* fallthrough */
case IN_ACTION:
wattron(win, COLOR_PAIR(BLUE));
wprintw(win, "%s ", line->timestr);
@@ -558,20 +564,15 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
if (key == user_settings->key_half_page_up) {
line_info_page_up(self, hst);
- }
- else if (key == user_settings->key_half_page_down) {
+ } else if (key == user_settings->key_half_page_down) {
line_info_page_down(self, hst);
- }
- else if (key == user_settings->key_scroll_line_up) {
+ } else if (key == user_settings->key_scroll_line_up) {
line_info_scroll_up(hst);
- }
- else if (key == user_settings->key_scroll_line_down) {
+ } else if (key == user_settings->key_scroll_line_down) {
line_info_scroll_down(hst);
- }
- else if (key == user_settings->key_page_bottom) {
+ } else if (key == user_settings->key_page_bottom) {
line_info_reset_start(self, hst);
- }
- else {
+ } else {
match = false;
}
diff --git a/src/line_info.h b/src/line_info.h
index 0d65cb9..d33419d 100644
--- a/src/line_info.h
+++ b/src/line_info.h
@@ -52,7 +52,7 @@ struct line_info {
char name1[TOXIC_MAX_NAME_LENGTH + 1];
char name2[TOXIC_MAX_NAME_LENGTH + 1];
char msg[MAX_LINE_INFO_MSG_SIZE];
- uint64_t timestamp;
+ time_t timestamp;
uint8_t type;
uint8_t bold;
uint8_t colour;
diff --git a/src/log.c b/src/log.c
index 2d48dbc..24ef560 100644
--- a/src/log.c
+++ b/src/log.c
@@ -262,6 +262,7 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
return 0;
on_error:
+
if (log_on)
log_enable(src, selfkey, otherkey, log, LOG_CHAT);
diff --git a/src/log.h b/src/log.h
index 4bfa708..fb2889c 100644
--- a/src/log.h
+++ b/src/log.h
@@ -25,7 +25,7 @@
struct chatlog {
FILE *file;
- uint64_t lastwrite;
+ time_t lastwrite;
char path[MAX_STR_SIZE];
bool log_on; /* specific to current chat window */
};
diff --git a/src/message_queue.h b/src/message_queue.h
index df0317e..6b41529 100644
--- a/src/message_queue.h
+++ b/src/message_queue.h
@@ -29,7 +29,7 @@ struct cqueue_msg {
int line_id;
uint8_t type;
uint32_t receipt;
- uint64_t last_send_try;
+ time_t last_send_try;
struct cqueue_msg *next;
struct cqueue_msg *prev;
};
diff --git a/src/misc_tools.c b/src/misc_tools.c
index eee59db..f20660d 100644
--- a/src/misc_tools.c
+++ b/src/misc_tools.c
@@ -26,7 +26,9 @@
#include
#include
#include
+
#include
+#include
#include "toxic.h"
#include "windows.h"
@@ -37,8 +39,6 @@
extern ToxWindow *prompt;
extern struct user_settings *user_settings;
-static uint64_t current_unix_time;
-
void hst_to_net(uint8_t *num, uint16_t numbytes)
{
#ifndef WORDS_BIGENDIAN
@@ -54,19 +54,13 @@ void hst_to_net(uint8_t *num, uint16_t numbytes)
return;
}
-/* Note: The time functions are not thread safe */
-void update_unix_time(void)
+time_t get_unix_time(void)
{
- current_unix_time = (uint64_t) time(NULL);
-}
-
-uint64_t get_unix_time(void)
-{
- return current_unix_time;
+ return time(NULL);
}
/* Returns 1 if connection has timed out, 0 otherwise */
-int timed_out(uint64_t timestamp, uint64_t timeout)
+int timed_out(time_t timestamp, time_t timeout)
{
return timestamp + timeout <= get_unix_time();
}
@@ -75,8 +69,8 @@ int timed_out(uint64_t timestamp, uint64_t timeout)
struct tm *get_time(void)
{
struct tm *timeinfo;
- uint64_t t = get_unix_time();
- timeinfo = localtime((const time_t*) &t);
+ time_t t = get_unix_time();
+ timeinfo = localtime((const time_t *) &t);
return timeinfo;
}
@@ -93,7 +87,7 @@ void get_time_str(char *buf, int bufsize)
}
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
-void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs)
+void get_elapsed_time_str(char *buf, int bufsize, time_t secs)
{
if (!secs)
return;
@@ -180,7 +174,7 @@ int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_
size_t i;
for (i = 0; i < TOX_ADDRESS_SIZE; ++i)
- snprintf(&output[i*2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
+ snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
return 0;
}
@@ -211,7 +205,7 @@ int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n)
if (n < len)
return -1;
- if ((len = mbstowcs(buf, string, n)) == (size_t) -1)
+ if ((len = mbstowcs(buf, string, n)) == (size_t) - 1)
return -1;
return len;
@@ -225,7 +219,7 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n)
if (n < len)
return -1;
- if ((len = wcstombs(buf, string, n)) == (size_t) -1)
+ if ((len = wcstombs(buf, string, n)) == (size_t) - 1)
return -1;
return len;
@@ -252,11 +246,11 @@ int valid_nick(const char *nick)
for (i = 0; nick[i]; ++i) {
if ((nick[i] == ' ' && nick[i + 1] == ' ')
- || nick[i] == '/'
- || nick[i] == '\n'
- || nick[i] == '\t'
- || nick[i] == '\v'
- || nick[i] == '\r')
+ || nick[i] == '/'
+ || nick[i] == '\n'
+ || nick[i] == '\t'
+ || nick[i] == '\v'
+ || nick[i] == '\r')
return 0;
}
@@ -398,9 +392,13 @@ size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
}
/* returns index of the first instance of ch in s starting at idx.
- returns length of s if char not found */
+ returns length of s if char not found or 0 if s is NULL. */
int char_find(int idx, const char *s, char ch)
{
+ if (!s) {
+ return 0;
+ }
+
int i = idx;
for (i = idx; s[i]; ++i) {
@@ -412,9 +410,13 @@ int char_find(int idx, const char *s, char ch)
}
/* returns index of the last instance of ch in s starting at len.
- returns 0 if char not found (skips 0th index). */
+ returns 0 if char not found or s is NULL (skips 0th index). */
int char_rfind(const char *s, char ch, int len)
{
+ if (!s) {
+ return 0;
+ }
+
int i = 0;
for (i = len; i > 0; --i) {
@@ -501,3 +503,36 @@ void set_window_title(ToxWindow *self, const char *title, int len)
snprintf(self->name, sizeof(self->name), "%s", cpy);
}
+
+/* Return true if address appears to be a valid ipv4 address. */
+bool is_ip4_address(const char *address)
+{
+ struct sockaddr_in s_addr;
+ return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0;
+}
+
+/* Return true if address roughly appears to be a valid ipv6 address.
+ *
+ * TODO: Improve this function (inet_pton behaves strangely with ipv6).
+ * for now the only guarantee is that it won't return true if the
+ * address is a domain or ipv4 address, and should only be used if you're
+ * reasonably sure that the address is one of the three (ipv4, ipv6 or a domain).
+ */
+bool is_ip6_address(const char *address)
+{
+ size_t i;
+ size_t num_colons = 0;
+ char ch = 0;
+
+ for (i = 0; (ch = address[i]); ++i) {
+ if (ch == '.') {
+ return false;
+ }
+
+ if (ch == ':') {
+ ++num_colons;
+ }
+ }
+
+ return num_colons > 1 && num_colons < 8;
+}
diff --git a/src/misc_tools.h b/src/misc_tools.h
index 79b7af1..7c4797e 100644
--- a/src/misc_tools.h
+++ b/src/misc_tools.h
@@ -61,13 +61,13 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr);
int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size);
/* get the current unix time (not thread safe) */
-uint64_t get_unix_time(void);
+time_t get_unix_time(void);
/* Puts the current time in buf in the format of [HH:mm:ss] (not thread safe) */
void get_time_str(char *buf, int bufsize);
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
-void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs);
+void get_elapsed_time_str(char *buf, int bufsize, time_t secs);
/* Converts seconds to string in format H hours, m minutes, s seconds */
void get_elapsed_time_str_2(char *buf, int bufsize, uint64_t secs);
@@ -75,9 +75,6 @@ void get_elapsed_time_str_2(char *buf, int bufsize, uint64_t secs);
/* get the current local time (not thread safe) */
struct tm *get_time(void);
-/* updates current unix time (should be run once per do_toxic loop) */
-void update_unix_time(void);
-
/* Returns 1 if the string is empty, 0 otherwise */
int string_is_empty(const char *string);
@@ -94,7 +91,7 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n);
int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
/* Returns 1 if connection has timed out, 0 otherwise */
-int timed_out(uint64_t timestamp, uint64_t timeout);
+int timed_out(time_t timestamp, time_t timeout);
/* Colours the window tab according to type. Beeps if is_beep is true */
void alert_window(ToxWindow *self, int type, bool is_beep);
@@ -140,11 +137,11 @@ int get_group_nick_truncate(Tox *m, char *buf, uint32_t peer_id, int groupnum);
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length);
/* returns index of the first instance of ch in s starting at idx.
- returns length of s if char not found */
+ returns length of s if char not found or 0 if s is NULL. */
int char_find(int idx, const char *s, char ch);
-/* returns index of the last instance of ch in s
- returns 0 if char not found */
+/* returns index of the last instance of ch in s starting at len.
+ returns 0 if char not found or s is NULL (skips 0th index). */
int char_rfind(const char *s, char ch, int len);
/* Converts bytes to appropriate unit and puts in buf as a string */
@@ -165,4 +162,16 @@ int check_file_signature(const char *signature, size_t size, FILE *fp);
/* sets window title in tab bar. */
void set_window_title(ToxWindow *self, const char *title, int len);
+/* Return true if address appears to be a valid ipv4 address. */
+bool is_ip4_address(const char *address);
+
+/* Return true if address roughly appears to be a valid ipv6 address.
+ *
+ * TODO: Improve this function (inet_pton behaves strangely with ipv6).
+ * for now the only guarantee is that it won't return true if the
+ * address is a domain or ipv4 address, and should only be used if you're
+ * reasonably sure that the address is one of the three (ipv4, ipv6 or a domain).
+ */
+bool is_ip6_address(const char *address);
+
#endif /* #define MISC_TOOLS_H */
diff --git a/src/name_lookup.c b/src/name_lookup.c
index 3fc7e36..2b68bb4 100644
--- a/src/name_lookup.c
+++ b/src/name_lookup.c
@@ -22,7 +22,6 @@
#include
#include
-#include /* for u_char */
#include
#include "toxic.h"
@@ -31,9 +30,10 @@
#include "global_commands.h"
#include "misc_tools.h"
#include "configdir.h"
+#include "curl_util.h"
extern struct arg_opts arg_opts;
-extern struct Winthread Winthread;;
+extern struct Winthread Winthread;
#define NAMESERVER_API_PATH "api"
#define SERVER_KEY_SIZE 32
@@ -41,9 +41,6 @@ extern struct Winthread Winthread;;
#define MAX_DOMAIN_SIZE 32
#define MAX_SERVER_LINE MAX_DOMAIN_SIZE + (SERVER_KEY_SIZE * 2) + 3
-/* List based on Mozilla's recommended configurations for modern browsers */
-#define TLS_CIPHER_SUITE_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
-
struct Nameservers {
int lines;
char names[MAX_SERVERS][MAX_DOMAIN_SIZE];
@@ -56,8 +53,8 @@ static struct thread_data {
char id_bin[TOX_ADDRESS_SIZE];
char addr[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
- bool busy;
bool disabled;
+ volatile bool busy;
} t_data;
static struct lookup_thread {
@@ -189,40 +186,17 @@ static bool get_domain_match(char *pubkey, char *out_domain, size_t out_domain_s
return false;
}
-#define MAX_RECV_LOOKUP_DATA_SIZE 1024
-
-/* Holds raw data received from name server */
-struct Recv_Data {
- char data[MAX_RECV_LOOKUP_DATA_SIZE];
- size_t size;
-};
-
-size_t write_lookup_data(void *data, size_t size, size_t nmemb, void *user_pointer)
-{
- struct Recv_Data *recv_data = (struct Recv_Data *) user_pointer;
- size_t real_size = size * nmemb;
-
- if (real_size >= MAX_RECV_LOOKUP_DATA_SIZE)
- return 0;
-
- memcpy(&recv_data->data, data, real_size);
- recv_data->size = real_size;
- recv_data->data[real_size] = '\0';
-
- return real_size;
-}
-
/* Converts Tox ID string contained in recv_data to binary format and puts it in thread's ID buffer.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
#define ID_PREFIX "\"tox_id\": \""
-static int process_response(struct Recv_Data *recv_data)
+static int process_response(struct Recv_Curl_Data *recv_data)
{
size_t prefix_size = strlen(ID_PREFIX);
- if (recv_data->size < TOX_ADDRESS_SIZE * 2 + prefix_size)
+ if (recv_data->length < TOX_ADDRESS_SIZE * 2 + prefix_size)
return -1;
const char *IDstart = strstr(recv_data->data, ID_PREFIX);
@@ -243,47 +217,6 @@ static int process_response(struct Recv_Data *recv_data)
return 0;
}
-/* Sets proxy info for given CURL handler.
- *
- * Returns 0 on success or if no proxy is set by the client.
- * Returns -1 on failure.
- */
-static int set_lookup_proxy(ToxWindow *self, CURL *c_handle, const char *proxy_address, uint16_t port, uint8_t proxy_type)
-{
- if (proxy_type == TOX_PROXY_TYPE_NONE)
- return 0;
-
- if (proxy_address == NULL || port == 0) {
- lookup_error(self, "Unknown proxy error");
- return -1;
- }
-
- int ret = curl_easy_setopt(c_handle, CURLOPT_PROXYPORT, (long) port);
-
- if (ret != CURLE_OK) {
- lookup_error(self, "Failed to set proxy port (libcurl error %d)", ret);
- return -1;
- }
-
- long int type = proxy_type == TOX_PROXY_TYPE_SOCKS5 ? CURLPROXY_SOCKS5_HOSTNAME : CURLPROXY_HTTP;
-
- ret = curl_easy_setopt(c_handle, CURLOPT_PROXYTYPE, type);
-
- if (ret != CURLE_OK) {
- lookup_error(self, "Failed to set proxy type (libcurl error %d)", ret);
- return -1;
- }
-
- ret = curl_easy_setopt(c_handle, CURLOPT_PROXY, proxy_address);
-
- if (ret != CURLE_OK) {
- lookup_error(self, "Failed to set proxy (libcurl error %d)", ret);
- return -1;
- }
-
- return 0;
-}
-
void *lookup_thread_func(void *data)
{
ToxWindow *self = t_data.self;
@@ -301,7 +234,7 @@ void *lookup_thread_func(void *data)
if (!get_domain_match(nameserver_key, real_domain, sizeof(real_domain), input_domain)) {
if (!strcasecmp(input_domain, "utox.org"))
- lookup_error(self, "utox.org uses deprecated DNS-based lookups and is no longer supported by Toxic");
+ lookup_error(self, "utox.org uses deprecated DNS-based lookups and is no longer supported by Toxic.");
else
lookup_error(self, "Name server domain not found.");
@@ -315,26 +248,38 @@ void *lookup_thread_func(void *data)
kill_lookup_thread();
}
- struct Recv_Data recv_data;
- memset(&recv_data, 0, sizeof(struct Recv_Data));
+ struct Recv_Curl_Data recv_data;
+
+ memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
char post_data[MAX_STR_SIZE];
+
snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name);
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json");
+
headers = curl_slist_append(headers, "charsets: utf-8");
curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers);
+
curl_easy_setopt(c_handle, CURLOPT_URL, real_domain);
- curl_easy_setopt(c_handle, CURLOPT_WRITEFUNCTION, write_lookup_data);
+
+ curl_easy_setopt(c_handle, CURLOPT_WRITEFUNCTION, curl_cb_write_data);
+
curl_easy_setopt(c_handle, CURLOPT_WRITEDATA, &recv_data);
+
curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
+
curl_easy_setopt(c_handle, CURLOPT_POSTFIELDS, post_data);
- if (set_lookup_proxy(self, c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type) == -1)
+ int proxy_ret = set_curl_proxy(c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type);
+
+ if (proxy_ret != 0) {
+ lookup_error(self, "Failed to set proxy (error %d)\n");
goto on_exit;
+ }
int ret = curl_easy_setopt(c_handle, CURLOPT_USE_SSL, CURLUSESSL_ALL);
@@ -437,9 +382,9 @@ void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr,
* Returns -2 if the nameserver list cannot be found.
* Returns -3 if the nameserver list does not contain any valid entries.
*/
-int name_lookup_init(void)
+int name_lookup_init(int curl_init_status)
{
- if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
+ if (curl_init_status != 0) {
t_data.disabled = true;
return -1;
}
@@ -454,8 +399,3 @@ int name_lookup_init(void)
return 0;
}
-
-void name_lookup_cleanup(void)
-{
- curl_global_cleanup();
-}
diff --git a/src/name_lookup.h b/src/name_lookup.h
index c1419d8..e9b8ed4 100644
--- a/src/name_lookup.h
+++ b/src/name_lookup.h
@@ -29,8 +29,7 @@
* Returns 0 on success.
* Returns -1 on failure.
*/
-int name_lookup_init(void);
-void name_lookup_cleanup(void);
+int name_lookup_init(int curl_init_status);
int name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message);
diff --git a/src/notify.c b/src/notify.c
index 093ad95..eaed79e 100644
--- a/src/notify.c
+++ b/src/notify.c
@@ -38,24 +38,24 @@
#include "xtra.h"
#if defined(AUDIO) || defined(SOUND_NOTIFY)
- #ifdef __APPLE__
- #include
- #include
- #else
- #include
- #include
- /* compatibility with older versions of OpenAL */
- #ifndef ALC_ALL_DEVICES_SPECIFIER
- #include
- #endif
- #endif
- #ifdef SOUND_NOTIFY
- #include /* freealut packet */
- #endif
+#ifdef __APPLE__
+#include
+#include
+#else
+#include
+#include
+/* compatibility with older versions of OpenAL */
+#ifndef ALC_ALL_DEVICES_SPECIFIER
+#include
+#endif
+#endif
+#ifdef SOUND_NOTIFY
+#include /* freealut packet */
+#endif
#endif /* AUDIO */
#ifdef BOX_NOTIFY
- #include
+#include
#endif
#define MAX_BOX_MSG_LEN 127
@@ -75,7 +75,7 @@ struct Control {
#ifdef SOUND_NOTIFY
uint32_t device_idx; /* index of output device */
- char* sounds[SOUNDS_SIZE];
+ char *sounds[SOUNDS_SIZE];
#endif /* SOUND_NOTIFY */
} Control = {0};
@@ -88,7 +88,7 @@ struct _ActiveNotifications {
bool active;
int *id_indicator;
#ifdef BOX_NOTIFY
- NotifyNotification* box;
+ NotifyNotification *box;
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
char title[64];
size_t size;
@@ -188,15 +188,17 @@ void graceful_clear()
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].active) {
- #ifdef BOX_NOTIFY
+#ifdef BOX_NOTIFY
+
if (actives[i].box) {
- GError* ignore;
+ GError *ignore;
notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL;
}
- #endif
- if(actives[i].id_indicator)
+#endif
+
+ if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */
if ( actives[i].looping ) {
@@ -221,11 +223,11 @@ void graceful_clear()
control_unlock();
}
-void* do_playing(void* _p)
+void *do_playing(void *_p)
{
(void)_p;
- while(true) {
+ while (true) {
control_lock();
if (!Control.poll_active) {
@@ -240,59 +242,67 @@ void* do_playing(void* _p)
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].looping) has_looping = true;
+
test_active_notify = actives[i].active && !actives[i].looping;
- #ifdef BOX_NOTIFY
- test_active_notify = test_active_notify && !actives[i].box;
- #endif
+#ifdef BOX_NOTIFY
+ test_active_notify = test_active_notify && !actives[i].box;
+#endif
+
if (test_active_notify) {
- if(actives[i].id_indicator)
+ if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */
if (!is_playing(actives[i].source)) {
- /* Close */
+ /* Close */
alSourceStop(actives[i].source);
alDeleteSources(1, &actives[i].source);
alDeleteBuffers(1, &actives[i].buffer);
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
}
}
- #ifdef BOX_NOTIFY
- else if (actives[i].box && time(NULL) >= actives[i].n_timeout)
- {
- GError* ignore;
+
+#ifdef BOX_NOTIFY
+ else if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
+ GError *ignore;
notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL;
- if(actives[i].id_indicator)
+
+ if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */
if (!actives[i].looping && !is_playing(actives[i].source)) {
- /* stop source if not looping or playing, just terminate box */
+ /* stop source if not looping or playing, just terminate box */
alSourceStop(actives[i].source);
alDeleteSources(1, &actives[i].source);
alDeleteBuffers(1, &actives[i].buffer);
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
}
}
- #endif
+
+#endif
}
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
if (device_opened && !has_looping &&
- (time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
+ (time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
m_close_device();
}
+
has_looping = false;
control_unlock();
usleep(10000);
}
+
pthread_exit(NULL);
}
int play_source(uint32_t source, uint32_t buffer, bool looping)
{
int i = 0;
+
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
+
if ( i == ACTIVE_NOTIFS_MAX ) {
return -1; /* Full */
}
@@ -308,11 +318,11 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
}
#elif BOX_NOTIFY
-void* do_playing(void* _p)
+void *do_playing(void *_p)
{
(void)_p;
- while(true) {
+ while (true) {
control_lock();
if (!Control.poll_active) {
@@ -323,20 +333,22 @@ void* do_playing(void* _p)
int i;
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
- if (actives[i].box && time(NULL) >= actives[i].n_timeout)
- {
- GError* ignore;
+ if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
+ GError *ignore;
notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL;
- if(actives[i].id_indicator)
+
+ if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
}
}
+
control_unlock();
usleep(10000);
}
+
pthread_exit(NULL);
}
@@ -347,7 +359,7 @@ void graceful_clear()
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].box) {
- GError* ignore;
+ GError *ignore;
notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL;
}
@@ -378,6 +390,7 @@ int init_notify(int login_cooldown, int notification_timeout)
#endif /* SOUND_NOTIFY */
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
+
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
return -1;
@@ -419,7 +432,9 @@ void terminate_notify()
#ifdef SOUND_NOTIFY
int i = 0;
+
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
+
alutExit();
#endif /* SOUND_NOTIFY */
@@ -429,7 +444,7 @@ void terminate_notify()
}
#ifdef SOUND_NOTIFY
-int set_sound(Notification sound, const char* value)
+int set_sound(Notification sound, const char *value)
{
if (sound == silent) return 0;
@@ -457,10 +472,11 @@ int play_sound_internal(Notification what, bool loop)
alSourcei(source, AL_LOOPING, loop);
int rc = play_source(source, buffer, loop);
+
if (rc < 0) {
alSourceStop(source);
alDeleteSources(1, &source);
- alDeleteBuffers(1,&buffer);
+ alDeleteBuffers(1, &buffer);
return -1;
}
@@ -472,7 +488,8 @@ int play_notify_sound(Notification notif, uint64_t flags)
int rc = -1;
if (flags & NT_BEEP) beep();
- else if (notif != silent) {
+
+ if (notif != silent) {
if ( !Control.poll_active || !Control.sounds[notif] )
return -1;
@@ -487,17 +504,21 @@ void stop_sound(int id)
{
if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active ) {
#ifdef BOX_NOTIFY
+
if (actives[id].box) {
- GError* ignore;
+ GError *ignore;
notify_notification_close(actives[id].box, &ignore);
}
+
#endif
+
if (actives[id].id_indicator)
*actives[id].id_indicator = -1;
+
// alSourcei(actives[id].source, AL_LOOPING, false);
alSourceStop(actives[id].source);
alDeleteSources(1, &actives[id].source);
- alDeleteBuffers(1,&actives[id].buffer);
+ alDeleteBuffers(1, &actives[id].buffer);
memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
}
}
@@ -508,6 +529,7 @@ static int m_play_sound(Notification notif, uint64_t flags)
#ifdef SOUND_NOTIFY
return play_notify_sound(notif, flags);
#else
+
if (notif != silent)
beep();
@@ -516,12 +538,12 @@ static int m_play_sound(Notification notif, uint64_t flags)
}
#ifdef BOX_NOTIFY
-void m_notify_action(NotifyNotification *box, char *action, void* data)
+void m_notify_action(NotifyNotification *box, char *action, void *data)
{
}
#endif
-int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator)
+int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator)
{
tab_notify(self, flags);
@@ -540,6 +562,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
if (id == -1) {
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++);
+
if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock();
return -1; /* Full */
@@ -558,7 +581,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
return id;
}
-int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
+int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id)
{
tab_notify(self, flags);
@@ -566,6 +589,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
return -1;
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
+
#ifdef SOUND_NOTIFY
control_lock();
@@ -578,7 +602,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
alSourceStop(actives[id].source);
alDeleteSources(1, &actives[id].source);
- alDeleteBuffers(1,&actives[id].buffer);
+ alDeleteBuffers(1, &actives[id].buffer);
alGenSources(1, &actives[id].source);
alGenBuffers(1, &actives[id].buffer);
@@ -592,6 +616,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
return id;
#else
+
if (notif != silent)
beep();
@@ -599,7 +624,8 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
#endif /* SOUND_NOTIFY */
}
-int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...)
+int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator, const char *title,
+ const char *format, ...)
{
if (notifications_are_disabled(flags)) {
tab_notify(self, flags);
@@ -613,9 +639,11 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
control_lock();
#ifdef SOUND_NOTIFY
+
if (id == -1) { /* Could not play */
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
+
if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock();
return -1; /* Full */
@@ -623,17 +651,23 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
actives[id].active = 1;
actives[id].id_indicator = id_indicator;
+
if (id_indicator) *id_indicator = id;
}
+
#else
+
if (id == -1)
return -1;
+
#endif /* SOUND_NOTIFY */
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
+
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
- va_list __ARGS__; va_start (__ARGS__, format);
+ va_list __ARGS__;
+ va_start (__ARGS__, format);
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__);
@@ -656,7 +690,7 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
#endif /* BOX_NOTIFY */
}
-int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...)
+int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, const char *format, ...)
{
if (notifications_are_disabled(flags)) {
tab_notify(self, flags);
@@ -675,7 +709,8 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
return -1;
}
- va_list __ARGS__; va_start (__ARGS__, format);
+ va_list __ARGS__;
+ va_start (__ARGS__, format);
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__);
@@ -688,7 +723,8 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
char formated[128 * 129] = {'\0'};
int i = 0;
- for (; i 23) strcpy(actives[id].title + 20, "...");
- va_list __ARGS__; va_start (__ARGS__, format);
+ va_list __ARGS__;
+ va_start (__ARGS__, format);
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__);
@@ -756,7 +796,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
#endif
}
-int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...)
+int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...)
{
tab_notify(self, flags);
@@ -772,7 +812,8 @@ int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* form
}
- va_list __ARGS__; va_start (__ARGS__, format);
+ va_list __ARGS__;
+ va_start (__ARGS__, format);
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__);
@@ -785,7 +826,8 @@ int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* form
char formated[128 * 129] = {'\0'};
int i = 0;
- for (; i
#include "windows.h"
-typedef enum _Notification
-{
+typedef enum _Notification {
silent = -1,
notif_error,
self_log_in,
@@ -63,18 +62,19 @@ typedef enum _Flags {
int init_notify(int login_cooldown, int notification_timeout);
void terminate_notify();
-int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator);
-int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id);
+int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator);
+int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id);
void stop_sound(int id);
-int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
-int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...);
-int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
-int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...);
+int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator, const char *title,
+ const char *format, ...);
+int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, const char *format, ...);
+int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const char *title, const char *format, ...);
+int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...);
#ifdef SOUND_NOTIFY
-int set_sound(Notification sound, const char* value);
+int set_sound(Notification sound, const char *value);
#endif /* SOUND_NOTIFY */
#endif /* NOTIFY_H */
diff --git a/src/osx_video.h b/src/osx_video.h
index fce78fe..413ba32 100644
--- a/src/osx_video.h
+++ b/src/osx_video.h
@@ -31,13 +31,16 @@
#endif /* __OBJC__ */
#define RELEASE_CHK(func, obj) if ((obj))\
- func((obj));
+ func((obj));
void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height);
#ifdef __OBJC__
-@interface OSXVideo : NSObject
-- (instancetype)initWithDeviceNames:(char **)device_names AmtDevices:(int *)size;
+@interface OSXVideo :
+NSObject
+- (instancetype)initWithDeviceNames:
+(char **)device_names AmtDevices:
+(int *)size;
@end
#endif /* __OBJC__ */
diff --git a/src/osx_video.m b/src/osx_video.m
index befbc4c..b745675 100644
--- a/src/osx_video.m
+++ b/src/osx_video.m
@@ -44,19 +44,19 @@
static uint8_t rgb_to_y(int r, int g, int b)
{
int y = ((9798 * r + 19235 * g + 3736 * b) >> 15);
- return y>255? 255 : y<0 ? 0 : y;
+ return y > 255 ? 255 : y < 0 ? 0 : y;
}
static uint8_t rgb_to_u(int r, int g, int b)
{
int u = ((-5538 * r + -10846 * g + 16351 * b) >> 15) + 128;
- return u>255? 255 : u<0 ? 0 : u;
+ return u > 255 ? 255 : u < 0 ? 0 : u;
}
static uint8_t rgb_to_v(int r, int g, int b)
{
int v = ((16351 * r + -13697 * g + -2664 * b) >> 15) + 128;
- return v>255? 255 : v<0 ? 0 : v;
+ return v > 255 ? 255 : v < 0 ? 0 : v;
}
void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height)
@@ -65,9 +65,10 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
uint8_t *p;
uint8_t r, g, b;
- for(y = 0; y != height; y += 2) {
+ for (y = 0; y != height; y += 2) {
p = rgb;
- for(x = 0; x != width; x++) {
+
+ for (x = 0; x != width; x++) {
b = *rgb++;
g = *rgb++;
r = *rgb++;
@@ -76,7 +77,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
*plane_y++ = rgb_to_y(r, g, b);
}
- for(x = 0; x != width / 2; x++) {
+ for (x = 0; x != width / 2; x++) {
b = *rgb++;
g = *rgb++;
r = *rgb++;
@@ -91,9 +92,12 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
*plane_y++ = rgb_to_y(r, g, b);
- b = ((int)b + (int)*(rgb - 8) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
- g = ((int)g + (int)*(rgb - 7) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
- r = ((int)r + (int)*(rgb - 6) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
+ b = ((int)b + (int) * (rgb - 8) + (int) * p + (int) * (p + 4) + 2) / 4;
+ p++;
+ g = ((int)g + (int) * (rgb - 7) + (int) * p + (int) * (p + 4) + 2) / 4;
+ p++;
+ r = ((int)r + (int) * (rgb - 6) + (int) * p + (int) * (p + 4) + 2) / 4;
+ p++;
p++;
*plane_u++ = rgb_to_u(r, g, b);
@@ -122,22 +126,26 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
BOOL _shouldMangleDimensions;
}
-- (instancetype)initWithDeviceNames: (char **)device_names AmtDevices: (int *)size {
+- (instancetype)initWithDeviceNames:
+(char **)device_names AmtDevices:
+(int *)size {
_session = [[AVCaptureSession alloc] init];
- NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
+NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
int i;
+
for (i = 0; i < [devices count]; ++i) {
- AVCaptureDevice *device = [devices objectAtIndex:i];
+AVCaptureDevice *device = [devices objectAtIndex: i];
char *video_input_name;
NSString *localizedName = [device localizedName];
- video_input_name = (char*)malloc(strlen([localizedName cStringUsingEncoding:NSUTF8StringEncoding]) + 1);
- strcpy(video_input_name, (char*)[localizedName cStringUsingEncoding:NSUTF8StringEncoding]);
+video_input_name = (char *)malloc(strlen([localizedName cStringUsingEncoding: NSUTF8StringEncoding]) + 1);
+strcpy(video_input_name, (char *)[localizedName cStringUsingEncoding: NSUTF8StringEncoding]);
device_names[i] = video_input_name;
}
if ( i <= 0 )
return nil;
+
*size = i;
return self;
@@ -151,14 +159,17 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
[super dealloc];
}
-- (int)openVideoDeviceIndex: (uint32_t)device_idx Width: (uint16_t *)width Height: (uint16_t *)height {
+- (int)openVideoDeviceIndex:
+(uint32_t)device_idx Width:
+(uint16_t *)width Height:
+(uint16_t *)height {
pthread_mutex_init(&_frameLock, NULL);
pthread_mutex_lock(&_frameLock);
_processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL);
- NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
- AVCaptureDevice *device = [devices objectAtIndex:device_idx];
+NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
+AVCaptureDevice *device = [devices objectAtIndex: device_idx];
NSError *error = NULL;
- AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
+AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
if ( error != NULL ) {
[input release];
@@ -166,7 +177,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
}
[_session beginConfiguration];
- [_session addInput:input];
+[_session addInput: input];
//_session.sessionPreset = AVCaptureSessionPreset640x480;
//*width = 640;
//*height = 480;
@@ -176,8 +187,9 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
[device release];
/* Obtain device resolution */
- AVCaptureInputPort *port = [input.ports objectAtIndex:0];
+ AVCaptureInputPort *port = [input.ports objectAtIndex: 0];
CMFormatDescriptionRef format_description = port.formatDescription;
+
if ( format_description ) {
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
*width = dimensions.width;
@@ -188,36 +200,44 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
}
_linkerVideo = [[AVCaptureVideoDataOutput alloc] init];
- [_linkerVideo setSampleBufferDelegate:self queue:_processingQueue];
+[_linkerVideo setSampleBufferDelegate: self queue: _processingQueue];
+
// TODO possibly get a better pixel format
if (_shouldMangleDimensions) {
- [_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
- (id)kCVPixelBufferWidthKey: @640,
- (id)kCVPixelBufferHeightKey: @480}];
+[_linkerVideo setVideoSettings: @ {
+(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
+(id)kCVPixelBufferWidthKey: @640,
+(id)kCVPixelBufferHeightKey: @480
+ }];
} else {
- [_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
+[_linkerVideo setVideoSettings: @{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
}
- [_session addOutput:_linkerVideo];
+[_session addOutput: _linkerVideo];
[_session startRunning];
pthread_mutex_unlock(&_frameLock);
return 0;
}
-- (void)closeVideoDeviceIndex: (uint32_t)device_idx {
- NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
- AVCaptureDevice *device = [devices objectAtIndex:device_idx];
+- (void)closeVideoDeviceIndex:
+(uint32_t)device_idx {
+NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
+AVCaptureDevice *device = [devices objectAtIndex: device_idx];
NSError *error = NULL;
- AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
+AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
[_session stopRunning];
- [_session removeOutput:_linkerVideo];
- [_session removeInput:input];
+[_session removeOutput: _linkerVideo];
+[_session removeInput: input];
[_linkerVideo release];
}
-- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
+- (void)captureOutput:
+(AVCaptureOutput *)captureOutput didOutputSampleBuffer:
+(CMSampleBufferRef)sampleBuffer fromConnection:
+(AVCaptureConnection *)connection {
pthread_mutex_lock(&_frameLock);
CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer);
+
if (!img) {
NSLog(@"Toxic WARNING: Bad sampleBuffer from AVfoundation!");
} else {
@@ -231,7 +251,12 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
pthread_mutex_unlock(&_frameLock);
}
-- (int)getVideoFrameY: (uint8_t *)y U: (uint8_t *)u V: (uint8_t *)v Width: (uint16_t *)width Height: (uint16_t *)height {
+- (int)getVideoFrameY:
+(uint8_t *)y U:
+(uint8_t *)u V:
+(uint8_t *)v Width:
+(uint16_t *)width Height:
+(uint16_t *)height {
if (!_currentFrame) {
return -1;
}
@@ -240,6 +265,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
CFRetain(_currentFrame);
CFTypeID imageType = CFGetTypeID(_currentFrame);
+
if (imageType == CVPixelBufferGetTypeID()) {
// TODO maybe handle other formats
bgrxtoyuv420(y, u, v, CVPixelBufferGetBaseAddress(_currentFrame), *width, *height);
@@ -263,11 +289,11 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
/*
* C-interface for OSXVideo
*/
-static OSXVideo* _OSXVideo = nil;
+static OSXVideo *_OSXVideo = nil;
int osx_video_init(char **device_names, int *size)
{
- _OSXVideo = [[OSXVideo alloc] initWithDeviceNames: device_names AmtDevices: size];
+_OSXVideo = [[OSXVideo alloc] initWithDeviceNames: device_names AmtDevices: size];
if ( _OSXVideo == nil )
return -1;
@@ -286,12 +312,12 @@ int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height)
if ( _OSXVideo == nil )
return -1;
- return [_OSXVideo openVideoDeviceIndex: selection Width: width Height: height];
+return [_OSXVideo openVideoDeviceIndex: selection Width: width Height: height];
}
void osx_video_close_device(uint32_t device_idx)
{
- [_OSXVideo closeVideoDeviceIndex: device_idx];
+[_OSXVideo closeVideoDeviceIndex: device_idx];
}
int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, uint16_t *height)
@@ -299,7 +325,7 @@ int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, u
if ( _OSXVideo == nil )
return -1;
- return [_OSXVideo getVideoFrameY: y U: u V: v Width: width Height: height];
+return [_OSXVideo getVideoFrameY: y U: u V: v Width: width Height: height];
}
/*
* End of C-interface for OSXVideo
diff --git a/src/prompt.c b/src/prompt.c
index 77e48d1..d485a3f 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -215,11 +215,11 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
diff = dir_match(self, m, ctx->line, L"/avatar");
- else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0){
+ else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
const char status_cmd_list[3][8] = {
- {"online"},
- {"away"},
- {"busy"},
+ {"online"},
+ {"away"},
+ {"busy"},
};
diff = complete_line(self, status_cmd_list, 3, 8);
} else
@@ -239,8 +239,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else if (key == '\r') {
rm_trailing_spaces_buf(ctx);
- if (!wstring_is_empty(ctx->line))
- {
+ if (!wstring_is_empty(ctx->line)) {
add_line_to_hist(ctx);
wstrsubst(ctx->line, L'¶', L'\n');
@@ -302,10 +301,12 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
status_text = "Online";
colour = GREEN;
break;
+
case TOX_USER_STATUS_AWAY:
status_text = "Away";
colour = YELLOW;
break;
+
case TOX_USER_STATUS_BUSY:
status_text = "Busy";
colour = RED;
@@ -336,7 +337,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_lock(&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m);
- tox_self_get_status_message (m, (uint8_t*) statusmsg);
+ tox_self_get_status_message (m, (uint8_t *) statusmsg);
statusmsg[slen] = '\0';
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
@@ -370,7 +371,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x);
- wrefresh(self->window);
+ wnoutrefresh(self->window);
if (self->help->active)
help_onDraw(self);
@@ -405,8 +406,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
else
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
"Toxic", "%s has come online", nick );
- }
- else if (connection_status == TOX_CONNECTION_NONE) {
+ } else if (connection_status == TOX_CONNECTION_NONE) {
msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true);
diff --git a/src/settings.c b/src/settings.c
index 47b1af8..f6871f3 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -32,41 +32,46 @@
#include "misc_tools.h"
#ifdef AUDIO
- #include "audio_device.h"
+#include "audio_device.h"
#endif /* AUDIO */
#include "settings.h"
#include "line_info.h"
#ifndef PACKAGE_DATADIR
- #define PACKAGE_DATADIR "."
+#define PACKAGE_DATADIR "."
#endif
#define NO_SOUND "silent"
static struct ui_strings {
- const char* self;
- const char* timestamps;
- const char* time_format;
- const char* timestamp_format;
- const char* log_timestamp_format;
- const char* alerts;
- const char* native_colors;
- const char* autolog;
- const char* history_size;
- const char* show_typing_self;
- const char* show_typing_other;
- const char* show_welcome_msg;
- const char* show_connection_msg;
+ const char *self;
+ const char *timestamps;
+ const char *time_format;
+ const char *timestamp_format;
+ const char *log_timestamp_format;
+ const char *alerts;
+ const char *bell_on_message;
+ const char *bell_on_filetrans;
+ const char *bell_on_filetrans_accept;
+ const char *bell_on_invite;
+ const char *native_colors;
+ const char *autolog;
+ const char *history_size;
+ const char *show_typing_self;
+ const char *show_typing_other;
+ const char *show_welcome_msg;
+ const char *show_connection_msg;
+ const char *nodeslist_update_freq;
- const char* line_join;
- const char* line_quit;
- const char* line_alert;
- const char* line_normal;
- const char* line_special;
+ const char *line_join;
+ const char *line_quit;
+ const char *line_alert;
+ const char *line_normal;
+ const char *line_special;
- const char* mplex_away;
- const char* mplex_away_note;
+ const char *mplex_away;
+ const char *mplex_away_note;
} ui_strings = {
"ui",
"timestamps",
@@ -74,6 +79,10 @@ static struct ui_strings {
"timestamp_format",
"log_timestamp_format",
"alerts",
+ "bell_on_message",
+ "bell_on_filetrans",
+ "bell_on_filetrans_accept",
+ "bell_on_invite",
"native_colors",
"autolog",
"history_size",
@@ -81,6 +90,7 @@ static struct ui_strings {
"show_typing_other",
"show_welcome_msg",
"show_connection_msg",
+ "nodeslist_update_freq",
"line_join",
"line_quit",
"line_alert",
@@ -90,7 +100,7 @@ static struct ui_strings {
"mplex_away_note",
};
-static void ui_defaults(struct user_settings* settings)
+static void ui_defaults(struct user_settings *settings)
{
settings->timestamps = TIMESTAMPS_ON;
snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT);
@@ -98,12 +108,17 @@ static void ui_defaults(struct user_settings* settings)
settings->autolog = AUTOLOG_OFF;
settings->alerts = ALERTS_ENABLED;
+ settings->bell_on_message = 0;
+ settings->bell_on_filetrans = 0;
+ settings->bell_on_filetrans_accept = 0;
+ settings->bell_on_invite = 0;
settings->colour_theme = DFLT_COLS;
settings->history_size = 700;
settings->show_typing_self = SHOW_TYPING_ON;
settings->show_typing_other = SHOW_TYPING_ON;
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
settings->show_connection_msg = SHOW_CONNECTION_MSG_ON;
+ settings->nodeslist_update_freq = 7;
snprintf(settings->line_join, LINE_HINT_MAX + 1, "%s", LINE_JOIN);
snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT);
@@ -119,18 +134,18 @@ static void ui_defaults(struct user_settings* settings)
}
static const struct keys_strings {
- const char* self;
- const char* next_tab;
- const char* prev_tab;
- const char* scroll_line_up;
- const char* scroll_line_down;
- const char* half_page_up;
- const char* half_page_down;
- const char* page_bottom;
- const char* peer_list_up;
- const char* peer_list_down;
- const char* toggle_peerlist;
- const char* toggle_pastemode;
+ const char *self;
+ const char *next_tab;
+ const char *prev_tab;
+ const char *scroll_line_up;
+ const char *scroll_line_down;
+ const char *half_page_up;
+ const char *half_page_down;
+ const char *page_bottom;
+ const char *peer_list_up;
+ const char *peer_list_down;
+ const char *toggle_peerlist;
+ const char *toggle_pastemode;
} key_strings = {
"keys",
"next_tab",
@@ -147,7 +162,7 @@ static const struct keys_strings {
};
/* defines from toxic.h */
-static void key_defaults(struct user_settings* settings)
+static void key_defaults(struct user_settings *settings)
{
settings->key_next_tab = T_KEY_NEXT;
settings->key_prev_tab = T_KEY_PREV;
@@ -163,11 +178,11 @@ static void key_defaults(struct user_settings* settings)
}
static const struct tox_strings {
- const char* self;
- const char* download_path;
- const char* chatlogs_path;
- const char* avatar_path;
- const char* password_eval;
+ const char *self;
+ const char *download_path;
+ const char *chatlogs_path;
+ const char *avatar_path;
+ const char *password_eval;
} tox_strings = {
"tox",
"download_path",
@@ -176,7 +191,7 @@ static const struct tox_strings {
"password_eval",
};
-static void tox_defaults(struct user_settings* settings)
+static void tox_defaults(struct user_settings *settings)
{
strcpy(settings->download_path, "");
strcpy(settings->chatlogs_path, "");
@@ -186,10 +201,10 @@ static void tox_defaults(struct user_settings* settings)
#ifdef AUDIO
static const struct audio_strings {
- const char* self;
- const char* input_device;
- const char* output_device;
- const char* VAD_treshold;
+ const char *self;
+ const char *input_device;
+ const char *output_device;
+ const char *VAD_treshold;
} audio_strings = {
"audio",
"input_device",
@@ -197,7 +212,7 @@ static const struct audio_strings {
"VAD_treshold",
};
-static void audio_defaults(struct user_settings* settings)
+static void audio_defaults(struct user_settings *settings)
{
settings->audio_in_dev = 0;
settings->audio_out_dev = 0;
@@ -207,17 +222,17 @@ static void audio_defaults(struct user_settings* settings)
#ifdef SOUND_NOTIFY
static const struct sound_strings {
- const char* self;
- const char* notif_error;
- const char* self_log_in;
- const char* self_log_out;
- const char* user_log_in;
- const char* user_log_out;
- const char* call_incoming;
- const char* call_outgoing;
- const char* generic_message;
- const char* transfer_pending;
- const char* transfer_completed;
+ const char *self;
+ const char *notif_error;
+ const char *self_log_in;
+ const char *self_log_out;
+ const char *user_log_in;
+ const char *user_log_out;
+ const char *call_incoming;
+ const char *call_outgoing;
+ const char *generic_message;
+ const char *transfer_pending;
+ const char *transfer_completed;
} sound_strings = {
"sounds",
"notif_error",
@@ -233,11 +248,12 @@ static const struct sound_strings {
};
#endif
-static int key_parse(const char **bind) {
+static int key_parse(const char **bind)
+{
int len = strlen(*bind);
if (len > 5) {
- if(strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') /* ctrl+m cannot be used */
+ if (strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') /* ctrl+m cannot be used */
return toupper(bind[0][5]) - 'A' + 1;
}
@@ -250,7 +266,8 @@ static int key_parse(const char **bind) {
return -1;
}
-static void set_key_binding(int *key, const char **bind) {
+static void set_key_binding(int *key, const char **bind)
+{
int code = key_parse(bind);
if (code != -1) {
@@ -306,6 +323,7 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
int time = 24;
+
if ( config_setting_lookup_int(setting, ui_strings.time_format, &time) ) {
if (time == 12) {
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p");
@@ -322,26 +340,49 @@ int settings_load(struct user_settings *s, const char *patharg)
}
config_setting_lookup_bool(setting, ui_strings.alerts, &s->alerts);
+
+ if (config_setting_lookup_bool(setting, ui_strings.bell_on_message, &s->bell_on_message)) {
+ s->bell_on_message = s->bell_on_message ? NT_BEEP : 0;
+ }
+
+ if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans, &s->bell_on_filetrans)) {
+ s->bell_on_filetrans = s->bell_on_filetrans ? NT_BEEP : 0;
+ }
+
+ if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans_accept, &s->bell_on_filetrans_accept)) {
+ s->bell_on_filetrans_accept = s->bell_on_filetrans_accept ? NT_BEEP : 0;
+ }
+
+ if (config_setting_lookup_bool(setting, ui_strings.bell_on_invite, &s->bell_on_invite)) {
+ s->bell_on_invite = s->bell_on_invite ? NT_BEEP : 0;
+ }
+
config_setting_lookup_bool(setting, ui_strings.autolog, &s->autolog);
config_setting_lookup_bool(setting, ui_strings.native_colors, &s->colour_theme);
- config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
config_setting_lookup_bool(setting, ui_strings.show_typing_self, &s->show_typing_self);
config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other);
config_setting_lookup_bool(setting, ui_strings.show_welcome_msg, &s->show_welcome_msg);
config_setting_lookup_bool(setting, ui_strings.show_connection_msg, &s->show_connection_msg);
+ config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
+ config_setting_lookup_int(setting, ui_strings.nodeslist_update_freq, &s->nodeslist_update_freq);
+
if ( config_setting_lookup_string(setting, ui_strings.line_join, &str) ) {
snprintf(s->line_join, sizeof(s->line_join), "%s", str);
}
+
if ( config_setting_lookup_string(setting, ui_strings.line_quit, &str) ) {
snprintf(s->line_quit, sizeof(s->line_quit), "%s", str);
}
+
if ( config_setting_lookup_string(setting, ui_strings.line_alert, &str) ) {
snprintf(s->line_alert, sizeof(s->line_alert), "%s", str);
}
+
if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) {
snprintf(s->line_normal, sizeof(s->line_normal), "%s", str);
}
+
if ( config_setting_lookup_string(setting, ui_strings.line_special, &str) ) {
snprintf(s->line_special, sizeof(s->line_special), "%s", str);
}
@@ -395,32 +436,44 @@ int settings_load(struct user_settings *s, const char *patharg)
/* keys */
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
- const char* tmp = NULL;
+ const char *tmp = NULL;
+
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp))
set_key_binding(&s->key_next_tab, &tmp);
+
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp))
set_key_binding(&s->key_prev_tab, &tmp);
+
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp))
set_key_binding(&s->key_scroll_line_up, &tmp);
+
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp))
set_key_binding(&s->key_scroll_line_down, &tmp);
+
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp))
set_key_binding(&s->key_half_page_up, &tmp);
+
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp))
set_key_binding(&s->key_half_page_down, &tmp);
+
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp))
set_key_binding(&s->key_page_bottom, &tmp);
+
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp))
set_key_binding(&s->key_peer_list_up, &tmp);
+
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp))
set_key_binding(&s->key_peer_list_down, &tmp);
+
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp))
set_key_binding(&s->key_toggle_peerlist, &tmp);
+
if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp))
set_key_binding(&s->key_toggle_pastemode, &tmp);
}
#ifdef AUDIO
+
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev;
@@ -430,9 +483,11 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
}
+
#endif
#ifdef SOUND_NOTIFY
+
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
!set_sound(notif_error, str) ) {
@@ -481,8 +536,7 @@ int settings_load(struct user_settings *s, const char *patharg)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
}
- }
- else {
+ } else {
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
@@ -492,6 +546,7 @@ int settings_load(struct user_settings *s, const char *patharg)
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
}
+
#endif
config_destroy(cfg);
diff --git a/src/settings.h b/src/settings.h
index 9bc9353..32bb70f 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -37,6 +37,12 @@ struct user_settings {
int autolog; /* boolean */
int alerts; /* boolean */
+ /* boolean (is set to NT_BEEP or 0 after loading) */
+ int bell_on_message;
+ int bell_on_filetrans;
+ int bell_on_filetrans_accept;
+ int bell_on_invite;
+
int timestamps; /* boolean */
char timestamp_format[TIME_STR_SIZE];
char log_timestamp_format[TIME_STR_SIZE];
@@ -47,6 +53,7 @@ struct user_settings {
int show_typing_other; /* boolean */
int show_welcome_msg; /* boolean */
int show_connection_msg; /* boolean */
+ int nodeslist_update_freq; /* int (<= 0 to disable updates) */
char line_join[LINE_HINT_MAX + 1];
char line_quit[LINE_HINT_MAX + 1];
diff --git a/src/term_mplex.c b/src/term_mplex.c
index 35bf082..505586f 100644
--- a/src/term_mplex.c
+++ b/src/term_mplex.c
@@ -52,8 +52,7 @@ extern struct Winthread Winthread;
#define PATH_SEP_S "/"
#define PATH_SEP_C '/'
-typedef enum
-{
+typedef enum {
MPLEX_NONE,
MPLEX_SCREEN,
MPLEX_TMUX,
@@ -97,13 +96,14 @@ static char *read_into_dyn_buffer (FILE *stream)
char *dyn_buffer = NULL;
int dyn_buffer_size = 1; /* account for the \0 */
- while ((input_ptr = fgets (buffer, BUFFER_SIZE, stream)) != NULL)
- {
+ while ((input_ptr = fgets (buffer, BUFFER_SIZE, stream)) != NULL) {
int length = dyn_buffer_size + strlen (input_ptr);
+
if (dyn_buffer)
- dyn_buffer = (char*) realloc (dyn_buffer, length);
+ dyn_buffer = (char *) realloc (dyn_buffer, length);
else
- dyn_buffer = (char*) malloc (length);
+ dyn_buffer = (char *) malloc (length);
+
strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr);
dyn_buffer_size = length;
}
@@ -116,26 +116,29 @@ static char *extract_socket_path (const char *info)
const char *search_str = " Socket";
const char *pos = strstr (info, search_str);
char *end = NULL;
- char* path = NULL;
+ char *path = NULL;
if (!pos)
return NULL;
pos += strlen (search_str);
pos = strchr (pos, PATH_SEP_C);
+
if (!pos)
return NULL;
end = strchr (pos, '\n');
+
if (!end)
return NULL;
*end = '\0';
end = strrchr (pos, '.');
+
if (!end)
return NULL;
- path = (char*) malloc (end - pos + 1);
+ path = (char *) malloc (end - pos + 1);
*end = '\0';
return strcpy (path, pos);
}
@@ -147,14 +150,17 @@ static int detect_gnu_screen ()
char *dyn_buffer = NULL;
socket_name = getenv ("STY");
+
if (!socket_name)
goto nomplex;
session_info_stream = popen ("env LC_ALL=C screen -ls", "r");
+
if (!session_info_stream)
goto nomplex;
dyn_buffer = read_into_dyn_buffer (session_info_stream);
+
if (!dyn_buffer)
goto nomplex;
@@ -162,6 +168,7 @@ static int detect_gnu_screen ()
session_info_stream = NULL;
socket_path = extract_socket_path (dyn_buffer);
+
if (!socket_path)
goto nomplex;
@@ -181,23 +188,29 @@ static int detect_gnu_screen ()
return 1;
nomplex:
+
if (session_info_stream)
pclose (session_info_stream);
+
if (dyn_buffer)
free (dyn_buffer);
+
if (socket_path)
free(socket_path);
+
return 0;
}
static int detect_tmux ()
{
char *tmux_env = getenv ("TMUX"), *pos;
+
if (!tmux_env)
return 0;
/* find second separator */
pos = strrchr (tmux_env, ',');
+
if (!pos)
return 0;
@@ -230,6 +243,7 @@ static int gnu_screen_is_detached ()
return 0;
struct stat sb;
+
if (stat (mplex_data, &sb) != 0)
return 0;
@@ -257,10 +271,12 @@ static int tmux_is_detached ()
const int numstr_len = strlen (mplex_data);
session_info_stream = popen ("env LC_ALL=C tmux list-sessions", "r");
+
if (!session_info_stream)
goto fail;
dyn_buffer = read_into_dyn_buffer (session_info_stream);
+
if (!dyn_buffer)
goto fail;
@@ -268,7 +284,7 @@ static int tmux_is_detached ()
session_info_stream = NULL;
/* prepare search string, for finding the current session's entry */
- search_str = (char*) malloc (numstr_len + 4);
+ search_str = (char *) malloc (numstr_len + 4);
search_str[0] = '\n';
strcpy (search_str + 1, mplex_data);
strcat (search_str, ": ");
@@ -295,12 +311,16 @@ static int tmux_is_detached ()
return attached_pos == NULL || attached_pos > nl_pos;
fail:
+
if (session_info_stream)
pclose (session_info_stream);
+
if (dyn_buffer)
free (dyn_buffer);
+
if (search_str)
free (search_str);
+
return 0;
}
@@ -332,26 +352,21 @@ static void mplex_timer_handler (Tox *m)
current_status = tox_self_get_status (m);
pthread_mutex_unlock (&Winthread.lock);
- if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached)
- {
+ if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached) {
auto_away_active = false;
new_status = prev_status;
new_note = prev_note;
- }
- else
- if (current_status == TOX_USER_STATUS_NONE && detached)
- {
+ } else if (current_status == TOX_USER_STATUS_NONE && detached) {
auto_away_active = true;
prev_status = current_status;
new_status = TOX_USER_STATUS_AWAY;
pthread_mutex_lock (&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m);
- tox_self_get_status_message (m, (uint8_t*) prev_note);
+ tox_self_get_status_message (m, (uint8_t *) prev_note);
prev_note[slen] = '\0';
pthread_mutex_unlock (&Winthread.lock);
new_note = user_settings->mplex_away_note;
- }
- else
+ } else
return;
char argv[3][MAX_STR_SIZE];
diff --git a/src/toxic.c b/src/toxic.c
index 7a41305..46a877e 100644
--- a/src/toxic.c
+++ b/src/toxic.c
@@ -41,6 +41,7 @@
#include
#include
+#include
#include
#include
@@ -61,9 +62,10 @@
#include "execute.h"
#include "term_mplex.h"
#include "name_lookup.h"
+#include "bootstrap.h"
#ifdef X11
- #include "xtra.h"
+#include "xtra.h"
#endif
#ifdef AUDIO
@@ -75,7 +77,7 @@ ToxAV *av;
#endif /* AUDIO */
#ifndef PACKAGE_DATADIR
- #define PACKAGE_DATADIR "."
+#define PACKAGE_DATADIR "."
#endif
/* Export for use in Callbacks */
@@ -164,7 +166,7 @@ void exit_toxic_success(Tox *m)
free_global_data();
tox_kill(m);
endwin();
- name_lookup_cleanup();
+ curl_global_cleanup();
#ifdef X11
/* We have to terminate xtra last coz reasons
@@ -281,153 +283,6 @@ static void print_init_messages(ToxWindow *toxwin)
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
}
-#define MIN_NODE_LINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.chat = 8) */
-#define MAX_NODE_LINE 256 /* Approx max number of chars in a sever line (name + port + key) */
-#define MAXNODES 50
-#define NODELEN (MAX_NODE_LINE - TOX_PUBLIC_KEY_SIZE - 7)
-
-static struct toxNodes {
- int lines;
- char nodes[MAXNODES][NODELEN];
- uint16_t ports[MAXNODES];
- char keys[MAXNODES][TOX_PUBLIC_KEY_SIZE];
-} toxNodes;
-
-static int load_nodelist(const char *filename)
-{
- if (!filename)
- return 1;
-
- FILE *fp = fopen(filename, "r");
-
- if (fp == NULL)
- return 1;
-
- char line[MAX_NODE_LINE];
-
- while (fgets(line, sizeof(line), fp) && toxNodes.lines < MAXNODES) {
- size_t line_len = strlen(line);
-
- if (line_len >= MIN_NODE_LINE && line_len <= MAX_NODE_LINE) {
- const char *name = strtok(line, " ");
- const char *port_str = strtok(NULL, " ");
- const char *key_ascii = strtok(NULL, " ");
-
- if (name == NULL || port_str == NULL || key_ascii == NULL)
- continue;
-
- long int port = strtol(port_str, NULL, 10);
-
- if (port <= 0 || port > MAX_PORT_RANGE)
- continue;
-
- size_t key_len = strlen(key_ascii);
- size_t name_len = strlen(name);
-
- if (key_len < TOX_PUBLIC_KEY_SIZE * 2 || name_len >= NODELEN)
- continue;
-
- snprintf(toxNodes.nodes[toxNodes.lines], sizeof(toxNodes.nodes[toxNodes.lines]), "%s", name);
- toxNodes.nodes[toxNodes.lines][NODELEN - 1] = 0;
- toxNodes.ports[toxNodes.lines] = port;
-
- /* remove possible trailing newline from key string */
- char real_ascii_key[TOX_PUBLIC_KEY_SIZE * 2 + 1];
- memcpy(real_ascii_key, key_ascii, TOX_PUBLIC_KEY_SIZE * 2);
- key_len = TOX_PUBLIC_KEY_SIZE * 2;
- real_ascii_key[key_len] = '\0';
-
- if (hex_string_to_bin(real_ascii_key, key_len, toxNodes.keys[toxNodes.lines], TOX_PUBLIC_KEY_SIZE) == -1)
- continue;
-
- toxNodes.lines++;
- }
- }
-
- fclose(fp);
-
- if (toxNodes.lines < 1)
- return 1;
-
- return 0;
-}
-
-/* Bootstraps and adds as TCP relay.
- * Returns 0 if both actions are successful.
- * Returns -1 otherwise.
- */
-int init_connection_helper(Tox *m, int line)
-{
- TOX_ERR_BOOTSTRAP err;
- tox_bootstrap(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line], &err);
-
- if (err != TOX_ERR_BOOTSTRAP_OK) {
- fprintf(stderr, "Failed to bootstrap %s:%d\n", toxNodes.nodes[line], toxNodes.ports[line]);
- return -1;
- }
-
- tox_add_tcp_relay(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line], &err);
-
- if (err != TOX_ERR_BOOTSTRAP_OK) {
- fprintf(stderr, "Failed to add TCP relay %s:%d\n", toxNodes.nodes[line], toxNodes.ports[line]);
- return -1;
- }
-
- return 0;
-}
-
-/* Connects to a random DHT node listed in the DHTnodes file
- *
- * return codes:
- * 0: success
- * 1: failed to open node file
- * 2: no line of sufficient length in node file
- * 3: failed to resolve name to IP
- * 4: nodelist file contains no acceptable line
- */
-static bool srvlist_loaded = false;
-
-#define NUM_INIT_NODES 5
-
-int init_connection(Tox *m)
-{
- if (toxNodes.lines > 0) { /* already loaded nodelist */
- init_connection_helper(m, rand() % toxNodes.lines);
- return 0;
- }
-
- /* only once:
- * - load the nodelist
- * - connect to "everyone" inside
- */
- if (!srvlist_loaded) {
- srvlist_loaded = true;
- int res;
-
- if (!arg_opts.nodes_path[0])
- res = load_nodelist(PACKAGE_DATADIR "/DHTnodes");
- else
- res = load_nodelist(arg_opts.nodes_path);
-
- if (res != 0)
- return res;
-
- res = 3;
- int i;
- int n = MIN(NUM_INIT_NODES, toxNodes.lines);
-
- for (i = 0; i < n; ++i) {
- if (init_connection_helper(m, rand() % toxNodes.lines) == 0)
- res = 0;
- }
-
- return res;
- }
-
- /* empty nodelist file */
- return 4;
-}
-
static void load_groups(Tox *m)
{
size_t i;
@@ -477,8 +332,10 @@ static int password_prompt(char *buf, int size)
/* eat overflowed stdin and return error */
if (buf[--len] != '\n') {
int ch;
+
while ((ch = getchar()) != '\n' && ch > 0)
;
+
return 0;
}
@@ -495,6 +352,7 @@ static int password_eval(char *buf, int size)
/* Run password_eval command */
FILE *f = popen(user_settings->password_eval, "r");
+
if (f == NULL) {
fprintf(stderr, "Executing password_eval failed\n");
return 0;
@@ -502,6 +360,7 @@ static int password_eval(char *buf, int size)
/* Get output from command */
char *ret = fgets(buf, size, f);
+
if (ret == NULL) {
fprintf(stderr, "Reading password from password_eval command failed\n");
pclose(f);
@@ -510,6 +369,7 @@ static int password_eval(char *buf, int size)
/* Get exit status */
int status = pclose(f);
+
if (status != 0) {
fprintf(stderr, "password_eval command returned error %d\n", status);
return 0;
@@ -517,6 +377,7 @@ static int password_eval(char *buf, int size)
/* Removez whitespace or \n at end */
int i, len = strlen(buf);
+
for (i = len - 1; i > 0 && isspace(buf[i]); i--) {
buf[i] = 0;
len--;
@@ -535,7 +396,7 @@ static void first_time_encrypt(const char *msg)
printf("%s ", msg);
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
- || !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
+ || !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
break;
} while (fgets(ch, sizeof(ch), stdin));
@@ -613,6 +474,7 @@ int store_data(Tox *m, const char *path)
char *data = malloc(data_len * sizeof(char));
if (data == NULL) {
+ fclose(fp);
return -1;
}
@@ -623,6 +485,7 @@ int store_data(Tox *m, const char *path)
char *enc_data = malloc(enc_len * sizeof(char));
if (enc_data == NULL) {
+ fclose(fp);
free(data);
return -1;
}
@@ -747,14 +610,14 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
if (len == 0) {
fclose(fp);
- exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
+ exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
}
char data[len];
if (fread(data, sizeof(data), 1, fp) != 1) {
fclose(fp);
- exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
+ exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
}
bool is_encrypted = tox_is_data_encrypted((uint8_t *) data);
@@ -762,7 +625,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
/* attempt to encrypt an already encrypted data file */
if (arg_opts.encrypt_data && is_encrypted) {
fclose(fp);
- exit_toxic_err("failed in load_toxic", FATALERR_ENCRYPT);
+ exit_toxic_err("failed in load_tox", FATALERR_ENCRYPT);
}
if (arg_opts.unencrypt_data && is_encrypted)
@@ -776,6 +639,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
size_t pwlen = 0;
int pweval = user_settings->password_eval[0];
+
if (!pweval) {
system("clear"); // TODO: is this portable?
printf("Enter password (q to quit) ");
@@ -790,6 +654,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
} else {
pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
}
+
user_password.len = pwlen;
if (strcasecmp(user_password.pass, "q") == 0) {
@@ -848,7 +713,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
fclose(fp);
} else { /* Data file does not/should not exist */
if (file_exists(data_path))
- exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
+ exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_NONE;
@@ -858,7 +723,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
return NULL;
if (store_data(m, data_path) == -1)
- exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
+ exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
}
return m;
@@ -894,33 +759,9 @@ static Tox *load_toxic(char *data_path)
return m;
}
-#define TRY_BOOTSTRAP_INTERVAL 5
-static uint64_t last_bootstrap_time = 0;
-
-static void do_bootstrap(Tox *m)
-{
- static int conn_err = 0;
-
- if (!timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL))
- return;
-
- if (tox_self_get_connection_status(m) != TOX_CONNECTION_NONE)
- return;
-
- if (conn_err != 0)
- return;
-
- last_bootstrap_time = get_unix_time();
- conn_err = init_connection(m);
-
- if (conn_err != 0)
- line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Auto-connect failed with error code %d", conn_err);
-}
-
-static void do_toxic(Tox *m, ToxWindow *prompt)
+static void do_toxic(Tox *m)
{
pthread_mutex_lock(&Winthread.lock);
- update_unix_time();
if (arg_opts.no_connect) {
pthread_mutex_unlock(&Winthread.lock);
@@ -928,7 +769,7 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
}
tox_iterate(m);
- do_bootstrap(m);
+ do_tox_connection(m);
pthread_mutex_unlock(&Winthread.lock);
}
@@ -973,7 +814,7 @@ void *thread_cqueue(void *data)
ToxWindow *toxwin = get_window_ptr(i);
if (toxwin != NULL && toxwin->is_chat
- && tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE)
+ && tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE)
cqueue_try_send(toxwin, m);
}
@@ -1110,10 +951,6 @@ static void parse_args(int argc, char *argv[])
case 'n':
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg);
-
- if (!file_exists(arg_opts.nodes_path))
- queue_init_message("DHTnodes file not found");
-
break;
case 'o':
@@ -1125,10 +962,10 @@ static void parse_args(int argc, char *argv[])
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
- if (++optind > argc || argv[optind-1][0] == '-')
+ if (++optind > argc || argv[optind - 1][0] == '-')
exit_toxic_err("Proxy error", FATALERR_PROXY);
- port = strtol(argv[optind-1], NULL, 10);
+ port = strtol(argv[optind - 1], NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE)
exit_toxic_err("Proxy error", FATALERR_PROXY);
@@ -1140,10 +977,10 @@ static void parse_args(int argc, char *argv[])
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
- if (++optind > argc || argv[optind-1][0] == '-')
+ if (++optind > argc || argv[optind - 1][0] == '-')
exit_toxic_err("Proxy error", FATALERR_PROXY);
- port = strtol(argv[optind-1], NULL, 10);
+ port = strtol(argv[optind - 1], NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE)
exit_toxic_err("Proxy error", FATALERR_PROXY);
@@ -1269,7 +1106,7 @@ static void init_default_data_files(void)
// this doesn't do anything (yet)
#ifdef X11
-void DnD_callback(const char* asdv, DropType dt)
+void DnD_callback(const char *asdv, DropType dt)
{
// if (dt != DT_plain)
// return;
@@ -1282,7 +1119,6 @@ void DnD_callback(const char* asdv, DropType dt)
int main(int argc, char **argv)
{
- update_unix_time();
parse_args(argc, argv);
/* Use the -b flag to enable stderr */
@@ -1302,9 +1138,6 @@ int main(int argc, char **argv)
bool datafile_exists = file_exists(DATA_FILE);
- if (datafile_exists)
- last_bootstrap_time = get_unix_time();
-
if (!datafile_exists && !arg_opts.unencrypt_data)
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
else if (arg_opts.encrypt_data)
@@ -1319,21 +1152,26 @@ int main(int argc, char **argv)
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
- if (settings_load(user_settings, p) == -1)
- queue_init_message("Failed to load user settings");
+ if (settings_load(user_settings, p) == -1) {
+ queue_init_message("Failed to load user settings");
+ }
- int nameserver_ret = name_lookup_init();
+ int curl_init = curl_global_init(CURL_GLOBAL_ALL);
+ int nameserver_ret = name_lookup_init(curl_init);
- if (nameserver_ret == -1)
+ if (nameserver_ret == -1) {
queue_init_message("curl failed to initialize; name lookup service is disabled.");
- else if (nameserver_ret == -2)
+ } else if (nameserver_ret == -2) {
queue_init_message("Name lookup server list could not be found.");
- else if (nameserver_ret == -3)
+ } else if (nameserver_ret == -3) {
queue_init_message("Name lookup server list does not contain any valid entries.");
+ }
#ifdef X11
+
if (init_xtra(DnD_callback) == -1)
queue_init_message("X failed to initialize");
+
#endif
Tox *m = load_toxic(DATA_FILE);
@@ -1358,7 +1196,6 @@ int main(int argc, char **argv)
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
-
#ifdef AUDIO
av = init_audio(prompt, m);
@@ -1376,6 +1213,7 @@ int main(int argc, char **argv)
set_primary_device(output, user_settings->audio_out_dev);
#elif SOUND_NOTIFY
+
if ( init_devices() == de_InternalError )
queue_init_message("Failed to init audio devices");
@@ -1387,6 +1225,12 @@ int main(int argc, char **argv)
if (init_mplex_away_timer(m) == -1)
queue_init_message("Failed to init mplex auto-away.");
+ int nodeslist_ret = load_DHT_nodeslist();
+
+ if (nodeslist_ret != 0) {
+ queue_init_message("DHT nodeslist failed to load (error %d)", nodeslist_ret);
+ }
+
pthread_mutex_lock(&Winthread.lock);
load_groups(m);
print_init_messages(prompt);
@@ -1399,17 +1243,19 @@ int main(int argc, char **argv)
snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path);
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);
- uint64_t last_save = (uint64_t) time(NULL);
+ time_t last_save = get_unix_time();
while (true) {
- do_toxic(m, prompt);
+ do_toxic(m);
- uint64_t cur_time = get_unix_time();
+ time_t cur_time = get_unix_time();
if (timed_out(last_save, AUTOSAVE_FREQ)) {
pthread_mutex_lock(&Winthread.lock);
+
if (store_data(m, DATA_FILE) != 0)
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
+
pthread_mutex_unlock(&Winthread.lock);
last_save = cur_time;
diff --git a/src/toxic.h b/src/toxic.h
index 7758e2a..adb2a32 100644
--- a/src/toxic.h
+++ b/src/toxic.h
@@ -107,13 +107,15 @@ int store_data(Tox *m, const char *path);
/* callbacks */
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION status, void *userdata);
-void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length, void *userdata);
+void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
+ void *userdata);
void on_action(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata);
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort);
-void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata);
+void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
+ void *userdata);
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
size_t length, void *userdata);
void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata);
@@ -124,14 +126,18 @@ void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *user
void on_group_invite(Tox *m, uint32_t friendnumber, const uint8_t *invite_data, size_t length, void *userdata);
void on_group_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type,
const uint8_t *message, size_t length, void *userdata);
-void on_group_private_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *message, size_t length, void *userdata);
+void on_group_private_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *message, size_t length,
+ void *userdata);
void on_group_peer_join(Tox *m, uint32_t groupnumber, uint32_t peernumber, void *userdata);
-void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *partmsg, size_t length, void *userdata);
-void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *topic, size_t length, void *userdata);
+void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *partmsg, size_t length,
+ void *userdata);
+void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *topic, size_t length,
+ void *userdata);
void on_group_peer_limit(Tox *m, uint32_t groupnumber, uint32_t peer_limit, void *userdata);
void on_group_privacy_state(Tox *m, uint32_t groupnumber, TOX_GROUP_PRIVACY_STATE privacy_state, void *userdata);
void on_group_password(Tox *m, uint32_t groupnumber, const uint8_t *password, size_t length, void *userdata);
-void on_group_nick_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *newname, size_t length, void *userdata);
+void on_group_nick_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *newname, size_t length,
+ void *userdata);
void on_group_status_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_USER_STATUS status, void *userdata);
void on_group_self_join(Tox *m, uint32_t groupnumber, void *userdata);
void on_group_rejected(Tox *m, uint32_t groupnumber, TOX_GROUP_JOIN_FAIL type, void *userdata);
diff --git a/src/toxic_strings.c b/src/toxic_strings.c
index e17c5bb..cd93ecd 100644
--- a/src/toxic_strings.c
+++ b/src/toxic_strings.c
@@ -136,13 +136,13 @@ int del_word_buf(ChatContext *ctx)
int i = ctx->pos, count = 0;
/* traverse past empty space */
- while (i > 0 && ctx->line[i-1] == L' ') {
+ while (i > 0 && ctx->line[i - 1] == L' ') {
++count;
--i;
}
/* traverse past last entered word */
- while (i > 0 && ctx->line[i-1] != L' ') {
+ while (i > 0 && ctx->line[i - 1] != L' ') {
++count;
--i;
}
@@ -243,18 +243,20 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
ctx->len = h_len;
}
-void strsubst(char* str, char old, char new)
+void strsubst(char *str, char old, char new)
{
int i;
+
for (i = 0; str[i] != '\0'; ++i)
if (str[i] == old)
- str[i] = new;
+ str[i] = new;
}
-void wstrsubst(wchar_t* str, wchar_t old, wchar_t new)
+void wstrsubst(wchar_t *str, wchar_t old, wchar_t new)
{
int i;
+
for (i = 0; str[i] != L'\0'; ++i)
if (str[i] == old)
- str[i] = new;
+ str[i] = new;
}
diff --git a/src/toxic_strings.h b/src/toxic_strings.h
index c9e402c..11e7c1b 100644
--- a/src/toxic_strings.h
+++ b/src/toxic_strings.h
@@ -49,7 +49,7 @@ void reset_buf(ChatContext *ctx);
Return 0 on success, -1 if yank buffer is empty or too long */
int yank_buf(ChatContext *ctx);
-/* Deletes all characters from line starting at pos and going backwards
+/* Deletes all characters from line starting at pos and going backwards
until we find a space or run out of characters.
Return 0 on success, -1 if no line or already at the beginning */
int del_word_buf(ChatContext *ctx);
diff --git a/src/video_call.c b/src/video_call.c
index 7a3282b..c04f943 100644
--- a/src/video_call.c
+++ b/src/video_call.c
@@ -40,13 +40,13 @@
#define default_video_bit_rate 5000
void receive_video_frame_cb( ToxAV *av, uint32_t friend_number,
- uint16_t width, uint16_t height,
- uint8_t const *y, uint8_t const *u, uint8_t const *v,
- int32_t ystride, int32_t ustride, int32_t vstride,
- void *user_data );
+ uint16_t width, uint16_t height,
+ uint8_t const *y, uint8_t const *u, uint8_t const *v,
+ int32_t ystride, int32_t ustride, int32_t vstride,
+ void *user_data );
void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
- uint32_t video_bit_rate, void *user_data);
+ uint32_t video_bit_rate, void *user_data);
static void print_err (ToxWindow *self, const char *error_str)
{
@@ -82,22 +82,24 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
void terminate_video()
{
int i;
+
for (i = 0; i < MAX_CALLS; ++i) {
- Call* this_call = &CallControl.calls[i];
+ Call *this_call = &CallControl.calls[i];
stop_video_transmission(this_call, i);
- if( this_call->vout_idx != -1 )
+ if ( this_call->vout_idx != -1 )
close_video_device(vdt_output, this_call->vout_idx);
}
terminate_video_devices();
}
-void read_video_device_callback(int16_t width, int16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, void* data)
+void read_video_device_callback(int16_t width, int16_t height, const uint8_t *y, const uint8_t *u, const uint8_t *v,
+ void *data)
{
- uint32_t friend_number = *((uint32_t*)data); /* TODO: Or pass an array of call_idx's */
- Call* this_call = &CallControl.calls[friend_number];
+ uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
+ Call *this_call = &CallControl.calls[friend_number];
TOXAV_ERR_SEND_FRAME error;
/* Drop frame if video sending is disabled */
@@ -117,9 +119,9 @@ void read_video_device_callback(int16_t width, int16_t height, const uint8_t* y,
}
void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_t height,
- uint8_t const *y, uint8_t const *u, uint8_t const *v,
- int32_t ystride, int32_t ustride, int32_t vstride,
- void *user_data)
+ uint8_t const *y, uint8_t const *u, uint8_t const *v,
+ int32_t ystride, int32_t ustride, int32_t vstride,
+ void *user_data)
{
write_video_out(width, height, y, u, v, ystride, ustride, vstride, user_data);
}
@@ -175,16 +177,16 @@ int stop_video_transmission(Call *call, int friend_number)
* Callbacks
*/
void receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
- uint16_t width, uint16_t height,
- uint8_t const *y, uint8_t const *u, uint8_t const *v,
- int32_t ystride, int32_t ustride, int32_t vstride,
- void *user_data)
+ uint16_t width, uint16_t height,
+ uint8_t const *y, uint8_t const *u, uint8_t const *v,
+ int32_t ystride, int32_t ustride, int32_t vstride,
+ void *user_data)
{
write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data);
}
void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
- uint32_t video_bit_rate, void *user_data)
+ uint32_t video_bit_rate, void *user_data)
{
CallControl.video_bit_rate = video_bit_rate;
toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL);
@@ -192,7 +194,7 @@ void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_
void callback_recv_video_starting(uint32_t friend_number)
{
- Call* this_call = &CallControl.calls[friend_number];
+ Call *this_call = &CallControl.calls[friend_number];
if ( this_call->vout_idx != -1 )
return;
@@ -201,21 +203,22 @@ void callback_recv_video_starting(uint32_t friend_number)
}
void callback_recv_video_end(uint32_t friend_number)
{
- Call* this_call = &CallControl.calls[friend_number];
+ Call *this_call = &CallControl.calls[friend_number];
close_video_device(vdt_output, this_call->vout_idx);
this_call->vout_idx = -1;
}
void callback_video_starting(uint32_t friend_number)
{
- ToxWindow* windows = CallControl.prompt;
- Call* this_call = &CallControl.calls[friend_number];
+ ToxWindow *windows = CallControl.prompt;
+ Call *this_call = &CallControl.calls[friend_number];
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error);
if (error == TOXAV_ERR_CALL_CONTROL_OK) {
size_t i;
+
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if ( windows[i].is_call && windows[i].num == friend_number ) {
if ( 0 != start_video_transmission(&windows[i], CallControl.av, this_call) ) {
@@ -244,7 +247,7 @@ void callback_video_end(uint32_t friend_number)
void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
const char *error_str;
- Call* this_call = &CallControl.calls[self->num];
+ Call *this_call = &CallControl.calls[self->num];
if ( argc != 0 ) {
error_str = "Unknown arguments.";
@@ -387,18 +390,18 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
}
if ( video_selection_valid(type, selection) == vde_InvalidSelection ) {
- error_str="Invalid selection!";
+ error_str = "Invalid selection!";
goto on_error;
}
/* If call is active, change device */
if ( self->is_call ) {
- Call* this_call = &CallControl.calls[self->num];
+ Call *this_call = &CallControl.calls[self->num];
+
if ( this_call->ttas ) {
if ( type == vdt_output ) {
- }
- else {
+ } else {
/* TODO: check for failure */
close_video_device(vdt_input, this_call->vin_idx);
open_video_device(vdt_input, selection, &this_call->vin_idx);
@@ -410,7 +413,7 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
self->video_device_selection[type] = selection;
return;
- on_error:
+on_error:
print_err (self, error_str);
}
diff --git a/src/video_device.c b/src/video_device.c
index 19b4508..4a47853 100644
--- a/src/video_device.c
+++ b/src/video_device.c
@@ -62,7 +62,7 @@ struct VideoBuffer {
typedef struct VideoDevice {
VideoDataHandleCallback cb; /* Use this to handle data from input device usually */
- void* cb_data; /* Data to be passed to callback */
+ void *cb_data; /* Data to be passed to callback */
int32_t friend_number; /* ToxAV friend number */
#if defined(__linux__) || defined(__FreeBSD__)
@@ -93,7 +93,7 @@ VideoDevice *video_devices_running[2][MAX_DEVICES] = {{NULL}}; /* Running de
uint32_t primary_video_device[2]; /* Primary device */
#ifdef VIDEO
-static ToxAV* av = NULL;
+static ToxAV *av = NULL;
#endif /* VIDEO */
/* q_mutex */
@@ -102,15 +102,16 @@ static ToxAV* av = NULL;
pthread_mutex_t video_mutex;
bool video_thread_running = true,
- video_thread_paused = true; /* Thread control */
+ video_thread_paused = true; /* Thread control */
-void* video_thread_poll(void*);
+void *video_thread_poll(void *);
static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
- const uint8_t *u, const uint8_t *v, unsigned int ystride,
- unsigned int ustride, unsigned int vstride, uint8_t *out)
+ const uint8_t *u, const uint8_t *v, unsigned int ystride,
+ unsigned int ustride, unsigned int vstride, uint8_t *out)
{
unsigned long int i, j;
+
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
uint8_t *point = out + 4 * ((i * width) + j);
@@ -123,9 +124,9 @@ static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
int g = (298 * (t_y - 16) - 100 * (t_u - 128) - 208 * (t_v - 128) + 128) >> 8;
int b = (298 * (t_y - 16) + 516 * (t_u - 128) + 128) >> 8;
- point[2] = r>255? 255 : r<0 ? 0 : r;
- point[1] = g>255? 255 : g<0 ? 0 : g;
- point[0] = b>255? 255 : b<0 ? 0 : b;
+ point[2] = r > 255 ? 255 : r < 0 ? 0 : r;
+ point[1] = g > 255 ? 255 : g < 0 ? 0 : g;
+ point[0] = b > 255 ? 255 : b < 0 ? 0 : b;
point[3] = ~0;
}
}
@@ -133,11 +134,13 @@ static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
#if defined(__linux__) || defined(__FreeBSD__)
static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
- uint8_t *input, uint16_t width, uint16_t height)
+ uint8_t *input, uint16_t width, uint16_t height)
{
uint8_t *end = input + width * height * 2;
+
while (input != end) {
uint8_t *line_end = input + width * 2;
+
while (input != line_end) {
*plane_y++ = *input++;
*plane_u++ = *input++;
@@ -146,6 +149,7 @@ static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
}
line_end = input + width * 2;
+
while (input != line_end) {
*plane_y++ = *input++;
input++;//u
@@ -170,7 +174,7 @@ static int xioctl(int fh, unsigned long request, void *arg)
/* Meet devices */
#ifdef VIDEO
-VideoDeviceError init_video_devices(ToxAV* av_)
+VideoDeviceError init_video_devices(ToxAV *av_)
#else
VideoDeviceError init_video_devices()
#endif /* VIDEO */
@@ -178,31 +182,34 @@ VideoDeviceError init_video_devices()
size[vdt_input] = 0;
#if defined(__linux__) || defined(__FreeBSD__)
+
for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
int fd;
char device_address[] = "/dev/videoXX";
snprintf(device_address + 10, sizeof(char) * strlen(device_address) - 10, "%i", size[vdt_input]);
fd = open(device_address, O_RDWR | O_NONBLOCK, 0);
+
if ( fd == -1 ) {
break;
} else {
struct v4l2_capability cap;
- char* video_input_name;
+ char *video_input_name;
/* Query V4L for capture capabilities */
if ( -1 != ioctl(fd, VIDIOC_QUERYCAP, &cap) ) {
- video_input_name = (char*)malloc(strlen((const char*)cap.card) + strlen(device_address) + 4);
- strcpy(video_input_name, (char*)cap.card);
+ video_input_name = (char *)malloc(strlen((const char *)cap.card) + strlen(device_address) + 4);
+ strcpy(video_input_name, (char *)cap.card);
strcat(video_input_name, " (");
- strcat(video_input_name, (char*)device_address);
+ strcat(video_input_name, (char *)device_address);
strcat(video_input_name, ")");
} else {
- video_input_name = (char*)malloc(strlen(device_address) + 3);
+ video_input_name = (char *)malloc(strlen(device_address) + 3);
strcpy(video_input_name, "(");
strcat(video_input_name, device_address);
strcat(video_input_name, ")");
}
+
video_devices_names[vdt_input][size[vdt_input]] = video_input_name;
close(fd);
@@ -210,12 +217,14 @@ VideoDeviceError init_video_devices()
}
#else /* __OSX__ */
- if( osx_video_init((char**)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
+
+ if ( osx_video_init((char **)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
return vde_InternalError;
+
#endif
size[vdt_output] = 1;
- char* video_output_name = "Toxic Video Receiver";
+ char *video_output_name = "Toxic Video Receiver";
video_devices_names[vdt_output][0] = video_output_name;
// Start poll thread
@@ -223,6 +232,7 @@ VideoDeviceError init_video_devices()
return vde_InternalError;
pthread_t thread_id;
+
if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 )
return vde_InternalError;
@@ -236,12 +246,16 @@ VideoDeviceError init_video_devices()
VideoDeviceError terminate_video_devices()
{
/* Cleanup if needed */
+ lock;
video_thread_running = false;
+ unlock;
+
usleep(20000);
int i;
+
for (i = 0; i < size[vdt_input]; ++i) {
- free((void*)video_devices_names[vdt_input][i]);
+ free((void *)video_devices_names[vdt_input][i]);
}
if ( pthread_mutex_destroy(&video_mutex) != 0 )
@@ -255,14 +269,19 @@ VideoDeviceError terminate_video_devices()
}
VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t device_idx,
- VideoDataHandleCallback callback, void* data)
+ VideoDataHandleCallback callback, void *data)
{
#if defined(__linux__) || defined(__FreeBSD__)
- if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] || !video_devices_running[vdt_input][device_idx]->fd )
+
+ if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]
+ || !video_devices_running[vdt_input][device_idx]->fd )
return vde_InvalidSelection;
+
#else /* __OSX__ */
+
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
return vde_InvalidSelection;
+
#endif
lock;
@@ -283,7 +302,7 @@ VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selectio
return vde_None;
}
-VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t* device_idx)
+VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t *device_idx)
{
return open_video_device(type, primary_video_device[type], device_idx);
}
@@ -293,7 +312,7 @@ void get_primary_video_device_name(VideoDeviceType type, char *buf, int size)
memcpy(buf, dvideo_device_names[type], size);
}
-VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t* device_idx)
+VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx)
{
if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection;
@@ -324,7 +343,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
}
}
- VideoDevice* device = video_devices_running[type][temp_idx] = calloc(1, sizeof(VideoDevice));
+ VideoDevice *device = video_devices_running[type][temp_idx] = calloc(1, sizeof(VideoDevice));
device->selection = selection;
if ( pthread_mutex_init(device->mutex, NULL) != 0 ) {
@@ -342,6 +361,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
snprintf(device_address + 10 , sizeof(device_address) - 10, "%i", selection);
device->fd = open(device_address, O_RDWR);
+
if ( device->fd == -1 ) {
unlock;
return vde_FailedStart;
@@ -349,6 +369,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
/* Obtain video device capabilities */
struct v4l2_capability cap;
+
if ( -1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap) ) {
close(device->fd);
free(device);
@@ -362,7 +383,8 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- if( -1 == xioctl(device->fd, VIDIOC_G_FMT, &fmt) ) {
+
+ if ( -1 == xioctl(device->fd, VIDIOC_S_FMT, &fmt) ) {
close(device->fd);
free(device);
unlock;
@@ -378,6 +400,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
+
if ( -1 == xioctl(device->fd, VIDIOC_REQBUFS, &req) ) {
close(device->fd);
free(device);
@@ -411,20 +434,22 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
device->buffers[i].length = buf.length;
device->buffers[i].start = mmap(NULL /* start anywhere */,
- buf.length,
- PROT_READ | PROT_WRITE /* required */,
- MAP_SHARED /* recommended */,
- device->fd, buf.m.offset);
+ buf.length,
+ PROT_READ | PROT_WRITE /* required */,
+ MAP_SHARED /* recommended */,
+ device->fd, buf.m.offset);
if ( MAP_FAILED == device->buffers[i].start ) {
for (i = 0; i < buf.index; ++i)
munmap(device->buffers[i].start, device->buffers[i].length);
+
close(device->fd);
free(device);
unlock;
return vde_FailedStart;
}
}
+
device->n_buffers = i;
enum v4l2_buf_type type;
@@ -440,6 +465,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
for (i = 0; i < device->n_buffers; ++i)
munmap(device->buffers[i].start, device->buffers[i].length);
+
close(device->fd);
free(device);
unlock;
@@ -457,11 +483,13 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
}
#else /* __OSX__ */
+
if ( osx_video_open_device(selection, &device->video_width, &device->video_height) != 0 ) {
free(device);
unlock;
return vde_FailedStart;
}
+
#endif
/* Create X11 window associated to device */
@@ -474,15 +502,15 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
int screen = DefaultScreen(device->x_display);
if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
- device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen),
- BlackPixel(device->x_display, screen))) ) {
+ device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen),
+ BlackPixel(device->x_display, screen))) ) {
close_video_device(vdt_input, temp_idx);
unlock;
return vde_FailedStart;
}
XStoreName(device->x_display, device->x_window, "Video Preview");
- XSelectInput(device->x_display, device->x_window, ExposureMask|ButtonPressMask|KeyPressMask);
+ XSelectInput(device->x_display, device->x_window, ExposureMask | ButtonPressMask | KeyPressMask);
if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) {
close_video_device(vdt_input, temp_idx);
@@ -514,14 +542,14 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
int screen = DefaultScreen(device->x_display);
if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
- 100, 100, 0, BlackPixel(device->x_display, screen), BlackPixel(device->x_display, screen))) ) {
+ 100, 100, 0, BlackPixel(device->x_display, screen), BlackPixel(device->x_display, screen))) ) {
close_video_device(vdt_output, temp_idx);
unlock;
return vde_FailedStart;
}
XStoreName(device->x_display, device->x_window, "Video Receive");
- XSelectInput(device->x_display, device->x_window, ExposureMask|ButtonPressMask|KeyPressMask);
+ XSelectInput(device->x_display, device->x_window, ExposureMask | ButtonPressMask | KeyPressMask);
if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) {
close_video_device(vdt_output, temp_idx);
@@ -548,15 +576,15 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
}
__inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
- uint8_t const *y, uint8_t const *u, uint8_t const *v,
- int32_t ystride, int32_t ustride, int32_t vstride,
- void *user_data)
+ uint8_t const *y, uint8_t const *u, uint8_t const *v,
+ int32_t ystride, int32_t ustride, int32_t vstride,
+ void *user_data)
{
- VideoDevice* device = video_devices_running[vdt_output][0];
+ VideoDevice *device = video_devices_running[vdt_output][0];
if ( !device ) return vde_DeviceNotActive;
- if( !device->x_window ) return vde_DeviceNotActive;
+ if ( !device->x_window ) return vde_DeviceNotActive;
pthread_mutex_lock(device->mutex);
@@ -591,7 +619,7 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
.red_mask = 0xFF0000,
.green_mask = 0xFF00,
.blue_mask = 0xFF,
- .data = (char*)img_data
+ .data = (char *)img_data
};
/* Render image data */
@@ -606,7 +634,7 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
return vde_None;
}
-void* video_thread_poll (void* arg) // TODO: maybe use thread for every input source
+void *video_thread_poll (void *arg) // TODO: maybe use thread for every input source
{
/*
* NOTE: We only need to poll input devices for data.
@@ -614,18 +642,24 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
(void)arg;
uint32_t i;
- while (video_thread_running)
- {
+ while (1) {
+ lock;
+
+ if (!video_thread_running) {
+ unlock;
+ break;
+ }
+
+ unlock;
+
if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */
- else
- {
- for (i = 0; i < size[vdt_input]; ++i)
- {
+ else {
+ for (i = 0; i < size[vdt_input]; ++i) {
lock;
- if ( video_devices_running[vdt_input][i] != NULL )
- {
+
+ if ( video_devices_running[vdt_input][i] != NULL ) {
/* Obtain frame image data from device buffers */
- VideoDevice* device = video_devices_running[vdt_input][i];
+ VideoDevice *device = video_devices_running[vdt_input][i];
uint16_t video_width = device->video_width;
uint16_t video_height = device->video_height;
uint8_t *y = device->input.planes[0];
@@ -644,16 +678,18 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
continue;
}
- void *data = (void*)device->buffers[buf.index].start;
+ void *data = (void *)device->buffers[buf.index].start;
/* Convert frame image data to YUV420 for ToxAV */
yuv422to420(y, u, v, data, video_width, video_height);
#else /* __OSX__*/
+
if ( osx_video_read_device(y, u, v, &video_width, &video_height) != 0 ) {
unlock;
continue;
}
+
#endif
/* Send frame data to friend through ToxAV */
@@ -663,7 +699,7 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
/* Convert YUV420 data to BGR */
uint8_t *img_data = malloc(video_width * video_height * 4);
yuv420tobgr(video_width, video_height, y, u, v,
- video_width, video_width/2, video_width/2, img_data);
+ video_width, video_width / 2, video_width / 2, img_data);
/* Allocate image data in X11 */
XImage image = {
@@ -679,7 +715,7 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
.red_mask = 0xFF0000,
.green_mask = 0xFF00,
.blue_mask = 0xFF,
- .data = (char*)img_data
+ .data = (char *)img_data
};
/* Render image data */
@@ -691,15 +727,19 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
free(img_data);
#if defined(__linux__) || defined(__FreeBSD__)
+
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
unlock;
continue;
}
+
#endif /* __linux__ */
}
+
unlock;
}
+
usleep(1000 * 1000 / 24);
}
}
@@ -727,13 +767,16 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
if ( type == vdt_input ) {
#if defined(__linux__) || defined(__FreeBSD__)
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if( -1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type) ) {}
+
+ if ( -1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type) ) {}
int i;
+
for (i = 0; i < device->n_buffers; ++i) {
if ( -1 == munmap(device->buffers[i].start, device->buffers[i].length) ) {
}
}
+
close(device->fd);
#else /* __OSX__ */
@@ -759,14 +802,13 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
free(device);
}
- }
- else device->ref_count--;
+ } else device->ref_count--;
unlock;
return rc;
}
-void print_video_devices(ToxWindow* self, VideoDeviceType type)
+void print_video_devices(ToxWindow *self, VideoDeviceType type)
{
int i;
diff --git a/src/video_device.h b/src/video_device.h
index c32cffc..ed84e53 100644
--- a/src/video_device.h
+++ b/src/video_device.h
@@ -45,10 +45,11 @@ typedef enum VideoDeviceError {
vde_CaptureError = -9,
} VideoDeviceError;
-typedef void (*VideoDataHandleCallback) (int16_t width, int16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, void* data);
+typedef void (*VideoDataHandleCallback) (int16_t width, int16_t height, const uint8_t *y, const uint8_t *u,
+ const uint8_t *v, void *data);
#ifdef VIDEO
-VideoDeviceError init_video_devices(ToxAV* av);
+VideoDeviceError init_video_devices(ToxAV *av);
#else
VideoDeviceError init_video_devices();
#endif /* VIDEO */
@@ -56,20 +57,22 @@ VideoDeviceError init_video_devices();
VideoDeviceError terminate_video_devices();
/* Callback handles ready data from INPUT device */
-VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback, void* data);
-void* get_video_device_callback_data(uint32_t device_idx);
+VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback,
+ void *data);
+void *get_video_device_callback_data(uint32_t device_idx);
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection);
-VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t* device_idx);
+VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t *device_idx);
/* Start device */
-VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t* device_idx);
+VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx);
/* Stop device */
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx);
/* Write data to device */
-VideoDeviceError write_video_out(uint16_t width, uint16_t height, uint8_t const *y, uint8_t const *u, uint8_t const *v, int32_t ystride, int32_t ustride, int32_t vstride, void *user_data);
+VideoDeviceError write_video_out(uint16_t width, uint16_t height, uint8_t const *y, uint8_t const *u, uint8_t const *v,
+ int32_t ystride, int32_t ustride, int32_t vstride, void *user_data);
-void print_video_devices(ToxWindow* self, VideoDeviceType type);
+void print_video_devices(ToxWindow *self, VideoDeviceType type);
void get_primary_video_device_name(VideoDeviceType type, char *buf, int size);
VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection);
diff --git a/src/windows.c b/src/windows.c
index 69994db..5047d51 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -230,7 +230,7 @@ void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peer_id, const ui
}
void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *topic, size_t length,
- void *userdata)
+ void *userdata)
{
char data[MAX_STR_SIZE + 1];
length = copy_tox_str(data, sizeof(data), (const char *) topic, length);
@@ -550,10 +550,12 @@ void on_window_resize(void)
}
#ifdef AUDIO
+
if (w->chatwin->infobox.active) {
delwin(w->chatwin->infobox.win);
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
}
+
#endif /* AUDIO */
scrollok(w->chatwin->history, 0);
@@ -563,19 +565,28 @@ void on_window_resize(void)
static void draw_window_tab(ToxWindow *toxwin)
{
pthread_mutex_lock(&Winthread.lock);
+
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
+
pthread_mutex_unlock(&Winthread.lock);
clrtoeol();
printw(" [%s]", toxwin->name);
pthread_mutex_lock(&Winthread.lock);
+
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
+
pthread_mutex_unlock(&Winthread.lock);
}
static void draw_bar(void)
{
+ int y, x;
+
+ // save current cursor position
+ getyx(active_window->window, y, x);
+
attron(COLOR_PAIR(BLUE));
mvhline(LINES - 2, 0, '_', COLS);
attroff(COLOR_PAIR(BLUE));
@@ -613,6 +624,9 @@ static void draw_bar(void)
attroff(A_BOLD);
}
+ // restore cursor position after drawing
+ move(y, x);
+
refresh();
}
@@ -630,6 +644,7 @@ void draw_active_window(Tox *m)
touchwin(a->window);
a->onDraw(a, m);
+ wrefresh(a->window);
/* Handle input */
bool ltr;
diff --git a/src/windows.h b/src/windows.h
index ad49525..17b6b15 100644
--- a/src/windows.h
+++ b/src/windows.h
@@ -163,7 +163,7 @@ struct ToxWindow {
#ifdef VIDEO
int video_device_selection[2]; /* -1 if not set, if set uses these selections instead of primary video device */
-
+
#endif /* VIDEO */
#endif /* AUDIO */
@@ -214,8 +214,8 @@ struct infobox {
bool hide;
bool active;
- uint64_t lastupdate;
- uint64_t starttime;
+ time_t lastupdate;
+ time_t starttime;
char timestr[TIME_STR_SIZE];
WINDOW *win;
diff --git a/src/xtra.c b/src/xtra.c
index 1ff34bd..77c625d 100644
--- a/src/xtra.c
+++ b/src/xtra.c
@@ -57,8 +57,7 @@ struct _Xtra {
Atom expecting_type;
} Xtra;
-typedef struct _Property
-{
+typedef struct _Property {
unsigned char *data;
int read_format;
unsigned long read_num;
@@ -97,21 +96,23 @@ Property read_property(Window s, Atom p)
Atom get_dnd_type(long *a, int l)
{
int i = 0;
+
for (; i < l; i ++) {
if (a[i] != XtraNil) return a[i]; /* Get first valid */
}
+
return XtraNil;
}
/* TODO maybe support only certain types in the future */
-static void handle_xdnd_enter(XClientMessageEvent* e)
+static void handle_xdnd_enter(XClientMessageEvent *e)
{
Xtra.handling_version = (e->data.l[1] >> 24);
if ((e->data.l[1] & 1)) {
// Fetch the list of possible conversions
Property p = read_property(e->data.l[0], XdndTypeList);
- Xtra.expecting_type = get_dnd_type((long*)p.data, p.read_num);
+ Xtra.expecting_type = get_dnd_type((long *)p.data, p.read_num);
XFree(p.data);
} else {
// Use the available list
@@ -119,7 +120,7 @@ static void handle_xdnd_enter(XClientMessageEvent* e)
}
}
-static void handle_xdnd_position(XClientMessageEvent* e)
+static void handle_xdnd_position(XClientMessageEvent *e)
{
XEvent ev = {
.xclient = {
@@ -143,7 +144,7 @@ static void handle_xdnd_position(XClientMessageEvent* e)
XFlush(Xtra.display);
}
-static void handle_xdnd_drop(XClientMessageEvent* e)
+static void handle_xdnd_drop(XClientMessageEvent *e)
{
/* Not expecting any type */
if (Xtra.expecting_type == XtraNil) {
@@ -172,7 +173,7 @@ static void handle_xdnd_drop(XClientMessageEvent* e)
}
}
-static void handle_xdnd_selection(XSelectionEvent* e)
+static void handle_xdnd_selection(XSelectionEvent *e)
{
/* DnD succesfully finished, send finished and call callback */
XEvent ev = {
@@ -199,12 +200,12 @@ static void handle_xdnd_selection(XSelectionEvent* e)
/* Call callback for every entry */
- if (Xtra.on_drop && p.read_num)
- {
+ if (Xtra.on_drop && p.read_num) {
char *sptr;
char *str = strtok_r((char *) p.data, "\n\r", &sptr);
if (str) Xtra.on_drop(str, dt);
+
while ((str = strtok_r(NULL, "\n\r", &sptr)))
Xtra.on_drop(str, dt);
}
@@ -212,7 +213,7 @@ static void handle_xdnd_selection(XSelectionEvent* e)
if (p.data) XFree(p.data);
}
-void *event_loop(void* p)
+void *event_loop(void *p)
{
/* Handle events like a real nigga */
@@ -221,30 +222,27 @@ void *event_loop(void* p)
XEvent event;
int pending;
- while (Xtra.display)
- {
+ while (Xtra.display) {
/* NEEDMOEVENTSFODEMPROGRAMS */
XLockDisplay(Xtra.display);
- if((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
- if (!pending)
- {
+ if ((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
+
+ if (!pending) {
XUnlockDisplay(Xtra.display);
usleep(10000);
continue;
}
- if (event.type == ClientMessage)
- {
+ if (event.type == ClientMessage) {
Atom type = event.xclient.message_type;
if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
else if (type == XtraTerminate) break;
- }
- else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
+ } else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
/* AINNOBODYCANHANDLEDEMEVENTS*/
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
@@ -256,6 +254,7 @@ void *event_loop(void* p)
* otherwise HEWUSAGUDBOI happens
*/
if (Xtra.display) XCloseDisplay(Xtra.display);
+
return (Xtra.display = NULL);
}
@@ -267,6 +266,7 @@ int init_xtra(drop_callback d)
else Xtra.on_drop = d;
XInitThreads();
+
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
Xtra.terminal_window = focused_window_id();
@@ -274,7 +274,7 @@ int init_xtra(drop_callback d)
/* OSX: if focused window is 0, it means toxic is ran from
* native terminal and not X11 terminal window, silently exit */
if (!Xtra.terminal_window)
- return 0;
+ return 0;
{
/* Create an invisible window which will act as proxy for the DnD operation. */
@@ -300,15 +300,15 @@ int init_xtra(drop_callback d)
&root, &x, &y, &wht, &hht, &b, &d);
if (! (Xtra.proxy_window = XCreateWindow
- (Xtra.display, Xtra.terminal_window, /* Parent */
- 0, 0, /* Position */
- wht, hht, /* Width + height */
- 0, /* Border width */
- CopyFromParent, /* Depth */
- InputOnly, /* Class */
- CopyFromParent, /* Visual */
- CWEventMask | CWCursor, /* Value mask */
- &attr)) ) /* Attributes for value mask */
+ (Xtra.display, Xtra.terminal_window, /* Parent */
+ 0, 0, /* Position */
+ wht, hht, /* Width + height */
+ 0, /* Border width */
+ CopyFromParent, /* Depth */
+ InputOnly, /* Class */
+ CopyFromParent, /* Visual */
+ CWEventMask | CWCursor, /* Value mask */
+ &attr)) ) /* Attributes for value mask */
return -1;
}
@@ -335,9 +335,10 @@ int init_xtra(drop_callback d)
XA_ATOM,
32,
PropModeReplace,
- (unsigned char*)&XdndVersion, 1);
+ (unsigned char *)&XdndVersion, 1);
pthread_t id;
+
if (pthread_create(&id, NULL, event_loop, NULL) != 0)
return -1;
diff --git a/src/xtra.h b/src/xtra.h
index 59038de..ba380f2 100644
--- a/src/xtra.h
+++ b/src/xtra.h
@@ -28,10 +28,10 @@
typedef enum {
DT_plain,
DT_file_list
-}
+}
DropType;
-typedef void (*drop_callback) (const char*, DropType);
+typedef void (*drop_callback) (const char *, DropType);
int init_xtra(drop_callback d);
void terminate_xtra();