1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-22 21:03:02 +01:00

Merge with master branch

This commit is contained in:
Jfreegman 2016-09-24 23:31:20 -04:00
commit c6f2a9cb59
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
58 changed files with 2444 additions and 920 deletions

503
CHANGELOG.md Normal file
View File

@ -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)*

View File

@ -11,10 +11,10 @@ CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
CFLAGS += $(USER_CFLAGS) CFLAGS += $(USER_CFLAGS)
LDFLAGS = $(USER_LDFLAGS) LDFLAGS = $(USER_LDFLAGS)
OBJ = chat.o chat_commands.o configdir.o execute.o file_transfers.o notify.o OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o OBJ += file_transfers.o friendlist.o global_commands.o group_commands.o groupchat.o help.o input.o
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.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 += group_commands.o term_mplex.o avatars.o name_lookup.o qr_code.o OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
# Check on wich system we are running # Check on wich system we are running
UNAME_S = $(shell uname -s) UNAME_S = $(shell uname -s)

View File

@ -1,5 +1,5 @@
# Version # Version
TOXIC_VERSION = 0.7.0 TOXIC_VERSION = 0.7.1
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error") REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
ifneq (, $(findstring error, $(REV))) ifneq (, $(findstring error, $(REV)))
VERSION = $(TOXIC_VERSION) VERSION = $(TOXIC_VERSION)
@ -16,7 +16,7 @@ MISC_DIR = $(BASE_DIR)/misc
# Project files # Project files
MANFILES = toxic.1 toxic.conf.5 MANFILES = toxic.1 toxic.conf.5
DATAFILES = DHTnodes nameservers toxic.conf.example DATAFILES = nameservers toxic.conf.example
DESKFILE = toxic.desktop DESKFILE = toxic.desktop
SNDFILES = ToxicContactOnline.wav ToxicContactOffline.wav ToxicError.wav SNDFILES = ToxicContactOnline.wav ToxicContactOffline.wav ToxicError.wav
SNDFILES += ToxicRecvMessage.wav ToxicOutgoingCall.wav ToxicIncomingCall.wav SNDFILES += ToxicRecvMessage.wav ToxicOutgoingCall.wav ToxicIncomingCall.wav

View File

@ -2,12 +2,12 @@
.\" Title: toxic .\" Title: toxic
.\" Author: [see the "AUTHORS" section] .\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/> .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2015-12-07 .\" Date: 2016-09-20
.\" Manual: Toxic Manual .\" Manual: Toxic Manual
.\" Source: toxic __VERSION__ .\" Source: toxic __VERSION__
.\" Language: English .\" 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 .\" * Define some portability stuff
.\" ----------------------------------------------------------------- .\" -----------------------------------------------------------------
@ -82,8 +82,8 @@ Show help message
.RS 4 .RS 4
Use specified Use specified
\fInodes\-file\fR \fInodes\-file\fR
for DHT bootstrap nodes, instead of for DHT bootstrap nodes instead of
\fI__DATADIR__/DHTnodes\fR \fI~/\&.config/tox/DHTnodes\&.json\fR
.RE .RE
.PP .PP
\-o, \-\-noconnect \-o, \-\-noconnect
@ -122,9 +122,11 @@ Unencrypt a data file\&. A warning will appear if this option is used with a dat
.RE .RE
.SH "FILES" .SH "FILES"
.PP .PP
__DATADIR__/DHTnodes ~/\&.config/tox/DHTnodes\&.json
.RS 4 .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 .RE
.PP .PP
~/\&.config/tox/toxic_profile\&.tox ~/\&.config/tox/toxic_profile\&.tox

View File

@ -41,8 +41,7 @@ OPTIONS
Show help message Show help message
-n, --nodes nodes-file:: -n, --nodes nodes-file::
Use specified 'nodes-file' for DHT bootstrap nodes, instead of Use specified 'nodes-file' for DHT bootstrap nodes instead of '~/.config/tox/DHTnodes.json'
'{datadir}/DHTnodes'
-o, --noconnect:: -o, --noconnect::
Do not connect to the DHT network Do not connect to the DHT network
@ -68,8 +67,9 @@ OPTIONS
FILES FILES
----- -----
{datadir}/DHTnodes:: ~/.config/tox/DHTnodes.json::
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 *toxic.conf*(5) for details on controlling the update frequency.
~/.config/tox/toxic_profile.tox:: ~/.config/tox/toxic_profile.tox::
Savestate which contains your personal info (nickname, Tox ID, contacts, Savestate which contains your personal info (nickname, Tox ID, contacts,

View File

@ -2,12 +2,12 @@
.\" Title: toxic.conf .\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section] .\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/> .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2016-02-28 .\" Date: 2016-07-21
.\" Manual: Toxic Manual .\" Manual: Toxic Manual
.\" Source: toxic __VERSION__ .\" Source: toxic __VERSION__
.\" Language: English .\" 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 .\" * Define some portability stuff
.\" ----------------------------------------------------------------- .\" -----------------------------------------------------------------
@ -85,7 +85,7 @@ Time format string for logging enclosed by double quotes\&. See
.PP .PP
\fBalerts\fR \fBalerts\fR
.RS 4 .RS 4
Enable or disable terminal alerts on events\&. true or false Enable or disable acoustic alerts on events\&. true or false
.RE .RE
.PP .PP
\fBnative_colors\fR \fBnative_colors\fR
@ -118,6 +118,11 @@ Show welcome message on startup\&. true or false
Enable friend connection change notifications\&. true or false Enable friend connection change notifications\&. true or false
.RE .RE
.PP .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 \fBhistory_size\fR
.RS 4 .RS 4
Maximum lines for chat window history\&. Integer value\&. (for example: 700) 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 \fBmplex_away_note\fR
.RS 4 .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\&. 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
.RE .RE
.PP .PP

View File

@ -55,7 +55,7 @@ OPTIONS
See *date*(1) See *date*(1)
*alerts*;; *alerts*;;
Enable or disable terminal alerts on events. true or false Enable or disable acoustic alerts on events. true or false
*native_colors*;; *native_colors*;;
Select between native terminal colors and toxic color theme. true or false Select between native terminal colors and toxic color theme. true or false
@ -75,6 +75,9 @@ OPTIONS
*show_connection_msg*;; *show_connection_msg*;;
Enable friend connection change notifications. true or false 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*;; *history_size*;;
Maximum lines for chat window history. Integer value. (for example: 700) 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 detach. When attaching, the status message is set back to the original
value. 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*:: *audio*::
Configuration related to audio devices. Configuration related to audio devices.

View File

@ -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

View File

@ -5,9 +5,21 @@ ui = {
// true to enable timestamps, false to disable // true to enable timestamps, false to disable
timestamps=true; timestamps=true;
// true to enable terminal alerts on messages, false to disable // true to enable acoustic alerts on messages, false to disable
alerts=true; 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 // true to use native terminal colours, false to use toxic default colour theme
native_colors=false; native_colors=false;
@ -17,7 +29,7 @@ ui = {
// 24 or 12 hour time // 24 or 12 hour time
time_format=24; 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"; timestamp_format="%H:%M:%S";
// true to show you when others are typing a message in 1-on-1 chats // 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 // true to show friend connection change messages on the home screen
show_connection_msg=true; 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 // maximum lines for chat window history
history_size=700; history_size=700;
@ -92,8 +107,7 @@ sounds = {
}; };
// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive) // Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
// Note: All printable keys register as input // Note: Ctrl+M does not work
// Note2: Ctrl+M does not work
keys = { keys = {
next_tab="Ctrl+P"; next_tab="Ctrl+P";
prev_tab="Ctrl+O"; prev_tab="Ctrl+O";

View File

@ -61,7 +61,7 @@ extern FriendsList Friends;
#define frame_size (CallControl.audio_sample_rate * CallControl.audio_frame_duration / 1000) #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->in_idx = -1;
call->out_idx = -1; call->out_idx = -1;
@ -75,9 +75,9 @@ static int set_call(Call* call, bool start)
if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) if ( pthread_mutex_init(&call->mutex, NULL) != 0 )
return -1; return -1;
} } else {
else {
call->ttid = 0; call->ttid = 0;
if ( pthread_mutex_destroy(&call->mutex) != 0 ) if ( pthread_mutex_destroy(&call->mutex) != 0 )
return -1; return -1;
} }
@ -85,7 +85,8 @@ static int set_call(Call* call, bool start)
return 0; 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 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, 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 ); 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_rejected ( uint32_t friend_number );
void callback_call_ended ( 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 ); uint32_t sample_rate );
static void print_err (ToxWindow *self, const char *error_str) static void print_err (ToxWindow *self, const char *error_str)
@ -158,6 +159,7 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
void terminate_audio() void terminate_audio()
{ {
int i; int i;
for (i = 0; i < MAX_CALLS; ++i) for (i = 0; i < MAX_CALLS; ++i)
stop_transmission(&CallControl.calls[i], i); stop_transmission(&CallControl.calls[i], i);
@ -167,7 +169,7 @@ void terminate_audio()
terminate_devices(); 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; TOXAV_ERR_SEND_FRAME error;
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */ uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
@ -177,11 +179,11 @@ void read_device_callback(const int16_t* captured, uint32_t size, void* data)
if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number, if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number,
captured, sample_count, captured, sample_count,
CallControl.audio_channels, CallControl.audio_channels,
CallControl.audio_sample_rate, &error) == false ) 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) uint32_t sample_rate)
{ {
if ( CallControl.calls[friend_number].ttas ) if ( CallControl.calls[friend_number].ttas )
@ -228,7 +230,7 @@ int stop_transmission(Call *call, uint32_t friend_number)
if ( call->ttas ) { if ( call->ttas ) {
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK; 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); toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_CANCEL, &error);
if ( error == TOXAV_ERR_CALL_CONTROL_OK ) { if ( error == TOXAV_ERR_CALL_CONTROL_OK ) {
@ -287,6 +289,7 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
CallControl.pending_call = false; CallControl.pending_call = false;
break; break;
case ( TOXAV_FRIEND_CALL_STATE_FINISHED ): case ( TOXAV_FRIEND_CALL_STATE_FINISHED ):
if ( CallControl.pending_call ) if ( CallControl.pending_call )
callback_call_rejected(friend_number); callback_call_rejected(friend_number);
@ -305,6 +308,7 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
CallControl.pending_call = false; CallControl.pending_call = false;
break; break;
default: default:
if ( CallControl.pending_call ) { if ( CallControl.pending_call ) {
/* Start answered call */ /* Start answered call */
@ -313,6 +317,7 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
} else { } else {
#ifdef VIDEO #ifdef VIDEO
/* Handle receiving client video call states */ /* Handle receiving client video call states */
if ( state & TOXAV_FRIEND_CALL_STATE_SENDING_V ) if ( state & TOXAV_FRIEND_CALL_STATE_SENDING_V )
callback_recv_video_starting(friend_number); callback_recv_video_starting(friend_number);
@ -373,12 +378,14 @@ void callback_recv_ringing(uint32_t friend_number)
} }
void callback_recv_starting(uint32_t friend_number) void callback_recv_starting(uint32_t friend_number)
{ {
ToxWindow* windows = CallControl.prompt; ToxWindow *windows = CallControl.prompt;
int i; int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if ( windows[i].onStarting != NULL && windows[i].num == friend_number ) { if ( windows[i].onStarting != NULL && windows[i].num == friend_number ) {
windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state); windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state);
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */ 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!"); 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) void callback_call_started(uint32_t friend_number)
{ {
ToxWindow* windows = CallControl.prompt; ToxWindow *windows = CallControl.prompt;
int i; int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) for (i = 0; i < MAX_WINDOWS_NUM; ++i)
if ( windows[i].onStart != NULL && windows[i].num == friend_number ) { if ( windows[i].onStart != NULL && windows[i].num == friend_number ) {
windows[i].onStart(&windows[i], CallControl.av, friend_number, CallControl.call_state); windows[i].onStart(&windows[i], CallControl.av, friend_number, CallControl.call_state);
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) {/* YEAH! */ 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!"); line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
return; 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); 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_OK ) {
if ( error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL ) error_str = "Already in a call!"; 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"; 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); 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_OK ) {
if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING ) error_str = "No incoming call!"; 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!"; 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 ) { if ( set_primary_device(type, selection) == de_InvalidSelection ) {
error_str="Invalid selection!"; error_str = "Invalid selection!";
goto on_error; 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 ) { if ( selection_valid(type, selection) == de_InvalidSelection ) {
error_str="Invalid selection!"; error_str = "Invalid selection!";
goto on_error; goto on_error;
} }
/* If call is active, change device */ /* If call is active, change device */
if ( self->is_call ) { if ( self->is_call ) {
Call* this_call = &CallControl.calls[self->num]; Call *this_call = &CallControl.calls[self->num];
if ( this_call->ttas ) { if ( this_call->ttas ) {
@ -725,8 +737,7 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels)
== de_None ? 1 : 0; == de_None ? 1 : 0;
pthread_mutex_unlock(&this_call->mutex); pthread_mutex_unlock(&this_call->mutex);
} } else {
else {
/* TODO: check for failure */ /* TODO: check for failure */
close_device(input, this_call->in_idx); close_device(input, this_call->in_idx);
open_device(input, selection, &this_call->in_idx, CallControl.audio_sample_rate, open_device(input, selection, &this_call->in_idx, CallControl.audio_sample_rate,
@ -740,7 +751,7 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
self->device_selection[type] = selection; self->device_selection[type] = selection;
return; return;
on_error: on_error:
print_err (self, error_str); 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 call is active, use this_call values */
if ( self->is_call ) { if ( self->is_call ) {
Call* this_call = &CallControl.calls[self->num]; Call *this_call = &CallControl.calls[self->num];
pthread_mutex_lock(&this_call->mutex); pthread_mutex_lock(&this_call->mutex);
if ( type == input ) { if ( type == input ) {
device_mute(type, this_call->in_idx); device_mute(type, this_call->in_idx);
self->chatwin->infobox.in_is_muted ^= 1; 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); device_mute(type, this_call->out_idx);
self->chatwin->infobox.out_is_muted ^= 1; self->chatwin->infobox.out_is_muted ^= 1;
} }
pthread_mutex_unlock(&this_call->mutex); pthread_mutex_unlock(&this_call->mutex);
} }
return; return;
on_error: on_error:
print_err (self, error_str); 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 ) { if ( CallControl.pending_call ) {
toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL); toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL);

View File

@ -56,7 +56,7 @@ typedef struct Device {
ALCdevice *dhndl; /* Handle of device selected/opened */ ALCdevice *dhndl; /* Handle of device selected/opened */
ALCcontext *ctx; /* Device context */ ALCcontext *ctx; /* Device context */
DataHandleCallback cb; /* Use this to handle data from input device usually */ 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 */ int32_t friend_number; /* ToxAV friend number */
uint32_t source, buffers[OPENAL_BUFS]; /* Playback source/buffers */ 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 */ uint32_t primary_device[2]; /* Primary device */
#ifdef AUDIO #ifdef AUDIO
static ToxAV* av = NULL; static ToxAV *av = NULL;
#endif /* AUDIO */ #endif /* AUDIO */
/* q_mutex */ /* q_mutex */
@ -92,10 +92,10 @@ pthread_mutex_t mutex;
bool thread_running = true, bool thread_running = true,
thread_paused = true; /* Thread control */ thread_paused = true; /* Thread control */
void* thread_poll(void*); void *thread_poll(void *);
/* Meet devices */ /* Meet devices */
#ifdef AUDIO #ifdef AUDIO
DeviceError init_devices(ToxAV* av_) DeviceError init_devices(ToxAV *av_)
#else #else
DeviceError init_devices() DeviceError init_devices()
#endif /* AUDIO */ #endif /* AUDIO */
@ -103,6 +103,7 @@ DeviceError init_devices()
const char *stringed_device_list; const char *stringed_device_list;
size[input] = 0; size[input] = 0;
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) { if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
@ -113,7 +114,13 @@ DeviceError init_devices()
} }
size[output] = 0; 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); ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output] ) { for ( ; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output] ) {
@ -127,6 +134,7 @@ DeviceError init_devices()
return de_InternalError; return de_InternalError;
pthread_t thread_id; pthread_t thread_id;
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0) if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
return de_InternalError; return de_InternalError;
@ -155,9 +163,10 @@ DeviceError terminate_devices()
DeviceError device_mute(DeviceType type, uint32_t device_idx) DeviceError device_mute(DeviceType type, uint32_t device_idx)
{ {
if (device_idx >= MAX_DEVICES) return de_InvalidSelection; if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock; lock;
Device* device = running[type][device_idx]; Device *device = running[type][device_idx];
if (!device) { if (!device) {
unlock; 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) DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
{ {
if (device_idx >= MAX_DEVICES) return de_InvalidSelection; if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock; lock;
Device* device = running[input][device_idx]; Device *device = running[input][device_idx];
if (!device) { if (!device) {
unlock; 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) DeviceError set_primary_device(DeviceType type, int32_t selection)
{ {
if (size[type] <= selection || selection < 0) return de_InvalidSelection; if (size[type] <= selection || selection < 0) return de_InvalidSelection;
primary_device[type] = selection; primary_device[type] = selection;
return de_None; 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); 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 // 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; 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); const uint32_t frame_size = (sample_rate * frame_duration / 1000);
uint32_t i; uint32_t i;
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; ++i); for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; ++i);
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; } if (i == MAX_DEVICES) {
else *device_idx = i; unlock;
return de_AllDevicesBusy;
} else *device_idx = i;
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */ for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
if ( running[type][i] && running[type][i]->selection == 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->selection = selection;
device->sample_rate = sample_rate; device->sample_rate = sample_rate;
@ -254,12 +270,12 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
if (type == input) { if (type == input) {
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection], device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
sample_rate, device->sound_mode, frame_size * 2); sample_rate, device->sound_mode, frame_size * 2);
#ifdef AUDIO #ifdef AUDIO
device->VAD_treshold = user_settings->VAD_treshold; device->VAD_treshold = user_settings->VAD_treshold;
#endif #endif
} } else {
else {
device->dhndl = alcOpenDevice(devices_names[type][selection]); device->dhndl = alcOpenDevice(devices_names[type][selection]);
if ( !device->dhndl ) { if ( !device->dhndl ) {
free(device); free(device);
running[type][*device_idx] = NULL; 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); alSourcei(device->source, AL_LOOPING, AL_FALSE);
uint16_t zeros[frame_size]; uint16_t zeros[frame_size];
memset(zeros, 0, frame_size*2); memset(zeros, 0, frame_size * 2);
for ( i = 0; i < OPENAL_BUFS; ++i ) { 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); 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; if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock; lock;
Device* device = running[type][device_idx]; Device *device = running[type][device_idx];
DeviceError rc = de_None; DeviceError rc = de_None;
if (!device) { if (!device) {
@ -317,32 +333,30 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
running[type][device_idx] = NULL; running[type][device_idx] = NULL;
if ( !device->ref_count ) { if ( !device->ref_count ) {
// printf("Closed device ");
if (type == input) { if (type == input) {
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError; if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
} } else {
else {
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx); if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
alDeleteSources(1, &device->source); alDeleteSources(1, &device->source);
alDeleteBuffers(OPENAL_BUFS, device->buffers); alDeleteBuffers(OPENAL_BUFS, device->buffers);
alcMakeContextCurrent(NULL); alcMakeContextCurrent(NULL);
if ( device->ctx ) alcDestroyContext(device->ctx); if ( device->ctx ) alcDestroyContext(device->ctx);
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError; if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
} }
free(device); free(device);
} } else device->ref_count--;
else device->ref_count--;
unlock; unlock;
return rc; 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) if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return de_InvalidSelection; return de_InvalidSelection;
@ -357,12 +371,12 @@ DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx
return de_None; 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) uint32_t sample_rate)
{ {
if (device_idx >= MAX_DEVICES) return de_InvalidSelection; 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; 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_PROCESSED, &processed);
alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued); alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
if(processed) { if (processed) {
ALuint bufids[processed]; ALuint bufids[processed];
alSourceUnqueueBuffers(device->source, processed, bufids); alSourceUnqueueBuffers(device->source, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1); alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0]; bufid = bufids[0];
} } else if (queued < 16) alGenBuffers(1, &bufid);
else if(queued < 16) alGenBuffers(1, &bufid);
else { else {
pthread_mutex_unlock(device->mutex); pthread_mutex_unlock(device->mutex);
return de_Busy; 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); alSourceQueueBuffers(device->source, 1, &bufid);
ALint state; ALint state;
alGetSourcei(device->source, AL_SOURCE_STATE, &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); pthread_mutex_unlock(device->mutex);
return de_None; 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. * 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; int32_t sample = 0;
while (true) while (1) {
{
lock; lock;
if (!thread_running) { if (!thread_running) {
unlock; unlock;
break; break;
} }
bool paused = thread_paused;
unlock; unlock;
if (thread_paused) usleep(10000); /* Wait for unpause. */ /* Wait for unpause. */
else if (paused) {
{ usleep(10000);
for (i = 0; i < size[input]; ++i) }
{
else {
for (i = 0; i < size[input]; ++i) {
lock; lock;
if (running[input][i] != NULL)
{ if (running[input][i] != NULL) {
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample); 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); 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; unlock;
continue; continue;
} }
Device* device = running[input][i];
Device *device = running[input][i];
int16_t frame[16000]; int16_t frame[16000];
alcCaptureSamples(device->dhndl, frame, f_size); 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); if ( device->cb ) device->cb(frame, f_size, device->cb_data);
} }
unlock; unlock;
} }
usleep(5000); usleep(5000);
} }
} }
@ -456,7 +477,7 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
pthread_exit(NULL); pthread_exit(NULL);
} }
void print_devices(ToxWindow* self, DeviceType type) void print_devices(ToxWindow *self, DeviceType type)
{ {
int i; int i;
@ -471,7 +492,7 @@ DeviceError selection_valid(DeviceType type, int32_t selection)
return (size[type] <= selection || selection < 0) ? de_InvalidSelection : de_None; 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) if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return NULL; return NULL;

View File

@ -52,11 +52,11 @@ typedef enum DeviceError {
de_AlError = -9, de_AlError = -9,
} DeviceError; } 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 #ifdef AUDIO
DeviceError init_devices(ToxAV* av); DeviceError init_devices(ToxAV *av);
#else #else
DeviceError init_devices(); DeviceError init_devices();
#endif /* AUDIO */ #endif /* AUDIO */
@ -64,8 +64,9 @@ DeviceError init_devices();
DeviceError terminate_devices(); DeviceError terminate_devices();
/* Callback handles ready data from INPUT device */ /* 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); DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
void* get_device_callback_data(uint32_t device_idx); void *data, bool enable_VAD);
void *get_device_callback_data(uint32_t device_idx);
/* toggle device mute */ /* toggle device mute */
DeviceError device_mute(DeviceType type, uint32_t device_idx); 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 #endif
DeviceError set_primary_device(DeviceType type, int32_t selection); 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 */ /* 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 */ /* Stop device */
DeviceError close_device(DeviceType type, uint32_t device_idx); DeviceError close_device(DeviceType type, uint32_t device_idx);
/* Write data to device */ /* 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); void get_primary_device_name(DeviceType type, char *buf, int size);
DeviceError selection_valid(DeviceType type, int32_t selection); DeviceError selection_valid(DeviceType type, int32_t selection);

View File

@ -25,10 +25,10 @@
#include <limits.h> #include <limits.h>
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/types.h> #include <sys/types.h>
#include <sys/dir.h> #include <sys/dir.h>
#else #else
#include <dirent.h> #include <dirent.h>
#endif /* ifdef __APPLE__ */ #endif /* ifdef __APPLE__ */
#include "windows.h" #include "windows.h"
@ -185,6 +185,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
int n_endchrs = strlen(endchrs); int n_endchrs = strlen(endchrs);
int strt = ctx->pos - s_len; int strt = ctx->pos - s_len;
int diff = match_len - s_len + n_endchrs; int diff = match_len - s_len + n_endchrs;
if (ctx->len + diff >= MAX_STR_SIZE) if (ctx->len + diff >= MAX_STR_SIZE)
return -1; return -1;

View File

@ -55,6 +55,7 @@ int avatar_send(Tox *m, uint32_t friendnum)
TOX_ERR_FILE_SEND err; TOX_ERR_FILE_SEND err;
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size, 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); NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
if (Avatar.size == 0) if (Avatar.size == 0)
return 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) { } else if (ft->state == FILE_TRANSFER_PAUSED) {
ft->state = FILE_TRANSFER_STARTED; ft->state = FILE_TRANSFER_STARTED;
} }
break; break;
case TOX_FILE_CONTROL_PAUSE: case TOX_FILE_CONTROL_PAUSE:

