mirror of
https://github.com/Tha14/toxic.git
synced 2025-06-27 17:46:44 +02:00
Compare commits
68 Commits
Author | SHA1 | Date | |
---|---|---|---|
3515623159 | |||
2194b9e259 | |||
c24e1bd2b8 | |||
38ec96e96a | |||
d2b572ede1 | |||
703d5419a3 | |||
221d761ff4 | |||
151f5f0c51 | |||
4f6c603543 | |||
a009f11c0c | |||
1f8c11a33a | |||
5e20e6b279 | |||
1f02bb2be5 | |||
98154b3cba | |||
379ad9e116 | |||
cb21672600 | |||
4019395f44 | |||
ee084c572c | |||
41a8401ac5 | |||
d8a3f7de4c | |||
c425aa2f27 | |||
94e026d114 | |||
f89638635a | |||
402b86687f | |||
5b1b420ac0 | |||
62ec514f17 | |||
f893dd755f | |||
9aedcf7753 | |||
d3effa26b5 | |||
2ec180789b | |||
9f74d3a3a8 | |||
9fcbc3bde0 | |||
cf16849b37 | |||
32442b6286 | |||
50f227418b | |||
fc06a625a6 | |||
70bd39eb74 | |||
4e0e322e32 | |||
e73ac9b6a4 | |||
bcda6e476e | |||
5b29ce7132 | |||
f43f644451 | |||
d6fdac9739 | |||
c6a2bb8a90 | |||
04576fea7e | |||
e6f839f9ac | |||
eb02424f8a | |||
2e609c46f6 | |||
a474e3bf39 | |||
93835f0455 | |||
ac6d8ff89c | |||
88e74224ed | |||
deccaec40e | |||
4419be36e8 | |||
b34b51e8c1 | |||
74416b4b58 | |||
675712cea0 | |||
36feebfe8d | |||
3fe9abd84d | |||
fd6432c727 | |||
1feffcc2f0 | |||
6bba3cb9e2 | |||
3cb6db3d60 | |||
77238eeadf | |||
88270827a9 | |||
aade65bfe1 | |||
b24c5d8cf8 | |||
9f0feb7223 |
503
CHANGELOG.md
Normal file
503
CHANGELOG.md
Normal 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)*
|
8
Makefile
8
Makefile
@ -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)
|
||||||
|
@ -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
|
||||||
|
26
doc/toxic.1
26
doc/toxic.1
@ -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-07-08
|
.\" Date: 2016-09-20
|
||||||
.\" Manual: Toxic Manual
|
.\" Manual: Toxic Manual
|
||||||
.\" Source: toxic __VERSION__
|
.\" Source: toxic __VERSION__
|
||||||
.\" Language: English
|
.\" Language: English
|
||||||
.\"
|
.\"
|
||||||
.TH "TOXIC" "1" "2015\-07\-08" "toxic __VERSION__" "Toxic Manual"
|
.TH "TOXIC" "1" "2016\-09\-20" "toxic __VERSION__" "Toxic Manual"
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
.\" * Define some portability stuff
|
.\" * Define some portability stuff
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
@ -70,7 +70,7 @@ Encrypt an unencrypted data file\&. An error will occur if this option is used w
|
|||||||
Use specified
|
Use specified
|
||||||
\fIdata\-file\fR
|
\fIdata\-file\fR
|
||||||
instead of
|
instead of
|
||||||
\fI~/\&.config/tox/data\fR
|
\fI~/\&.config/tox/toxic_profile\&.tox\fR
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\-h, \-\-help
|
\-h, \-\-help
|
||||||
@ -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,12 +122,14 @@ 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/data
|
~/\&.config/tox/toxic_profile\&.tox
|
||||||
.RS 4
|
.RS 4
|
||||||
Savestate which contains your personal info (nickname, Tox ID, contacts, etc)
|
Savestate which contains your personal info (nickname, Tox ID, contacts, etc)
|
||||||
.RE
|
.RE
|
||||||
@ -144,7 +146,11 @@ Configuration example\&.
|
|||||||
.RE
|
.RE
|
||||||
.SH "BUGS"
|
.SH "BUGS"
|
||||||
.sp
|
.sp
|
||||||
Unicode characters with a width larger than 1 column may cause strange behaviour\&. Expect more bugs and bad behaviour: this software is in a pre\-alpha stage\&.
|
\-Unicode characters with a width larger than 1 column may cause strange behaviour\&.
|
||||||
|
.sp
|
||||||
|
\-Text occasionally fails to auto\-scroll to the bottom\&.
|
||||||
|
.sp
|
||||||
|
\-Screen flickering sometimes occurs on certain terminals\&.
|
||||||
.SH "AUTHORS"
|
.SH "AUTHORS"
|
||||||
.sp
|
.sp
|
||||||
JFreegman <JFreegman@gmail\&.com>
|
JFreegman <JFreegman@gmail\&.com>
|
||||||
@ -153,6 +159,6 @@ JFreegman <JFreegman@gmail\&.com>
|
|||||||
\fBtoxic\&.conf\fR(5)
|
\fBtoxic\&.conf\fR(5)
|
||||||
.SH "LINKS"
|
.SH "LINKS"
|
||||||
.sp
|
.sp
|
||||||
Project page: https://github\&.com/Tox/toxic
|
Project page: https://github\&.com/JFreegman/toxic
|
||||||
.sp
|
.sp
|
||||||
IRC channel: chat\&.freenode\&.net#tox
|
IRC channel: chat\&.freenode\&.net#tox
|
||||||
|
@ -35,14 +35,13 @@ OPTIONS
|
|||||||
is used with an encrypted data file.
|
is used with an encrypted data file.
|
||||||
|
|
||||||
-f, --file data-file::
|
-f, --file data-file::
|
||||||
Use specified 'data-file' instead of '~/.config/tox/data'
|
Use specified 'data-file' instead of '~/.config/tox/toxic_profile.tox'
|
||||||
|
|
||||||
-h, --help::
|
-h, --help::
|
||||||
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,10 +67,11 @@ 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/data::
|
~/.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,
|
||||||
etc)
|
etc)
|
||||||
|
|
||||||
@ -83,9 +83,12 @@ FILES
|
|||||||
|
|
||||||
BUGS
|
BUGS
|
||||||
----
|
----
|
||||||
Unicode characters with a width larger than 1 column may cause strange
|
-Unicode characters with a width larger than 1 column may cause strange
|
||||||
behaviour. Expect more bugs and bad behaviour: this software is in a
|
behaviour.
|
||||||
pre-alpha stage.
|
|
||||||
|
-Text occasionally fails to auto-scroll to the bottom.
|
||||||
|
|
||||||
|
-Screen flickering sometimes occurs on certain terminals.
|
||||||
|
|
||||||
AUTHORS
|
AUTHORS
|
||||||
-------
|
-------
|
||||||
@ -97,6 +100,6 @@ SEE ALSO
|
|||||||
|
|
||||||
LINKS
|
LINKS
|
||||||
-----
|
-----
|
||||||
Project page: <https://github.com/Tox/toxic>
|
Project page: <https://github.com/JFreegman/toxic>
|
||||||
|
|
||||||
IRC channel: chat.freenode.net#tox
|
IRC channel: chat.freenode.net#tox
|
||||||
|
@ -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: 2015-03-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" "2015\-03\-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
|
||||||
@ -113,6 +113,16 @@ Show others when you\(cqre typing in a 1\-on\-1 chat\&. true or false
|
|||||||
Show welcome message on startup\&. true or false
|
Show welcome message on startup\&. true or false
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
\fBshow_connection_msg\fR
|
||||||
|
.RS 4
|
||||||
|
Enable friend connection change notifications\&. true or false
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBnodelist_update_freq\fR
|
||||||
|
.RS 4
|
||||||
|
How often in days to update the DHT nodes list\&. (0 to disable updates)
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
\fBhistory_size\fR
|
\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)
|
||||||
@ -146,6 +156,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
|
||||||
@ -189,6 +231,11 @@ Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
|
|||||||
.RS 4
|
.RS 4
|
||||||
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
|
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
|
||||||
.RE
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBpassword_eval\fR
|
||||||
|
.RS 4
|
||||||
|
Replace password prompt by running this command and using its output as the password\&.
|
||||||
|
.RE
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\fBsounds\fR
|
\fBsounds\fR
|
||||||
@ -303,6 +350,11 @@ Key combination to scroll contacts list down\&.
|
|||||||
.RS 4
|
.RS 4
|
||||||
Toggle the peer list on and off\&.
|
Toggle the peer list on and off\&.
|
||||||
.RE
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBtoggle_paste_mode\fR
|
||||||
|
.RS 4
|
||||||
|
Toggle treating linebreaks as enter key press\&.
|
||||||
|
.RE
|
||||||
.RE
|
.RE
|
||||||
.SH "FILES"
|
.SH "FILES"
|
||||||
.PP
|
.PP
|
||||||
@ -320,7 +372,7 @@ Configuration example\&.
|
|||||||
\fBtoxic\fR(1)
|
\fBtoxic\fR(1)
|
||||||
.SH "RESOURCES"
|
.SH "RESOURCES"
|
||||||
.sp
|
.sp
|
||||||
Project page: https://github\&.com/Tox/toxic
|
Project page: https://github\&.com/JFreegman/toxic
|
||||||
.sp
|
.sp
|
||||||
IRC channel: chat\&.freenode\&.net#tox
|
IRC channel: chat\&.freenode\&.net#tox
|
||||||
.SH "AUTHORS"
|
.SH "AUTHORS"
|
||||||
|
@ -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
|
||||||
@ -72,6 +72,12 @@ OPTIONS
|
|||||||
*show_welcome_msg*;;
|
*show_welcome_msg*;;
|
||||||
Show welcome message on startup. true or false
|
Show welcome message on startup. true or false
|
||||||
|
|
||||||
|
*show_connection_msg*;;
|
||||||
|
Enable friend connection change notifications. true or false
|
||||||
|
|
||||||
|
*nodelist_update_freq*;;
|
||||||
|
How often in days to update the DHT nodes list. (0 to disable updates)
|
||||||
|
|
||||||
*history_size*;;
|
*history_size*;;
|
||||||
Maximum lines for chat window history. Integer value. (for example: 700)
|
Maximum lines for chat window history. Integer value. (for example: 700)
|
||||||
|
|
||||||
@ -97,6 +103,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.
|
||||||
|
|
||||||
@ -123,6 +146,10 @@ OPTIONS
|
|||||||
*chatlogs_path*;;
|
*chatlogs_path*;;
|
||||||
Default path for chatlogs. String value. Absolute path for chatlog files.
|
Default path for chatlogs. String value. Absolute path for chatlog files.
|
||||||
|
|
||||||
|
*password_eval*;;
|
||||||
|
Replace password prompt by running this command and using its output as
|
||||||
|
the password.
|
||||||
|
|
||||||
*sounds*::
|
*sounds*::
|
||||||
Configuration related to notification sounds.
|
Configuration related to notification sounds.
|
||||||
Special value "silent" can be used to disable a specific notification. +
|
Special value "silent" can be used to disable a specific notification. +
|
||||||
@ -194,6 +221,9 @@ OPTIONS
|
|||||||
*toggle_peerlist*;;
|
*toggle_peerlist*;;
|
||||||
Toggle the peer list on and off.
|
Toggle the peer list on and off.
|
||||||
|
|
||||||
|
*toggle_paste_mode*;;
|
||||||
|
Toggle treating linebreaks as enter key press.
|
||||||
|
|
||||||
|
|
||||||
FILES
|
FILES
|
||||||
-----
|
-----
|
||||||
@ -211,7 +241,7 @@ SEE ALSO
|
|||||||
|
|
||||||
RESOURCES
|
RESOURCES
|
||||||
---------
|
---------
|
||||||
Project page: <https://github.com/Tox/toxic>
|
Project page: <https://github.com/JFreegman/toxic>
|
||||||
|
|
||||||
IRC channel: chat.freenode.net#tox
|
IRC channel: chat.freenode.net#tox
|
||||||
|
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
144.76.60.215 33445 04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
|
|
||||||
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
|
|
||||||
178.21.112.187 33445 4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057
|
|
||||||
195.154.119.113 33445 E398A69646B8CEACA9F0B84F553726C1C49270558C57DF5F3C368F05A7D71354
|
|
||||||
192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
|
|
||||||
46.38.239.179 33445 F5A1A38EFB6BD3C2C8AF8B10D85F0F89E931704D349F1D0720C3C4059AF2440A
|
|
||||||
178.62.250.138 33445 788236D34978D1D5BD822F0A5BEBD2C53C64CC31CD3149350EE27D4D9A2F9B6B
|
|
||||||
130.133.110.14 33445 461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F
|
|
||||||
104.167.101.29 33445 5918AC3C06955962A75AD7DF4F80A5D7C34F7DB9E1498D2E0495DE35B3FE8A57
|
|
||||||
205.185.116.116 33445 A179B09749AC826FF01F37A9613F6B57118AE014D4196A0E1105A98F93A54702
|
|
||||||
198.98.51.198 33445 1D5A5F2F5D6233058BF0259B09622FB40B482E4FA0931EB8FD3AB8E7BF7DAF6F
|
|
||||||
80.232.246.79 33445 A7A060D553B017D9D8F038E265C7AFB6C70BAAC55070197F9C007432D0038E0F
|
|
||||||
108.61.165.198 33445 8E7D0B859922EF569298B4D261A8CCB5FEA14FB91ED412A7603A585A25698832
|
|
||||||
212.71.252.109 33445 C4CEB8C7AC607C6B374E2E782B3C00EA3A63B80D4910B8649CCACDD19F260819
|
|
||||||
194.249.212.109 33445 3CEE1F054081E7A011234883BC4FC39F661A55B73637A5AC293DDF1251D9432B
|
|
||||||
185.25.116.107 33445 DA4E4ED4B697F2E9B000EEFE3A34B554ACD3F45F5C96EAEA2516DD7FF9AF7B43
|
|
||||||
192.99.168.140 33445 6A4D0607A296838434A6A7DDF99F50EF9D60A2C510BBF31FE538A25CB6B4652F
|
|
@ -1,2 +1 @@
|
|||||||
toxme.io 1A39E7A5D5FA9CF155C751570A32E625698A60A55F6D88028F949F66144F4F25
|
toxme.io 1A39E7A5D5FA9CF155C751570A32E625698A60A55F6D88028F949F66144F4F25
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -29,6 +41,12 @@ ui = {
|
|||||||
// true to show the welcome message on startup
|
// true to show the welcome message on startup
|
||||||
show_welcome_msg=true;
|
show_welcome_msg=true;
|
||||||
|
|
||||||
|
// true to show friend connection change messages on the home screen
|
||||||
|
show_connection_msg=true;
|
||||||
|
|
||||||
|
// How often in days to update the DHT nodes list. (0 to disable updates)
|
||||||
|
nodeslist_update_freq=7;
|
||||||
|
|
||||||
// maximum lines for chat window history
|
// maximum lines for chat window history
|
||||||
history_size=700;
|
history_size=700;
|
||||||
|
|
||||||
@ -57,7 +75,7 @@ audio = {
|
|||||||
|
|
||||||
// preferred audio output device; numbers correspond to /lsdev out
|
// preferred audio output device; numbers correspond to /lsdev out
|
||||||
output_device=0;
|
output_device=0;
|
||||||
|
|
||||||
// default VAD treshold; float (recommended values are around 40)
|
// default VAD treshold; float (recommended values are around 40)
|
||||||
VAD_treshold=40.0;
|
VAD_treshold=40.0;
|
||||||
};
|
};
|
||||||
@ -86,7 +104,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
|
||||||
keys = {
|
keys = {
|
||||||
next_tab="Ctrl+P";
|
next_tab="Ctrl+P";
|
||||||
prev_tab="Ctrl+O";
|
prev_tab="Ctrl+O";
|
||||||
@ -98,5 +116,6 @@ keys = {
|
|||||||
peer_list_up="Ctrl+[";
|
peer_list_up="Ctrl+[";
|
||||||
peer_list_down="Ctrl+]";
|
peer_list_down="Ctrl+]";
|
||||||
toggle_peerlist="Ctrl+b";
|
toggle_peerlist="Ctrl+b";
|
||||||
|
toggle_paste_mode="Ctrl+T";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -103,7 +103,8 @@ 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 size );
|
void write_device_callback( uint32_t friend_number, const int16_t* PCM, uint16_t sample_count, uint8_t channels,
|
||||||
|
uint32_t sample_rate );
|
||||||
|
|
||||||
static void print_err (ToxWindow *self, const char *error_str)
|
static void print_err (ToxWindow *self, const char *error_str)
|
||||||
{
|
{
|
||||||
@ -120,9 +121,9 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
|
|||||||
CallControl.av = toxav_new(tox, &error);
|
CallControl.av = toxav_new(tox, &error);
|
||||||
|
|
||||||
CallControl.audio_enabled = true;
|
CallControl.audio_enabled = true;
|
||||||
CallControl.audio_bit_rate = 48;
|
CallControl.audio_bit_rate = 64;
|
||||||
CallControl.audio_sample_rate = 48000;
|
CallControl.audio_sample_rate = 48000;
|
||||||
CallControl.audio_frame_duration = 10;
|
CallControl.audio_frame_duration = 20;
|
||||||
CallControl.audio_channels = 1;
|
CallControl.audio_channels = 1;
|
||||||
|
|
||||||
#ifndef VIDEO
|
#ifndef VIDEO
|
||||||
@ -180,10 +181,11 @@ void read_device_callback(const int16_t* captured, uint32_t size, void* data)
|
|||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_device_callback(uint32_t friend_number, const int16_t* PCM, uint16_t size)
|
void write_device_callback(uint32_t friend_number, const int16_t* PCM, uint16_t sample_count, uint8_t channels,
|
||||||
|
uint32_t sample_rate)
|
||||||
{
|
{
|
||||||
if ( CallControl.calls[friend_number].ttas )
|
if ( CallControl.calls[friend_number].ttas )
|
||||||
write_out(CallControl.calls[friend_number].out_idx, PCM, size, CallControl.audio_channels);
|
write_out(CallControl.calls[friend_number].out_idx, PCM, sample_count, channels, sample_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_transmission(ToxWindow *self, Call *call)
|
int start_transmission(ToxWindow *self, Call *call)
|
||||||
@ -226,7 +228,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 ) {
|
||||||
@ -328,7 +330,7 @@ void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
|
|||||||
int16_t const *pcm, size_t sample_count,
|
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)
|
||||||
{
|
{
|
||||||
write_device_callback(friend_number, pcm, frame_size);
|
write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
|
void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
|
||||||
@ -570,8 +572,8 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
{
|
{
|
||||||
const char *error_str = NULL;
|
const char *error_str = NULL;
|
||||||
|
|
||||||
if ( !self->is_call ) {
|
if ( !CallControl.av ) {
|
||||||
error_str = "Not in a call.";
|
error_str = "Audio not supported!";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,8 +582,8 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !CallControl.av ) {
|
if ( !self->is_call && !CallControl.pending_call ) {
|
||||||
error_str = "Audio not supported!";
|
error_str = "Not in a call.";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,18 +591,7 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
callback_video_end(self->num);
|
callback_video_end(self->num);
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
if ( CallControl.pending_call ) {
|
stop_current_call(self);
|
||||||
/* Manually send a cancel call control because call hasn't started */
|
|
||||||
toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL);
|
|
||||||
callback_call_canceled(self->num);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
stop_transmission(&CallControl.calls[self->num], self->num);
|
|
||||||
callback_call_ended(self->num);
|
|
||||||
}
|
|
||||||
|
|
||||||
CallControl.pending_call = false;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
@ -833,8 +824,13 @@ on_error:
|
|||||||
|
|
||||||
void stop_current_call(ToxWindow* self)
|
void stop_current_call(ToxWindow* self)
|
||||||
{
|
{
|
||||||
Call *this_call = &CallControl.calls[self->num];
|
if ( CallControl.pending_call ) {
|
||||||
|
toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL);
|
||||||
|
callback_call_canceled(self->num);
|
||||||
|
} else {
|
||||||
|
stop_transmission(&CallControl.calls[self->num], self->num);
|
||||||
|
callback_call_ended(self->num);
|
||||||
|
}
|
||||||
|
|
||||||
if (this_call && self->is_call)
|
CallControl.pending_call = false;
|
||||||
stop_transmission(this_call, self->num);
|
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,11 @@ 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] ) {
|
||||||
@ -317,9 +321,6 @@ 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;
|
||||||
}
|
}
|
||||||
@ -357,7 +358,8 @@ 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 length, uint8_t channels)
|
inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t sample_count, uint8_t channels,
|
||||||
|
uint32_t sample_rate)
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
||||||
|
|
||||||
@ -386,7 +388,7 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
alBufferData(bufid, device->sound_mode, data, length * 2 * channels, device->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;
|
||||||
@ -409,23 +411,26 @@ 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);
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* You can have multiple sources (Input devices) but only one output device.
|
* You can have multiple sources (Input devices) but only one output device.
|
||||||
* Pass buffers to output device via write();
|
* Pass buffers to output device via write();
|
||||||
* Read from running input device(s) via select()/callback combo.
|
* Read from running input device(s) via select()/callback combo.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
|||||||
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);
|
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);
|
||||||
|
@ -53,12 +53,14 @@ static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* puts match in match buffer. if more than one match, add first n chars that are identical.
|
/* puts match in match buffer. if more than one match, add first n chars that are identical.
|
||||||
e.g. if matches contains: [foo, foobar, foe] we put fo in matches. */
|
* e.g. if matches contains: [foo, foobar, foe] we put fo in match.
|
||||||
static void get_str_match(ToxWindow *self, char *match, char (*matches)[MAX_STR_SIZE], int n)
|
*
|
||||||
|
* Returns the length of the match.
|
||||||
|
*/
|
||||||
|
static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char (*matches)[MAX_STR_SIZE], int n)
|
||||||
{
|
{
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
strcpy(match, matches[0]);
|
return snprintf(match, match_sz, "%s", matches[0]);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
@ -71,14 +73,14 @@ static void get_str_match(ToxWindow *self, char *match, char (*matches)[MAX_STR_
|
|||||||
char ch2 = matches[j][i];
|
char ch2 = matches[j][i];
|
||||||
|
|
||||||
if (ch1 != ch2 || !ch1) {
|
if (ch1 != ch2 || !ch1) {
|
||||||
strcpy(match, matches[0]);
|
snprintf(match, match_sz, "%s", matches[0]);
|
||||||
match[i] = '\0';
|
match[i] = '\0';
|
||||||
return;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(match, matches[0]);
|
return snprintf(match, match_sz, "%s", matches[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* looks for all instances in list that begin with the last entered word in line according to pos,
|
/* looks for all instances in list that begin with the last entered word in line according to pos,
|
||||||
@ -164,8 +166,11 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
|
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
|
||||||
|
|
||||||
char match[MAX_STR_SIZE];
|
char match[MAX_STR_SIZE];
|
||||||
get_str_match(self, match, matches, n_matches);
|
size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches);
|
||||||
size_t match_len = strlen(match);
|
|
||||||
|
if (match_len == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (dir_search) {
|
if (dir_search) {
|
||||||
if (n_matches == 1)
|
if (n_matches == 1)
|
||||||
@ -180,15 +185,15 @@ 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;
|
||||||
|
|
||||||
char tmpend[MAX_STR_SIZE];
|
char tmpend[MAX_STR_SIZE];
|
||||||
snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
|
snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
|
||||||
|
|
||||||
if (match_len + n_endchrs + strlen(tmpend) >= sizeof(ubuf))
|
if (match_len + n_endchrs + strlen(tmpend) >= sizeof(ubuf)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(&ubuf[strt], match);
|
strcpy(&ubuf[strt], match);
|
||||||
strcpy(&ubuf[strt + match_len], endchrs);
|
strcpy(&ubuf[strt + match_len], endchrs);
|
||||||
@ -197,8 +202,9 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
/* convert to widechar and copy back to original buf */
|
/* convert to widechar and copy back to original buf */
|
||||||
wchar_t newbuf[MAX_STR_SIZE];
|
wchar_t newbuf[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (mbs_to_wcs_buf(newbuf, ubuf, sizeof(newbuf) / sizeof(wchar_t)) == -1)
|
if (mbs_to_wcs_buf(newbuf, ubuf, sizeof(newbuf) / sizeof(wchar_t)) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
wcscpy(ctx->line, newbuf);
|
wcscpy(ctx->line, newbuf);
|
||||||
|
|
||||||
|
584
src/bootstrap.c
Normal file
584
src/bootstrap.c
Normal file
@ -0,0 +1,584 @@
|
|||||||
|
/* 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
42
src/bootstrap.h
Normal 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 */
|
143
src/chat.c
143
src/chat.c
@ -126,11 +126,6 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
|||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
|
||||||
kill_all_file_transfers_friend(m, self->num);
|
|
||||||
log_disable(ctx->log);
|
|
||||||
line_info_cleanup(ctx->hst);
|
|
||||||
cqueue_cleanup(ctx->cqueue);
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
stop_video_stream(self);
|
stop_video_stream(self);
|
||||||
@ -138,6 +133,11 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
|||||||
stop_current_call(self);
|
stop_current_call(self);
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
kill_all_file_transfers_friend(m, self->num);
|
||||||
|
log_disable(ctx->log);
|
||||||
|
line_info_cleanup(ctx->hst);
|
||||||
|
cqueue_cleanup(ctx->cqueue);
|
||||||
|
|
||||||
delwin(ctx->linewin);
|
delwin(ctx->linewin);
|
||||||
delwin(ctx->history);
|
delwin(ctx->history);
|
||||||
delwin(statusbar->topline);
|
delwin(statusbar->topline);
|
||||||
@ -160,9 +160,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,
|
||||||
@ -174,9 +176,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)
|
||||||
@ -215,7 +219,14 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
|
|||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
get_nick_truncate(m, nick, num);
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
if (connection_status != TOX_CONNECTION_NONE && statusbar->connection == TOX_CONNECTION_NONE) {
|
TOX_CONNECTION prev_status = statusbar->connection;
|
||||||
|
statusbar->connection = connection_status;
|
||||||
|
|
||||||
|
if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prev_status == TOX_CONNECTION_NONE) {
|
||||||
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
|
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
|
||||||
? tox_friend_get_typing(m, num, NULL) : false;
|
? tox_friend_get_typing(m, num, NULL) : false;
|
||||||
chat_resume_file_senders(self, m, num);
|
chat_resume_file_senders(self, m, num);
|
||||||
@ -235,8 +246,6 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
statusbar->connection = connection_status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onTypingChange(ToxWindow *self, Tox *m, uint32_t num, bool is_typing)
|
static void chat_onTypingChange(ToxWindow *self, Tox *m, uint32_t num, bool is_typing)
|
||||||
@ -449,7 +458,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;
|
||||||
@ -591,11 +600,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, int32_t friendnumber, uint8_t type, const char *group_pub_key,
|
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key,
|
||||||
@ -618,7 +627,7 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, ui
|
|||||||
Friends.list[friendnumber].group_invite.length = length;
|
Friends.list[friendnumber].group_invite.length = length;
|
||||||
Friends.list[friendnumber].group_invite.type = type;
|
Friends.list[friendnumber].group_invite.type = type;
|
||||||
|
|
||||||
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);
|
||||||
@ -646,7 +655,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!");
|
||||||
@ -770,33 +779,6 @@ void chat_onEnd (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
|||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
void chat_onRequestTimeout (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
|
||||||
{
|
|
||||||
if (!self || self->num != friend_number)
|
|
||||||
return;
|
|
||||||
|
|
||||||
self->is_call = false;
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No answer!");
|
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
|
||||||
stop_sound(self->ringing_sound);
|
|
||||||
#endif /* SOUND_NOTIFY */
|
|
||||||
}
|
|
||||||
|
|
||||||
void chat_onPeerTimeout (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
|
||||||
{
|
|
||||||
if (!self || self->num != friend_number)
|
|
||||||
return;
|
|
||||||
|
|
||||||
self->is_call = false;
|
|
||||||
kill_infobox(self);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer disconnected; call ended!");
|
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
|
||||||
stop_sound(self->ringing_sound);
|
|
||||||
#endif /* SOUND_NOTIFY */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_infobox(ToxWindow *self)
|
static void init_infobox(ToxWindow *self)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
@ -843,7 +825,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)
|
||||||
@ -880,7 +862,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 */
|
||||||
@ -905,7 +887,6 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
|||||||
|
|
||||||
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||||
{
|
{
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
|
||||||
@ -916,12 +897,15 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ctx->pastemode && key == '\r')
|
||||||
|
key = '\n';
|
||||||
|
|
||||||
if (self->help->active) {
|
if (self->help->active) {
|
||||||
help_onKey(self, key);
|
help_onKey(self, key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ltr) { /* char is printable */
|
if (ltr || key == '\n') { /* char is printable */
|
||||||
input_new_char(self, key, x, y, x2, y2);
|
input_new_char(self, key, x, y, x2, y2);
|
||||||
|
|
||||||
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE)
|
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE)
|
||||||
@ -963,38 +947,42 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
sound_notify(self, notif_error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (key == '\n') {
|
} else if (key == '\r') {
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
|
|
||||||
char line[MAX_STR_SIZE];
|
if (!wstring_is_empty(ctx->line))
|
||||||
|
{
|
||||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
|
||||||
memset(&line, 0, sizeof(line));
|
|
||||||
|
|
||||||
if (!string_is_empty(line))
|
|
||||||
add_line_to_hist(ctx);
|
add_line_to_hist(ctx);
|
||||||
|
|
||||||
if (line[0] == '/') {
|
wstrsubst(ctx->line, L'¶', L'\n');
|
||||||
if (strcmp(line, "/close") == 0) {
|
|
||||||
kill_chat_window(self, m);
|
char line[MAX_STR_SIZE] = {0};
|
||||||
return;
|
|
||||||
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
||||||
send_action(self, ctx, m, line + strlen("/me "));
|
memset(&line, 0, sizeof(line));
|
||||||
|
|
||||||
|
if (line[0] == '/') {
|
||||||
|
if (strcmp(line, "/close") == 0) {
|
||||||
|
kill_chat_window(self, m);
|
||||||
|
return;
|
||||||
|
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
||||||
|
send_action(self, ctx, m, line + strlen("/me "));
|
||||||
|
} else {
|
||||||
|
execute(ctx->history, self, m, line, CHAT_COMMAND_MODE);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
execute(ctx->history, self, m, line, CHAT_COMMAND_MODE);
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
|
|
||||||
|
size_t len = tox_self_get_name_size(m);
|
||||||
|
selfname[len] = '\0';
|
||||||
|
|
||||||
|
char timefrmt[TIME_STR_SIZE];
|
||||||
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
|
line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
|
||||||
|
cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, ctx->hst->line_end->id + 1);
|
||||||
}
|
}
|
||||||
} else if (!string_is_empty(line)) {
|
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
|
||||||
tox_self_get_name(m, (uint8_t *) selfname);
|
|
||||||
|
|
||||||
size_t len = tox_self_get_name_size(m);
|
|
||||||
selfname[len] = '\0';
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
|
||||||
|
|
||||||
line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
|
|
||||||
cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, ctx->hst->line_end->id + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wclear(ctx->linewin);
|
wclear(ctx->linewin);
|
||||||
@ -1116,12 +1104,11 @@ 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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
@ -99,16 +99,13 @@ char *get_user_config_dir(void)
|
|||||||
|
|
||||||
# endif /* __APPLE__ */
|
# endif /* __APPLE__ */
|
||||||
|
|
||||||
if (!file_exists(user_config_dir)) {
|
|
||||||
free(user_config_dir);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -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
93
src/curl_util.c
Normal 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
55
src/curl_util.h
Normal 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 */
|
@ -38,87 +38,48 @@ extern FriendsList Friends;
|
|||||||
/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
||||||
#define NUM_PROG_MARKS 50
|
#define NUM_PROG_MARKS 50
|
||||||
|
|
||||||
/* Checks for timed out file transfers and closes them. */
|
|
||||||
#define CHECK_FILE_TIMEOUT_INTERAVAL 5
|
|
||||||
void check_file_transfer_timeouts(Tox *m)
|
|
||||||
{
|
|
||||||
char msg[MAX_STR_SIZE];
|
|
||||||
static uint64_t last_check = 0;
|
|
||||||
|
|
||||||
if (!timed_out(last_check, CHECK_FILE_TIMEOUT_INTERAVAL))
|
|
||||||
return;
|
|
||||||
|
|
||||||
last_check = get_unix_time();
|
|
||||||
|
|
||||||
size_t i, j;
|
|
||||||
|
|
||||||
for (i = 0; i < Friends.max_idx; ++i) {
|
|
||||||
if (!Friends.list[i].active)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (j = 0; j < MAX_FILES; ++j) {
|
|
||||||
struct FileTransfer *ft_send = &Friends.list[i].file_sender[j];
|
|
||||||
|
|
||||||
if (ft_send->state > FILE_TRANSFER_PAUSED) {
|
|
||||||
if (timed_out(ft_send->last_keep_alive, TIMEOUT_FILESENDER)) {
|
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", ft_send->file_name);
|
|
||||||
close_file_transfer(ft_send->window, m, ft_send, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FileTransfer *ft_recv = &Friends.list[i].file_receiver[j];
|
|
||||||
|
|
||||||
if (ft_recv->state > FILE_TRANSFER_PAUSED) {
|
|
||||||
if (timed_out(ft_recv->last_keep_alive, TIMEOUT_FILESENDER)) {
|
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", ft_recv->file_name);
|
|
||||||
close_file_transfer(ft_recv->window, m, ft_recv, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* creates initial progress line that will be updated during file transfer.
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
Assumes progline is of size MAX_STR_SIZE */
|
Assumes progline has room for at least MAX_STR_SIZE bytes */
|
||||||
void init_progress_bar(char *progline)
|
void init_progress_bar(char *progline)
|
||||||
{
|
{
|
||||||
strcpy(progline, "0.0 B/s [");
|
strcpy(progline, "0% [");
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < NUM_PROG_MARKS; ++i)
|
for (i = 0; i < NUM_PROG_MARKS; ++i)
|
||||||
strcat(progline, "-");
|
strcat(progline, "-");
|
||||||
|
|
||||||
strcat(progline, "] 0%");
|
strcat(progline, "] 0.0 B/s");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prints a progress bar for file transfers.
|
/* prints a progress bar for file transfers. */
|
||||||
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
|
||||||
void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id)
|
void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id)
|
||||||
{
|
{
|
||||||
if (bps < 0 || pct_done < 0 || pct_done > 100)
|
if (bps < 0 || pct_done < 0 || pct_done > 100)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char msg[MAX_STR_SIZE];
|
char pct_str[24];
|
||||||
bytes_convert_str(msg, sizeof(msg), bps);
|
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
|
||||||
strcat(msg, "/s [");
|
|
||||||
|
|
||||||
|
char bps_str[24];
|
||||||
|
bytes_convert_str(bps_str, sizeof(bps_str), bps);
|
||||||
|
|
||||||
|
char prog_line[NUM_PROG_MARKS + 1] = {0};
|
||||||
int n = pct_done / (100 / NUM_PROG_MARKS);
|
int n = pct_done / (100 / NUM_PROG_MARKS);
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i)
|
||||||
strcat(msg, "#");
|
strcat(prog_line, "=");
|
||||||
|
|
||||||
for (j = i; j < NUM_PROG_MARKS; ++j)
|
if (pct_done < 100)
|
||||||
strcat(msg, "-");
|
strcpy(prog_line + n, ">");
|
||||||
|
|
||||||
strcat(msg, "] ");
|
for (j = i; j < NUM_PROG_MARKS - 1; ++j)
|
||||||
|
strcat(prog_line, "-");
|
||||||
|
|
||||||
char pctstr[16];
|
char full_line[strlen(pct_str) + NUM_PROG_MARKS + strlen(bps_str) + 7];
|
||||||
const char *frmt = pct_done == 100 ? "%.f%%" : "%.1f%%";
|
snprintf(full_line, sizeof(full_line), "%s [%s] %s/s", pct_str, prog_line, bps_str);
|
||||||
snprintf(pctstr, sizeof(pctstr), frmt, pct_done);
|
|
||||||
strcat(msg, pctstr);
|
|
||||||
|
|
||||||
line_info_set(self, line_id, msg);
|
line_info_set(self, line_id, full_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer *ft)
|
static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer *ft)
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
#define GiB 1073741824 /* 1024^3 */
|
#define GiB 1073741824 /* 1024^3 */
|
||||||
|
|
||||||
#define MAX_FILES 32
|
#define MAX_FILES 32
|
||||||
#define TIMEOUT_FILESENDER 120
|
|
||||||
|
|
||||||
typedef enum FILE_TRANSFER_STATE {
|
typedef enum FILE_TRANSFER_STATE {
|
||||||
FILE_TRANSFER_INACTIVE,
|
FILE_TRANSFER_INACTIVE,
|
||||||
@ -62,15 +61,12 @@ 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];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Checks for timed out file transfers and closes them. */
|
|
||||||
void check_file_transfer_timeouts(Tox *m);
|
|
||||||
|
|
||||||
/* creates initial progress line that will be updated during file transfer.
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
progline must be at lesat MAX_STR_SIZE bytes */
|
progline must be at lesat MAX_STR_SIZE bytes */
|
||||||
void init_progress_bar(char *progline);
|
void init_progress_bar(char *progline);
|
||||||
|
@ -133,17 +133,24 @@ void kill_friendlist(void)
|
|||||||
#define TEMP_BLOCKLIST_EXT ".tmp"
|
#define TEMP_BLOCKLIST_EXT ".tmp"
|
||||||
static int save_blocklist(char *path)
|
static int save_blocklist(char *path)
|
||||||
{
|
{
|
||||||
if (path == NULL)
|
if (path == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int len = sizeof(BlockedFriend) * Blocked.num_blocked;
|
int len = sizeof(BlockedFriend) * Blocked.num_blocked;
|
||||||
char data[len];
|
char *data = malloc(len * sizeof(char));
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int i, count = 0;
|
int i, count = 0;
|
||||||
|
|
||||||
for (i = 0; i < Blocked.max_idx; ++i) {
|
for (i = 0; i < Blocked.max_idx; ++i) {
|
||||||
if (count > Blocked.num_blocked)
|
if (count > Blocked.num_blocked) {
|
||||||
|
free(data);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (Blocked.list[i].active) {
|
if (Blocked.list[i].active) {
|
||||||
BlockedFriend tmp;
|
BlockedFriend tmp;
|
||||||
@ -164,8 +171,11 @@ static int save_blocklist(char *path)
|
|||||||
|
|
||||||
/* Blocklist is empty, we can remove the empty file */
|
/* Blocklist is empty, we can remove the empty file */
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
if (remove(path) != 0)
|
free(data);
|
||||||
|
|
||||||
|
if (remove(path) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -175,19 +185,24 @@ static int save_blocklist(char *path)
|
|||||||
|
|
||||||
FILE *fp = fopen(temp_path, "wb");
|
FILE *fp = fopen(temp_path, "wb");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL) {
|
||||||
|
free(data);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (fwrite(data, len, 1, fp) != 1) {
|
if (fwrite(data, len, 1, fp) != 1) {
|
||||||
fprintf(stderr, "Failed to write blocklist data.\n");
|
fprintf(stderr, "Failed to write blocklist data.\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
|
|
||||||
if (rename(temp_path, path) != 0)
|
if (rename(temp_path, path) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -299,7 +314,7 @@ 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*)×tamp);
|
Friends.list[num].last_online.tm = *localtime((const time_t*)×tamp);
|
||||||
@ -424,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;
|
||||||
@ -757,7 +772,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case '\n':
|
case '\r':
|
||||||
if (blocklist_view)
|
if (blocklist_view)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -895,7 +910,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);
|
||||||
@ -1032,7 +1047,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) {
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "avatars.h"
|
#include "avatars.h"
|
||||||
#include "name_lookup.h"
|
#include "name_lookup.h"
|
||||||
#include "qr_code.h"
|
#include "qr_code.h"
|
||||||
|
#include "toxic_strings.h"
|
||||||
|
|
||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
@ -513,22 +514,37 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove opening and closing quotes */
|
/* remove opening and closing quotes and replace linebreaks with spaces */
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
snprintf(msg, sizeof(msg), "%s", &argv[1][1]);
|
snprintf(msg, sizeof(msg), "%s", &argv[1][1]);
|
||||||
int len = strlen(msg) - 1;
|
int len = strlen(msg) - 1;
|
||||||
msg[len] = '\0';
|
msg[len] = '\0';
|
||||||
|
strsubst(msg, '\n', ' ');
|
||||||
|
|
||||||
prompt_update_statusmessage(prompt, m, msg);
|
prompt_update_statusmessage(prompt, m, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
uint32_t nospam = rand(); /* should be random enough */
|
long int nospam = rand();
|
||||||
tox_self_set_nospam(m, nospam);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your Tox ID has been changed to:");
|
if (argc > 0) {
|
||||||
|
nospam = strtol(argv[1], NULL, 16);
|
||||||
|
|
||||||
|
if ((nospam == 0 && strcmp(argv[1], "0")) || nospam < 0) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid nospam value.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t old_nospam = tox_self_get_nospam(m);
|
||||||
|
tox_self_set_nospam(m, (uint32_t) nospam);
|
||||||
|
|
||||||
|
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, "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, "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])
|
||||||
|
@ -258,7 +258,7 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
|
|||||||
|
|
||||||
/* 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);
|
||||||
@ -296,7 +296,7 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
|
|||||||
selfnick[n_len] = '\0';
|
selfnick[n_len] = '\0';
|
||||||
|
|
||||||
if (strcasestr(action, selfnick)) {
|
if (strcasestr(action, selfnick)) {
|
||||||
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, action );
|
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
|
||||||
@ -387,7 +387,7 @@ struct group_add_thrd {
|
|||||||
ToxWindow *self;
|
ToxWindow *self;
|
||||||
int peernum;
|
int peernum;
|
||||||
int groupnum;
|
int groupnum;
|
||||||
uint64_t timestamp;
|
time_t timestamp;
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
};
|
};
|
||||||
@ -571,7 +571,10 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ltr) { /* char is printable */
|
if (ctx->pastemode && key == '\r')
|
||||||
|
key = '\n';
|
||||||
|
|
||||||
|
if (ltr || key == '\n') { /* char is printable */
|
||||||
input_new_char(self, key, x, y, x2, y2);
|
input_new_char(self, key, x, y, x2, y2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -615,30 +618,34 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
} else if (key == user_settings->key_peer_list_up) {
|
} else if (key == user_settings->key_peer_list_up) {
|
||||||
if (groupchats[self->num].side_pos > 0)
|
if (groupchats[self->num].side_pos > 0)
|
||||||
--groupchats[self->num].side_pos;
|
--groupchats[self->num].side_pos;
|
||||||
} else if (key == '\n') {
|
} else if (key == '\r') {
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
|
|
||||||
char line[MAX_STR_SIZE];
|
if (!wstring_is_empty(ctx->line))
|
||||||
|
{
|
||||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
|
||||||
memset(&line, 0, sizeof(line));
|
|
||||||
|
|
||||||
if (!string_is_empty(line))
|
|
||||||
add_line_to_hist(ctx);
|
add_line_to_hist(ctx);
|
||||||
|
|
||||||
if (line[0] == '/') {
|
wstrsubst(ctx->line, L'¶', L'\n');
|
||||||
if (strcmp(line, "/close") == 0) {
|
|
||||||
close_groupchat(self, m, self->num);
|
char line[MAX_STR_SIZE];
|
||||||
return;
|
|
||||||
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
||||||
send_group_action(self, ctx, m, line + strlen("/me "));
|
memset(&line, 0, sizeof(line));
|
||||||
|
|
||||||
|
if (line[0] == '/') {
|
||||||
|
if (strcmp(line, "/close") == 0) {
|
||||||
|
close_groupchat(self, m, self->num);
|
||||||
|
return;
|
||||||
|
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
||||||
|
send_group_action(self, ctx, m, line + strlen("/me "));
|
||||||
|
} else {
|
||||||
|
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
|
if (tox_group_message_send(m, self->num, (uint8_t *) line, strlen(line)) == -1) {
|
||||||
}
|
const char *errmsg = " * Failed to send message.";
|
||||||
} else if (!string_is_empty(line)) {
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
|
||||||
if (tox_group_message_send(m, self->num, (uint8_t *) line, strlen(line)) == -1) {
|
}
|
||||||
const char *errmsg = " * Failed to send message.";
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,7 +683,9 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT);
|
mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT);
|
||||||
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
|
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
int num_peers = groupchats[self->num].num_peers;
|
int num_peers = groupchats[self->num].num_peers;
|
||||||
|
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);
|
||||||
@ -691,12 +700,19 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
for (i = 0; i < num_peers && i < maxlines; ++i) {
|
for (i = 0; i < num_peers && i < maxlines; ++i) {
|
||||||
wmove(ctx->sidebar, i + 2, 1);
|
wmove(ctx->sidebar, i + 2, 1);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
int peer = i + groupchats[self->num].side_pos;
|
int peer = i + groupchats[self->num].side_pos;
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
/* truncate nick to fit in side panel without modifying list */
|
/* truncate nick to fit in side panel without modifying list */
|
||||||
char tmpnck[TOX_MAX_NAME_LENGTH];
|
char tmpnck[TOX_MAX_NAME_LENGTH];
|
||||||
int maxlen = SIDEBAR_WIDTH - 2;
|
int maxlen = SIDEBAR_WIDTH - 2;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
memcpy(tmpnck, &groupchats[self->num].peer_names[peer * TOX_MAX_NAME_LENGTH], maxlen);
|
memcpy(tmpnck, &groupchats[self->num].peer_names[peer * TOX_MAX_NAME_LENGTH], maxlen);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
tmpnck[maxlen] = '\0';
|
tmpnck[maxlen] = '\0';
|
||||||
|
|
||||||
wprintw(ctx->sidebar, "%s\n", tmpnck);
|
wprintw(ctx->sidebar, "%s\n", tmpnck);
|
||||||
|
@ -64,7 +64,7 @@ typedef struct {
|
|||||||
uint8_t type;
|
uint8_t type;
|
||||||
int num_peers;
|
int num_peers;
|
||||||
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
||||||
uint64_t start_time;
|
time_t start_time;
|
||||||
uint8_t *peer_names;
|
uint8_t *peer_names;
|
||||||
uint8_t *oldpeer_names;
|
uint8_t *oldpeer_names;
|
||||||
uint16_t *peer_name_lengths;
|
uint16_t *peer_name_lengths;
|
||||||
|
@ -154,7 +154,7 @@ static void help_draw_global(ToxWindow *self)
|
|||||||
wprintw(win, " /status <type> <msg> : Set status with optional note\n");
|
wprintw(win, " /status <type> <msg> : Set status with optional note\n");
|
||||||
wprintw(win, " /note <msg> : Set a personal note\n");
|
wprintw(win, " /note <msg> : Set a personal note\n");
|
||||||
wprintw(win, " /nick <nick> : Set your nickname\n");
|
wprintw(win, " /nick <nick> : Set your nickname\n");
|
||||||
wprintw(win, " /nospam : Change part of your Tox ID to stop spam\n");
|
wprintw(win, " /nospam <value> : Change part of your Tox ID to stop spam\n");
|
||||||
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
|
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
|
||||||
wprintw(win, " /group <type> : Create a group chat where type: text | audio\n");
|
wprintw(win, " /group <type> : Create a group chat where type: text | audio\n");
|
||||||
wprintw(win, " /myid : Print your Tox ID\n");
|
wprintw(win, " /myid : Print your Tox ID\n");
|
||||||
@ -245,7 +245,9 @@ static void help_draw_keys(ToxWindow *self)
|
|||||||
wprintw(win, " Ctrl+F and Ctrl+V : Scroll window history half a page\n");
|
wprintw(win, " Ctrl+F and Ctrl+V : Scroll window history half a page\n");
|
||||||
wprintw(win, " Ctrl+H : Move to the bottom of window history\n");
|
wprintw(win, " Ctrl+H : Move to the bottom of window history\n");
|
||||||
wprintw(win, " Ctrl+[ and Ctrl+] : Scroll peer list in groupchats\n");
|
wprintw(win, " Ctrl+[ and Ctrl+] : Scroll peer list in groupchats\n");
|
||||||
wprintw(win, " Ctrl+B : Toggle the groupchat peerlist\n\n");
|
wprintw(win, " Ctrl+B : Toggle the groupchat peerlist\n");
|
||||||
|
wprintw(win, " Ctrl+J : Insert new line\n");
|
||||||
|
wprintw(win, " Ctrl+T : Toggle paste mode\n\n");
|
||||||
wprintw(win, " (Note: Custom keybindings override these defaults.)\n\n");
|
wprintw(win, " (Note: Custom keybindings override these defaults.)\n\n");
|
||||||
|
|
||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
@ -335,7 +337,7 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'k':
|
case 'k':
|
||||||
help_init_window(self, 13, 80);
|
help_init_window(self, 15, 80);
|
||||||
self->help->type = HELP_KEYS;
|
self->help->type = HELP_KEYS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
23
src/input.c
23
src/input.c
@ -42,9 +42,12 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
|
|||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
/* this is the only place we need to do this check */
|
||||||
|
if (key == '\n')
|
||||||
|
key = L'¶';
|
||||||
|
|
||||||
int cur_len = wcwidth(key);
|
int cur_len = wcwidth(key);
|
||||||
|
|
||||||
/* this is the only place we need to do this check */
|
|
||||||
if (cur_len == -1) {
|
if (cur_len == -1) {
|
||||||
sound_notify(self, notif_error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
return;
|
||||||
@ -266,15 +269,19 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
|||||||
|
|
||||||
/* TODO: this special case is ugly.
|
/* TODO: this special case is ugly.
|
||||||
maybe convert entire function to if/else and make them all customizable keys? */
|
maybe convert entire function to if/else and make them all customizable keys? */
|
||||||
if (!match && key == user_settings->key_toggle_peerlist) {
|
if (!match) {
|
||||||
if (self->is_groupchat) {
|
if (key == user_settings->key_toggle_peerlist) {
|
||||||
self->show_peerlist ^= 1;
|
if (self->is_groupchat) {
|
||||||
redraw_groupchat_win(self);
|
self->show_peerlist ^= 1;
|
||||||
|
redraw_groupchat_win(self);
|
||||||
|
}
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
else if (key == user_settings->key_toggle_pastemode) {
|
||||||
|
self->chatwin->pastemode ^= 1;
|
||||||
|
match = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
match = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
@ -323,17 +323,27 @@ void line_info_print(ToxWindow *self)
|
|||||||
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
|
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
|
||||||
wattroff(win, COLOR_PAIR(nameclr));
|
wattroff(win, COLOR_PAIR(nameclr));
|
||||||
|
|
||||||
if (line->msg[0] == '>')
|
char* msg = line->msg;
|
||||||
wattron(win, COLOR_PAIR(GREEN));
|
while (msg)
|
||||||
else if (line->msg[0] == '<')
|
{
|
||||||
wattron(win, COLOR_PAIR(RED));
|
char* line = strsep(&msg, "\n");
|
||||||
|
|
||||||
wprintw(win, "%s", line->msg);
|
if (line[0] == '>')
|
||||||
|
wattron(win, COLOR_PAIR(GREEN));
|
||||||
|
else if (line[0] == '<')
|
||||||
|
wattron(win, COLOR_PAIR(RED));
|
||||||
|
|
||||||
if (line->msg[0] == '>')
|
wprintw(win, "%s%c", line, msg ? '\n' : '\0');
|
||||||
wattroff(win, COLOR_PAIR(GREEN));
|
|
||||||
else if (line->msg[0] == '<')
|
if (line[0] == '>')
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
wattroff(win, COLOR_PAIR(GREEN));
|
||||||
|
else if (line[0] == '<')
|
||||||
|
wattroff(win, COLOR_PAIR(RED));
|
||||||
|
|
||||||
|
// change the \0 set by strsep back to \n
|
||||||
|
if (msg)
|
||||||
|
msg[-1] = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
||||||
wattron(win, COLOR_PAIR(RED));
|
wattron(win, COLOR_PAIR(RED));
|
||||||
|
@ -50,7 +50,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;
|
||||||
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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,7 +69,7 @@ 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;
|
||||||
@ -176,6 +170,15 @@ int string_is_empty(const char *string)
|
|||||||
return string[0] == '\0';
|
return string[0] == '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns 1 if the string is empty, 0 otherwise */
|
||||||
|
int wstring_is_empty(const wchar_t *string)
|
||||||
|
{
|
||||||
|
if (!string)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return string[0] == L'\0';
|
||||||
|
}
|
||||||
|
|
||||||
/* convert a multibyte string to a wide character string and puts in buf. */
|
/* convert a multibyte string to a wide character string and puts in buf. */
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -358,9 +361,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) {
|
||||||
@ -372,9 +379,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) {
|
||||||
@ -461,3 +472,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;
|
||||||
|
}
|
||||||
|
@ -61,23 +61,23 @@ 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);
|
||||||
|
|
||||||
/* 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);
|
||||||
|
|
||||||
|
/* Same as above but for wide character strings */
|
||||||
|
int wstring_is_empty(const wchar_t *string);
|
||||||
|
|
||||||
/* convert a multibyte string to a wide character string (must provide buffer) */
|
/* convert a multibyte string to a wide character string (must provide buffer) */
|
||||||
int char_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
|
int char_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
|
||||||
|
|
||||||
@ -88,7 +88,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);
|
||||||
@ -133,11 +133,11 @@ int get_group_nick_truncate(Tox *m, char *buf, int peernum, 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 */
|
||||||
@ -158,4 +158,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 */
|
||||||
|
@ -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,8 +248,8 @@ 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);
|
||||||
@ -328,13 +261,17 @@ void *lookup_thread_func(void *data)
|
|||||||
|
|
||||||
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, (void *) &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 +374,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 +391,3 @@ int name_lookup_init(void)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void name_lookup_cleanup(void)
|
|
||||||
{
|
|
||||||
curl_global_cleanup();
|
|
||||||
}
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
15
src/notify.c
15
src/notify.c
@ -234,17 +234,17 @@ void* do_playing(void* _p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool has_looping = false;
|
bool has_looping = false;
|
||||||
|
bool test_active_notify = false;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
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;
|
||||||
if (actives[i].active && !actives[i].looping
|
#ifdef BOX_NOTIFY
|
||||||
#ifdef BOX_NOTIFY
|
test_active_notify = test_active_notify && !actives[i].box;
|
||||||
&& !actives[i].box
|
#endif
|
||||||
#endif
|
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 */
|
||||||
|
|
||||||
@ -472,7 +472,7 @@ 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;
|
||||||
|
|
||||||
@ -580,7 +580,6 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
|||||||
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);
|
||||||
actives[id].buffer = alutCreateBufferFromFile(Control.sounds[notif]);
|
actives[id].buffer = alutCreateBufferFromFile(Control.sounds[notif]);
|
||||||
|
32
src/prompt.c
32
src/prompt.c
@ -189,13 +189,16 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
if (x2 <= 0 || y2 <= 0)
|
if (x2 <= 0 || y2 <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ctx->pastemode && key == '\r')
|
||||||
|
key = '\n';
|
||||||
|
|
||||||
/* ignore non-menu related input if active */
|
/* ignore non-menu related input if active */
|
||||||
if (self->help->active) {
|
if (self->help->active) {
|
||||||
help_onKey(self, key);
|
help_onKey(self, key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ltr) { /* char is printable */
|
if (ltr || key == '\n') { /* char is printable */
|
||||||
input_new_char(self, key, x, y, x2, y2);
|
input_new_char(self, key, x, y, x2, y2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -232,19 +235,22 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
} else {
|
} else {
|
||||||
sound_notify(self, notif_error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
} else if (key == '\n') {
|
} else if (key == '\r') {
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
|
|
||||||
char line[MAX_STR_SIZE] = {0};
|
if (!wstring_is_empty(ctx->line))
|
||||||
|
{
|
||||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
|
||||||
memset(&line, 0, sizeof(line));
|
|
||||||
|
|
||||||
if (!string_is_empty(line))
|
|
||||||
add_line_to_hist(ctx);
|
add_line_to_hist(ctx);
|
||||||
|
wstrsubst(ctx->line, L'¶', L'\n');
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
|
char line[MAX_STR_SIZE] = {0};
|
||||||
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
|
|
||||||
|
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
||||||
|
memset(&line, 0, sizeof(line));
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
|
||||||
|
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
wclear(ctx->linewin);
|
wclear(ctx->linewin);
|
||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
@ -363,7 +369,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);
|
||||||
@ -383,6 +389,10 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
|
|||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
|
||||||
|
if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (connection_status != TOX_CONNECTION_NONE && Friends.list[friendnum].connection_status == TOX_CONNECTION_NONE) {
|
if (connection_status != TOX_CONNECTION_NONE && Friends.list[friendnum].connection_status == TOX_CONNECTION_NONE) {
|
||||||
msg = "has come online";
|
msg = "has come online";
|
||||||
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
||||||
|
@ -51,12 +51,18 @@ static struct ui_strings {
|
|||||||
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* bell_on_message;
|
||||||
|
const char* bell_on_filetrans;
|
||||||
|
const char* bell_on_filetrans_accept;
|
||||||
|
const char* bell_on_invite;
|
||||||
const char* native_colors;
|
const char* native_colors;
|
||||||
const char* autolog;
|
const char* autolog;
|
||||||
const char* history_size;
|
const char* history_size;
|
||||||
const char* show_typing_self;
|
const char* show_typing_self;
|
||||||
const char* show_typing_other;
|
const char* show_typing_other;
|
||||||
const char* show_welcome_msg;
|
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;
|
||||||
@ -72,12 +78,18 @@ 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",
|
||||||
"show_typing_self",
|
"show_typing_self",
|
||||||
"show_typing_other",
|
"show_typing_other",
|
||||||
"show_welcome_msg",
|
"show_welcome_msg",
|
||||||
|
"show_connection_msg",
|
||||||
|
"nodeslist_update_freq",
|
||||||
"line_join",
|
"line_join",
|
||||||
"line_quit",
|
"line_quit",
|
||||||
"line_alert",
|
"line_alert",
|
||||||
@ -94,11 +106,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->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);
|
||||||
@ -124,6 +142,7 @@ static const struct keys_strings {
|
|||||||
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;
|
||||||
} key_strings = {
|
} key_strings = {
|
||||||
"keys",
|
"keys",
|
||||||
"next_tab",
|
"next_tab",
|
||||||
@ -136,6 +155,7 @@ static const struct keys_strings {
|
|||||||
"peer_list_up",
|
"peer_list_up",
|
||||||
"peer_list_down",
|
"peer_list_down",
|
||||||
"toggle_peerlist",
|
"toggle_peerlist",
|
||||||
|
"toggle_paste_mode",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* defines from toxic.h */
|
/* defines from toxic.h */
|
||||||
@ -151,6 +171,7 @@ static void key_defaults(struct user_settings* settings)
|
|||||||
settings->key_peer_list_up = T_KEY_C_LB;
|
settings->key_peer_list_up = T_KEY_C_LB;
|
||||||
settings->key_peer_list_down = T_KEY_C_RB;
|
settings->key_peer_list_down = T_KEY_C_RB;
|
||||||
settings->key_toggle_peerlist = T_KEY_C_B;
|
settings->key_toggle_peerlist = T_KEY_C_B;
|
||||||
|
settings->key_toggle_pastemode = T_KEY_C_T;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct tox_strings {
|
static const struct tox_strings {
|
||||||
@ -158,11 +179,13 @@ static const struct tox_strings {
|
|||||||
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;
|
||||||
} tox_strings = {
|
} tox_strings = {
|
||||||
"tox",
|
"tox",
|
||||||
"download_path",
|
"download_path",
|
||||||
"chatlogs_path",
|
"chatlogs_path",
|
||||||
"avatar_path",
|
"avatar_path",
|
||||||
|
"password_eval",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void tox_defaults(struct user_settings* settings)
|
static void tox_defaults(struct user_settings* settings)
|
||||||
@ -170,6 +193,7 @@ static void tox_defaults(struct user_settings* settings)
|
|||||||
strcpy(settings->download_path, "");
|
strcpy(settings->download_path, "");
|
||||||
strcpy(settings->chatlogs_path, "");
|
strcpy(settings->chatlogs_path, "");
|
||||||
strcpy(settings->avatar_path, "");
|
strcpy(settings->avatar_path, "");
|
||||||
|
strcpy(settings->password_eval, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
@ -221,11 +245,11 @@ 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)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +262,14 @@ static int key_parse(const char** bind){
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_key_binding(int *key, const char **bind) {
|
||||||
|
int code = key_parse(bind);
|
||||||
|
|
||||||
|
if (code != -1) {
|
||||||
|
*key = code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int settings_load(struct user_settings *s, const char *patharg)
|
int settings_load(struct user_settings *s, const char *patharg)
|
||||||
{
|
{
|
||||||
config_t cfg[1];
|
config_t cfg[1];
|
||||||
@ -302,12 +334,29 @@ 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_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);
|
||||||
@ -359,31 +408,41 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
if (len >= sizeof(s->avatar_path))
|
if (len >= sizeof(s->avatar_path))
|
||||||
s->avatar_path[0] = '\0';
|
s->avatar_path[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( config_setting_lookup_string(setting, tox_strings.password_eval, &str) ) {
|
||||||
|
snprintf(s->password_eval, sizeof(s->password_eval), "%s", str);
|
||||||
|
int len = strlen(str);
|
||||||
|
|
||||||
|
if (len >= sizeof(s->password_eval))
|
||||||
|
s->password_eval[0] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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))
|
||||||
s->key_next_tab = key_parse(&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))
|
||||||
s->key_prev_tab = key_parse(&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))
|
||||||
s->key_scroll_line_up = key_parse(&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))
|
||||||
s->key_scroll_line_down= key_parse(&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))
|
||||||
s->key_half_page_up = key_parse(&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))
|
||||||
s->key_half_page_down = key_parse(&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))
|
||||||
s->key_page_bottom = key_parse(&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))
|
||||||
s->key_peer_list_up = key_parse(&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))
|
||||||
s->key_peer_list_down = key_parse(&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))
|
||||||
s->key_toggle_peerlist = key_parse(&tmp);
|
set_key_binding(&s->key_toggle_peerlist, &tmp);
|
||||||
|
if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp))
|
||||||
|
set_key_binding(&s->key_toggle_pastemode, &tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
@ -30,11 +30,19 @@
|
|||||||
/* Represents line_* hints max strlen */
|
/* Represents line_* hints max strlen */
|
||||||
#define LINE_HINT_MAX 3
|
#define LINE_HINT_MAX 3
|
||||||
|
|
||||||
|
#define PASSWORD_EVAL_MAX 512
|
||||||
|
|
||||||
/* holds user setting values */
|
/* holds user setting values */
|
||||||
struct user_settings {
|
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];
|
||||||
@ -44,6 +52,8 @@ struct user_settings {
|
|||||||
int show_typing_self; /* boolean */
|
int show_typing_self; /* boolean */
|
||||||
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 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];
|
||||||
@ -53,6 +63,7 @@ struct user_settings {
|
|||||||
char download_path[PATH_MAX];
|
char download_path[PATH_MAX];
|
||||||
char chatlogs_path[PATH_MAX];
|
char chatlogs_path[PATH_MAX];
|
||||||
char avatar_path[PATH_MAX];
|
char avatar_path[PATH_MAX];
|
||||||
|
char password_eval[PASSWORD_EVAL_MAX];
|
||||||
|
|
||||||
int key_next_tab;
|
int key_next_tab;
|
||||||
int key_prev_tab;
|
int key_prev_tab;
|
||||||
@ -64,6 +75,7 @@ struct user_settings {
|
|||||||
int key_peer_list_up;
|
int key_peer_list_up;
|
||||||
int key_peer_list_down;
|
int key_peer_list_down;
|
||||||
int key_toggle_peerlist;
|
int key_toggle_peerlist;
|
||||||
|
int key_toggle_pastemode;
|
||||||
|
|
||||||
int mplex_away; /* boolean (1 for reaction to terminal attach/detach) */
|
int mplex_away; /* boolean (1 for reaction to terminal attach/detach) */
|
||||||
char mplex_away_note [TOX_MAX_STATUS_MESSAGE_LENGTH];
|
char mplex_away_note [TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
@ -94,6 +106,9 @@ enum {
|
|||||||
SHOW_WELCOME_MSG_OFF = 0,
|
SHOW_WELCOME_MSG_OFF = 0,
|
||||||
SHOW_WELCOME_MSG_ON = 1,
|
SHOW_WELCOME_MSG_ON = 1,
|
||||||
|
|
||||||
|
SHOW_CONNECTION_MSG_OFF = 0,
|
||||||
|
SHOW_CONNECTION_MSG_ON = 1,
|
||||||
|
|
||||||
DFLT_HST_SIZE = 700,
|
DFLT_HST_SIZE = 700,
|
||||||
|
|
||||||
MPLEX_OFF = 0,
|
MPLEX_OFF = 0,
|
||||||
|
336
src/toxic.c
336
src/toxic.c
@ -39,7 +39,9 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
#include <tox/toxencryptsave.h>
|
#include <tox/toxencryptsave.h>
|
||||||
|
|
||||||
@ -59,6 +61,7 @@
|
|||||||
#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"
|
||||||
@ -162,7 +165,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
|
||||||
@ -199,6 +202,7 @@ static void init_term(void)
|
|||||||
cbreak();
|
cbreak();
|
||||||
keypad(stdscr, 1);
|
keypad(stdscr, 1);
|
||||||
noecho();
|
noecho();
|
||||||
|
nonl();
|
||||||
timeout(100);
|
timeout(100);
|
||||||
|
|
||||||
if (has_colors()) {
|
if (has_colors()) {
|
||||||
@ -278,153 +282,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_friendlist(Tox *m)
|
static void load_friendlist(Tox *m)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
@ -472,6 +329,45 @@ static int password_prompt(char *buf, int size)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the password from the eval command.
|
||||||
|
* return length of password on success, 0 on failure
|
||||||
|
*/
|
||||||
|
static int password_eval(char *buf, int size)
|
||||||
|
{
|
||||||
|
buf[0] = '\0';
|
||||||
|
|
||||||
|
/* Run password_eval command */
|
||||||
|
FILE *f = popen(user_settings->password_eval, "r");
|
||||||
|
if (f == NULL) {
|
||||||
|
fprintf(stderr, "Executing password_eval failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get output from command */
|
||||||
|
char *ret = fgets(buf, size, f);
|
||||||
|
if (ret == NULL) {
|
||||||
|
fprintf(stderr, "Reading password from password_eval command failed\n");
|
||||||
|
pclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get exit status */
|
||||||
|
int status = pclose(f);
|
||||||
|
if (status != 0) {
|
||||||
|
fprintf(stderr, "password_eval command returned error %d\n", status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Removez whitespace or \n at end */
|
||||||
|
int i, len = strlen(buf);
|
||||||
|
for (i = len - 1; i > 0 && isspace(buf[i]); i--) {
|
||||||
|
buf[i] = 0;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
/* Ask user if they would like to encrypt the data file and set password */
|
/* Ask user if they would like to encrypt the data file and set password */
|
||||||
static void first_time_encrypt(const char *msg)
|
static void first_time_encrypt(const char *msg)
|
||||||
{
|
{
|
||||||
@ -543,25 +439,38 @@ static void first_time_encrypt(const char *msg)
|
|||||||
#define TEMP_PROFILE_EXT ".tmp"
|
#define TEMP_PROFILE_EXT ".tmp"
|
||||||
int store_data(Tox *m, const char *path)
|
int store_data(Tox *m, const char *path)
|
||||||
{
|
{
|
||||||
if (path == NULL)
|
if (path == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
char temp_path[strlen(path) + strlen(TEMP_PROFILE_EXT) + 1];
|
char temp_path[strlen(path) + strlen(TEMP_PROFILE_EXT) + 1];
|
||||||
snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_PROFILE_EXT);
|
snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_PROFILE_EXT);
|
||||||
|
|
||||||
FILE *fp = fopen(temp_path, "wb");
|
FILE *fp = fopen(temp_path, "wb");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
size_t data_len = tox_get_savedata_size(m);
|
size_t data_len = tox_get_savedata_size(m);
|
||||||
char data[data_len];
|
char *data = malloc(data_len * sizeof(char));
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
tox_get_savedata(m, (uint8_t *) data);
|
tox_get_savedata(m, (uint8_t *) data);
|
||||||
|
|
||||||
if (user_password.data_is_encrypted && !arg_opts.unencrypt_data) {
|
if (user_password.data_is_encrypted && !arg_opts.unencrypt_data) {
|
||||||
size_t enc_len = data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
|
size_t enc_len = data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
|
||||||
char enc_data[enc_len];
|
char *enc_data = malloc(enc_len * sizeof(char));
|
||||||
|
|
||||||
|
if (enc_data == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
TOX_ERR_ENCRYPTION err;
|
TOX_ERR_ENCRYPTION err;
|
||||||
tox_pass_encrypt((uint8_t *) data, data_len, (uint8_t *) user_password.pass, user_password.len,
|
tox_pass_encrypt((uint8_t *) data, data_len, (uint8_t *) user_password.pass, user_password.len,
|
||||||
@ -570,26 +479,35 @@ int store_data(Tox *m, const char *path)
|
|||||||
if (err != TOX_ERR_ENCRYPTION_OK) {
|
if (err != TOX_ERR_ENCRYPTION_OK) {
|
||||||
fprintf(stderr, "tox_pass_encrypt() failed with error %d\n", err);
|
fprintf(stderr, "tox_pass_encrypt() failed with error %d\n", err);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
|
free(enc_data);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(enc_data, enc_len, 1, fp) != 1) {
|
if (fwrite(enc_data, enc_len, 1, fp) != 1) {
|
||||||
fprintf(stderr, "Failed to write profile data.\n");
|
fprintf(stderr, "Failed to write profile data.\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
|
free(enc_data);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(enc_data);
|
||||||
} else { /* data will not be encrypted */
|
} else { /* data will not be encrypted */
|
||||||
if (fwrite(data, data_len, 1, fp) != 1) {
|
if (fwrite(data, data_len, 1, fp) != 1) {
|
||||||
fprintf(stderr, "Failed to write profile data.\n");
|
fprintf(stderr, "Failed to write profile data.\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
|
|
||||||
if (rename(temp_path, path) != 0)
|
if (rename(temp_path, path) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -665,14 +583,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);
|
||||||
@ -680,7 +598,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)
|
||||||
@ -693,14 +611,21 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
|
|||||||
user_password.data_is_encrypted = true;
|
user_password.data_is_encrypted = true;
|
||||||
|
|
||||||
size_t pwlen = 0;
|
size_t pwlen = 0;
|
||||||
system("clear"); // TODO: is this portable?
|
int pweval = user_settings->password_eval[0];
|
||||||
printf("Enter password (q to quit) ");
|
if (!pweval) {
|
||||||
|
system("clear"); // TODO: is this portable?
|
||||||
|
printf("Enter password (q to quit) ");
|
||||||
|
}
|
||||||
|
|
||||||
size_t plain_len = len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
|
size_t plain_len = len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
|
||||||
char plain[plain_len];
|
char plain[plain_len];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
|
if (pweval) {
|
||||||
|
pwlen = password_eval(user_password.pass, sizeof(user_password.pass));
|
||||||
|
} else {
|
||||||
|
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) {
|
||||||
@ -712,6 +637,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
|
|||||||
system("clear");
|
system("clear");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
printf("Invalid password. Try again. ");
|
printf("Invalid password. Try again. ");
|
||||||
|
pweval = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -736,6 +662,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
|
|||||||
system("clear");
|
system("clear");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
printf("Invalid password. Try again. ");
|
printf("Invalid password. Try again. ");
|
||||||
|
pweval = 0;
|
||||||
} else {
|
} else {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
exit_toxic_err("tox_pass_decrypt() failed", pwerr);
|
exit_toxic_err("tox_pass_decrypt() failed", pwerr);
|
||||||
@ -757,7 +684,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;
|
||||||
|
|
||||||
@ -767,7 +694,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;
|
||||||
@ -803,33 +730,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);
|
||||||
@ -837,8 +740,7 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tox_iterate(m);
|
tox_iterate(m);
|
||||||
do_bootstrap(m);
|
do_tox_connection(m);
|
||||||
check_file_transfer_timeouts(m);
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1020,10 +922,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':
|
||||||
@ -1177,25 +1075,6 @@ static void init_default_data_files(void)
|
|||||||
free(user_config_dir);
|
free(user_config_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define REC_TOX_DO_LOOPS_PER_SEC 25
|
|
||||||
|
|
||||||
/* Adjusts usleep value so that tox_do runs close to the recommended number of times per second */
|
|
||||||
static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, uint64_t cur_time, useconds_t msleepval)
|
|
||||||
{
|
|
||||||
useconds_t new_sleep = MAX(msleepval, 3);
|
|
||||||
++(*loopcount);
|
|
||||||
|
|
||||||
if (*looptimer == cur_time)
|
|
||||||
return new_sleep;
|
|
||||||
|
|
||||||
if (*loopcount != REC_TOX_DO_LOOPS_PER_SEC)
|
|
||||||
new_sleep *= (double) *loopcount / REC_TOX_DO_LOOPS_PER_SEC;
|
|
||||||
|
|
||||||
*looptimer = cur_time;
|
|
||||||
*loopcount = 0;
|
|
||||||
return new_sleep;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
||||||
@ -1230,9 +1109,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)
|
||||||
@ -1247,17 +1123,20 @@ 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)
|
||||||
@ -1286,7 +1165,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);
|
||||||
@ -1315,6 +1193,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);
|
||||||
print_init_messages(prompt);
|
print_init_messages(prompt);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
@ -1326,15 +1210,12 @@ 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();
|
||||||
uint64_t looptimer = last_save;
|
|
||||||
useconds_t msleepval = 40000;
|
|
||||||
uint64_t loopcount = 0;
|
|
||||||
|
|
||||||
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);
|
||||||
@ -1345,8 +1226,7 @@ int main(int argc, char **argv)
|
|||||||
last_save = cur_time;
|
last_save = cur_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
msleepval = optimal_msleepval(&looptimer, &loopcount, cur_time, msleepval);
|
usleep(tox_iteration_interval(m) * 1000);
|
||||||
usleep(msleepval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -70,6 +70,7 @@
|
|||||||
#define T_KEY_C_L 0x0C /* ctrl-l */
|
#define T_KEY_C_L 0x0C /* ctrl-l */
|
||||||
#define T_KEY_C_W 0x17 /* ctrl-w */
|
#define T_KEY_C_W 0x17 /* ctrl-w */
|
||||||
#define T_KEY_C_B 0x02 /* ctrl-b */
|
#define T_KEY_C_B 0x02 /* ctrl-b */
|
||||||
|
#define T_KEY_C_T 0x14 /* ctrl-t */
|
||||||
#define T_KEY_TAB 0x09 /* TAB key */
|
#define T_KEY_TAB 0x09 /* TAB key */
|
||||||
|
|
||||||
#define ONLINE_CHAR "*"
|
#define ONLINE_CHAR "*"
|
||||||
|
@ -166,19 +166,19 @@ void reset_buf(ChatContext *ctx)
|
|||||||
ctx->start = 0;
|
ctx->start = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Removes trailing spaces from line. */
|
/* Removes trailing spaces and newlines from line. */
|
||||||
void rm_trailing_spaces_buf(ChatContext *ctx)
|
void rm_trailing_spaces_buf(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->len <= 0)
|
if (ctx->len <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ctx->line[ctx->len - 1] != ' ')
|
if (ctx->line[ctx->len - 1] != ' ' && ctx->line[ctx->len - 1] != L'¶')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = ctx->len - 1; i >= 0; --i) {
|
for (i = ctx->len - 1; i >= 0; --i) {
|
||||||
if (ctx->line[i] != ' ')
|
if (ctx->line[i] != ' ' && ctx->line[i] != L'¶')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,3 +242,19 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
|
|||||||
ctx->pos = h_len;
|
ctx->pos = h_len;
|
||||||
ctx->len = h_len;
|
ctx->len = h_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void strsubst(char* str, char old, char new)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; str[i] != '\0'; ++i)
|
||||||
|
if (str[i] == old)
|
||||||
|
str[i] = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wstrsubst(wchar_t* str, wchar_t old, wchar_t new)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; str[i] != L'\0'; ++i)
|
||||||
|
if (str[i] == old)
|
||||||
|
str[i] = new;
|
||||||
|
}
|
||||||
|
@ -66,4 +66,8 @@ void add_line_to_hist(ChatContext *ctx);
|
|||||||
resets line if at end of history */
|
resets line if at end of history */
|
||||||
void fetch_hist_item(ChatContext *ctx, int key_dir);
|
void fetch_hist_item(ChatContext *ctx, int key_dir);
|
||||||
|
|
||||||
|
/* Substitutes all occurrences of old with new. */
|
||||||
|
void strsubst(char *str, char old, char new);
|
||||||
|
void wstrsubst(wchar_t *str, wchar_t old, wchar_t new);
|
||||||
|
|
||||||
#endif /* #define TOXIC_STRINGS_H */
|
#endif /* #define TOXIC_STRINGS_H */
|
||||||
|
@ -236,7 +236,10 @@ 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;
|
||||||
@ -362,7 +365,7 @@ 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;
|
||||||
@ -614,16 +617,19 @@ 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) {
|
||||||
{
|
lock;
|
||||||
|
if (!video_thread_running) {
|
||||||
|
unlock;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unlock;
|
||||||
|
|
||||||
if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */
|
if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */
|
||||||
else
|
else {
|
||||||
{
|
for (i = 0; i < size[vdt_input]; ++i) {
|
||||||
for (i = 0; i < size[vdt_input]; ++i)
|
|
||||||
{
|
|
||||||
lock;
|
lock;
|
||||||
if ( video_devices_running[vdt_input][i] != NULL )
|
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;
|
||||||
|
@ -471,6 +471,11 @@ static void draw_window_tab(ToxWindow *toxwin)
|
|||||||
|
|
||||||
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));
|
||||||
@ -508,6 +513,9 @@ static void draw_bar(void)
|
|||||||
attroff(A_BOLD);
|
attroff(A_BOLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore cursor position after drawing
|
||||||
|
move(y, x);
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,6 +533,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;
|
||||||
|
@ -153,7 +153,7 @@ struct ToxWindow {
|
|||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
|
|
||||||
int video_device_selection[2]; /* -1 if not set, if set uses these selections instead of primary video device */
|
int video_device_selection[2]; /* -1 if not set, if set uses these selections instead of primary video device */
|
||||||
|
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
@ -204,8 +204,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;
|
||||||
@ -237,6 +237,7 @@ struct ChatContext {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t self_is_typing;
|
uint8_t self_is_typing;
|
||||||
|
uint8_t pastemode; /* whether to translate \r to \n */
|
||||||
|
|
||||||
WINDOW *history;
|
WINDOW *history;
|
||||||
WINDOW *linewin;
|
WINDOW *linewin;
|
||||||
|
@ -271,6 +271,11 @@ int init_xtra(drop_callback d)
|
|||||||
|
|
||||||
Xtra.terminal_window = focused_window_id();
|
Xtra.terminal_window = focused_window_id();
|
||||||
|
|
||||||
|
/* OSX: if focused window is 0, it means toxic is ran from
|
||||||
|
* native terminal and not X11 terminal window, silently exit */
|
||||||
|
if (!Xtra.terminal_window)
|
||||||
|
return 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Create an invisible window which will act as proxy for the DnD operation. */
|
/* Create an invisible window which will act as proxy for the DnD operation. */
|
||||||
XSetWindowAttributes attr = {0};
|
XSetWindowAttributes attr = {0};
|
||||||
@ -343,7 +348,7 @@ int init_xtra(drop_callback d)
|
|||||||
|
|
||||||
void terminate_xtra()
|
void terminate_xtra()
|
||||||
{
|
{
|
||||||
if (!Xtra.display) return;
|
if (!Xtra.display || !Xtra.terminal_window) return;
|
||||||
|
|
||||||
XEvent terminate = {
|
XEvent terminate = {
|
||||||
.xclient = {
|
.xclient = {
|
||||||
|
Reference in New Issue
Block a user