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();