586
src/bootstrap.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <limits.h>
#include <curl/curl.h>
#include <tox/tox.h>
#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();
}
}

42
src/bootstrap.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
#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 */

View File

@ -48,9 +48,9 @@
#include "message_queue.h" #include "message_queue.h"
#ifdef AUDIO #ifdef AUDIO
#include "audio_call.h" #include "audio_call.h"
#ifdef VIDEO #ifdef VIDEO
#include "video_call.h" #include "video_call.h"
#endif /* VIDEO */ #endif /* VIDEO */
#endif /* AUDIO */ #endif /* AUDIO */
@ -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); write_to_log(msg, nick, ctx->log, false);
if (self->active_box != -1) 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 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, 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); write_to_log(action, nick, ctx->log, true);
if (self->active_box != -1) 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 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) static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *msg, size_t len)
@ -455,7 +459,7 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
char progline[MAX_STR_SIZE]; char progline[MAX_STR_SIZE];
init_progress_bar(progline); init_progress_bar(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", 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; ft->line_id = self->chatwin->hst->line_end->id + 2;
} else if (ft->state == FILE_TRANSFER_PAUSED) { /* transfer is resumed */ } else if (ft->state == FILE_TRANSFER_PAUSED) { /* transfer is resumed */
ft->state = FILE_TRANSFER_STARTED; ft->state = FILE_TRANSFER_STARTED;
@ -463,10 +467,12 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
break; break;
} }
case TOX_FILE_CONTROL_PAUSE: { case TOX_FILE_CONTROL_PAUSE: {
ft->state = FILE_TRANSFER_PAUSED; ft->state = FILE_TRANSFER_PAUSED;
break; break;
} }
case TOX_FILE_CONTROL_CANCEL: { case TOX_FILE_CONTROL_CANCEL: {
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name); snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
close_file_transfer(self, m, ft, -1, msg, notif_error); 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); tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL);
if (self->active_box != -1) if (self->active_box != -1)
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box, box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
"Incoming file: %s", filename ); self->active_box, "Incoming file: %s", filename );
else else
box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, &self->active_box, self->name, box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
"Incoming file: %s", filename ); &self->active_box, self->name, "Incoming file: %s", filename );
} }
static void chat_onGroupInvite(ToxWindow *self, Tox *m, uint32_t friendnumber, const char *invite_data, 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); memcpy(Friends.list[friendnumber].group_invite.data, invite_data, length);
Friends.list[friendnumber].group_invite.length = 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]; char name[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, name, friendnumber); 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\""); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Incoming audio call! Type: \"/answer\" or \"/reject\"");
if (self->ringing_sound == -1) 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) if (self->active_box != -1)
box_silent_notify2(self, NT_NOFOCUS | NT_WNDALERT_0, self->active_box, "Incoming audio call!"); 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
if (self->ringing_sound == -1) if (self->ringing_sound == -1)
sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound); sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound);
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
} }
@ -815,7 +823,7 @@ static void draw_infobox(ToxWindow *self)
if (x2 < INFOBOX_WIDTH || y2 < INFOBOX_HEIGHT) if (x2 < INFOBOX_WIDTH || y2 < INFOBOX_HEIGHT)
return; return;
uint64_t curtime = get_unix_time(); time_t curtime = get_unix_time();
/* update elapsed time string once per second */ /* update elapsed time string once per second */
if (curtime > infobox->lastupdate) if (curtime > infobox->lastupdate)
@ -852,7 +860,7 @@ static void draw_infobox(ToxWindow *self)
wprintw(infobox->win, "%.2f\n", infobox->vad_lvl); wprintw(infobox->win, "%.2f\n", infobox->vad_lvl);
wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_TTEE, ' ', ACS_LLCORNER, ' '); wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_TTEE, ' ', ACS_LLCORNER, ' ');
wrefresh(infobox->win); wnoutrefresh(infobox->win);
} }
#endif /* AUDIO */ #endif /* AUDIO */
@ -917,7 +925,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
diff = dir_match(self, m, ctx->line, L"/sendfile"); diff = dir_match(self, m, ctx->line, L"/sendfile");
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) { } else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
diff = dir_match(self, m, ctx->line, L"/avatar"); 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] = { const char status_cmd_list[3][8] = {
{"online"}, {"online"},
{"away"}, {"away"},
@ -940,8 +948,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else if (key == '\r') { } else if (key == '\r') {
rm_trailing_spaces_buf(ctx); rm_trailing_spaces_buf(ctx);
if (!wstring_is_empty(ctx->line)) if (!wstring_is_empty(ctx->line)) {
{
add_line_to_hist(ctx); add_line_to_hist(ctx);
wstrsubst(ctx->line, L'', L'\n'); wstrsubst(ctx->line, L'', L'\n');
@ -1019,9 +1026,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
case TOX_USER_STATUS_NONE: case TOX_USER_STATUS_NONE:
colour = GREEN; colour = GREEN;
break; break;
case TOX_USER_STATUS_AWAY: case TOX_USER_STATUS_AWAY:
colour = YELLOW; colour = YELLOW;
break; break;
case TOX_USER_STATUS_BUSY: case TOX_USER_STATUS_BUSY:
colour = RED; colour = RED;
break; 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)); int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x); wmove(self->window, y + 1, new_x);
wrefresh(self->window); wnoutrefresh(self->window);
#ifdef AUDIO #ifdef AUDIO
if (ctx->infobox.active) { if (ctx->infobox.active) {
draw_infobox(self); draw_infobox(self);
wrefresh(self->window);
} }
#endif #endif
if (self->help->active) if (self->help->active)

View File

@ -102,6 +102,7 @@ void cmd_groupaccept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
uint32_t groupnumber = tox_group_invite_accept(m, Friends.list[self->num].group_invite.data, uint32_t groupnumber = tox_group_invite_accept(m, Friends.list[self->num].group_invite.data,
Friends.list[self->num].group_invite.length, Friends.list[self->num].group_invite.length,
(uint8_t *) passwd, passwd_len, &err); (uint8_t *) passwd, passwd_len, &err);
if (err != TOX_ERR_GROUP_INVITE_ACCEPT_OK) { if (err != TOX_ERR_GROUP_INVITE_ACCEPT_OK) {
if (err == TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG) 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."); 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; TOX_ERR_GROUP_INVITE_FRIEND err;
if (!tox_group_invite_friend(m, groupnum, self->num, &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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d).", err);
return; return;
@ -192,6 +194,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return; return;
on_recv_error: on_recv_error:
switch (err) { switch (err) {
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND: 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
@ -284,6 +287,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return; return;
on_send_error: on_send_error:
switch (err) { switch (err) {
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
errmsg = "File transfer failed: Invalid friend."; errmsg = "File transfer failed: Invalid friend.";

View File

@ -33,7 +33,7 @@
#include "configdir.h" #include "configdir.h"
#include "misc_tools.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) void get_home_dir(char *home, int size)
{ {
struct passwd pwd; struct passwd pwd;
@ -102,8 +102,10 @@ char *get_user_config_dir(void)
return user_config_dir; 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) int create_user_config_dirs(char *path)
{ {

View File

@ -34,8 +34,23 @@
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif #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); char *get_user_config_dir(void);
/* get the user's home directory. */
void get_home_dir(char *home, int size); 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); int create_user_config_dirs(char *path);
#endif /* #define CONFIGDIR_H */ #endif /* #define CONFIGDIR_H */

93
src/curl_util.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include <curl/curl.h>
#include <tox/tox.h>
#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;
}

55
src/curl_util.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
#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 */

View File

@ -61,8 +61,8 @@ struct FileTransfer {
size_t index; size_t index;
uint64_t file_size; uint64_t file_size;
uint64_t position; uint64_t position;
uint64_t last_line_progress; /* The last time we updated the progress bar */ time_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_keep_alive; /* The last time we sent or received data */
uint32_t line_id; uint32_t line_id;
uint8_t file_id[TOX_FILE_ID_LENGTH]; uint8_t file_id[TOX_FILE_ID_LENGTH];
}; };

View File

@ -314,10 +314,10 @@ static void sort_blocklist_index(void)
qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block); 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.last_on = timestamp;
Friends.list[num].last_online.tm = *localtime((const time_t*)&timestamp); Friends.list[num].last_online.tm = *localtime((const time_t *)&timestamp);
/* if the format changes make sure TIME_STR_SIZE is the correct size */ /* if the format changes make sure TIME_STR_SIZE is the correct size */
const char *t = user_settings->timestamp_format; 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); fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", pkerr);
TOX_ERR_FRIEND_GET_LAST_ONLINE loerr; 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) if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK)
t = 0; t = 0;
@ -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) static void delete_friend(Tox *m, uint32_t f_num)
{ {
TOX_ERR_FRIEND_DELETE err; TOX_ERR_FRIEND_DELETE err;
if (tox_friend_delete(m, f_num, &err) != true) { if (tox_friend_delete(m, f_num, &err) != true) {
fprintf(stderr, "tox_friend_delete failed with error %d\n", err); fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
return; return;
@ -641,10 +642,12 @@ static void draw_del_popup(void)
wattron(PendingDelete.popup, A_BOLD); wattron(PendingDelete.popup, A_BOLD);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
if (blocklist_view == 0) if (blocklist_view == 0)
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name); wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
else else
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name); wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
wattroff(PendingDelete.popup, A_BOLD); 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); block_friend(m, f);
else else
unblock_friend(m, f); unblock_friend(m, f);
break; break;
case KEY_RIGHT: 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); select_friend(self, key, &Friends.num_selected, Friends.num_friends);
else else
select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked); select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked);
break; break;
} }
} }
@ -906,7 +911,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
return; 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); struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
wattron(self->window, A_BOLD); wattron(self->window, A_BOLD);
@ -966,9 +971,11 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
case TOX_USER_STATUS_NONE: case TOX_USER_STATUS_NONE:
colour = GREEN; colour = GREEN;
break; break;
case TOX_USER_STATUS_AWAY: case TOX_USER_STATUS_AWAY:
colour = YELLOW; colour = YELLOW;
break; break;
case TOX_USER_STATUS_BUSY: case TOX_USER_STATUS_BUSY:
colour = RED; colour = RED;
break; break;
@ -1043,7 +1050,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wattroff(self->window, COLOR_PAIR(BLUE)); wattroff(self->window, COLOR_PAIR(BLUE));
pthread_mutex_lock(&Winthread.lock); 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); pthread_mutex_unlock(&Winthread.lock);
if (last_seen != 0) { if (last_seen != 0) {
@ -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) static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{ {
assert(0); assert(0);
if( friend_number >= Friends.max_idx)
if ( friend_number >= Friends.max_idx)
return; return;
assert(0); 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 (Friends.list[friend_number].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) { 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)); Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
set_active_window(Friends.list[friend_number].chatwin); set_active_window(Friends.list[friend_number].chatwin);
} }

View File

@ -130,6 +130,7 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
break; break;
case TOX_ERR_FRIEND_ADD_NULL: case TOX_ERR_FRIEND_ADD_NULL:
/* fallthrough */ /* fallthrough */
default: default:
errmsg = "Faile to add friend: Unknown error."; errmsg = "Faile to add friend: Unknown error.";
@ -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]; 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) { 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
return; return;
@ -281,6 +283,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
case TOX_ERR_BOOTSTRAP_NULL: case TOX_ERR_BOOTSTRAP_NULL:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
break; break;
default: default:
break; 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) { if (err != TOX_ERR_GROUP_NEW_OK) {
switch (err) { switch (err) {
case TOX_ERR_GROUP_NEW_TOO_LONG: { 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; break;
} }
case TOX_ERR_GROUP_NEW_EMPTY: { case TOX_ERR_GROUP_NEW_EMPTY: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name cannot be empty."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name cannot be empty.");
break; break;
} }
default: { default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d).", err); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d).", err);
break; 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."); 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); tox_group_leave(m, groupnum, NULL, 0, NULL);
} else if (init == -2) { } 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); 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."); 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); tox_group_leave(m, groupnum, NULL, 0, NULL);
} else if (init == -2) { } 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); 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:"); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:");
cmd_myid(window, self, m, 0, NULL); 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, "");
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,
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); "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]) void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])

View File

@ -70,6 +70,7 @@ void cmd_ignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
} }
TOX_ERR_GROUP_TOGGLE_IGNORE err; TOX_ERR_GROUP_TOGGLE_IGNORE err;
if (!tox_group_toggle_ignore(m, self->num, peer_id, true, &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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to ignore %s (error %d).", nick, err);
return; 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: { case TOX_ERR_GROUP_MOD_REMOVE_PEER_OK: {
return; return;
} }
case TOX_ERR_GROUP_MOD_REMOVE_PEER_PERMISSIONS: { 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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to %s %s.", type_str, nick);
return; return;
} }
default: { 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; 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); struct tm tm_set = *localtime((const time_t *) &time_set);
char time_str[64]; char time_str[64];
strftime(time_str, sizeof(time_str), "%e %b %Y %H:%M:%S%p", &tm_set); 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); 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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban list entry with id %d has been removed.", ban_id);
return; return;
} }
case TOX_ERR_GROUP_MOD_REMOVE_BAN_PERMISSIONS: { 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unban peers.");
return; return;
} }
case TOX_ERR_GROUP_MOD_REMOVE_BAN_FAIL_ACTION: { 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID does not exist.");
return; return;
} }
default: { default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to remove ban list entry (error %d).", err); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to remove ban list entry (error %d).", err);
return; 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: { case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return; return;
} }
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to promote moderators.");
return; return;
} }
case TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT: { 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "This peer is already a moderator.");
return; return;
} }
default: { default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to promote peer to moderator (error %d).", err); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to promote peer to moderator (error %d).", err);
return; 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: { case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return; return;
} }
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Nice try."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Nice try.");
return; return;
} }
default: { 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; return;
} }
} }
@ -302,6 +318,7 @@ void cmd_mykey(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
char pk[TOX_GROUP_PEER_PUBLIC_KEY_SIZE]; char pk[TOX_GROUP_PEER_PUBLIC_KEY_SIZE];
TOX_ERR_GROUP_SELF_QUERY err; TOX_ERR_GROUP_SELF_QUERY err;
if (!tox_group_self_get_public_key(m, self->num, (uint8_t *) pk, &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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to fetch your public key (error %d)", err);
return; return;
@ -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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been set to %s.", passwd);
else else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been unset."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been unset.");
return; return;
} }
case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG: { 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; return;
} }
case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS: { 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the password.");
return; return;
} }
default: { default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set password (error %d).", err); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set password (error %d).", err);
return; 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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit has been set to %d.", maxpeers);
return; return;
} }
case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS: { 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the peer limit.");
return; return;
} }
default: { default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the peer limit (error %d).", err); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the peer limit (error %d).", err);
return; return;
@ -423,7 +447,8 @@ void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
return; 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_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE err;
tox_group_founder_set_privacy_state(m, self->num, 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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state has been set to %s.", pstate_str);
return; return;
} }
case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS: { 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the privacy state.");
return; return;
} }
default: { default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error setting privacy state (error %d).", err); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error setting privacy state (error %d).", err);
return; 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: { case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return; return;
} }
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { 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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to silence %s.", nick);
return; return;
} }
default: { default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to silence %s (error %d).", nick, err); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to silence %s (error %d).", nick, err);
return; 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: { case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return; return;
} }
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: { 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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unsilence %s.", nick);
return; return;
} }
default: { default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unsilence %s (error %d).", nick, err); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unsilence %s (error %d).", nick, err);
return; 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]) void cmd_rejoin(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
TOX_ERR_GROUP_RECONNECT err; TOX_ERR_GROUP_RECONNECT err;
if (!tox_group_reconnect(m, self->num, &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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to rejoin group (error %d).", err);
return; return;
@ -564,14 +596,17 @@ void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
/* handled below switch */ /* handled below switch */
break; break;
} }
case TOX_ERR_GROUP_TOPIC_SET_TOO_LONG: { 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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic length must not exceed %d.", TOX_GROUP_MAX_TOPIC_LENGTH);
return; return;
} }
case TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS: { 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."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the topic.");
return; return;
} }
default: { default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the topic (error %d).", err); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the topic (error %d).", err);
return; return;
@ -615,6 +650,7 @@ void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
} }
TOX_ERR_GROUP_TOGGLE_IGNORE err; TOX_ERR_GROUP_TOGGLE_IGNORE err;
if (!tox_group_toggle_ignore(m, self->num, peer_id, false, &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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unignore %s (error %d).", nick, err);
return; return;

View File

@ -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: { case TOX_ERR_GROUP_SELF_NAME_SET_OK: {
break; break;
} }
case TOX_ERR_GROUP_SELF_NAME_SET_TAKEN: { 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."); line_info_add(self, NULL, NULL, 0, SYS_MSG, 0, RED, "-!- That nick is already in use.");
break; break;
} }
default: { default: {
if (groupchats[i].time_connected > 0) if (groupchats[i].time_connected > 0)
line_info_add(self, NULL, NULL, 0, SYS_MSG, 0, RED, "-!- Failed to set nick (error %d).", err); line_info_add(self, NULL, NULL, 0, SYS_MSG, 0, RED, "-!- Failed to set nick (error %d).", err);
@ -512,7 +514,7 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum,
/* Only play sound if mentioned by someone else */ /* Only play sound if mentioned by someone else */
if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) { 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) if (self->active_box != -1)
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg); box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
@ -590,7 +592,8 @@ static void groupchat_onGroupPeerLimit(ToxWindow *self, Tox *m, uint32_t groupnu
char timefrmt[TIME_STR_SIZE]; char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt)); 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]; char tmp_event[MAX_STR_SIZE];
snprintf(tmp_event, sizeof(tmp_event), " set the peer limit to %d", peer_limit); 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]; char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt)); 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]; char tmp_event[MAX_STR_SIZE];
snprintf(tmp_event, sizeof(tmp_event), " set the group to %s.", state_str); snprintf(tmp_event, sizeof(tmp_event), " set the group to %s.", state_str);
@ -844,12 +848,15 @@ static void groupchat_onGroupRejected(ToxWindow *self, Tox *m, uint32_t groupnum
case TOX_GROUP_JOIN_FAIL_NAME_TAKEN: case TOX_GROUP_JOIN_FAIL_NAME_TAKEN:
msg = "Nick already in use. Change your nick and use the '/rejoin' command."; msg = "Nick already in use. Change your nick and use the '/rejoin' command.";
break; break;
case TOX_GROUP_JOIN_FAIL_PEER_LIMIT: case TOX_GROUP_JOIN_FAIL_PEER_LIMIT:
msg = "Group is full. Try again with the '/rejoin' command."; msg = "Group is full. Try again with the '/rejoin' command.";
break; break;
case TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD: case TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD:
msg = "Invalid password."; msg = "Invalid password.";
break; break;
case TOX_GROUP_JOIN_FAIL_UNKNOWN: case TOX_GROUP_JOIN_FAIL_UNKNOWN:
msg = "Failed to join group. Try again with the '/rejoin' command."; msg = "Failed to join group. Try again with the '/rejoin' command.";
break; break;
@ -892,24 +899,30 @@ static void groupchat_onGroupModeration(ToxWindow *self, Tox *m, uint32_t groupn
case TOX_GROUP_MOD_EVENT_KICK: 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); line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, RED, "-!- %s has been kicked by %s", tgt_name, src_name);
break; break;
case TOX_GROUP_MOD_EVENT_BAN: 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); line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, RED, "-!- %s has been banned by %s", tgt_name, src_name);
break; break;
case TOX_GROUP_MOD_EVENT_OBSERVER: case TOX_GROUP_MOD_EVENT_OBSERVER:
chat->peer_list[tgt_index].role = TOX_GROUP_ROLE_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); 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); sort_peerlist(groupnum);
break; break;
case TOX_GROUP_MOD_EVENT_USER: case TOX_GROUP_MOD_EVENT_USER:
chat->peer_list[tgt_index].role = TOX_GROUP_ROLE_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); 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); sort_peerlist(groupnum);
break; break;
case TOX_GROUP_MOD_EVENT_MODERATOR: case TOX_GROUP_MOD_EVENT_MODERATOR:
chat->peer_list[tgt_index].role = TOX_GROUP_ROLE_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); sort_peerlist(groupnum);
break; break;
default: default:
return; return;
} }
@ -973,6 +986,7 @@ static void send_group_message(ToxWindow *self, Tox *m, uint32_t groupnum, const
} }
TOX_ERR_GROUP_SEND_MESSAGE err; TOX_ERR_GROUP_SEND_MESSAGE err;
if (!tox_group_send_message(m, groupnum, type, (uint8_t *) msg, strlen(msg), &err)) { if (!tox_group_send_message(m, groupnum, type, (uint8_t *) msg, strlen(msg), &err)) {
if (err == TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS) { if (err == TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * You are silenced."); 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; const char *msg = data + name_length + 1;
TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE err; TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE err;
if (!tox_group_send_private_message(m, groupnum, peer_id, (uint8_t *) msg, msg_len, &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) { if (err == TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PERMISSIONS) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * You are silenced."); 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); mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
pthread_mutex_unlock(&Winthread.lock);
wmove(ctx->sidebar, 0, 1); wmove(ctx->sidebar, 0, 1);
wattron(ctx->sidebar, A_BOLD); wattron(ctx->sidebar, A_BOLD);
@ -1231,6 +1247,9 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
char tmpnck[TOX_MAX_NAME_LENGTH]; char tmpnck[TOX_MAX_NAME_LENGTH];
int maxlen = SIDEBAR_WIDTH - maxlen_offset; int maxlen = SIDEBAR_WIDTH - maxlen_offset;
memcpy(tmpnck, chat->peer_list[p].name, maxlen); memcpy(tmpnck, chat->peer_list[p].name, maxlen);
pthread_mutex_lock(&Winthread.lock);
pthread_mutex_unlock(&Winthread.lock);
tmpnck[maxlen] = '\0'; tmpnck[maxlen] = '\0';
int namecolour = WHITE; int namecolour = WHITE;

View File

@ -323,7 +323,7 @@ static void help_draw_contacts(ToxWindow *self)
void help_onKey(ToxWindow *self, wint_t key) void help_onKey(ToxWindow *self, wint_t key)
{ {
switch(key) { switch (key) {
case 'x': case 'x':
case T_KEY_ESC: case T_KEY_ESC:
help_exit(self); help_exit(self);
@ -377,7 +377,7 @@ void help_onDraw(ToxWindow *self)
{ {
curs_set(0); curs_set(0);
switch(self->help->type) { switch (self->help->type) {
case HELP_MENU: case HELP_MENU:
help_draw_menu(self); help_draw_menu(self);
return; return;

View File

@ -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; self->show_peerlist ^= 1;
redraw_groupchat_win(self); redraw_groupchat_win(self);
} }
match = true; match = true;
} } else if (key == user_settings->key_toggle_pastemode) {
else if (key == user_settings->key_toggle_pastemode) {
self->chatwin->pastemode ^= 1; self->chatwin->pastemode ^= 1;
match = true; match = true;
} }

View File

@ -158,12 +158,14 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
/* for type-specific formatting in print function */ /* for type-specific formatting in print function */
switch (type) { switch (type) {
case IN_ACTION: case IN_ACTION:
/* fallthrough */ /* fallthrough */
case OUT_ACTION: case OUT_ACTION:
len += strlen(user_settings->line_normal) + 2; len += strlen(user_settings->line_normal) + 2;
break; break;
case IN_MSG: case IN_MSG:
/* fallthrough */ /* fallthrough */
case OUT_MSG: case OUT_MSG:
len += strlen(user_settings->line_normal) + 3; len += strlen(user_settings->line_normal) + 3;
@ -309,8 +311,10 @@ void line_info_print(ToxWindow *self)
switch (type) { switch (type) {
case OUT_MSG: case OUT_MSG:
/* fallthrough */ /* fallthrough */
case OUT_MSG_READ: case OUT_MSG_READ:
/* fallthrough */ /* fallthrough */
case IN_MSG: case IN_MSG:
case IN_PRVT_MSG: case IN_PRVT_MSG:
@ -327,16 +331,16 @@ void line_info_print(ToxWindow *self)
nameclr = CYAN; nameclr = CYAN;
wattron(win, COLOR_PAIR(nameclr)); wattron(win, COLOR_PAIR(nameclr));
wprintw(win, "%s %s: ",(type != OUT_PRVT_MSG && type != IN_PRVT_MSG) ? wprintw(win, "%s %s: ", (type != OUT_PRVT_MSG && type != IN_PRVT_MSG) ?
user_settings->line_normal : user_settings->line_normal :
user_settings->line_special, user_settings->line_special,
line->name1); line->name1);
wattroff(win, COLOR_PAIR(nameclr)); wattroff(win, COLOR_PAIR(nameclr));
char* msg = line->msg; char *msg = line->msg;
while (msg)
{ while (msg) {
char* line = strsep(&msg, "\n"); char *line = strsep(&msg, "\n");
if (line[0] == '>') if (line[0] == '>')
wattron(win, COLOR_PAIR(GREEN)); wattron(win, COLOR_PAIR(GREEN));
@ -370,8 +374,10 @@ void line_info_print(ToxWindow *self)
break; break;
case OUT_ACTION_READ: case OUT_ACTION_READ:
/* fallthrough */ /* fallthrough */
case OUT_ACTION: case OUT_ACTION:
/* fallthrough */ /* fallthrough */
case IN_ACTION: case IN_ACTION:
wattron(win, COLOR_PAIR(BLUE)); wattron(win, COLOR_PAIR(BLUE));
@ -558,20 +564,15 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
if (key == user_settings->key_half_page_up) { if (key == user_settings->key_half_page_up) {
line_info_page_up(self, hst); 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); 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); 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); 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); line_info_reset_start(self, hst);
} } else {
else {
match = false; match = false;
} }

View File

@ -52,7 +52,7 @@ struct line_info {
char name1[TOXIC_MAX_NAME_LENGTH + 1]; char name1[TOXIC_MAX_NAME_LENGTH + 1];
char name2[TOXIC_MAX_NAME_LENGTH + 1]; char name2[TOXIC_MAX_NAME_LENGTH + 1];
char msg[MAX_LINE_INFO_MSG_SIZE]; char msg[MAX_LINE_INFO_MSG_SIZE];
uint64_t timestamp; time_t timestamp;
uint8_t type; uint8_t type;
uint8_t bold; uint8_t bold;
uint8_t colour; uint8_t colour;

View File

@ -262,6 +262,7 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
return 0; return 0;
on_error: on_error:
if (log_on) if (log_on)
log_enable(src, selfkey, otherkey, log, LOG_CHAT); log_enable(src, selfkey, otherkey, log, LOG_CHAT);

View File

@ -25,7 +25,7 @@
struct chatlog { struct chatlog {
FILE *file; FILE *file;
uint64_t lastwrite; time_t lastwrite;
char path[MAX_STR_SIZE]; char path[MAX_STR_SIZE];
bool log_on; /* specific to current chat window */ bool log_on; /* specific to current chat window */
}; };

View File

@ -29,7 +29,7 @@ struct cqueue_msg {
int line_id; int line_id;
uint8_t type; uint8_t type;
uint32_t receipt; uint32_t receipt;
uint64_t last_send_try; time_t last_send_try;
struct cqueue_msg *next; struct cqueue_msg *next;
struct cqueue_msg *prev; struct cqueue_msg *prev;
}; };

View File

@ -26,7 +26,9 @@
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
#include <dirent.h> #include <dirent.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <arpa/inet.h>
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
@ -37,8 +39,6 @@
extern ToxWindow *prompt; extern ToxWindow *prompt;
extern struct user_settings *user_settings; extern struct user_settings *user_settings;
static uint64_t current_unix_time;
void hst_to_net(uint8_t *num, uint16_t numbytes) void hst_to_net(uint8_t *num, uint16_t numbytes)
{ {
#ifndef WORDS_BIGENDIAN #ifndef WORDS_BIGENDIAN
@ -54,19 +54,13 @@ void hst_to_net(uint8_t *num, uint16_t numbytes)
return; return;
} }
/* Note: The time functions are not thread safe */ time_t get_unix_time(void)
void update_unix_time(void)
{ {
current_unix_time = (uint64_t) time(NULL); return time(NULL);
}
uint64_t get_unix_time(void)
{
return current_unix_time;
} }
/* Returns 1 if connection has timed out, 0 otherwise */ /* 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(); 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 *get_time(void)
{ {
struct tm *timeinfo; struct tm *timeinfo;
uint64_t t = get_unix_time(); time_t t = get_unix_time();
timeinfo = localtime((const time_t*) &t); timeinfo = localtime((const time_t *) &t);
return timeinfo; 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 */ /* 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) if (!secs)
return; 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; size_t i;
for (i = 0; i < TOX_ADDRESS_SIZE; ++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; return 0;
} }
@ -211,7 +205,7 @@ int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n)
if (n < len) if (n < len)
return -1; return -1;
if ((len = mbstowcs(buf, string, n)) == (size_t) -1) if ((len = mbstowcs(buf, string, n)) == (size_t) - 1)
return -1; return -1;
return len; return len;
@ -225,7 +219,7 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n)
if (n < len) if (n < len)
return -1; return -1;
if ((len = wcstombs(buf, string, n)) == (size_t) -1) if ((len = wcstombs(buf, string, n)) == (size_t) - 1)
return -1; return -1;
return len; return len;
@ -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 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) int char_find(int idx, const char *s, char ch)
{ {
if (!s) {
return 0;
}
int i = idx; int i = idx;
for (i = idx; s[i]; ++i) { 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 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) int char_rfind(const char *s, char ch, int len)
{ {
if (!s) {
return 0;
}
int i = 0; int i = 0;
for (i = len; i > 0; --i) { 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); 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;
}

View File

@ -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); 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) */ /* 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) */ /* Puts the current time in buf in the format of [HH:mm:ss] (not thread safe) */
void get_time_str(char *buf, int bufsize); void get_time_str(char *buf, int bufsize);
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */ /* 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 */ /* 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); 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) */ /* get the current local time (not thread safe) */
struct tm *get_time(void); 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 */ /* Returns 1 if the string is empty, 0 otherwise */
int string_is_empty(const char *string); 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); int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
/* Returns 1 if connection has timed out, 0 otherwise */ /* 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 */ /* Colours the window tab according to type. Beeps if is_beep is true */
void alert_window(ToxWindow *self, int type, bool is_beep); 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); 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 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); int char_find(int idx, const char *s, char ch);
/* returns index of the last instance of ch in s /* returns index of the last instance of ch in s starting at len.
returns 0 if char not found */ returns 0 if char not found or s is NULL (skips 0th index). */
int char_rfind(const char *s, char ch, int len); int char_rfind(const char *s, char ch, int len);
/* Converts bytes to appropriate unit and puts in buf as a string */ /* 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. */ /* sets window title in tab bar. */
void set_window_title(ToxWindow *self, const char *title, int len); 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 */ #endif /* #define MISC_TOOLS_H */

View File

@ -22,7 +22,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> /* for u_char */
#include <curl/curl.h> #include <curl/curl.h>
#include "toxic.h" #include "toxic.h"
@ -31,9 +30,10 @@
#include "global_commands.h" #include "global_commands.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "configdir.h" #include "configdir.h"
#include "curl_util.h"
extern struct arg_opts arg_opts; extern struct arg_opts arg_opts;
extern struct Winthread Winthread;; extern struct Winthread Winthread;
#define NAMESERVER_API_PATH "api" #define NAMESERVER_API_PATH "api"
#define SERVER_KEY_SIZE 32 #define SERVER_KEY_SIZE 32
@ -41,9 +41,6 @@ extern struct Winthread Winthread;;
#define MAX_DOMAIN_SIZE 32 #define MAX_DOMAIN_SIZE 32
#define MAX_SERVER_LINE MAX_DOMAIN_SIZE + (SERVER_KEY_SIZE * 2) + 3 #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 { struct Nameservers {
int lines; int lines;
char names[MAX_SERVERS][MAX_DOMAIN_SIZE]; char names[MAX_SERVERS][MAX_DOMAIN_SIZE];
@ -56,8 +53,8 @@ static struct thread_data {
char id_bin[TOX_ADDRESS_SIZE]; char id_bin[TOX_ADDRESS_SIZE];
char addr[MAX_STR_SIZE]; char addr[MAX_STR_SIZE];
char msg[MAX_STR_SIZE]; char msg[MAX_STR_SIZE];
bool busy;
bool disabled; bool disabled;
volatile bool busy;
} t_data; } t_data;
static struct lookup_thread { 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; 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. /* Converts Tox ID string contained in recv_data to binary format and puts it in thread's ID buffer.
* *
* Returns 0 on success. * Returns 0 on success.
* Returns -1 on failure. * Returns -1 on failure.
*/ */
#define ID_PREFIX "\"tox_id\": \"" #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); 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; return -1;
const char *IDstart = strstr(recv_data->data, ID_PREFIX); const char *IDstart = strstr(recv_data->data, ID_PREFIX);
@ -243,47 +217,6 @@ static int process_response(struct Recv_Data *recv_data)
return 0; 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) void *lookup_thread_func(void *data)
{ {
ToxWindow *self = t_data.self; 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 (!get_domain_match(nameserver_key, real_domain, sizeof(real_domain), input_domain)) {
if (!strcasecmp(input_domain, "utox.org")) 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 else
lookup_error(self, "Name server domain not found."); lookup_error(self, "Name server domain not found.");
@ -315,26 +248,38 @@ void *lookup_thread_func(void *data)
kill_lookup_thread(); kill_lookup_thread();
} }
struct Recv_Data recv_data; struct Recv_Curl_Data recv_data;
memset(&recv_data, 0, sizeof(struct Recv_Data));
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
char post_data[MAX_STR_SIZE]; char post_data[MAX_STR_SIZE];
snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name); snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name);
struct curl_slist *headers = NULL; struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json"); headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charsets: utf-8"); headers = curl_slist_append(headers, "charsets: utf-8");
curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(c_handle, CURLOPT_URL, real_domain); 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_WRITEDATA, &recv_data);
curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(c_handle, CURLOPT_POSTFIELDS, post_data); 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; goto on_exit;
}
int ret = curl_easy_setopt(c_handle, CURLOPT_USE_SSL, CURLUSESSL_ALL); 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 -2 if the nameserver list cannot be found.
* Returns -3 if the nameserver list does not contain any valid entries. * 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; t_data.disabled = true;
return -1; return -1;
} }
@ -454,8 +399,3 @@ int name_lookup_init(void)
return 0; return 0;
} }
void name_lookup_cleanup(void)
{
curl_global_cleanup();
}

View File

@ -29,8 +29,7 @@
* Returns 0 on success. * Returns 0 on success.
* Returns -1 on failure. * Returns -1 on failure.
*/ */
int name_lookup_init(void); int name_lookup_init(int curl_init_status);
void name_lookup_cleanup(void);
int name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message); int name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message);

View File

@ -38,24 +38,24 @@
#include "xtra.h" #include "xtra.h"
#if defined(AUDIO) || defined(SOUND_NOTIFY) #if defined(AUDIO) || defined(SOUND_NOTIFY)
#ifdef __APPLE__ #ifdef __APPLE__
#include <OpenAL/al.h> #include <OpenAL/al.h>
#include <OpenAL/alc.h> #include <OpenAL/alc.h>
#else #else
#include <AL/al.h> #include <AL/al.h>
#include <AL/alc.h> #include <AL/alc.h>
/* compatibility with older versions of OpenAL */ /* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER #ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h> #include <AL/alext.h>
#endif #endif
#endif #endif
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
#include <AL/alut.h> /* freealut packet */ #include <AL/alut.h> /* freealut packet */
#endif #endif
#endif /* AUDIO */ #endif /* AUDIO */
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
#include <libnotify/notify.h> #include <libnotify/notify.h>
#endif #endif
#define MAX_BOX_MSG_LEN 127 #define MAX_BOX_MSG_LEN 127
@ -75,7 +75,7 @@ struct Control {
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
uint32_t device_idx; /* index of output device */ uint32_t device_idx; /* index of output device */
char* sounds[SOUNDS_SIZE]; char *sounds[SOUNDS_SIZE];
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
} Control = {0}; } Control = {0};
@ -88,7 +88,7 @@ struct _ActiveNotifications {
bool active; bool active;
int *id_indicator; int *id_indicator;
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
NotifyNotification* box; NotifyNotification *box;
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1]; char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
char title[64]; char title[64];
size_t size; size_t size;
@ -188,15 +188,17 @@ void graceful_clear()
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) { for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].active) { if (actives[i].active) {
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
if (actives[i].box) { if (actives[i].box) {
GError* ignore; GError *ignore;
notify_notification_close(actives[i].box, &ignore); notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL; actives[i].box = NULL;
} }
#endif
if(actives[i].id_indicator) #endif
if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */ *actives[i].id_indicator = -1; /* reset indicator value */
if ( actives[i].looping ) { if ( actives[i].looping ) {
@ -221,11 +223,11 @@ void graceful_clear()
control_unlock(); control_unlock();
} }
void* do_playing(void* _p) void *do_playing(void *_p)
{ {
(void)_p; (void)_p;
while(true) { while (true) {
control_lock(); control_lock();
if (!Control.poll_active) { if (!Control.poll_active) {
@ -240,12 +242,14 @@ void* do_playing(void* _p)
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) { for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].looping) has_looping = true; if (actives[i].looping) has_looping = true;
test_active_notify = actives[i].active && !actives[i].looping; test_active_notify = actives[i].active && !actives[i].looping;
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
test_active_notify = test_active_notify && !actives[i].box; test_active_notify = test_active_notify && !actives[i].box;
#endif #endif
if (test_active_notify) { if (test_active_notify) {
if(actives[i].id_indicator) if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */ *actives[i].id_indicator = -1; /* reset indicator value */
if (!is_playing(actives[i].source)) { if (!is_playing(actives[i].source)) {
@ -256,13 +260,14 @@ void* do_playing(void* _p)
memset(&actives[i], 0, sizeof(struct _ActiveNotifications)); memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
} }
} }
#ifdef BOX_NOTIFY
else if (actives[i].box && time(NULL) >= actives[i].n_timeout) #ifdef BOX_NOTIFY
{ else if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
GError* ignore; GError *ignore;
notify_notification_close(actives[i].box, &ignore); notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL; actives[i].box = NULL;
if(actives[i].id_indicator)
if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */ *actives[i].id_indicator = -1; /* reset indicator value */
if (!actives[i].looping && !is_playing(actives[i].source)) { if (!actives[i].looping && !is_playing(actives[i].source)) {
@ -273,7 +278,8 @@ void* do_playing(void* _p)
memset(&actives[i], 0, sizeof(struct _ActiveNotifications)); memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
} }
} }
#endif
#endif
} }
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/ /* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
@ -281,18 +287,22 @@ void* do_playing(void* _p)
(time(NULL) - last_opened_update) > DEVICE_COOLDOWN) { (time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
m_close_device(); m_close_device();
} }
has_looping = false; has_looping = false;
control_unlock(); control_unlock();
usleep(10000); usleep(10000);
} }
pthread_exit(NULL); pthread_exit(NULL);
} }
int play_source(uint32_t source, uint32_t buffer, bool looping) int play_source(uint32_t source, uint32_t buffer, bool looping)
{ {
int i = 0; int i = 0;
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++); for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
if ( i == ACTIVE_NOTIFS_MAX ) { if ( i == ACTIVE_NOTIFS_MAX ) {
return -1; /* Full */ return -1; /* Full */
} }
@ -308,11 +318,11 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
} }
#elif BOX_NOTIFY #elif BOX_NOTIFY
void* do_playing(void* _p) void *do_playing(void *_p)
{ {
(void)_p; (void)_p;
while(true) { while (true) {
control_lock(); control_lock();
if (!Control.poll_active) { if (!Control.poll_active) {
@ -323,20 +333,22 @@ void* do_playing(void* _p)
int i; int i;
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) { for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].box && time(NULL) >= actives[i].n_timeout) if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
{ GError *ignore;
GError* ignore;
notify_notification_close(actives[i].box, &ignore); notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL; actives[i].box = NULL;
if(actives[i].id_indicator)
if (actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */ *actives[i].id_indicator = -1; /* reset indicator value */
memset(&actives[i], 0, sizeof(struct _ActiveNotifications)); memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
} }
} }
control_unlock(); control_unlock();
usleep(10000); usleep(10000);
} }
pthread_exit(NULL); pthread_exit(NULL);
} }
@ -347,7 +359,7 @@ void graceful_clear()
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) { for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].box) { if (actives[i].box) {
GError* ignore; GError *ignore;
notify_notification_close(actives[i].box, &ignore); notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL; actives[i].box = NULL;
} }
@ -378,6 +390,7 @@ int init_notify(int login_cooldown, int notification_timeout)
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) #if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0) if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
return -1; return -1;
@ -419,7 +432,9 @@ void terminate_notify()
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
int i = 0; int i = 0;
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]); for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
alutExit(); alutExit();
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
@ -429,7 +444,7 @@ void terminate_notify()
} }
#ifdef SOUND_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; if (sound == silent) return 0;
@ -457,10 +472,11 @@ int play_sound_internal(Notification what, bool loop)
alSourcei(source, AL_LOOPING, loop); alSourcei(source, AL_LOOPING, loop);
int rc = play_source(source, buffer, loop); int rc = play_source(source, buffer, loop);
if (rc < 0) { if (rc < 0) {
alSourceStop(source); alSourceStop(source);
alDeleteSources(1, &source); alDeleteSources(1, &source);
alDeleteBuffers(1,&buffer); alDeleteBuffers(1, &buffer);
return -1; return -1;
} }
@ -472,7 +488,8 @@ int play_notify_sound(Notification notif, uint64_t flags)
int rc = -1; int rc = -1;
if (flags & NT_BEEP) beep(); if (flags & NT_BEEP) beep();
else if (notif != silent) {
if (notif != silent) {
if ( !Control.poll_active || !Control.sounds[notif] ) if ( !Control.poll_active || !Control.sounds[notif] )
return -1; return -1;
@ -487,17 +504,21 @@ void stop_sound(int id)
{ {
if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active ) { if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active ) {
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
if (actives[id].box) { if (actives[id].box) {
GError* ignore; GError *ignore;
notify_notification_close(actives[id].box, &ignore); notify_notification_close(actives[id].box, &ignore);
} }
#endif #endif
if (actives[id].id_indicator) if (actives[id].id_indicator)
*actives[id].id_indicator = -1; *actives[id].id_indicator = -1;
// alSourcei(actives[id].source, AL_LOOPING, false); // alSourcei(actives[id].source, AL_LOOPING, false);
alSourceStop(actives[id].source); alSourceStop(actives[id].source);
alDeleteSources(1, &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)); memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
} }
} }
@ -508,6 +529,7 @@ static int m_play_sound(Notification notif, uint64_t flags)
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
return play_notify_sound(notif, flags); return play_notify_sound(notif, flags);
#else #else
if (notif != silent) if (notif != silent)
beep(); beep();
@ -516,12 +538,12 @@ static int m_play_sound(Notification notif, uint64_t flags)
} }
#ifdef BOX_NOTIFY #ifdef BOX_NOTIFY
void m_notify_action(NotifyNotification *box, char *action, void* data) void m_notify_action(NotifyNotification *box, char *action, void *data)
{ {
} }
#endif #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); tab_notify(self, flags);
@ -540,6 +562,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
if (id == -1) { if (id == -1) {
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++); for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++);
if ( id == ACTIVE_NOTIFS_MAX ) { if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock(); control_unlock();
return -1; /* Full */ return -1; /* Full */
@ -558,7 +581,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
return id; 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); tab_notify(self, flags);
@ -566,6 +589,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
return -1; return -1;
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1; if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
control_lock(); control_lock();
@ -578,7 +602,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
alSourceStop(actives[id].source); alSourceStop(actives[id].source);
alDeleteSources(1, &actives[id].source); alDeleteSources(1, &actives[id].source);
alDeleteBuffers(1,&actives[id].buffer); alDeleteBuffers(1, &actives[id].buffer);
alGenSources(1, &actives[id].source); alGenSources(1, &actives[id].source);
alGenBuffers(1, &actives[id].buffer); alGenBuffers(1, &actives[id].buffer);
@ -592,6 +616,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
return id; return id;
#else #else
if (notif != silent) if (notif != silent)
beep(); beep();
@ -599,7 +624,8 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
#endif /* SOUND_NOTIFY */ #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)) { if (notifications_are_disabled(flags)) {
tab_notify(self, flags); tab_notify(self, flags);
@ -613,9 +639,11 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
control_lock(); control_lock();
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
if (id == -1) { /* Could not play */ if (id == -1) { /* Could not play */
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++); for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
if ( id == ACTIVE_NOTIFS_MAX ) { if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock(); control_unlock();
return -1; /* Full */ 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].active = 1;
actives[id].id_indicator = id_indicator; actives[id].id_indicator = id_indicator;
if (id_indicator) *id_indicator = id; if (id_indicator) *id_indicator = id;
} }
#else #else
if (id == -1) if (id == -1)
return -1; return -1;
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title); snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
if (strlen(title) > 23) strcpy(actives[id].title + 20, "..."); 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__); vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__); va_end (__ARGS__);
@ -656,7 +690,7 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
#endif /* BOX_NOTIFY */ #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)) { if (notifications_are_disabled(flags)) {
tab_notify(self, flags); tab_notify(self, flags);
@ -675,7 +709,8 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
return -1; 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__); vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__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'}; char formated[128 * 129] = {'\0'};
int i = 0; int i = 0;
for (; i <actives[id].size; i ++) {
for (; i < actives[id].size; i ++) {
strcat(formated, actives[id].messages[i]); strcat(formated, actives[id].messages[i]);
strcat(formated, "\n"); strcat(formated, "\n");
} }
@ -706,7 +742,7 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
#endif #endif
} }
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...) int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const char *title, const char *format, ...)
{ {
tab_notify(self, flags); tab_notify(self, flags);
@ -718,7 +754,9 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
control_lock(); control_lock();
int id; int id;
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++); for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
if ( id == ACTIVE_NOTIFS_MAX ) { if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock(); control_unlock();
return -1; /* Full */ return -1; /* Full */
@ -730,9 +768,11 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
} }
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title); snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
if (strlen(title) > 23) strcpy(actives[id].title + 20, "..."); 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__); vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__); va_end (__ARGS__);
@ -756,7 +796,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
#endif #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); 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__); vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__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'}; char formated[128 * 129] = {'\0'};
int i = 0; int i = 0;
for (; i <actives[id].size; i ++) {
for (; i < actives[id].size; i ++) {
strcat(formated, actives[id].messages[i]); strcat(formated, actives[id].messages[i]);
strcat(formated, "\n"); strcat(formated, "\n");
} }

View File

@ -26,8 +26,7 @@
#include <inttypes.h> #include <inttypes.h>
#include "windows.h" #include "windows.h"
typedef enum _Notification typedef enum _Notification {
{
silent = -1, silent = -1,
notif_error, notif_error,
self_log_in, self_log_in,
@ -63,18 +62,19 @@ typedef enum _Flags {
int init_notify(int login_cooldown, int notification_timeout); int init_notify(int login_cooldown, int notification_timeout);
void terminate_notify(); void terminate_notify();
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);
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id); int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id);
void stop_sound(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_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator, const char *title,
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...); const char *format, ...);
int box_silent_notify(ToxWindow* self, 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_notify2(ToxWindow* self, 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 #ifdef SOUND_NOTIFY
int set_sound(Notification sound, const char* value); int set_sound(Notification sound, const char *value);
#endif /* SOUND_NOTIFY */ #endif /* SOUND_NOTIFY */
#endif /* NOTIFY_H */ #endif /* NOTIFY_H */

View File

@ -36,8 +36,11 @@
void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height); 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__ #ifdef __OBJC__
@interface OSXVideo : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate> @interface OSXVideo :
- (instancetype)initWithDeviceNames:(char **)device_names AmtDevices:(int *)size; NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
- (instancetype)initWithDeviceNames:
(char **)device_names AmtDevices:
(int *)size;
@end @end
#endif /* __OBJC__ */ #endif /* __OBJC__ */

View File

@ -44,19 +44,19 @@
static uint8_t rgb_to_y(int r, int g, int b) static uint8_t rgb_to_y(int r, int g, int b)
{ {
int y = ((9798 * r + 19235 * g + 3736 * b) >> 15); 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) static uint8_t rgb_to_u(int r, int g, int b)
{ {
int u = ((-5538 * r + -10846 * g + 16351 * b) >> 15) + 128; 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) static uint8_t rgb_to_v(int r, int g, int b)
{ {
int v = ((16351 * r + -13697 * g + -2664 * b) >> 15) + 128; 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) 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 *p;
uint8_t r, g, b; uint8_t r, g, b;
for(y = 0; y != height; y += 2) { for (y = 0; y != height; y += 2) {
p = rgb; p = rgb;
for(x = 0; x != width; x++) {
for (x = 0; x != width; x++) {
b = *rgb++; b = *rgb++;
g = *rgb++; g = *rgb++;
r = *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); *plane_y++ = rgb_to_y(r, g, b);
} }
for(x = 0; x != width / 2; x++) { for (x = 0; x != width / 2; x++) {
b = *rgb++; b = *rgb++;
g = *rgb++; g = *rgb++;
r = *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); *plane_y++ = rgb_to_y(r, g, b);
b = ((int)b + (int)*(rgb - 8) + (int)*p + (int)*(p + 4) + 2) / 4; p++; b = ((int)b + (int) * (rgb - 8) + (int) * p + (int) * (p + 4) + 2) / 4;
g = ((int)g + (int)*(rgb - 7) + (int)*p + (int)*(p + 4) + 2) / 4; p++; p++;
r = ((int)r + (int)*(rgb - 6) + (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++; p++;
*plane_u++ = rgb_to_u(r, g, b); *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; BOOL _shouldMangleDimensions;
} }
- (instancetype)initWithDeviceNames: (char **)device_names AmtDevices: (int *)size { - (instancetype)initWithDeviceNames:
(char **)device_names AmtDevices:
(int *)size {
_session = [[AVCaptureSession alloc] init]; _session = [[AVCaptureSession alloc] init];
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
int i; int i;
for (i = 0; i < [devices count]; ++i) { for (i = 0; i < [devices count]; ++i) {
AVCaptureDevice *device = [devices objectAtIndex:i]; AVCaptureDevice *device = [devices objectAtIndex: i];
char *video_input_name; char *video_input_name;
NSString *localizedName = [device localizedName]; NSString *localizedName = [device localizedName];
video_input_name = (char*)malloc(strlen([localizedName cStringUsingEncoding:NSUTF8StringEncoding]) + 1); video_input_name = (char *)malloc(strlen([localizedName cStringUsingEncoding: NSUTF8StringEncoding]) + 1);
strcpy(video_input_name, (char*)[localizedName cStringUsingEncoding:NSUTF8StringEncoding]); strcpy(video_input_name, (char *)[localizedName cStringUsingEncoding: NSUTF8StringEncoding]);
device_names[i] = video_input_name; device_names[i] = video_input_name;
} }
if ( i <= 0 ) if ( i <= 0 )
return nil; return nil;
*size = i; *size = i;
return self; return self;
@ -151,14 +159,17 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
[super dealloc]; [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_init(&_frameLock, NULL);
pthread_mutex_lock(&_frameLock); pthread_mutex_lock(&_frameLock);
_processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL); _processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL);
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
AVCaptureDevice *device = [devices objectAtIndex:device_idx]; AVCaptureDevice *device = [devices objectAtIndex: device_idx];
NSError *error = NULL; NSError *error = NULL;
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error]; AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
if ( error != NULL ) { if ( error != NULL ) {
[input release]; [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 beginConfiguration];
[_session addInput:input]; [_session addInput: input];
//_session.sessionPreset = AVCaptureSessionPreset640x480; //_session.sessionPreset = AVCaptureSessionPreset640x480;
//*width = 640; //*width = 640;
//*height = 480; //*height = 480;
@ -176,8 +187,9 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
[device release]; [device release];
/* Obtain device resolution */ /* Obtain device resolution */
AVCaptureInputPort *port = [input.ports objectAtIndex:0]; AVCaptureInputPort *port = [input.ports objectAtIndex: 0];
CMFormatDescriptionRef format_description = port.formatDescription; CMFormatDescriptionRef format_description = port.formatDescription;
if ( format_description ) { if ( format_description ) {
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description); CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
*width = dimensions.width; *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 = [[AVCaptureVideoDataOutput alloc] init];
[_linkerVideo setSampleBufferDelegate:self queue:_processingQueue]; [_linkerVideo setSampleBufferDelegate: self queue: _processingQueue];
// TODO possibly get a better pixel format // TODO possibly get a better pixel format
if (_shouldMangleDimensions) { if (_shouldMangleDimensions) {
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA), [_linkerVideo setVideoSettings: @ {
(id)kCVPixelBufferWidthKey: @640, (id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
(id)kCVPixelBufferHeightKey: @480}]; (id)kCVPixelBufferWidthKey: @640,
(id)kCVPixelBufferHeightKey: @480
}];
} else { } else {
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}]; [_linkerVideo setVideoSettings: @{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
} }
[_session addOutput:_linkerVideo]; [_session addOutput: _linkerVideo];
[_session startRunning]; [_session startRunning];
pthread_mutex_unlock(&_frameLock); pthread_mutex_unlock(&_frameLock);
return 0; return 0;
} }
- (void)closeVideoDeviceIndex: (uint32_t)device_idx { - (void)closeVideoDeviceIndex:
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; (uint32_t)device_idx {
AVCaptureDevice *device = [devices objectAtIndex:device_idx]; NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
AVCaptureDevice *device = [devices objectAtIndex: device_idx];
NSError *error = NULL; NSError *error = NULL;
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error]; AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
[_session stopRunning]; [_session stopRunning];
[_session removeOutput:_linkerVideo]; [_session removeOutput: _linkerVideo];
[_session removeInput:input]; [_session removeInput: input];
[_linkerVideo release]; [_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); pthread_mutex_lock(&_frameLock);
CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer); CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer);
if (!img) { if (!img) {
NSLog(@"Toxic WARNING: Bad sampleBuffer from AVfoundation!"); NSLog(@"Toxic WARNING: Bad sampleBuffer from AVfoundation!");
} else { } 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); 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) { if (!_currentFrame) {
return -1; return -1;
} }
@ -240,6 +265,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
CFRetain(_currentFrame); CFRetain(_currentFrame);
CFTypeID imageType = CFGetTypeID(_currentFrame); CFTypeID imageType = CFGetTypeID(_currentFrame);
if (imageType == CVPixelBufferGetTypeID()) { if (imageType == CVPixelBufferGetTypeID()) {
// TODO maybe handle other formats // TODO maybe handle other formats
bgrxtoyuv420(y, u, v, CVPixelBufferGetBaseAddress(_currentFrame), *width, *height); 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 * C-interface for OSXVideo
*/ */
static OSXVideo* _OSXVideo = nil; static OSXVideo *_OSXVideo = nil;
int osx_video_init(char **device_names, int *size) 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 ) if ( _OSXVideo == nil )
return -1; return -1;
@ -286,12 +312,12 @@ int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height)
if ( _OSXVideo == nil ) if ( _OSXVideo == nil )
return -1; 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) 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) 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 ) if ( _OSXVideo == nil )
return -1; 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 * End of C-interface for OSXVideo

View File

@ -215,7 +215,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
diff = dir_match(self, m, ctx->line, L"/avatar"); 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] = { const char status_cmd_list[3][8] = {
{"online"}, {"online"},
{"away"}, {"away"},
@ -239,8 +239,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else if (key == '\r') { } else if (key == '\r') {
rm_trailing_spaces_buf(ctx); rm_trailing_spaces_buf(ctx);
if (!wstring_is_empty(ctx->line)) if (!wstring_is_empty(ctx->line)) {
{
add_line_to_hist(ctx); add_line_to_hist(ctx);
wstrsubst(ctx->line, L'', L'\n'); wstrsubst(ctx->line, L'', L'\n');
@ -302,10 +301,12 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
status_text = "Online"; status_text = "Online";
colour = GREEN; colour = GREEN;
break; break;
case TOX_USER_STATUS_AWAY: case TOX_USER_STATUS_AWAY:
status_text = "Away"; status_text = "Away";
colour = YELLOW; colour = YELLOW;
break; break;
case TOX_USER_STATUS_BUSY: case TOX_USER_STATUS_BUSY:
status_text = "Busy"; status_text = "Busy";
colour = RED; colour = RED;
@ -336,7 +337,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m); 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'; statusmsg[slen] = '\0';
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg); snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = strlen(statusbar->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)); int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x); wmove(self->window, y + 1, new_x);
wrefresh(self->window); wnoutrefresh(self->window);
if (self->help->active) if (self->help->active)
help_onDraw(self); help_onDraw(self);
@ -405,8 +406,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
else else
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box, box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
"Toxic", "%s has come online", nick ); "Toxic", "%s has come online", nick );
} } else if (connection_status == TOX_CONNECTION_NONE) {
else if (connection_status == TOX_CONNECTION_NONE) {
msg = "has gone offline"; msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg); line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true); write_to_log(msg, nick, ctx->log, true);

View File

@ -32,41 +32,46 @@
#include "misc_tools.h" #include "misc_tools.h"
#ifdef AUDIO #ifdef AUDIO
#include "audio_device.h" #include "audio_device.h"
#endif /* AUDIO */ #endif /* AUDIO */
#include "settings.h" #include "settings.h"
#include "line_info.h" #include "line_info.h"
#ifndef PACKAGE_DATADIR #ifndef PACKAGE_DATADIR
#define PACKAGE_DATADIR "." #define PACKAGE_DATADIR "."
#endif #endif
#define NO_SOUND "silent" #define NO_SOUND "silent"
static struct ui_strings { static struct ui_strings {
const char* self; const char *self;
const char* timestamps; const char *timestamps;
const char* time_format; const char *time_format;
const char* timestamp_format; const char *timestamp_format;
const char* log_timestamp_format; const char *log_timestamp_format;
const char* alerts; const char *alerts;
const char* native_colors; const char *bell_on_message;
const char* autolog; const char *bell_on_filetrans;
const char* history_size; const char *bell_on_filetrans_accept;
const char* show_typing_self; const char *bell_on_invite;
const char* show_typing_other; const char *native_colors;
const char* show_welcome_msg; const char *autolog;
const char* show_connection_msg; 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_join;
const char* line_quit; const char *line_quit;
const char* line_alert; const char *line_alert;
const char* line_normal; const char *line_normal;
const char* line_special; const char *line_special;
const char* mplex_away; const char *mplex_away;
const char* mplex_away_note; const char *mplex_away_note;
} ui_strings = { } ui_strings = {
"ui", "ui",
"timestamps", "timestamps",
@ -74,6 +79,10 @@ static struct ui_strings {
"timestamp_format", "timestamp_format",
"log_timestamp_format", "log_timestamp_format",
"alerts", "alerts",
"bell_on_message",
"bell_on_filetrans",
"bell_on_filetrans_accept",
"bell_on_invite",
"native_colors", "native_colors",
"autolog", "autolog",
"history_size", "history_size",
@ -81,6 +90,7 @@ static struct ui_strings {
"show_typing_other", "show_typing_other",
"show_welcome_msg", "show_welcome_msg",
"show_connection_msg", "show_connection_msg",
"nodeslist_update_freq",
"line_join", "line_join",
"line_quit", "line_quit",
"line_alert", "line_alert",
@ -90,7 +100,7 @@ static struct ui_strings {
"mplex_away_note", "mplex_away_note",
}; };
static void ui_defaults(struct user_settings* settings) static void ui_defaults(struct user_settings *settings)
{ {
settings->timestamps = TIMESTAMPS_ON; settings->timestamps = TIMESTAMPS_ON;
snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT); 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->autolog = AUTOLOG_OFF;
settings->alerts = ALERTS_ENABLED; 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->colour_theme = DFLT_COLS;
settings->history_size = 700; settings->history_size = 700;
settings->show_typing_self = SHOW_TYPING_ON; settings->show_typing_self = SHOW_TYPING_ON;
settings->show_typing_other = SHOW_TYPING_ON; settings->show_typing_other = SHOW_TYPING_ON;
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON; settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
settings->show_connection_msg = SHOW_CONNECTION_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_join, LINE_HINT_MAX + 1, "%s", LINE_JOIN);
snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT); 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 { static const struct keys_strings {
const char* self; const char *self;
const char* next_tab; const char *next_tab;
const char* prev_tab; const char *prev_tab;
const char* scroll_line_up; const char *scroll_line_up;
const char* scroll_line_down; const char *scroll_line_down;
const char* half_page_up; const char *half_page_up;
const char* half_page_down; const char *half_page_down;
const char* page_bottom; const char *page_bottom;
const char* peer_list_up; const char *peer_list_up;
const char* peer_list_down; const char *peer_list_down;
const char* toggle_peerlist; const char *toggle_peerlist;
const char* toggle_pastemode; const char *toggle_pastemode;
} key_strings = { } key_strings = {
"keys", "keys",
"next_tab", "next_tab",
@ -147,7 +162,7 @@ static const struct keys_strings {
}; };
/* defines from toxic.h */ /* 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_next_tab = T_KEY_NEXT;
settings->key_prev_tab = T_KEY_PREV; settings->key_prev_tab = T_KEY_PREV;
@ -163,11 +178,11 @@ static void key_defaults(struct user_settings* settings)
} }
static const struct tox_strings { static const struct tox_strings {
const char* self; const char *self;
const char* download_path; const char *download_path;
const char* chatlogs_path; const char *chatlogs_path;
const char* avatar_path; const char *avatar_path;
const char* password_eval; const char *password_eval;
} tox_strings = { } tox_strings = {
"tox", "tox",
"download_path", "download_path",
@ -176,7 +191,7 @@ static const struct tox_strings {
"password_eval", "password_eval",
}; };
static void tox_defaults(struct user_settings* settings) static void tox_defaults(struct user_settings *settings)
{ {
strcpy(settings->download_path, ""); strcpy(settings->download_path, "");
strcpy(settings->chatlogs_path, ""); strcpy(settings->chatlogs_path, "");
@ -186,10 +201,10 @@ static void tox_defaults(struct user_settings* settings)
#ifdef AUDIO #ifdef AUDIO
static const struct audio_strings { static const struct audio_strings {
const char* self; const char *self;
const char* input_device; const char *input_device;
const char* output_device; const char *output_device;
const char* VAD_treshold; const char *VAD_treshold;
} audio_strings = { } audio_strings = {
"audio", "audio",
"input_device", "input_device",
@ -197,7 +212,7 @@ static const struct audio_strings {
"VAD_treshold", "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_in_dev = 0;
settings->audio_out_dev = 0; settings->audio_out_dev = 0;
@ -207,17 +222,17 @@ static void audio_defaults(struct user_settings* settings)
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
static const struct sound_strings { static const struct sound_strings {
const char* self; const char *self;
const char* notif_error; const char *notif_error;
const char* self_log_in; const char *self_log_in;
const char* self_log_out; const char *self_log_out;
const char* user_log_in; const char *user_log_in;
const char* user_log_out; const char *user_log_out;
const char* call_incoming; const char *call_incoming;
const char* call_outgoing; const char *call_outgoing;
const char* generic_message; const char *generic_message;
const char* transfer_pending; const char *transfer_pending;
const char* transfer_completed; const char *transfer_completed;
} sound_strings = { } sound_strings = {
"sounds", "sounds",
"notif_error", "notif_error",
@ -233,11 +248,12 @@ static const struct sound_strings {
}; };
#endif #endif
static int key_parse(const char **bind) { static int key_parse(const char **bind)
{
int len = strlen(*bind); int len = strlen(*bind);
if (len > 5) { 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; return toupper(bind[0][5]) - 'A' + 1;
} }
@ -250,7 +266,8 @@ static int key_parse(const char **bind) {
return -1; 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); int code = key_parse(bind);
if (code != -1) { 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); config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
int time = 24; int time = 24;
if ( config_setting_lookup_int(setting, ui_strings.time_format, &time) ) { if ( config_setting_lookup_int(setting, ui_strings.time_format, &time) ) {
if (time == 12) { if (time == 12) {
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p"); 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); 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.autolog, &s->autolog);
config_setting_lookup_bool(setting, ui_strings.native_colors, &s->colour_theme); 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_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_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_welcome_msg, &s->show_welcome_msg);
config_setting_lookup_bool(setting, ui_strings.show_connection_msg, &s->show_connection_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) ) { if ( config_setting_lookup_string(setting, ui_strings.line_join, &str) ) {
snprintf(s->line_join, sizeof(s->line_join), "%s", str); snprintf(s->line_join, sizeof(s->line_join), "%s", str);
} }
if ( config_setting_lookup_string(setting, ui_strings.line_quit, &str) ) { if ( config_setting_lookup_string(setting, ui_strings.line_quit, &str) ) {
snprintf(s->line_quit, sizeof(s->line_quit), "%s", str); snprintf(s->line_quit, sizeof(s->line_quit), "%s", str);
} }
if ( config_setting_lookup_string(setting, ui_strings.line_alert, &str) ) { if ( config_setting_lookup_string(setting, ui_strings.line_alert, &str) ) {
snprintf(s->line_alert, sizeof(s->line_alert), "%s", str); snprintf(s->line_alert, sizeof(s->line_alert), "%s", str);
} }
if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) { if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) {
snprintf(s->line_normal, sizeof(s->line_normal), "%s", str); snprintf(s->line_normal, sizeof(s->line_normal), "%s", str);
} }
if ( config_setting_lookup_string(setting, ui_strings.line_special, &str) ) { if ( config_setting_lookup_string(setting, ui_strings.line_special, &str) ) {
snprintf(s->line_special, sizeof(s->line_special), "%s", 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 */ /* keys */
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) { 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)) if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp))
set_key_binding(&s->key_next_tab, &tmp); set_key_binding(&s->key_next_tab, &tmp);
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp)) if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp))
set_key_binding(&s->key_prev_tab, &tmp); set_key_binding(&s->key_prev_tab, &tmp);
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp)) if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp))
set_key_binding(&s->key_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)) if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp))
set_key_binding(&s->key_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)) if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp))
set_key_binding(&s->key_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)) if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp))
set_key_binding(&s->key_half_page_down, &tmp); set_key_binding(&s->key_half_page_down, &tmp);
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp)) if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp))
set_key_binding(&s->key_page_bottom, &tmp); set_key_binding(&s->key_page_bottom, &tmp);
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp)) if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp))
set_key_binding(&s->key_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)) if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp))
set_key_binding(&s->key_peer_list_down, &tmp); set_key_binding(&s->key_peer_list_down, &tmp);
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp)) if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp))
set_key_binding(&s->key_toggle_peerlist, &tmp); set_key_binding(&s->key_toggle_peerlist, &tmp);
if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp)) if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp))
set_key_binding(&s->key_toggle_pastemode, &tmp); set_key_binding(&s->key_toggle_pastemode, &tmp);
} }
#ifdef AUDIO #ifdef AUDIO
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) { if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev); 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; 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); config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
} }
#endif #endif
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) { if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) || if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
!set_sound(notif_error, str) ) { !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) if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav"); set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
} }
} } else {
else {
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav"); set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav"); set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.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_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav"); set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
} }
#endif #endif
config_destroy(cfg); config_destroy(cfg);

View File

@ -37,6 +37,12 @@ struct user_settings {
int autolog; /* boolean */ int autolog; /* boolean */
int alerts; /* 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 */ int timestamps; /* boolean */
char timestamp_format[TIME_STR_SIZE]; char timestamp_format[TIME_STR_SIZE];
char log_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_typing_other; /* boolean */
int show_welcome_msg; /* boolean */ int show_welcome_msg; /* boolean */
int show_connection_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_join[LINE_HINT_MAX + 1];
char line_quit[LINE_HINT_MAX + 1]; char line_quit[LINE_HINT_MAX + 1];

View File

@ -52,8 +52,7 @@ extern struct Winthread Winthread;
#define PATH_SEP_S "/" #define PATH_SEP_S "/"
#define PATH_SEP_C '/' #define PATH_SEP_C '/'
typedef enum typedef enum {
{
MPLEX_NONE, MPLEX_NONE,
MPLEX_SCREEN, MPLEX_SCREEN,
MPLEX_TMUX, MPLEX_TMUX,
@ -97,13 +96,14 @@ static char *read_into_dyn_buffer (FILE *stream)
char *dyn_buffer = NULL; char *dyn_buffer = NULL;
int dyn_buffer_size = 1; /* account for the \0 */ 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); int length = dyn_buffer_size + strlen (input_ptr);
if (dyn_buffer) if (dyn_buffer)
dyn_buffer = (char*) realloc (dyn_buffer, length); dyn_buffer = (char *) realloc (dyn_buffer, length);
else else
dyn_buffer = (char*) malloc (length); dyn_buffer = (char *) malloc (length);
strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr); strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr);
dyn_buffer_size = length; dyn_buffer_size = length;
} }
@ -116,26 +116,29 @@ static char *extract_socket_path (const char *info)
const char *search_str = " Socket"; const char *search_str = " Socket";
const char *pos = strstr (info, search_str); const char *pos = strstr (info, search_str);
char *end = NULL; char *end = NULL;
char* path = NULL; char *path = NULL;
if (!pos) if (!pos)
return NULL; return NULL;
pos += strlen (search_str); pos += strlen (search_str);
pos = strchr (pos, PATH_SEP_C); pos = strchr (pos, PATH_SEP_C);
if (!pos) if (!pos)
return NULL; return NULL;
end = strchr (pos, '\n'); end = strchr (pos, '\n');
if (!end) if (!end)
return NULL; return NULL;
*end = '\0'; *end = '\0';
end = strrchr (pos, '.'); end = strrchr (pos, '.');
if (!end) if (!end)
return NULL; return NULL;
path = (char*) malloc (end - pos + 1); path = (char *) malloc (end - pos + 1);
*end = '\0'; *end = '\0';
return strcpy (path, pos); return strcpy (path, pos);
} }
@ -147,14 +150,17 @@ static int detect_gnu_screen ()
char *dyn_buffer = NULL; char *dyn_buffer = NULL;
socket_name = getenv ("STY"); socket_name = getenv ("STY");
if (!socket_name) if (!socket_name)
goto nomplex; goto nomplex;
session_info_stream = popen ("env LC_ALL=C screen -ls", "r"); session_info_stream = popen ("env LC_ALL=C screen -ls", "r");
if (!session_info_stream) if (!session_info_stream)
goto nomplex; goto nomplex;
dyn_buffer = read_into_dyn_buffer (session_info_stream); dyn_buffer = read_into_dyn_buffer (session_info_stream);
if (!dyn_buffer) if (!dyn_buffer)
goto nomplex; goto nomplex;
@ -162,6 +168,7 @@ static int detect_gnu_screen ()
session_info_stream = NULL; session_info_stream = NULL;
socket_path = extract_socket_path (dyn_buffer); socket_path = extract_socket_path (dyn_buffer);
if (!socket_path) if (!socket_path)
goto nomplex; goto nomplex;
@ -181,23 +188,29 @@ static int detect_gnu_screen ()
return 1; return 1;
nomplex: nomplex:
if (session_info_stream) if (session_info_stream)
pclose (session_info_stream); pclose (session_info_stream);
if (dyn_buffer) if (dyn_buffer)
free (dyn_buffer); free (dyn_buffer);
if (socket_path) if (socket_path)
free(socket_path); free(socket_path);
return 0; return 0;
} }
static int detect_tmux () static int detect_tmux ()
{ {
char *tmux_env = getenv ("TMUX"), *pos; char *tmux_env = getenv ("TMUX"), *pos;
if (!tmux_env) if (!tmux_env)
return 0; return 0;
/* find second separator */ /* find second separator */
pos = strrchr (tmux_env, ','); pos = strrchr (tmux_env, ',');
if (!pos) if (!pos)
return 0; return 0;
@ -230,6 +243,7 @@ static int gnu_screen_is_detached ()
return 0; return 0;
struct stat sb; struct stat sb;
if (stat (mplex_data, &sb) != 0) if (stat (mplex_data, &sb) != 0)
return 0; return 0;
@ -257,10 +271,12 @@ static int tmux_is_detached ()
const int numstr_len = strlen (mplex_data); const int numstr_len = strlen (mplex_data);
session_info_stream = popen ("env LC_ALL=C tmux list-sessions", "r"); session_info_stream = popen ("env LC_ALL=C tmux list-sessions", "r");
if (!session_info_stream) if (!session_info_stream)
goto fail; goto fail;
dyn_buffer = read_into_dyn_buffer (session_info_stream); dyn_buffer = read_into_dyn_buffer (session_info_stream);
if (!dyn_buffer) if (!dyn_buffer)
goto fail; goto fail;
@ -268,7 +284,7 @@ static int tmux_is_detached ()
session_info_stream = NULL; session_info_stream = NULL;
/* prepare search string, for finding the current session's entry */ /* 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'; search_str[0] = '\n';
strcpy (search_str + 1, mplex_data); strcpy (search_str + 1, mplex_data);
strcat (search_str, ": "); strcat (search_str, ": ");
@ -295,12 +311,16 @@ static int tmux_is_detached ()
return attached_pos == NULL || attached_pos > nl_pos; return attached_pos == NULL || attached_pos > nl_pos;
fail: fail:
if (session_info_stream) if (session_info_stream)
pclose (session_info_stream); pclose (session_info_stream);
if (dyn_buffer) if (dyn_buffer)
free (dyn_buffer); free (dyn_buffer);
if (search_str) if (search_str)
free (search_str); free (search_str);
return 0; return 0;
} }
@ -332,26 +352,21 @@ static void mplex_timer_handler (Tox *m)
current_status = tox_self_get_status (m); current_status = tox_self_get_status (m);
pthread_mutex_unlock (&Winthread.lock); 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; auto_away_active = false;
new_status = prev_status; new_status = prev_status;
new_note = prev_note; 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; auto_away_active = true;
prev_status = current_status; prev_status = current_status;
new_status = TOX_USER_STATUS_AWAY; new_status = TOX_USER_STATUS_AWAY;
pthread_mutex_lock (&Winthread.lock); pthread_mutex_lock (&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m); 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'; prev_note[slen] = '\0';
pthread_mutex_unlock (&Winthread.lock); pthread_mutex_unlock (&Winthread.lock);
new_note = user_settings->mplex_away_note; new_note = user_settings->mplex_away_note;
} } else
else
return; return;
char argv[3][MAX_STR_SIZE]; char argv[3][MAX_STR_SIZE];

View File

@ -41,6 +41,7 @@
#include <termios.h> #include <termios.h>
#include <ctype.h> #include <ctype.h>
#include <curl/curl.h>
#include <tox/tox.h> #include <tox/tox.h>
#include <tox/toxencryptsave.h> #include <tox/toxencryptsave.h>
@ -61,9 +62,10 @@
#include "execute.h" #include "execute.h"
#include "term_mplex.h" #include "term_mplex.h"
#include "name_lookup.h" #include "name_lookup.h"
#include "bootstrap.h"
#ifdef X11 #ifdef X11
#include "xtra.h" #include "xtra.h"
#endif #endif
#ifdef AUDIO #ifdef AUDIO
@ -75,7 +77,7 @@ ToxAV *av;
#endif /* AUDIO */ #endif /* AUDIO */
#ifndef PACKAGE_DATADIR #ifndef PACKAGE_DATADIR
#define PACKAGE_DATADIR "." #define PACKAGE_DATADIR "."
#endif #endif
/* Export for use in Callbacks */ /* Export for use in Callbacks */
@ -164,7 +166,7 @@ void exit_toxic_success(Tox *m)
free_global_data(); free_global_data();
tox_kill(m); tox_kill(m);
endwin(); endwin();
name_lookup_cleanup(); curl_global_cleanup();
#ifdef X11 #ifdef X11
/* We have to terminate xtra last coz reasons /* 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]); 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) static void load_groups(Tox *m)
{ {
size_t i; size_t i;
@ -477,8 +332,10 @@ static int password_prompt(char *buf, int size)
/* eat overflowed stdin and return error */ /* eat overflowed stdin and return error */
if (buf[--len] != '\n') { if (buf[--len] != '\n') {
int ch; int ch;
while ((ch = getchar()) != '\n' && ch > 0) while ((ch = getchar()) != '\n' && ch > 0)
; ;
return 0; return 0;
} }
@ -495,6 +352,7 @@ static int password_eval(char *buf, int size)
/* Run password_eval command */ /* Run password_eval command */
FILE *f = popen(user_settings->password_eval, "r"); FILE *f = popen(user_settings->password_eval, "r");
if (f == NULL) { if (f == NULL) {
fprintf(stderr, "Executing password_eval failed\n"); fprintf(stderr, "Executing password_eval failed\n");
return 0; return 0;
@ -502,6 +360,7 @@ static int password_eval(char *buf, int size)
/* Get output from command */ /* Get output from command */
char *ret = fgets(buf, size, f); char *ret = fgets(buf, size, f);
if (ret == NULL) { if (ret == NULL) {
fprintf(stderr, "Reading password from password_eval command failed\n"); fprintf(stderr, "Reading password from password_eval command failed\n");
pclose(f); pclose(f);
@ -510,6 +369,7 @@ static int password_eval(char *buf, int size)
/* Get exit status */ /* Get exit status */
int status = pclose(f); int status = pclose(f);
if (status != 0) { if (status != 0) {
fprintf(stderr, "password_eval command returned error %d\n", status); fprintf(stderr, "password_eval command returned error %d\n", status);
return 0; return 0;
@ -517,6 +377,7 @@ static int password_eval(char *buf, int size)
/* Removez whitespace or \n at end */ /* Removez whitespace or \n at end */
int i, len = strlen(buf); int i, len = strlen(buf);
for (i = len - 1; i > 0 && isspace(buf[i]); i--) { for (i = len - 1; i > 0 && isspace(buf[i]); i--) {
buf[i] = 0; buf[i] = 0;
len--; len--;
@ -613,6 +474,7 @@ int store_data(Tox *m, const char *path)
char *data = malloc(data_len * sizeof(char)); char *data = malloc(data_len * sizeof(char));
if (data == NULL) { if (data == NULL) {
fclose(fp);
return -1; return -1;
} }
@ -623,6 +485,7 @@ int store_data(Tox *m, const char *path)
char *enc_data = malloc(enc_len * sizeof(char)); char *enc_data = malloc(enc_len * sizeof(char));
if (enc_data == NULL) { if (enc_data == NULL) {
fclose(fp);
free(data); free(data);
return -1; return -1;
} }
@ -747,14 +610,14 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
if (len == 0) { if (len == 0) {
fclose(fp); fclose(fp);
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP); exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
} }
char data[len]; char data[len];
if (fread(data, sizeof(data), 1, fp) != 1) { if (fread(data, sizeof(data), 1, fp) != 1) {
fclose(fp); 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); 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 */ /* attempt to encrypt an already encrypted data file */
if (arg_opts.encrypt_data && is_encrypted) { if (arg_opts.encrypt_data && is_encrypted) {
fclose(fp); 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) 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; size_t pwlen = 0;
int pweval = user_settings->password_eval[0]; int pweval = user_settings->password_eval[0];
if (!pweval) { if (!pweval) {
system("clear"); // TODO: is this portable? system("clear"); // TODO: is this portable?
printf("Enter password (q to quit) "); 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 { } else {
pwlen = password_prompt(user_password.pass, sizeof(user_password.pass)); pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
} }
user_password.len = pwlen; user_password.len = pwlen;
if (strcasecmp(user_password.pass, "q") == 0) { 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); fclose(fp);
} else { /* Data file does not/should not exist */ } else { /* Data file does not/should not exist */
if (file_exists(data_path)) 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; 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; return NULL;
if (store_data(m, data_path) == -1) 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; return m;
@ -894,33 +759,9 @@ static Tox *load_toxic(char *data_path)
return m; return m;
} }
#define TRY_BOOTSTRAP_INTERVAL 5 static void do_toxic(Tox *m)
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)
{ {
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
update_unix_time();
if (arg_opts.no_connect) { if (arg_opts.no_connect) {
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
@ -928,7 +769,7 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
} }
tox_iterate(m); tox_iterate(m);
do_bootstrap(m); do_tox_connection(m);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
} }
@ -1110,10 +951,6 @@ static void parse_args(int argc, char *argv[])
case 'n': case 'n':
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg); 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; break;
case 'o': case 'o':
@ -1125,10 +962,10 @@ static void parse_args(int argc, char *argv[])
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5; arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg); 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); 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) if (port <= 0 || port > MAX_PORT_RANGE)
exit_toxic_err("Proxy error", FATALERR_PROXY); 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; arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg); 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); 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) if (port <= 0 || port > MAX_PORT_RANGE)
exit_toxic_err("Proxy error", FATALERR_PROXY); exit_toxic_err("Proxy error", FATALERR_PROXY);
@ -1269,7 +1106,7 @@ static void init_default_data_files(void)
// this doesn't do anything (yet) // this doesn't do anything (yet)
#ifdef X11 #ifdef X11
void DnD_callback(const char* asdv, DropType dt) void DnD_callback(const char *asdv, DropType dt)
{ {
// if (dt != DT_plain) // if (dt != DT_plain)
// return; // return;
@ -1282,7 +1119,6 @@ void DnD_callback(const char* asdv, DropType dt)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
update_unix_time();
parse_args(argc, argv); parse_args(argc, argv);
/* Use the -b flag to enable stderr */ /* Use the -b flag to enable stderr */
@ -1302,9 +1138,6 @@ int main(int argc, char **argv)
bool datafile_exists = file_exists(DATA_FILE); bool datafile_exists = file_exists(DATA_FILE);
if (datafile_exists)
last_bootstrap_time = get_unix_time();
if (!datafile_exists && !arg_opts.unencrypt_data) 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)"); first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
else if (arg_opts.encrypt_data) 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; const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
if (settings_load(user_settings, p) == -1) if (settings_load(user_settings, p) == -1) {
queue_init_message("Failed to load user settings"); 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."); 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."); 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."); queue_init_message("Name lookup server list does not contain any valid entries.");
}
#ifdef X11 #ifdef X11
if (init_xtra(DnD_callback) == -1) if (init_xtra(DnD_callback) == -1)
queue_init_message("X failed to initialize"); queue_init_message("X failed to initialize");
#endif #endif
Tox *m = load_toxic(DATA_FILE); 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) if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE); exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
#ifdef AUDIO #ifdef AUDIO
av = init_audio(prompt, m); av = init_audio(prompt, m);
@ -1376,6 +1213,7 @@ int main(int argc, char **argv)
set_primary_device(output, user_settings->audio_out_dev); set_primary_device(output, user_settings->audio_out_dev);
#elif SOUND_NOTIFY #elif SOUND_NOTIFY
if ( init_devices() == de_InternalError ) if ( init_devices() == de_InternalError )
queue_init_message("Failed to init audio devices"); 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) if (init_mplex_away_timer(m) == -1)
queue_init_message("Failed to init mplex auto-away."); 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); pthread_mutex_lock(&Winthread.lock);
load_groups(m); load_groups(m);
print_init_messages(prompt); print_init_messages(prompt);
@ -1399,17 +1243,19 @@ int main(int argc, char **argv)
snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path); snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path);
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE); 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) { 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)) { if (timed_out(last_save, AUTOSAVE_FREQ)) {
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
if (store_data(m, DATA_FILE) != 0) 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"); line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
last_save = cur_time; last_save = cur_time;

View File

@ -107,13 +107,15 @@ int store_data(Tox *m, const char *path);
/* callbacks */ /* callbacks */
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata); 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_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_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_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_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_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_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, 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); size_t length, void *userdata);
void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, 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_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, 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); 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_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_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *partmsg, size_t length,
void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *topic, size_t length, void *userdata); 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_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_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_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_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_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); void on_group_rejected(Tox *m, uint32_t groupnumber, TOX_GROUP_JOIN_FAIL type, void *userdata);

View File

@ -136,13 +136,13 @@ int del_word_buf(ChatContext *ctx)
int i = ctx->pos, count = 0; int i = ctx->pos, count = 0;
/* traverse past empty space */ /* traverse past empty space */
while (i > 0 && ctx->line[i-1] == L' ') { while (i > 0 && ctx->line[i - 1] == L' ') {
++count; ++count;
--i; --i;
} }
/* traverse past last entered word */ /* traverse past last entered word */
while (i > 0 && ctx->line[i-1] != L' ') { while (i > 0 && ctx->line[i - 1] != L' ') {
++count; ++count;
--i; --i;
} }
@ -243,17 +243,19 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
ctx->len = h_len; ctx->len = h_len;
} }
void strsubst(char* str, char old, char new) void strsubst(char *str, char old, char new)
{ {
int i; int i;
for (i = 0; str[i] != '\0'; ++i) for (i = 0; str[i] != '\0'; ++i)
if (str[i] == old) 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; int i;
for (i = 0; str[i] != L'\0'; ++i) for (i = 0; str[i] != L'\0'; ++i)
if (str[i] == old) if (str[i] == old)
str[i] = new; str[i] = new;

View File

@ -82,22 +82,24 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
void terminate_video() void terminate_video()
{ {
int i; int i;
for (i = 0; i < MAX_CALLS; ++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); 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); close_video_device(vdt_output, this_call->vout_idx);
} }
terminate_video_devices(); 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 */ uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
Call* this_call = &CallControl.calls[friend_number]; Call *this_call = &CallControl.calls[friend_number];
TOXAV_ERR_SEND_FRAME error; TOXAV_ERR_SEND_FRAME error;
/* Drop frame if video sending is disabled */ /* Drop frame if video sending is disabled */
@ -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) 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 ) if ( this_call->vout_idx != -1 )
return; return;
@ -201,21 +203,22 @@ void callback_recv_video_starting(uint32_t friend_number)
} }
void callback_recv_video_end(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); close_video_device(vdt_output, this_call->vout_idx);
this_call->vout_idx = -1; this_call->vout_idx = -1;
} }
void callback_video_starting(uint32_t friend_number) void callback_video_starting(uint32_t friend_number)
{ {
ToxWindow* windows = CallControl.prompt; ToxWindow *windows = CallControl.prompt;
Call* this_call = &CallControl.calls[friend_number]; Call *this_call = &CallControl.calls[friend_number];
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK; TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error); toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error);
if (error == TOXAV_ERR_CALL_CONTROL_OK) { if (error == TOXAV_ERR_CALL_CONTROL_OK) {
size_t i; size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if ( windows[i].is_call && windows[i].num == friend_number ) { if ( windows[i].is_call && windows[i].num == friend_number ) {
if ( 0 != start_video_transmission(&windows[i], CallControl.av, this_call) ) { 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]) void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
const char *error_str; const char *error_str;
Call* this_call = &CallControl.calls[self->num]; Call *this_call = &CallControl.calls[self->num];
if ( argc != 0 ) { if ( argc != 0 ) {
error_str = "Unknown arguments."; 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 ) { if ( video_selection_valid(type, selection) == vde_InvalidSelection ) {
error_str="Invalid selection!"; error_str = "Invalid selection!";
goto on_error; goto on_error;
} }
/* If call is active, change device */ /* If call is active, change device */
if ( self->is_call ) { if ( self->is_call ) {
Call* this_call = &CallControl.calls[self->num]; Call *this_call = &CallControl.calls[self->num];
if ( this_call->ttas ) { if ( this_call->ttas ) {
if ( type == vdt_output ) { if ( type == vdt_output ) {
} } else {
else {
/* TODO: check for failure */ /* TODO: check for failure */
close_video_device(vdt_input, this_call->vin_idx); close_video_device(vdt_input, this_call->vin_idx);
open_video_device(vdt_input, selection, &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; self->video_device_selection[type] = selection;
return; return;
on_error: on_error:
print_err (self, error_str); print_err (self, error_str);
} }

View File

@ -62,7 +62,7 @@ struct VideoBuffer {
typedef struct VideoDevice { typedef struct VideoDevice {
VideoDataHandleCallback cb; /* Use this to handle data from input device usually */ 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 */ int32_t friend_number; /* ToxAV friend number */
#if defined(__linux__) || defined(__FreeBSD__) #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 */ uint32_t primary_video_device[2]; /* Primary device */
#ifdef VIDEO #ifdef VIDEO
static ToxAV* av = NULL; static ToxAV *av = NULL;
#endif /* VIDEO */ #endif /* VIDEO */
/* q_mutex */ /* q_mutex */
@ -104,13 +104,14 @@ pthread_mutex_t video_mutex;
bool video_thread_running = true, 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, static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
const uint8_t *u, const uint8_t *v, unsigned int ystride, const uint8_t *u, const uint8_t *v, unsigned int ystride,
unsigned int ustride, unsigned int vstride, uint8_t *out) unsigned int ustride, unsigned int vstride, uint8_t *out)
{ {
unsigned long int i, j; unsigned long int i, j;
for (i = 0; i < height; ++i) { for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) { for (j = 0; j < width; ++j) {
uint8_t *point = out + 4 * ((i * 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 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; int b = (298 * (t_y - 16) + 516 * (t_u - 128) + 128) >> 8;
point[2] = r>255? 255 : r<0 ? 0 : r; point[2] = r > 255 ? 255 : r < 0 ? 0 : r;
point[1] = g>255? 255 : g<0 ? 0 : g; point[1] = g > 255 ? 255 : g < 0 ? 0 : g;
point[0] = b>255? 255 : b<0 ? 0 : b; point[0] = b > 255 ? 255 : b < 0 ? 0 : b;
point[3] = ~0; point[3] = ~0;
} }
} }
@ -136,8 +137,10 @@ 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; uint8_t *end = input + width * height * 2;
while (input != end) { while (input != end) {
uint8_t *line_end = input + width * 2; uint8_t *line_end = input + width * 2;
while (input != line_end) { while (input != line_end) {
*plane_y++ = *input++; *plane_y++ = *input++;
*plane_u++ = *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; line_end = input + width * 2;
while (input != line_end) { while (input != line_end) {
*plane_y++ = *input++; *plane_y++ = *input++;
input++;//u input++;//u
@ -170,7 +174,7 @@ static int xioctl(int fh, unsigned long request, void *arg)
/* Meet devices */ /* Meet devices */
#ifdef VIDEO #ifdef VIDEO
VideoDeviceError init_video_devices(ToxAV* av_) VideoDeviceError init_video_devices(ToxAV *av_)
#else #else
VideoDeviceError init_video_devices() VideoDeviceError init_video_devices()
#endif /* VIDEO */ #endif /* VIDEO */
@ -178,31 +182,34 @@ VideoDeviceError init_video_devices()
size[vdt_input] = 0; size[vdt_input] = 0;
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) { for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
int fd; int fd;
char device_address[] = "/dev/videoXX"; char device_address[] = "/dev/videoXX";
snprintf(device_address + 10, sizeof(char) * strlen(device_address) - 10, "%i", size[vdt_input]); snprintf(device_address + 10, sizeof(char) * strlen(device_address) - 10, "%i", size[vdt_input]);
fd = open(device_address, O_RDWR | O_NONBLOCK, 0); fd = open(device_address, O_RDWR | O_NONBLOCK, 0);
if ( fd == -1 ) { if ( fd == -1 ) {
break; break;
} else { } else {
struct v4l2_capability cap; struct v4l2_capability cap;
char* video_input_name; char *video_input_name;
/* Query V4L for capture capabilities */ /* Query V4L for capture capabilities */
if ( -1 != ioctl(fd, VIDIOC_QUERYCAP, &cap) ) { if ( -1 != ioctl(fd, VIDIOC_QUERYCAP, &cap) ) {
video_input_name = (char*)malloc(strlen((const char*)cap.card) + strlen(device_address) + 4); video_input_name = (char *)malloc(strlen((const char *)cap.card) + strlen(device_address) + 4);
strcpy(video_input_name, (char*)cap.card); strcpy(video_input_name, (char *)cap.card);
strcat(video_input_name, " ("); strcat(video_input_name, " (");
strcat(video_input_name, (char*)device_address); strcat(video_input_name, (char *)device_address);
strcat(video_input_name, ")"); strcat(video_input_name, ")");
} else { } else {
video_input_name = (char*)malloc(strlen(device_address) + 3); video_input_name = (char *)malloc(strlen(device_address) + 3);
strcpy(video_input_name, "("); strcpy(video_input_name, "(");
strcat(video_input_name, device_address); strcat(video_input_name, device_address);
strcat(video_input_name, ")"); strcat(video_input_name, ")");
} }
video_devices_names[vdt_input][size[vdt_input]] = video_input_name; video_devices_names[vdt_input][size[vdt_input]] = video_input_name;
close(fd); close(fd);
@ -210,12 +217,14 @@ VideoDeviceError init_video_devices()
} }
#else /* __OSX__ */ #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; return vde_InternalError;
#endif #endif
size[vdt_output] = 1; 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; video_devices_names[vdt_output][0] = video_output_name;
// Start poll thread // Start poll thread
@ -223,6 +232,7 @@ VideoDeviceError init_video_devices()
return vde_InternalError; return vde_InternalError;
pthread_t thread_id; pthread_t thread_id;
if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 ) if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 )
return vde_InternalError; return vde_InternalError;
@ -236,12 +246,16 @@ VideoDeviceError init_video_devices()
VideoDeviceError terminate_video_devices() VideoDeviceError terminate_video_devices()
{ {
/* Cleanup if needed */ /* Cleanup if needed */
lock;
video_thread_running = false; video_thread_running = false;
unlock;
usleep(20000); usleep(20000);
int i; int i;
for (i = 0; i < size[vdt_input]; ++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 ) 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, 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 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; return vde_InvalidSelection;
#else /* __OSX__ */ #else /* __OSX__ */
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] ) if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
return vde_InvalidSelection; return vde_InvalidSelection;
#endif #endif
lock; lock;
@ -283,7 +302,7 @@ VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selectio
return vde_None; 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); 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); 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; 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; device->selection = selection;
if ( pthread_mutex_init(device->mutex, NULL) != 0 ) { 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); snprintf(device_address + 10 , sizeof(device_address) - 10, "%i", selection);
device->fd = open(device_address, O_RDWR); device->fd = open(device_address, O_RDWR);
if ( device->fd == -1 ) { if ( device->fd == -1 ) {
unlock; unlock;
return vde_FailedStart; return vde_FailedStart;
@ -349,6 +369,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
/* Obtain video device capabilities */ /* Obtain video device capabilities */
struct v4l2_capability cap; struct v4l2_capability cap;
if ( -1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap) ) { if ( -1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap) ) {
close(device->fd); close(device->fd);
free(device); free(device);
@ -362,7 +383,8 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 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); close(device->fd);
free(device); free(device);
unlock; unlock;
@ -378,6 +400,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
req.count = 4; req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP; req.memory = V4L2_MEMORY_MMAP;
if ( -1 == xioctl(device->fd, VIDIOC_REQBUFS, &req) ) { if ( -1 == xioctl(device->fd, VIDIOC_REQBUFS, &req) ) {
close(device->fd); close(device->fd);
free(device); free(device);
@ -419,12 +442,14 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
if ( MAP_FAILED == device->buffers[i].start ) { if ( MAP_FAILED == device->buffers[i].start ) {
for (i = 0; i < buf.index; ++i) for (i = 0; i < buf.index; ++i)
munmap(device->buffers[i].start, device->buffers[i].length); munmap(device->buffers[i].start, device->buffers[i].length);
close(device->fd); close(device->fd);
free(device); free(device);
unlock; unlock;
return vde_FailedStart; return vde_FailedStart;
} }
} }
device->n_buffers = i; device->n_buffers = i;
enum v4l2_buf_type type; 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) ) { if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
for (i = 0; i < device->n_buffers; ++i) for (i = 0; i < device->n_buffers; ++i)
munmap(device->buffers[i].start, device->buffers[i].length); munmap(device->buffers[i].start, device->buffers[i].length);
close(device->fd); close(device->fd);
free(device); free(device);
unlock; unlock;
@ -457,11 +483,13 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
} }
#else /* __OSX__ */ #else /* __OSX__ */
if ( osx_video_open_device(selection, &device->video_width, &device->video_height) != 0 ) { if ( osx_video_open_device(selection, &device->video_width, &device->video_height) != 0 ) {
free(device); free(device);
unlock; unlock;
return vde_FailedStart; return vde_FailedStart;
} }
#endif #endif
/* Create X11 window associated to device */ /* Create X11 window associated to device */
@ -482,7 +510,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
} }
XStoreName(device->x_display, device->x_window, "Video Preview"); 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 ) { if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) {
close_video_device(vdt_input, temp_idx); close_video_device(vdt_input, temp_idx);
@ -521,7 +549,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
} }
XStoreName(device->x_display, device->x_window, "Video Receive"); 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 ) { if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) {
close_video_device(vdt_output, temp_idx); close_video_device(vdt_output, temp_idx);
@ -552,11 +580,11 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
int32_t ystride, int32_t ustride, int32_t vstride, int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data) 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 ) return vde_DeviceNotActive;
if( !device->x_window ) return vde_DeviceNotActive; if ( !device->x_window ) return vde_DeviceNotActive;
pthread_mutex_lock(device->mutex); pthread_mutex_lock(device->mutex);
@ -591,7 +619,7 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
.red_mask = 0xFF0000, .red_mask = 0xFF0000,
.green_mask = 0xFF00, .green_mask = 0xFF00,
.blue_mask = 0xFF, .blue_mask = 0xFF,
.data = (char*)img_data .data = (char *)img_data
}; };
/* Render image data */ /* Render image data */
@ -606,7 +634,7 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
return vde_None; 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. * 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; (void)arg;
uint32_t i; uint32_t i;
while (video_thread_running) while (1) {
{
if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */
else
{
for (i = 0; i < size[vdt_input]; ++i)
{
lock; lock;
if ( video_devices_running[vdt_input][i] != NULL )
{ 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) {
lock;
if ( video_devices_running[vdt_input][i] != NULL ) {
/* Obtain frame image data from device buffers */ /* 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_width = device->video_width;
uint16_t video_height = device->video_height; uint16_t video_height = device->video_height;
uint8_t *y = device->input.planes[0]; 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; 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 */ /* Convert frame image data to YUV420 for ToxAV */
yuv422to420(y, u, v, data, video_width, video_height); yuv422to420(y, u, v, data, video_width, video_height);
#else /* __OSX__*/ #else /* __OSX__*/
if ( osx_video_read_device(y, u, v, &video_width, &video_height) != 0 ) { if ( osx_video_read_device(y, u, v, &video_width, &video_height) != 0 ) {
unlock; unlock;
continue; continue;
} }
#endif #endif
/* Send frame data to friend through ToxAV */ /* 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 */ /* Convert YUV420 data to BGR */
uint8_t *img_data = malloc(video_width * video_height * 4); uint8_t *img_data = malloc(video_width * video_height * 4);
yuv420tobgr(video_width, video_height, y, u, v, 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 */ /* Allocate image data in X11 */
XImage image = { XImage image = {
@ -679,7 +715,7 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
.red_mask = 0xFF0000, .red_mask = 0xFF0000,
.green_mask = 0xFF00, .green_mask = 0xFF00,
.blue_mask = 0xFF, .blue_mask = 0xFF,
.data = (char*)img_data .data = (char *)img_data
}; };
/* Render image 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); free(img_data);
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) { if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
unlock; unlock;
continue; continue;
} }
#endif /* __linux__ */ #endif /* __linux__ */
} }
unlock; unlock;
} }
usleep(1000 * 1000 / 24); usleep(1000 * 1000 / 24);
} }
} }
@ -727,13 +767,16 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
if ( type == vdt_input ) { if ( type == vdt_input ) {
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 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; int i;
for (i = 0; i < device->n_buffers; ++i) { for (i = 0; i < device->n_buffers; ++i) {
if ( -1 == munmap(device->buffers[i].start, device->buffers[i].length) ) { if ( -1 == munmap(device->buffers[i].start, device->buffers[i].length) ) {
} }
} }
close(device->fd); close(device->fd);
#else /* __OSX__ */ #else /* __OSX__ */
@ -759,14 +802,13 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
free(device); free(device);
} }
} } else device->ref_count--;
else device->ref_count--;
unlock; unlock;
return rc; return rc;
} }
void print_video_devices(ToxWindow* self, VideoDeviceType type) void print_video_devices(ToxWindow *self, VideoDeviceType type)
{ {
int i; int i;

View File

@ -45,10 +45,11 @@ typedef enum VideoDeviceError {
vde_CaptureError = -9, vde_CaptureError = -9,
} VideoDeviceError; } 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 #ifdef VIDEO
VideoDeviceError init_video_devices(ToxAV* av); VideoDeviceError init_video_devices(ToxAV *av);
#else #else
VideoDeviceError init_video_devices(); VideoDeviceError init_video_devices();
#endif /* VIDEO */ #endif /* VIDEO */
@ -56,20 +57,22 @@ VideoDeviceError init_video_devices();
VideoDeviceError terminate_video_devices(); VideoDeviceError terminate_video_devices();
/* Callback handles ready data from INPUT device */ /* Callback handles ready data from INPUT device */
VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback, void* data); VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback,
void* get_video_device_callback_data(uint32_t device_idx); void *data);
void *get_video_device_callback_data(uint32_t device_idx);
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection); 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 */ /* 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 */ /* Stop device */
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx); VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx);
/* Write data to device */ /* 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); void get_primary_video_device_name(VideoDeviceType type, char *buf, int size);
VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection); VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection);

View File

@ -550,10 +550,12 @@ void on_window_resize(void)
} }
#ifdef AUDIO #ifdef AUDIO
if (w->chatwin->infobox.active) { if (w->chatwin->infobox.active) {
delwin(w->chatwin->infobox.win); delwin(w->chatwin->infobox.win);
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH); w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
} }
#endif /* AUDIO */ #endif /* AUDIO */
scrollok(w->chatwin->history, 0); scrollok(w->chatwin->history, 0);
@ -563,19 +565,28 @@ void on_window_resize(void)
static void draw_window_tab(ToxWindow *toxwin) static void draw_window_tab(ToxWindow *toxwin)
{ {
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert)); if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
clrtoeol(); clrtoeol();
printw(" [%s]", toxwin->name); printw(" [%s]", toxwin->name);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert)); if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
} }
static void draw_bar(void) static void draw_bar(void)
{ {
int y, x;
// save current cursor position
getyx(active_window->window, y, x);
attron(COLOR_PAIR(BLUE)); attron(COLOR_PAIR(BLUE));
mvhline(LINES - 2, 0, '_', COLS); mvhline(LINES - 2, 0, '_', COLS);
attroff(COLOR_PAIR(BLUE)); attroff(COLOR_PAIR(BLUE));
@ -613,6 +624,9 @@ static void draw_bar(void)
attroff(A_BOLD); attroff(A_BOLD);
} }
// restore cursor position after drawing
move(y, x);
refresh(); refresh();
} }
@ -630,6 +644,7 @@ void draw_active_window(Tox *m)
touchwin(a->window); touchwin(a->window);
a->onDraw(a, m); a->onDraw(a, m);
wrefresh(a->window);
/* Handle input */ /* Handle input */
bool ltr; bool ltr;

View File

@ -214,8 +214,8 @@ struct infobox {
bool hide; bool hide;
bool active; bool active;
uint64_t lastupdate; time_t lastupdate;
uint64_t starttime; time_t starttime;
char timestr[TIME_STR_SIZE]; char timestr[TIME_STR_SIZE];
WINDOW *win; WINDOW *win;

View File

@ -57,8 +57,7 @@ struct _Xtra {
Atom expecting_type; Atom expecting_type;
} Xtra; } Xtra;
typedef struct _Property typedef struct _Property {
{
unsigned char *data; unsigned char *data;
int read_format; int read_format;
unsigned long read_num; unsigned long read_num;
@ -97,21 +96,23 @@ Property read_property(Window s, Atom p)
Atom get_dnd_type(long *a, int l) Atom get_dnd_type(long *a, int l)
{ {
int i = 0; int i = 0;
for (; i < l; i ++) { for (; i < l; i ++) {
if (a[i] != XtraNil) return a[i]; /* Get first valid */ if (a[i] != XtraNil) return a[i]; /* Get first valid */
} }
return XtraNil; return XtraNil;
} }
/* TODO maybe support only certain types in the future */ /* 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); Xtra.handling_version = (e->data.l[1] >> 24);
if ((e->data.l[1] & 1)) { if ((e->data.l[1] & 1)) {
// Fetch the list of possible conversions // Fetch the list of possible conversions
Property p = read_property(e->data.l[0], XdndTypeList); 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); XFree(p.data);
} else { } else {
// Use the available list // 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 = { XEvent ev = {
.xclient = { .xclient = {
@ -143,7 +144,7 @@ static void handle_xdnd_position(XClientMessageEvent* e)
XFlush(Xtra.display); XFlush(Xtra.display);
} }
static void handle_xdnd_drop(XClientMessageEvent* e) static void handle_xdnd_drop(XClientMessageEvent *e)
{ {
/* Not expecting any type */ /* Not expecting any type */
if (Xtra.expecting_type == XtraNil) { 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 */ /* DnD succesfully finished, send finished and call callback */
XEvent ev = { XEvent ev = {
@ -199,12 +200,12 @@ static void handle_xdnd_selection(XSelectionEvent* e)
/* Call callback for every entry */ /* Call callback for every entry */
if (Xtra.on_drop && p.read_num) if (Xtra.on_drop && p.read_num) {
{
char *sptr; char *sptr;
char *str = strtok_r((char *) p.data, "\n\r", &sptr); char *str = strtok_r((char *) p.data, "\n\r", &sptr);
if (str) Xtra.on_drop(str, dt); if (str) Xtra.on_drop(str, dt);
while ((str = strtok_r(NULL, "\n\r", &sptr))) while ((str = strtok_r(NULL, "\n\r", &sptr)))
Xtra.on_drop(str, dt); Xtra.on_drop(str, dt);
} }
@ -212,7 +213,7 @@ static void handle_xdnd_selection(XSelectionEvent* e)
if (p.data) XFree(p.data); if (p.data) XFree(p.data);
} }
void *event_loop(void* p) void *event_loop(void *p)
{ {
/* Handle events like a real nigga */ /* Handle events like a real nigga */
@ -221,30 +222,27 @@ void *event_loop(void* p)
XEvent event; XEvent event;
int pending; int pending;
while (Xtra.display) while (Xtra.display) {
{
/* NEEDMOEVENTSFODEMPROGRAMS */ /* NEEDMOEVENTSFODEMPROGRAMS */
XLockDisplay(Xtra.display); 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); XUnlockDisplay(Xtra.display);
usleep(10000); usleep(10000);
continue; continue;
} }
if (event.type == ClientMessage) if (event.type == ClientMessage) {
{
Atom type = event.xclient.message_type; Atom type = event.xclient.message_type;
if (type == XdndEnter) handle_xdnd_enter(&event.xclient); if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
else if (type == XdndPosition) handle_xdnd_position(&event.xclient); else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient); else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
else if (type == XtraTerminate) break; 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*/ /* AINNOBODYCANHANDLEDEMEVENTS*/
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event); else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
@ -256,6 +254,7 @@ void *event_loop(void* p)
* otherwise HEWUSAGUDBOI happens * otherwise HEWUSAGUDBOI happens
*/ */
if (Xtra.display) XCloseDisplay(Xtra.display); if (Xtra.display) XCloseDisplay(Xtra.display);
return (Xtra.display = NULL); return (Xtra.display = NULL);
} }
@ -267,6 +266,7 @@ int init_xtra(drop_callback d)
else Xtra.on_drop = d; else Xtra.on_drop = d;
XInitThreads(); XInitThreads();
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1; if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
Xtra.terminal_window = focused_window_id(); Xtra.terminal_window = focused_window_id();
@ -335,9 +335,10 @@ int init_xtra(drop_callback d)
XA_ATOM, XA_ATOM,
32, 32,
PropModeReplace, PropModeReplace,
(unsigned char*)&XdndVersion, 1); (unsigned char *)&XdndVersion, 1);
pthread_t id; pthread_t id;
if (pthread_create(&id, NULL, event_loop, NULL) != 0) if (pthread_create(&id, NULL, event_loop, NULL) != 0)
return -1; return -1;

View File

@ -31,7 +31,7 @@ typedef enum {
} }
DropType; DropType;
typedef void (*drop_callback) (const char*, DropType); typedef void (*drop_callback) (const char *, DropType);
int init_xtra(drop_callback d); int init_xtra(drop_callback d);
void terminate_xtra(); void terminate_xtra();