1
0
mirror of https://github.com/Tha14/toxic.git synced 2025-06-26 22:56:46 +02:00

Compare commits

...

788 Commits

Author SHA1 Message Date
0239509439 Bump version to 0.11.3 and update toxcore version in static build script 2021-12-24 14:21:26 -05:00
602d9d97c1 Send file control cancel when we block or delete a friend 2021-12-22 14:53:09 -05:00
6f8f6f0ac5 Implement file transfer queue for offline friends
File transfers initiated for offline friends are now
added to a queue and initiated all at once when the friend
appears online.
2021-12-22 14:27:28 -05:00
8d58e8f4d6 chore: Fix BUILD format (we check this on toktok-stack now). 2021-12-21 12:23:01 +00:00
b6f892edf5 Remove unnecessary define for keeping track of string array size 2021-12-15 13:39:11 -05:00
f91d10c831 Add missing ifdef 2021-12-13 12:37:51 -05:00
3f18c6f8de cleanup: fix some uninitialized memory warnings and clarify some logic 2021-12-13 12:33:58 -05:00
bf1e1b73fc Do proper error handling for a few malloc calls 2021-12-12 11:30:27 -05:00
3eac65036c Make infer print full error log 2021-12-11 20:13:31 -05:00
85f9ec6b9a chore: Add "infer" static analysis action on CI. 2021-12-11 23:55:29 +00:00
5230616a9d chore: Fix CI: don't install bootstrap daemon. 2021-12-11 23:01:47 +00:00
8e0e318df1 chore: Add github CI workflow. 2021-12-11 22:47:54 +00:00
701c0e1e94 cleanup: Reduce the amount of "extern" in .c files.
There is no check at all that the types of externs actually match the
type of the definition. This just accidentally was not a problem, but now
the compiler helps a bit in keeping it that way.
2021-12-11 22:35:51 +00:00
71f6a8d4d6 cleanup: Avoid casting away constness from pointers. 2021-12-11 22:22:25 +00:00
1cace1e81d Do exact length check for string passed to tox_pk_string_to_bytes 2021-12-11 17:13:30 -05:00
3030cda47e Fix possible null dereference
game invite info needs to be set after calloc in case it fails
2021-12-10 13:44:33 -05:00
2946e0dc56 Zero-init coordinates
Not strictly necessary, but makes static analysis happy
2021-12-10 13:09:47 -05:00
da90ca8b74 Fix bazel build for games. 2021-12-10 17:52:43 +00:00
17e5cc1147 Merge branch 'toktok' 2021-12-08 14:38:39 -05:00
d02ac24de8 Fix regression causing typing notifications to break
Also a small refactor so we use less duplicate code and reduce mutex usage
2021-12-07 22:14:32 -05:00
66e4c590dc Fix some lazy/incorrect code in cmd_add()
This fixes a rare but possible scenario where a name@domain lookup that's
longer than a tox id won't work. It also fixes custom messages for domain
lookups
2021-12-07 13:27:38 -05:00
8176b43880 Update static build script
Bump curl and toxcore versions
2021-12-06 11:42:53 -05:00
b88dc9fda1 Bump version to 0.11.2 2021-12-06 11:08:17 -05:00
d7a19791b4 Remove CHANGELOG.md
This hasn't been updated in ages
2021-12-06 10:59:00 -05:00
e2c8497da9 Cleanup code around tox ID/pk conversion functions 2021-12-06 10:46:19 -05:00
afbd185222 /add command no longer requires quotes around the message 2021-12-06 10:06:49 -05:00
64794e14cd chore: Use toktok-stack 0.0.23 for cirrus builds. 2021-12-06 00:40:44 +00:00
e9a0a30408 Some documentation improvements 2021-12-05 17:03:42 -05:00
8aa57b0539 Fix issue with audio VAD threshold
The default VAD was always being set to 0. We now use the
value provided by the config file if defined
2021-12-05 16:36:13 -05:00
7b734f3996 Make tab completion case sensitive 2021-12-04 16:34:15 -05:00
27e20d6f44 Fix possible buffer overrun in python API 2021-11-26 18:57:40 -05:00
f39da4d7f2 chore: Add a bazel test that calls toxic with --help.
This way we at least know it doesn't crash on load. Some code runs. We'll
want some real tests at some point, but this ensures *something* works.
2021-11-26 23:57:39 +00:00
af70c3d660 chore: Remove travis; add cirrus ci.
We still need a GitHub workflow to test the "make" build. For now, we only
test toktok-stack and the bazel build.
2021-11-26 23:52:39 +00:00
58d0bd0663 Allow empty notes 2021-11-26 09:03:43 -05:00
090fcfffe3 Fix a couple data races 2021-11-26 08:51:38 -05:00
1cba726bb8 Show self connection type and small UI makeover
Connection type is now separated from status in the top status bar
2021-11-25 23:05:33 -05:00
50a074ed22 Remove some unnecessary calls to flag_interface_refresh() 2021-11-21 20:16:02 -05:00
3fddc410b3 Reduce sound notify polling by factor of 10
Polling 100 times per second is excessive. This should help reduce
Toxic's resource usage without a noticable difference to the user.
2021-11-21 14:52:09 -05:00
0a708e4a2e Make sure conference audio calls are properly flagged
This fixes a bug causing the conference audio noise animations
and indicators from properly displaying
2021-11-20 10:16:47 -05:00
b7002ef3f0 Allow ncurses refresh rate to be set dynamically
This allows us to have a higher refresh rate only when necessary (e.g. games)
2021-11-20 09:49:04 -05:00
1803da85c1 Refactor unread message flagging
This fixes an issue where the interface wasn't able to update
when the unread message flag changed. It also cleans up some
ugly code
2021-11-19 22:54:35 -05:00
f3f81111c8 Greatly reduce redundant window refreshing
This should substantially reduce CPU usage and possibly fix some
issues with interface jittering/flashing
2021-11-19 17:54:35 -05:00
13337041ce Show friend connection type (UDP/TCP) in friend status bar 2021-11-10 13:27:11 -05:00
41e93adbdb game_chess.c: always use "%s"-style format for printf()-style functions
`ncuses-6.3` added printf-style function attributes and now makes
it easier to catch cases when user input is used in palce of format
string when built with CFLAGS=-Werror=format-security:

    toxic/src/game_chess.c:1633:63: error:
      format not a string literal and no format arguments [-Werror=format-security]
     1633 |         mvwprintw(win, board->y_bottom_bound + 2, x_mid, state->status_message);
          |                                                          ~~~~~^~~~~~~~~~~~~~~~

Let's wrap all the missing places with "%s" format.
2021-11-04 09:44:33 +00:00
34b7c0a0d8 Options parsing code cleanup 2021-11-03 16:23:38 -04:00
bcdec5d624 Improve installation instructions 2021-09-12 16:58:28 +02:00
9e353443c2 Fix outdated help message 2021-08-16 11:14:09 -04:00
d02f3b4acb Fix a graphical bug with the game border on some terminal emulators 2021-07-27 14:15:36 -04:00
f2b1c81279 Fix static build script and update libcurl version 2021-06-28 23:07:03 -04:00
768617a129 Fix small build bug and bump to v0.11.1 2021-06-28 16:04:25 -04:00
8dfd009e0e Some minor fixes for game module 2021-06-28 13:54:25 -04:00
321f694bb8 Add ability to toggle colours in game of life 2021-06-03 14:45:03 -04:00
4514ecd839 Refactor game window sizing
- Add large square and rectangle window types
- Remove forced small windows
- Fit game of life to largest possible window type
- Hide cursor in game of life when game is running
2021-06-03 01:19:49 -04:00
5e67571908 Implement Conway's Game of Life 2021-06-01 23:00:00 -04:00
c293fbe0c7 Add support for game window notifications 2021-05-24 14:30:29 -04:00
93fb84206d Bump to version 0.11.0 2021-05-24 14:30:28 -04:00
35aa6922d6 Show previous window instead of Home after closing a window 2021-05-24 14:30:28 -04:00
7abf6388f8 Add ability to compile without game support 2021-05-24 14:30:28 -04:00
7aeb1a0aac Add networking to game engine / add multiplayer chess 2021-05-24 14:30:27 -04:00
60bdcf0ba5 Begin implementing chess 2021-05-24 14:30:27 -04:00
a623976a0e Add game module (WIP) 2021-05-24 14:30:26 -04:00
556a522637 Update man pages with new IRC server 2021-05-24 13:50:00 -04:00
a2f0f298aa Fix bug showing friends with busy status as online 2021-04-20 13:29:41 -04:00
0fc1d9e994 Add two missing mutex unlocks 2021-03-27 11:50:57 -04:00
80fd3d3b97 Fix buggy behaviour when printing non-ascii characters in Home input field
This line doesn't appear to be doing anything useful - most likely a leftover
from the recent UI overhaul
2021-01-25 22:36:05 -05:00
07a41f9e0b Show previous window instead of Home after closing a window 2021-01-25 17:09:23 -05:00
f643975941 Fix bug preventing the /clear command from working in Home window 2021-01-23 21:17:46 -05:00
a5246bcbc6 Bump to version 0.10.1 2021-01-20 16:18:43 -05:00
b37e28c2d0 Add a script for building minimal static toxic
The intention is that JFreegman would run it locally on his machine for
every Toxic release and publish the build artifacts on GitHub for
download, similarly to how the qTox team makes release builds. This
should mitigate the loss of the Jenkins build server to some extent,
which used to provide Toxic builds before.
2021-01-19 21:48:51 -05:00
973e60ef11 Fix Makefile assignment bug
When a user provides variable=value as an argument to make, all
assignments to that variable are ignored within the Makefile because the
user has explicitly overrode variable to be "value". This made the
ENABLE_ASAN assignment to be ignored, resulting in Toxic always enabling
ASAN unless you run `make ENABLE_ASAN=disabled`, which is not
documented and not how it's intended to work. This can be fixed by
prefixing the assignment with "override", but to be in line with other
argument assignments we just change the variable name.

See more at:
https://www.gnu.org/software/make/manual/html_node/Overriding.html
2021-01-19 20:18:24 -05:00
ae94bc593b Rename some build options for naming consistency 2021-01-19 15:21:31 -05:00
81eb58532e Fix bug sometimes causing join message spam on conference join 2021-01-17 17:10:10 -05:00
8464ea9a7a Fix minor display bug with the audio call info box 2021-01-12 19:18:22 -05:00
b77bff35a1 Add config man entries for colour scheme options 2020-12-06 11:52:46 -05:00
eb964b64c2 Fix off by one error and comment magic numbers 2020-12-05 20:53:09 -05:00
2ff9d29491 Custom colors proof of concept
Fix formatting

Fix repeated variable in example config
2020-12-05 17:46:13 -06:00
2640919318 Don't announce when ghost peers leave the group
This appears to be a toxcore bug, but nonetheless it looks ugly. Also changed
group -> conference for join/part messages
2020-12-03 11:49:48 -05:00
2fcbc4fa1c Remove lots of duplicate code related to printing timestamps 2020-11-30 17:55:57 -05:00
4330bf5867 Show peer join/part messages in conferences
Also a couple trivial fixes
2020-11-30 12:06:13 -05:00
3f1b7cdd26 Update config example and some default settings to reflect recent changes 2020-11-30 00:58:43 -05:00
1e985c1456 Interface improvements and bump to v0.10.0
- Give window tab and statusbar a make over
- Place window tab above input field
- Reduce input field to one square in height
- Refactor window tab so that it's now a subwin of its parent ToxWindow
- Fix bug causing notification counter to sometimes increment by 2
- No longer scroll on output when output is not at bottom of screen
- Show a small indicator on far left of window tab when output is
  not at bottom of screen
- Reduce ncurses/UI thread sleep time by half
- Handle nanosleep errors better
2020-11-29 23:26:51 -05:00
61740bda85 Fix a couple minor issues
Print a warning if remove() fails, and check if the win pointer is null
before using it (this is unnecessary but it's correct and shuts coverity up)
2020-11-26 18:25:37 -05:00
0d8e6d713e Update readme screenshot and bump to v0.9.1 2020-11-26 16:58:09 -05:00
39e4ff8bd6 Fix tab complete bug
If a directory contains a single entry tab complete will no longer fail
2020-11-26 16:20:51 -05:00
0434ac186a Fix bug causing file transfer status bars to be truncated 2020-11-26 16:17:00 -05:00
8d9d51640c Fix display bug caused by noread flag appended to unread messages
A line's line count now increments without messing up the formatting in cases where
the noread flag wraps to the next line.

Additionally, the way noread flags are handled has been refactored and made
more efficient.
2020-11-26 16:16:59 -05:00
c4c0c0d1f4 Another logging fix
When renaming a log file, if the new name already exists we just
start appending to it and delete the old file. There's no need
to create a backup.

This fixes an issue where leaving and rejoining the same group
multiple times will eventually lead to the logger not working
due to trying to use the same file name over and over again.
2020-11-26 16:10:59 -05:00
3f2826bd66 Add release and LLVM asan build options
The release build uses -O2 and flto, and has no debug symbols.
-Wmissing-field-initializer was removed due to false positives
on newer versions of clang
2020-11-26 16:04:54 -05:00
7b7ea0e386 Fix small regression
This wasn't supposed to make it into the commit
2020-11-24 23:42:25 -05:00
d35a38735b Fix line wrapping/padding issues
It should now parse messages with newlines properly as well as messages that
contain long sequences of characters with no spaces
2020-11-24 19:47:04 -05:00
f0c4906fdc Fix some off by one bugs with line scrolling and some cleanup
Instead of trying (and failing) to correctly calculate the number of lines on the
screen a given message will need space for, we dynamically set the value both
on initiation of a new line, and whenever that line is printed to the screen
using the print_wrap() function.

This should fix the screen occasionally not scrolling down the correct number of
lines when a new message is printed.
2020-11-24 19:36:03 -05:00
56ba61e061 Cleanup and refactor x11 code
- Deleted X11 code for an unfinished/broken feature
- Rename xtra -> x11focus
- Cleanup the remaining code a bit
2020-11-24 19:31:59 -05:00
898d89e95a Properly handle failures to convert widechar strings to multibyte 2020-11-24 16:41:42 -05:00
1fd1e27bdf Remove seconds from default timestamp
Also reduce the --- prefix to one dash before a message. These characters are taking
up valuable real-estate
2020-11-22 18:53:32 -05:00
8e84ac58d4 Implement word wrapping
It's about time
2020-11-22 18:41:12 -05:00
9d65997871 Add notification counters to bottom tab
A counter now increments in the bottom bar for unfocused windows showing how
many unread messages are pending. Tabs with no pending messages show [*]
instead of their index (showing the index is useless and somewhat confusing)
2020-11-21 11:25:41 -05:00
da2889f3ab Fix UI regression
The conference number needs to be displayed in the tab name
so that you can invite friends to conferences
2020-11-20 02:10:52 -05:00
312b38d253 A few small fixes
- Fix race condition in draw_peer()
- Handle realloc_peer_list() error
- Remove dead code in cmd_conference()
- Reduce scope of a few variable variables
- Fix possible buffer truncation in api.c
2020-11-19 14:23:32 -05:00
0554bf0240 Create backup of duplicate log file instead of deleting it
This case should never occur, but just in case it does it's good to handle it
without any data loss
2020-11-19 14:23:31 -05:00
53a7530e8a Some UI improvements
- Bottom tab now only shows indices of active chat windows unless focused
- Always focus Home screen on startup instead of the last loaded conference
- Conference tab names are no longer prefixed with the conference number
- Home and Contact tab names are now capitalized
2020-11-19 01:30:30 -05:00
41be04a142 Implement push-to-talk for conference audio 2020-11-18 16:57:26 -05:00
31f36318a2 Add config settings for audio channels 2020-11-18 16:29:01 -05:00
f882fdf608 Use two channels for conference audio 2020-11-17 16:31:17 -05:00
7e1e410307 Refactor logging
- Conference logging now behaves the same as 1-on-1 chats: Instead
  of creating a new log file every time we restat the client
  we use the unique conference ID to keep track of path names.
  This also allows us to load history for saved groups on client startup

- Added a log init function / general code refactor.

- Fixed a bug that caused log files to be created even when logging
  is disabled.
2020-11-17 16:05:20 -05:00
c135c812c2 Fix playing unallocated memory on opening audio device 2020-11-16 00:00:00 +00:00
6c239193ab Fix bug sometimes preventing typing status from being updated 2020-11-15 12:30:26 -05:00
de7db08352 Bump to version 0.9.0 2020-11-14 14:30:56 -05:00
ba5ded9bc2 Use compound literals to zero out structs instead of memset 2020-11-14 00:00:05 +00:00
4581dee4fc astyle 2020-11-14 00:00:05 +00:00
d75d6e8b60 sort includes 2020-11-14 00:00:05 +00:00
142ce642f0 Per-call pending status and state handling
* Proper handling of incoming video calls.
* Add command /vcall for initiating video calls
* Add command /res command to set video resolution
2020-11-14 00:00:10 +00:00
7dead5ec96 Implement simplistic VAD 2020-11-14 00:00:01 +00:00
ddcf224db2 Implement groupAV 2020-11-14 00:00:01 +00:00
daf794c4a2 Rework audio device handling
We now have at most one input and one output device open at any time,
but can have multiple capture callbacks and multiple output sources.
2020-11-14 00:00:01 +00:00
dac0124f0f Fix some issues with file transfers
- Fix bug causing failed avatar transfers to be sent as normal file transfers
      when a friend goes offline and comes back online
- Remove some unused members of the FileTransfer struct
- Rename filenum -> filenumber and friendnum -> friendnumber
2020-11-13 19:38:33 -05:00
15b7a30925 Fix some bugs/issues with the message queue
- It's no longer possible for messages to be sent out of order
- Check if logger is enabled before doing pointless API calls
- Fix linked list bug (a part of the code almost never executes)
2020-11-12 11:39:19 -05:00
77ab71f26f Refactor message queue
We now attempt to send all queued messages per call to cqueue_try_send() instead
of just the oldest message in the queue. This speeds things up substantially.

Also fixed a very unlikely bug where the read receipt might wrap around to zero
which we used as a reserved value for an unsent message
2020-11-11 16:28:50 -05:00
68e1ba312d Use compound literals to zero out structs instead of memset
This is cleaner and much less prone to bugs
2020-11-10 21:25:27 -05:00
752fc6d619 Fix race condition when window is closed with active notifications
A ToxWindow's notifications need to be halted before the window is freed
2020-11-10 17:20:40 -05:00
16bcb27ca7 Update openal version for macos travis build 2020-11-09 17:29:19 -05:00
71d7d355a6 Use enum to identify window types instead of bool variables 2020-11-09 17:01:22 -05:00
4188b392cc Rename: groupchats -> conferences
This is in line with the toxcore API naming scheme and is in preparation
for the merge with the new groupchat implementation
2020-11-08 10:08:24 -05:00
811fbfbb1e Fix char -> widechar comparisons 2020-11-08 00:07:28 -05:00
32eb7d3040 Filter invalid file names for inbound file transfers 2020-11-05 10:55:48 -05:00
42763905d7 Replace deprecated usleep function with nanosleep
usleep was declared obsolete in POSIX.1-2001
2020-11-04 22:05:59 -05:00
f64300d1d6 Close file handlers when inbound file transfer fails 2020-11-03 13:26:23 -05:00
1a723f0e8e Fix bad behaviour with duplicate file names
If the new path is too long for the buffer we cancel the file transfer
and return an error instead of truncating the file name and continuing.
2020-11-03 13:03:47 -05:00
a86884c40e Remove legacy code and fix a couple format specifiers
This code was added over 5 years ago and no longer serves a purpose
2020-11-03 01:00:08 -05:00
3f02e119f4 add missing malloc error checks and fix widechar to char comparison 2020-11-03 00:59:28 -05:00
1bbd50aac7 Fix a few issues
- realloc needs to be error checked
- use correct format specifiers
- make sure optarg and DATA_FILE aren't null before using them
2020-11-02 18:08:54 -05:00
e7a0c32a68 Refactor a few complex functions
Also moved some single use functions from misc_tools to their
respective files
2020-11-01 15:55:07 -05:00
7560bc9547 modularize string arrays for line completion
Instead of using various different forms of string arrays and having to handle them
differently for string completion, we now always use char pointer arrays. This allows
us to remove some large stack allocations, remove a bunch of confusing defines that
keep track of global array sizes, and generally unclutters the code so it's easier
to read.
2020-11-01 11:29:51 -05:00
2b43340c90 Convert all variable length arrays to heap allocations
VLA's are inherently unsafe so the safest option is to not use them
2020-11-01 11:29:48 -05:00
ff1620c923 fix invalid usage of stderr and incorrect formatting 2020-11-01 11:19:18 -05:00
1303053a27 Use c99 standard instead of gnu99
No gnu99 extensions are used or will be used
2020-10-29 19:29:28 -04:00
91f194c821 Fix pointer use after free bug
If toxcore fails to end a call we still need to do a cleanup
2020-10-28 23:59:28 -04:00
478762f76c Dynamically allocate audio frame buffer memory 2020-10-28 23:59:25 -04:00
4d96d6a753 Fix regression related to https lookups
Reducing the buffer size of HTTPS responses broke DHT nodelist fetching. This change
puts the old buffer size back and converts all stack allocations of the read buffer
to heap allocations.
2020-10-27 12:34:12 -04:00
3cdcfbf4e5 Reduce size of some large stack memory allocations 2020-10-25 13:48:14 -04:00
4c302da503 Fix a bunch of Wformat-truncation warnings due to snprintf() misuse 2020-10-24 14:44:41 -04:00
26b5fe8f9d fix: Fix incorrect file specified error when building in WSL from CLion 2020-10-24 12:52:43 +02:00
22d60232fb Bump to version 0.8.4 2020-10-22 22:14:33 -04:00
e428879beb Fix clashing key bindings
Scrolling the groupchat peer list now uses ctrl+up and down
2020-10-13 19:52:43 -04:00
3015138a5a Manually attempt to decode input char sequences
This is currently a fallback method for when the terminal doesn't
detect ctrl arrow sequences, but it is generalized for future additions
2020-10-13 16:12:55 -04:00
9c06ad608b Add ability to skip words in input field with ctrl-left/right arrow 2020-10-10 11:21:15 -04:00
015dbd9a96 fix: Fix non-working bell notifications
The problem with the bell notifications only happens when Toxic is
compiled with X11 support, but does not run under X. This commit changes
toxic's behavior such that it behaves identically when not running under an
X session, no matter if it has been compiled with X11 support or not.
2020-08-24 16:36:52 +02:00
a7466c3142 Add option to disable LAN 2020-08-10 21:56:45 -04:00
f012007cc4 A couple small fixes 2020-05-19 21:44:35 -04:00
dcf3baf60f Make sure logger file is closed after tox_kill 2020-05-18 13:58:55 -04:00
4bda799a4b Add the ability to log to file (#84) 2020-05-16 23:12:54 -04:00
bdeae33d48 Add macOS build.
Lots of features disabled, because I can't get it to work yet. We'll
enable features one by one as we get them to work.
2020-05-05 00:47:08 +01:00
47591d5298 chore: Use global release-drafter config. 2020-05-05 00:25:10 +01:00
b5ace27a3e chore: Remove astyle from travis build.
The astyle check is now done by restyled.
2020-05-04 23:50:31 +01:00
b334622d36 Add release-drafter config. 2020-05-04 22:01:33 +01:00
4bfb344caa Add option for toxcore logging in stderr 2020-05-04 16:15:28 -04:00
16d96d6faf Add restyled config for toxic. 2020-05-04 20:54:58 +01:00
0ab2bad226 Add CODEOWNERS and settings.yml files. 2020-04-25 03:40:02 +00:00
68db926f9f Check that files are formatted correctly.
Fail the CI build if they are not.
2020-04-23 01:16:57 +00:00
b270c1e8b7 Remove extra semicolon in lock/unlock macros.
lock/unlock are always expanded in a context followed by a semicolon.
2020-04-23 01:12:34 +00:00
e7142e49fd Terminate notify before windows
This fixes a use after free bug
2020-04-22 20:54:53 -04:00
610906d07f fix segfault on starting video 2020-04-17 00:00:00 +00:00
6f72a191ba Revert "Add feature flags and missing #includes."
This reverts commit dd5fa236ae.

Also, set `-std=gnu99` in Bazel build.
2020-04-17 19:37:22 +00:00
dd5fa236ae Add feature flags and missing #includes.
These are needed to compile on some strict Linuxes.
2020-04-15 21:34:30 +00:00
51e1ab94b3 Add QR disabling options to INSTALL.md 2020-04-04 23:20:52 -03:00
ddc8c53abf Fix unused variable warnings and change all (void)s to UNUSED macro 2020-03-30 16:02:27 -04:00
46513017e3 Half-hearted attempt at making toxic work on osx.
Video has no chance without X11 for now.
2020-03-30 18:14:43 +00:00
98cb7f58c0 Fix unused parameter and unused result warnings 2020-03-15 14:57:00 -04:00
206bf407fd Use rules_cc instead of native cc_binary rules. 2020-03-12 12:23:57 +00:00
0a8ac4de3b Fix yamllint warning about missing document start marker.
YAML apparently likes to have this marker, so let's have it.
2020-03-10 14:57:12 +00:00
87d54acad0 Add sponsorship button 2020-03-07 13:19:10 -05:00
45ff6d8bac Migrate to Camel_Case enum types.
UPPER_CASE enum types are deprecated and will be removed in 0.3.0.
2020-03-07 18:11:41 +00:00
437dd8baeb Some misc fixes 2020-02-29 14:14:56 -05:00
b080236ee5 Fix typo 2020-02-10 17:16:56 -05:00
116bff8cef format fixes 2019-12-07 23:17:02 -05:00
ddeca171a0 Add input line text to history on UP and DOWN 2019-12-07 18:29:33 -03:00
127f9462e0 make friend add fail if friend is in the block list 2019-11-16 01:55:47 -05:00
4b5a9abbd4 Fix A/V bug preventing the caller from being properly informed of call termination 2019-07-12 11:51:08 -04:00
bb2257973e Load conference titles on startup for saved conferences (#43) 2019-06-30 14:51:13 -04:00
12b9cd2386 Fix header issues 2019-03-27 01:38:15 -04:00
2cbe8fa880 Use correct integer types to fix groupchat peer scrolling bug 2019-03-26 23:05:24 -04:00
2e39bee05a Check for openal lib before attempting to build with video support 2019-03-15 16:05:54 -04:00
05eda76643 Partially fix autocomplete behaviour for input with spaces 2019-02-17 17:25:34 -05:00
f7b73af9a7 Add config option for the notification timeout duration 2018-11-10 08:54:59 -05:00
73aaa44d12 Add config option to set data file auto-save frequency 2018-10-30 18:22:30 -04:00
e4abd8b36b Bump version to 0.8.3 2018-10-30 18:03:44 -04:00
9e3d4f3889 Check if pointer is null before accessing 2018-10-28 07:09:37 -04:00
b7d67c1d86 re-init AV for unblocked contacts 2018-10-20 02:56:37 -04:00
c4a11f8dc7 Refactor ToxWindows
ToxWindow constructor functions now return pointers instead of structs
ToxWindow windows array now holds pointers instead of structs
Refactor some logic in windows.c pertaining to keeping track of active windows
Use uint8_t for window array indexing
2018-10-19 17:43:06 -04:00
d18cc8cbc2 Fix two memory leaks and properly clean up friendlist window 2018-10-19 17:43:03 -04:00
ce6d4861fb Fix bug where autocomplete added a forward slash to files with no extension
Also slightly refactored the line complete functions
2018-10-17 18:00:09 -04:00
8f0e6026f0 Add enum for file_type() and a little cleanup 2018-10-17 18:00:08 -04:00
258736995d Remove ability to set note with status command 2018-10-17 18:00:08 -04:00
56e03a3f8b No longer require quotes to enclose paths 2018-10-17 18:00:08 -04:00
b6c746b5f5 No longer require quotes for commands that take strings as arguments 2018-10-17 18:00:07 -04:00
03673cbced Improve readability of INSTALL.md 2018-10-11 14:22:37 -04:00
0fea930c24 Convert deprecated uppercase enums to camelcase 2018-10-10 13:34:17 -04:00
94d22a8853 Allow empty status messages 2018-10-09 18:21:05 -04:00
63cc23401a Improve readability of defines 2018-10-08 13:39:04 -04:00
f90a774470 Make Toxic easier to port 2018-10-03 22:00:43 +00:00
e7c5fbc873 Cleanup xtra.c
Privatise some functions that don't need to be public
Fix struct names starting with _ char
Remove unnecessary memset of Xtra struct in init_xtra()
2018-09-27 03:41:58 -04:00
d62902ffb3 Use (void) in prototypes instead of ().
Also, removed `__inline` from an extern function (why was it there?).
Also, moved one extern declaration to a header file. There are lots of
these that need to be moved, but one thing at a time.
2018-09-13 23:47:47 +00:00
bebff3be0e Use (void) for empty parameter list in C. 2018-09-08 17:23:07 +00:00
2be4847b53 Ignore warning about unused result.
These should be fixed, but for now we leave it as warning, not error.
2018-09-06 13:46:24 +00:00
4557614443 Enable .travis.yml check and use non-markdown license. 2018-08-17 23:49:01 +00:00
5b30ecf2e4 Use @x11 instead of the longer @x11//:X11 to link against xlib. 2018-08-14 09:55:54 +00:00
2413ad2b59 Use bazel import libs instead of global -l flags.
Import libs currently also point to the global system installed versions,
but at least we have the freedom to import them properly later.
2018-08-05 19:17:57 +00:00
52855b805a Add astyle check to travis. 2018-07-18 17:19:43 +00:00
20b5e46850 Rename callback implementations to be of the form on_$event.
So it's easy to map from implementation to the event without looking at
the `tox_callback_*` calls.
2018-07-18 17:06:28 +00:00
f2b796940e Add missing braces to if/for/while blocks.
Astyle doesn't quite catch all of them.
2018-07-18 15:56:21 +00:00
a37bf300f9 Update astylerc to match toxcore & reformat all source files 2018-07-18 11:33:16 -04:00
cb524dcbc3 Merge branch 'iphydf-local-libconfig' 2018-07-16 10:18:44 -04:00
4144b868ce Use libconfig built in the WORKSPACE rather than system installed.
Improves hermeticity and reproducibility.
2018-07-15 15:34:19 +00:00
af11f16bef fix merge mistake take 2 2018-07-07 10:29:12 -04:00
1d27a496ef fix merge mistake 2018-07-06 15:43:32 -04:00
32bd9dc1a7 Merge branch 'TokTok-master' 2018-07-06 12:35:46 -04:00
3cd2bc7e3c Don't compile A/V code if AUDIO/VIDEO are not #defined. 2018-07-06 15:46:12 +00:00
43ca840658 Conditionally compile api.c and python_api.c contents.
Based on `-DPYTHON`, instead of based on which files are listed in the
source list. This simplifies people's lives when compiling from the
command line with `cc *.c`.
2018-07-06 14:42:33 +00:00
685837357b Add bazel build file for toxic. 2018-07-06 14:41:16 +00:00
812a13b0fb Merge branch 'fx-carton-master' 2018-06-17 20:27:57 -04:00
641fa471d2 Merge branch 'master' of https://github.com/fx-carton/toxic into fx-carton-master 2018-06-17 20:23:12 -04:00
8d5755f2d8 Merge branch 'nieldk-master' 2018-06-17 20:21:05 -04:00
af510b6666 Merge branch 'master' of https://github.com/nieldk/toxic into nieldk-master 2018-06-17 20:09:14 -04:00
46f646afcf Add an option to disable qr codes 2018-06-16 05:07:16 +02:00
68ce17a57f Temp fix for nick change spam on group join 2018-04-19 22:23:49 -04:00
a69fad15c1 Use default timestamp format if provided one is invalid 2018-04-10 17:47:21 -04:00
7621fe9a62 fix macOS build (#494) 2018-03-31 21:10:17 -04:00
f6d9bc3a74 Update check_features.mk
Changed cfg/checks/check_features.mk to enable individual Audio/Video checks by adding proper DISABLE_VI option which takes "0" or "1" for disable/enable video checks/building.
2018-03-19 22:31:31 +01:00
29aea0b42c Remove libtoxav from install instructions as it's now part of the toxcore lib 2018-03-03 23:55:54 -05:00
815c29ee31 Significantly reduce time before trying to re-send a message with no read receipt
(also some formatting cleanup)
2018-03-03 23:54:12 -05:00
3917f664bf Bump to v0.8.2 2018-03-01 19:14:14 -05:00
a223329815 Fix persistent groupchat loading 2018-02-27 18:46:56 -05:00
3fec11d5f9 Update readme 2018-02-26 03:03:12 -05:00
221edb0012 add a .travis file and some build fixes 2018-02-26 02:34:38 -05:00
2710ab6034 Re-implement group nick change notifications 2018-02-25 03:43:19 -05:00
bc3ffac0ba re-add group peer list sorting 2018-02-25 01:21:22 -05:00
29f55c5277 Update API
-Removed usage of deprecated API functions
-Integrated conference changes with a few regressions
2018-02-25 00:00:06 -05:00
a290f0f7f8 Update toxav API calls 2018-02-24 15:38:07 -05:00
5cd196a769 Fix autocomplete bug
Formatting was messed up due to not accounting for null byte in directory list
2018-02-20 20:54:26 -05:00
b14d983a8c Merge branch 'iphydf-opaque-options' 2018-01-20 15:20:25 -05:00
51f1daeec8 Treat Tox_Options as opaque struct: no deref, no alloc.
We allocate it inside toxcore and dereference it inside as well. This
allows us to change the layout of that struct and add new members.
2018-01-20 19:51:13 +00:00
b799c6a8d7 Merge branch 'iphydf-fix-typedefs' 2018-01-20 13:34:53 -05:00
b9f9546e2b Fix typedef enums and potential uninitialised value. 2018-01-20 18:30:35 +00:00
846bc4613e Fix comment 2017-11-20 07:07:24 -05:00
a5a1f6015d Merge branch 'calls_fix' 2017-11-20 07:03:22 -05:00
fe6a7074ea Dynamically allocate audio calls structure
This fixes a bug that caused a segfault when attempting to call a friend with a
friend number above the MAX_CALLS limit
2017-11-20 07:02:56 -05:00
db7c9fe426 Merge branch 'master' of https://github.com/JFreegman/toxic 2017-11-17 18:17:47 -05:00
b1d8ab102f Bump to version 0.8.1 2017-11-17 17:44:56 -05:00
0bd5b4ddee Repair operating system checks (#474) 2017-11-16 16:59:51 -05:00
c387df35f8 Merge branch 'f8l-pkgsrc' 2017-11-16 16:03:20 -05:00
351a50c214 Do not assume what is not Linux or a BSD descendant is OSX 2017-11-15 21:02:10 +01:00
93175314b5 Merge branch 'aSourceFish-master' 2017-11-15 02:25:55 -05:00
b905a1a3c5 One more bit of standard... 2017-11-15 05:56:13 +02:00
c4386b195f A bit of standard... 2017-11-15 05:54:46 +02:00
ed1e617380 Make Toxic compile at NetBSD, STAGE 2 2017-11-15 05:50:00 +02:00
1382adb1f6 Make Toxic compile at NetBSD, STAGE 1 2017-11-15 05:46:47 +02:00
ecf1c317b7 Make Toxic compile at NetBSD, STAGE 0 2017-11-15 05:24:19 +02:00
cf0b99f1e5 Merge branch 'aramchandran-master' 2017-11-13 15:37:40 -05:00
3605a296a9 Update install.mk 2017-11-13 13:30:22 -05:00
9375d220f9 Merge branch 'aSourceFish-master' 2017-11-11 16:51:34 -05:00
8f94b0a218 Shut down the warning at *BSD 2017-11-11 21:17:34 +02:00
85a0becbf9 Make Toxic compile at OpenBSD 2017-11-11 21:04:45 +02:00
fec36ad9e6 Make Toxic compile at OpenBSD 2017-11-11 21:03:28 +02:00
ecdf6f01d2 Merge branch 'EnniRosario-refresh_devices' 2017-10-31 16:24:53 -04:00
e1bfa30769 Refresh device list on /lsdev. 2017-10-31 18:08:06 +02:00
ebcbc7497b Indicate selected device when printing. 2017-10-31 17:45:39 +02:00
e844ece28b Merge branch 'zugz-reduceRedrawing' 2017-10-29 16:00:46 -04:00
8508451ba6 avoid unnecessary redrawing 2017-10-29 16:50:42 +01:00
5cc83a7cb5 Merge branch 'patheticpat-fix-tmux' 2017-09-05 17:43:13 -04:00
febc725763 Fix tmux detached detection
The old code failed if the session had a custom name instead of the
default numeric id. To be safe in both cases, look for the session_id in
the tmux list-sessions output.
2017-09-05 12:49:48 +02:00
f2c116feb3 Fix potential string truncations with snprintf 2017-09-01 17:36:17 -04:00
52dd60dc86 Fix potential int truncation and double-check lengths before copy 2017-08-28 19:37:19 -04:00
80c0500299 Fix formatting bug caused by strings containing \r 2017-08-28 18:26:52 -04:00
ab490d28b4 Merge branch 'avoidr-status_cmd_feedback' 2017-08-28 17:13:53 -04:00
a9f7f85617 /status: give feedback to user on status change 2017-08-27 12:27:04 +02:00
1bfc1ba371 Merge branch 'Dako300-master' 2017-07-07 20:03:07 -04:00
2ede39369a added /bitrate 2017-07-07 23:47:59 +00:00
922c184195 Only include python libs when necessary 2017-06-06 19:03:40 -04:00
56a9571509 Make sure message id fits inside a signed int 2017-06-02 01:15:44 -04:00
0136f22076 Fix UI bugs & format
This fixes a bug where lines would sometimes be incorrectly marked as unread, as well as
a bug where inbound messages would sometimes be coloured incorrectly
2017-06-01 16:46:12 -04:00
c4ace288af Bump to v0.8.0 2017-05-24 15:10:50 -04:00
6d3fbfee59 Merge branch 'TsarFox-master' 2017-05-24 14:57:32 -04:00
=
be5e7906da Fix fortune.py input issues 2017-05-24 10:10:18 -04:00
369f26932e Fix error messages being printed when autorun_path is unset. 2017-05-23 19:12:53 -04:00
22ea522baf Add "/run" to autocompleter and fix example Python script. 2017-05-22 20:47:56 -04:00
4f60d546e6 Disable Python support in the default build 2017-05-21 16:18:39 -04:00
76d1eafdc0 Change visibility on Python commands list 2017-05-20 08:18:28 -04:00
37912f2d88 Update INSTALL.md 2017-05-19 21:09:29 -04:00
09710327c5 Merge branch 'Dako300-master' 2017-05-19 20:05:52 -04:00
acee4615f8 double signal handler prevents accidental closes 2017-05-19 14:38:39 -05:00
5ed26eda9b Added constants to the Python interface for calls to execute. 2017-05-19 15:35:31 -04:00
6d2b90ac9f Error reporting on failure of invoke_autoruns and solved issue with call to Py_FinalizeEx 2017-05-18 21:37:28 -04:00
02ea0fac44 get_status returns a string rather than an integer. 2017-05-17 08:39:29 -04:00
7d3d129624 Updated code style 2017-05-16 23:19:39 -04:00
b3ed8bc35c Finalized and documented the Python scripting interface. 2017-05-16 20:31:23 -04:00
90210daca7 Python interface for getting the user's nickname/status and executing commands 2017-05-15 22:12:28 -04:00
0e13a1f1bc Implemented a basic Python scripting engine, optional compilation. 2017-05-15 20:29:00 -04:00
09e2690211 Fixed INSTALL formatting (#443) 2017-04-12 12:00:43 -04:00
e65e3af274 Merge branch 'peetcamron-fix/fflush-for-musl' 2017-01-28 00:45:28 -05:00
c6c60d018e Added some fflush after the printf with no \n so we don't have a blank
screen when compiled with musl.
2017-01-28 00:06:03 -05:00
451d4ced80 Add option that prints toxic and toxcore version 2017-01-25 22:13:59 -05:00
7a7402ff86 Update text files with new toktok toxcore link 2016-12-21 17:08:32 -05:00
600e013adc Bump to version 0.7.2 2016-12-18 00:11:24 -05:00
1d71e2eb18 Port to toktok-c-toxcore branch 2016-12-18 00:01:51 -05:00
f858714edd Fix small nodeslist parsing bug 2016-10-23 12:26:18 -04:00
4df44a7274 Merge branch 'tharvik-master' 2016-10-18 12:21:58 -04:00
a26ed9d28f add missing implicit include 2016-10-18 09:38:28 +02:00
2bd5083b8f Corrected brew errors (#413)
Corrected brew errors
2016-10-07 13:24:31 -04:00
8805f694b9 Merge branch 'Ansa89-qr_png' 2016-10-06 11:48:33 -04:00
71040355fd QR: close file descriptor on error 2016-10-06 11:54:27 +02:00
6bc5d8c543 QR PNG: convert some variables to macros 2016-10-06 11:52:26 +02:00
abb39ea6b5 Fix a few resource leaks 2016-10-05 15:17:56 -04:00
15846d2b50 Merge branch 'Ansa89-qr' 2016-10-05 14:58:10 -04:00
958df9f2e8 Add possibility to save QR code in PNG file format 2016-10-05 20:57:50 +02:00
2fd43aebee Merge branch 'Ansa89-fix_checks' 2016-10-05 12:23:23 -04:00
34c29745cc Makefile: use correct variable name when checking video libs 2016-10-05 09:09:22 +02:00
da6fe41d75 Makefile: fix video libs check 2016-10-04 10:25:49 +02:00
e17fa89d8f Update misc_tools.c (#408)
* Update misc_tools.c

Fix build on FreeBSD with clang.

Without this patch, compilation fails with these messages:

  CC    misc_tools.o
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:479:24: error: variable has incomplete type 'struct sockaddr_in'
    struct sockaddr_in s_addr;
                       ^
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:479:12: note: forward declaration of 'struct sockaddr_in'
    struct sockaddr_in s_addr;
           ^
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:480:22: error: use of undeclared identifier 'AF_INET'
    return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0;
                     ^
2 errors generated.

* Fix build on FreeBSD with clang

Without this patch, compilation fails with these messages:

CC misc_tools.o
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:479:24: error: variable has incomplete type 'struct sockaddr_in'
struct sockaddr_in s_addr;
^
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:479:12: note: forward declaration of 'struct sockaddr_in'
struct sockaddr_in s_addr;
^
/usr/ports/net-im/toxic/work/toxic-0.7.1/src/misc_tools.c:480:22: error: use of undeclared identifier 'AF_INET'
return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0;
^
2 errors generated.
2016-09-25 22:32:17 -04:00
f056f13329 Astyle everything and add an astyle options script to repo 2016-09-24 21:07:04 -04:00
3515623159 Bump version to 0.7.1 2016-09-23 13:05:05 -04:00
2194b9e259 Use time_t instead of uint64_t for timestamps
Also call time() directly from get_unix_time() instead of manually updating the time val.
2016-09-22 18:31:52 -04:00
c24e1bd2b8 Fix a few A/V race conditions 2016-09-22 18:00:14 -04:00
38ec96e96a Thread nodeslist loading
This is necessary because DNS/http lookups block, and can do so for a very long time
2016-09-22 14:09:07 -04:00
d2b572ede1 Add ipv6 support for bootstrap nodes and refactor parsing code 2016-09-21 21:22:05 -04:00
703d5419a3 Ignore offline bootstrap nodes, small refactor of Nodes struct 2016-09-21 12:51:57 -04:00
221d761ff4 Ignore bootstrap nodes that use a domain instead of IP address
Domains cause toxcore to do blocking DNS requests which creates noticable lag
and might (??) leak IP addresses when using a proxy
2016-09-21 00:28:16 -04:00
151f5f0c51 Add setting to control DHT nodeslist update frequency
Also rename a few things and semi-fix man page format issues
2016-09-20 13:13:12 -04:00
4f6c603543 Rename DHTnodes to DHTnodes.json 2016-09-20 00:53:53 -04:00
a009f11c0c Automatically update DHT nodeslist
List is now automatically fetched from nodes.tox.chat and placed in the
user config directory. The list is updated once every 30 days, and
will attempt to detect problems and re-fetch the list if necessary.

Also fixed a couple file descriptor leaks and cleaned some things up.
2016-09-20 00:00:09 -04:00
1f8c11a33a These strlen() calls are unncessary 2016-09-18 11:34:13 -04:00
5e20e6b279 Switch to using json DHT nodes file
Parsing json manually like this is ugly, but this allows us to use the json formatted nodeslist file
at nodes.tox.chat instead of having to update the list by hand. We could also potentially
use curl to fetch the list and update it automatically.
2016-09-17 21:38:32 -04:00
1f02bb2be5 Refactor DHT bootstrap code
- Separate node list loading from connecting
- Put code in its own source file
- Rename a few functions
2016-09-17 14:26:23 -04:00
98154b3cba Merge branch 'kdhp-master' 2016-09-15 11:27:04 -04:00
379ad9e116 Use ALC_ENUMERATE_ALL_EXT when available 2016-09-14 05:43:10 -05:00
cb21672600 Merge pull request #403 from metala/fix-set-video-fmt
Changed video get format to set format
2016-07-28 12:30:28 -04:00
4019395f44 Changed video get format to set format
* Fixes issue #394
* This was obviously meant to set the video format.
2016-07-28 17:58:24 +02:00
ee084c572c Merge pull request #402 from metala/fix-chat-infobox-flicker
Remove chat infobox flicker
2016-07-27 22:38:23 -04:00
41a8401ac5 Merge branch 'master' into fix-chat-infobox-flicker
Fixed cursor position issue
2016-07-27 22:04:41 +02:00
d8a3f7de4c Merge pull request #401 from metala/fix-remote-help-flicker
Remove help window flicker
2016-07-27 12:16:12 -04:00
c425aa2f27 Fixed input lag 2016-07-27 18:06:33 +02:00
94e026d114 Remove chat infobox flicker 2016-07-27 02:39:31 +02:00
f89638635a Remove help window flicker 2016-07-27 02:07:31 +02:00
402b86687f Merge branch 'mphe-beep' 2016-07-21 11:35:22 -04:00
5b1b420ac0 Add further explanation to the beep_on* options
This also renames beep_on* to bell_on*.
2016-07-21 11:35:09 +02:00
62ec514f17 Merge pull request #400 from Encrypt/master
Added a changelog to the project
2016-07-19 14:04:05 -04:00
f893dd755f Added a changelog to the project 2016-07-19 00:06:52 +01:00
9aedcf7753 Update docs 2016-07-17 19:22:40 +02:00
d3effa26b5 Add options to enable terminal bell on certain events
Some terminals can mark the terminal window as urgent on bell.
This is useful for window managers that provide a shortcut to jump to an
urgent client.
2016-07-17 19:22:40 +02:00
2ec180789b Fix crash on AV error call state during active call 2016-07-11 17:42:57 -04:00
9f74d3a3a8 Fix memory leak 2016-06-29 21:36:54 -04:00
9fcbc3bde0 Fix tab-complete bug causing buffer to sometimes clear 2016-06-11 23:49:56 -04:00
cf16849b37 Dynamically allocate memory for save file instead of using stack 2016-05-03 14:13:16 -04:00
32442b6286 Disallow ctrl+m keybinding and revert to default settings on invalid bindings
Note: Ctrl+m uses the same control sequence as the enter key on many systems
2016-05-01 14:57:46 -04:00
50f227418b Update man pages 2016-04-25 22:04:43 -04:00
fc06a625a6 Put toxme.io back as it has a new owner 2016-04-25 14:49:23 -04:00
70bd39eb74 Fix small bug 2016-04-11 18:50:28 -04:00
4e0e322e32 Fix cross-client audio issue 2016-04-05 00:49:46 -04:00
e73ac9b6a4 Remove defunct nameserver 2016-03-30 00:30:47 -04:00
bcda6e476e Fix bug for real this time 2016-03-12 02:29:59 -05:00
5b29ce7132 Fix bug preventing friend connection status from changing 2016-03-03 20:49:48 -05:00
f43f644451 Merge branch 'mall0c-multiline' 2016-02-29 19:22:41 -05:00
d6fdac9739 Fix markup in multiline messages
A '<' or '>' at the beginning of a line will now highlight only this
particular line instead of the whole message.
2016-02-29 01:46:48 +01:00
c6a2bb8a90 Add settings option to set paste-mode key and update docs 2016-02-28 21:53:33 +01:00
04576fea7e Add paste-mode to allow multiline text pasting
Ctrl-T toggles paste mode.
Useful when pasting multiline text because it avoids triggering an
enter keypress after linebreaks.
Instead, every \r is translated to \n which is again translated to a
pilcrow (see previous commit).
The pasted text can then be sent as a whole instead of splitting up in
multiple messages.
2016-02-28 21:40:41 +01:00
e6f839f9ac Enable multiline input
Adds a nonl() call to avoid translation from \r to \n when pressing
enter.
C-J -> \n
Enter -> \r
To allow multiline input, \n chars (e.g. when pressing C-J) are replaced
with a pilcrow. After hitting enter, every pilcrow is substituted with
\n again.
2016-02-28 02:35:36 +01:00
eb02424f8a Update DHT nodes list 2016-02-25 19:04:37 -05:00
2e609c46f6 Remove file transfer timeoutes, and remove a couple unused functions 2016-02-25 17:58:02 -05:00
a474e3bf39 Add settings option to disable friend connection change notifications 2016-02-25 17:06:49 -05:00
93835f0455 Merge pull request #379 from FreakyPenguin/password_eval
Add password_eval option to skip password prompt
2016-01-19 18:31:04 -05:00
ac6d8ff89c Add password_eval option to skip password prompt
Runs a command and uses its output as the password. This can be used for
getting the password from a password manager such as pass.
2016-01-19 13:45:52 -08:00
88e74224ed Merge pull request #374 from quininer/master
sleep use tox_iteration_interval
2016-01-11 04:09:56 -05:00
deccaec40e fix milliseconds 2015-12-22 10:43:08 +08:00
4419be36e8 remove useless var 2015-12-21 20:00:48 +08:00
b34b51e8c1 use tox_iteration_interval 2015-12-21 18:13:03 +08:00
74416b4b58 Merge pull request #373 from wedge-jarrad/master
Fix #372 - can't start with missing ~/.config
2015-12-18 01:11:16 -05:00
675712cea0 Fix #372 - can't start with missing ~/.config
This block was added in fa0e645. I'm unsure what bug or corner case it
was intended to address but it causes Toxic to exit with an error if
the ~/.config directory doesn't exist. Without this block the ~/.config
directory and tox-specific subdirectories will be created when Toxic
starts.
2015-12-17 18:17:34 -08:00
36feebfe8d Merge branch 'RomeroMalaquias-master' 2015-12-09 01:32:07 -05:00
3fe9abd84d Avoiding conditional directives that split up parts os statements 2015-12-08 23:13:39 -03:00
fd6432c727 Avoiding conditional directives that split up parts os statements 2015-12-08 23:10:16 -03:00
1feffcc2f0 Merge pull request #369 from nil0x42/master
update doc: DATA_FILE is now `toxic_profile.tox`
2015-12-07 16:11:07 -05:00
6bba3cb9e2 update doc: DATA_FILE is now toxic_profile.tox 2015-12-07 13:38:07 +01:00
3cb6db3d60 Remove pointless null check 2015-12-05 00:19:11 -05:00
77238eeadf Improve file transfer progress bar 2015-12-04 19:41:50 -05:00
88270827a9 Merge pull request #367 from landswellsong/osx-terminal-xtra-fix
Correctly operational from OSX terminals
2015-11-25 03:42:55 -05:00
aade65bfe1 Correctly operational from OSX terminals 2015-11-25 10:26:12 +02:00
b24c5d8cf8 Fix AV bug
Pending call now properly hangs up when you use the /hangup command or close the chat window
2015-11-19 23:49:58 -05:00
9f0feb7223 Allow custom nospam values 2015-11-12 18:03:45 -05:00
74c1eef1d1 Bump version to 0.7.0 2015-11-12 17:18:37 -05:00
65c07a57db Properly close audio devices on quit 2015-11-12 17:14:10 -05:00
ab99c1ac73 Fix building on FreeBSD (courtesy of thierry-FreeBSD) 2015-11-12 05:04:37 -05:00
05f5f16af3 Fix various video bugs; it should be working now! 2015-11-12 05:01:28 -05:00
d16be574f3 Add stack protection compile flag to Makefile 2015-11-10 23:34:46 -05:00
7e0b8b4870 Slight improvement to qrcode printing 2015-11-09 02:28:41 -05:00
39c4b7ecdd Add ability to print your Tox ID's QR code to a file 2015-11-08 22:51:46 -05:00
c5d9aca3e1 Add coverity badge to readme 2015-11-08 03:59:12 -05:00
fa0e645a79 Fix a bunch of misc bugs and corner cases 2015-11-08 03:57:01 -05:00
14a8bdb874 Store temp data in same directory as original file 2015-11-07 21:38:32 -05:00
93a73cbef2 Merge pull request #351 from mneumann/fix_build_dragonfly
Fix compile for DragonFlyBSD
2015-11-07 17:26:30 -05:00
6aab9a79d8 Fix help menu 2015-11-07 01:00:56 -05:00
dfff777283 Save data in a safer manner
By saving to a temp file then renaming it we avoid the possibility of data corruption
due to an interrupt (hard reboot, power outage etc.)
2015-11-05 17:46:00 -05:00
a95fc7824c Fix bug causing profile to be overwritten under a rare condition 2015-11-05 16:15:59 -05:00
f707dce2da Disable recv video callback for now 2015-11-05 15:49:35 -05:00
0d07d14b13 Remove unnecessary/misleading line print 2015-11-05 15:28:24 -05:00
6cc1525daa Fix some build issues 2015-11-03 23:04:05 -05:00
49f5efaab0 A couple audio fixes (ugly but works)
- You will now receive an incoming call even if the caller's chat window is not opened
- Callbacks should all be working now
- Disable video command as video is currently broken
2015-11-03 20:36:41 -05:00
a5e5e98afc Disabled video calls for the time being 2015-11-03 23:50:01 +01:00
4ab99c73a0 Merge with master 2015-11-02 15:22:52 -05:00
e02cf1bb7d Use proxy for DNS requests when type is SOCKS5 2015-11-02 02:01:17 -05:00
9751cfc407 Force name lookups through proxy set by client 2015-11-01 21:34:42 -05:00
36963a5b38 rm redundant error message 2015-10-30 00:10:38 -04:00
7cf9c37aef Handle case where system doesn't support any of the specified TLS cipher suites 2015-10-29 20:35:31 -04:00
2b4b8c0289 Add more descriptive curl errors 2015-10-29 20:16:35 -04:00
368a1465ec Use a specified TLS cipher list for https name lookups 2015-10-29 15:13:42 -04:00
fea317ee24 Remove travis script. Goodbye old friend 2015-10-28 21:46:21 -04:00
8584feab80 Replace DNS-based username lookups with HTTPS & drop utox.org support 2015-10-28 17:14:17 -04:00
f7e48d294e Update README.md 2015-10-23 20:35:15 -04:00
928f25bd89 Update README.md 2015-10-23 20:34:08 -04:00
941ac1d951 Update DHTnodes 2015-10-23 04:40:33 -04:00
7af9327b37 Add note about logs not being encrypted 2015-10-22 19:55:48 -04:00
6b97df2615 Add command to change the Tox ID nospam value 2015-10-22 19:44:05 -04:00
cea5f1fe04 Fix avatar size limit and fix comment 2015-10-20 22:47:11 -04:00
abfdbfe468 Fix some new AV api changes 2015-10-20 17:59:14 -04:00
462cfca175 Merge new AV branch 2015-10-20 17:57:54 -04:00
db410cb01e Use profile name that conforms with the standard 2015-10-14 23:09:11 -04:00
a920f3edfe Replace toxme.se with toxme.io in DNSservers list and remove hardcoded servers from source 2015-09-12 21:31:19 -04:00
2c3921a9fb Fix compile for DragonFlyBSD 2015-09-09 13:23:48 +02:00
f295352495 Replace instances of unsafe atoi function with safe counterpart 2015-09-02 19:41:21 -04:00
ffcc804efe Moved version up 2015-09-01 13:00:56 -04:00
69be1bc398 Fix nodes parsing bug 2015-08-28 02:44:38 -04:00
b4464eda4d Fix more threading issues 2015-08-27 21:29:34 -04:00
28dd43608d Fix a few notify/threading bugs and fix DHTnodes loading bug 2015-08-27 15:13:13 -04:00
11701d22a1 Lots of bug fixes and general code cleanup 2015-08-27 03:38:08 -04:00
4e2db756be Merge remote-tracking branch 'upstream/master' 2015-08-21 00:52:27 -05:00
19cfe3d393 Display a user warning when log fails to initialize 2015-08-21 00:44:40 -05:00
c546df3917 Fix some filetransfer issues
- File transfers now timeout properly
- Small refactor related to creating new transfers
2015-08-21 00:44:40 -05:00
ed0a4fb3b8 simplify timeout function 2015-08-21 00:44:40 -05:00
271ca08eb2 fix a broken link 2015-08-21 00:44:40 -05:00
0e79b8a076 Update DHTnodes 2015-08-21 00:44:40 -05:00
1606d01158 Implemented video calls for OSX 2015-08-21 00:44:25 -05:00
c8a9ac21f3 Implemented OSX device listing 2015-08-21 00:44:25 -05:00
e91aaf6c73 Refactoring to compliment OSX 2015-08-21 00:44:13 -05:00
619fdc1098 Refactored cmd_video function 2015-08-21 00:44:12 -05:00
b7e613de32 Small fix to video cleanup 2015-08-21 00:44:12 -05:00
929fca3de1 Prevented user from manually closing video windows 2015-08-21 00:44:12 -05:00
b67792f9f2 Clear warnings from device listing fix 2015-08-21 00:44:12 -05:00
96162bf254 Fixed incorrect video device listing 2015-08-21 00:43:47 -05:00
8a66c3fa4c Changed to toggle video command rather than two separate commands 2015-08-21 00:43:47 -05:00
2cdcbc07a7 Fixed video call receiving issues 2015-08-21 00:43:30 -05:00
6e0d19b01d Refactored video calls 2015-08-21 00:42:57 -05:00
ad04fa4dcd Major refactoring and fixes towards AV 2015-08-21 00:42:28 -05:00
c2c612b85a Fixed v4l2 capture crash, and refactored to prepare for new features 2015-08-21 00:40:09 -05:00
d359ba6a54 Fixed YUV stride issues 2015-08-21 00:38:44 -05:00
54e2fe8d6f Implemented video frames ready to send through ToxAV. NOTE: Contains YUV stride issues 2015-08-21 00:37:57 -05:00
53353825e2 Implemented /endvideo command 2015-08-21 00:37:57 -05:00
fcdc8e8b67 Fixed incorrect colors during video capture 2015-08-21 00:37:23 -05:00
9b6efb65de Implemented video preview and preparations for ToxAV 2015-08-21 00:37:23 -05:00
c8ea02376e Progress on video call windows using X11 2015-08-21 00:36:52 -05:00
2369b5e9e2 Modified header files structuring 2015-08-21 00:36:28 -05:00
8f28f1d748 Progress on implementing v4l2 in video_device.* 2015-08-21 00:36:28 -05:00
a33e5f4bec Fixes to av.mk 2015-08-21 00:36:13 -05:00
e0a35a6569 Obtain names of video devices using v4l 2015-08-21 00:36:13 -05:00
9863dfc2ae Began implementing video_device.* 2015-08-21 00:35:55 -05:00
c755247434 Added video_device.h file 2015-08-21 00:35:55 -05:00
879b2b236e <not having red text 2015-08-21 00:35:55 -05:00
c6b9a288b6 Send file control cancel on failure to resume transfer 2015-08-21 00:35:55 -05:00
e9e5b5af8d Fix file transfers breaking when friends go offline 2015-08-21 00:35:55 -05:00
d175ff2480 Remove links to libtoxcore.so from readme 2015-08-21 00:35:55 -05:00
750258adef fix rare bug preventing toxcore from sleeping 2015-08-21 00:35:55 -05:00
60b4d62657 Makefile: allow overriding pkg-config 2015-08-21 00:35:55 -05:00
ea78dca756 Update dht nodes list and fix URL's 2015-08-21 00:35:54 -05:00
3cb412632b Add option to enable acting as TCP relay server 2015-08-21 00:35:54 -05:00
8301ab1bc2 Revert commit 312d0c3 (localization/gettext)
There were serious problems with branch merging that need to be resolved first
2015-08-21 00:35:40 -05:00
b6e90d2ebb update translations 2015-08-21 00:30:55 -05:00
06c268417f Fix some possible race conditions related to line printing 2015-08-21 00:29:33 -05:00
1458a6bbc5 s/tox.im/tox.chat/g -- reflect new tox domain 2015-08-21 00:29:32 -05:00
737d29864b Add localization system (gettext) 2015-08-21 00:29:26 -05:00
0a2ad23c15 Add localization system (gettext) 2015-08-21 00:24:02 -05:00
a455c80a1f travis.yml: update dependencies 2015-08-21 00:14:03 -05:00
43bda5f7d9 Refactoring and fix related to invite callback not being fired 2015-08-21 00:14:03 -05:00
f2121fae74 Implemented audio calls using new ToxAV API 2015-08-21 00:14:03 -05:00
3241551cfb Began conversion of audio code to new ToxAV API 2015-08-21 00:14:03 -05:00
6e90072fb8 Implemented OpenCV demo to demonstrate video device listing and set up code structure for video 2015-08-21 00:14:03 -05:00
ca1fca5aa5 separate bootstrapping and adding TCP relays per toxcore API changes 2015-08-21 00:14:03 -05:00
ef1068b6aa toxcore API changes to tox_new 2015-08-21 00:14:02 -05:00
72982cee97 default tox options on initialization 2015-08-21 00:14:02 -05:00
9a4eaa8693 correctly handle tox_new errors 2015-08-21 00:14:02 -05:00
64e7553fb0 not clear which error message is given for ipv6 failure 2015-08-21 00:14:02 -05:00
dd8df1df76 try to fall back to ipv4 if tox fails to init with ipv6 2015-08-21 00:14:02 -05:00
c8d102b02d null terminate status message 2015-08-21 00:14:02 -05:00
a3fa7fd524 fix possible segfault 2015-08-21 00:14:02 -05:00
b2ed8c0ead Makefile: try to fix Tox/toxic#307
@henriqueleng please test it and report back if it works for you.
2015-08-21 00:14:02 -05:00
bbdf4c96b9 fix a few avatar bugs 2015-08-21 00:14:02 -05:00
5496890b34 Update .travis.yml 2015-08-21 00:14:02 -05:00
fd85d8f87b Makefile: add uninstall target 2015-08-21 00:14:02 -05:00
37e7b4c3d3 Update .travis.yml 2015-08-21 00:14:02 -05:00
92d76c7f99 Display a user warning when log fails to initialize 2015-08-19 00:42:28 -04:00
2a787c1097 Fix some filetransfer issues
- File transfers now timeout properly
- Small refactor related to creating new transfers
2015-08-18 15:12:48 -04:00
327259c4c8 simplify timeout function 2015-08-18 01:46:22 -04:00
f173f4275e Merge pull request #350 from vinegret/patch-1
fix a broken link
2015-08-15 12:10:56 -04:00
48eaf8a14f fix a broken link 2015-08-15 15:42:32 +00:00
083611f18e Update DHTnodes 2015-08-13 15:03:02 -04:00
48ffae68a9 <not having red text 2015-08-11 19:22:57 -04:00
c39f8909cd Send file control cancel on failure to resume transfer 2015-08-10 20:41:11 -04:00
32e541bd1c Fix file transfers breaking when friends go offline 2015-08-10 14:22:13 -04:00
f559bdabfe Remove links to libtoxcore.so from readme 2015-08-08 16:51:04 -04:00
0047ba0e9f fix rare bug preventing toxcore from sleeping 2015-08-08 12:55:46 -04:00
ecefc19b23 Merge branch 'ony-master' 2015-07-14 02:15:38 -04:00
e83b397494 Makefile: allow overriding pkg-config 2015-07-14 08:27:07 +03:00
688ea927f8 Update dht nodes list and fix URL's 2015-07-08 22:40:17 -04:00
904f58c0e8 Add option to enable acting as TCP relay server 2015-07-08 21:01:32 -04:00
035420e5c7 Revert commit 312d0c3 (localization/gettext)
There were serious problems with branch merging that need to be resolved first
2015-07-04 01:19:16 -04:00
444d8e7a74 update translations 2015-06-30 23:51:27 -04:00
84a0276668 Fix some possible race conditions related to line printing 2015-06-30 22:40:45 -04:00
312d0c3f42 Merge branch 'Ansa89-add_translation' 2015-06-29 03:17:52 -04:00
d8eca8393c s/tox.im/tox.chat/g -- reflect new tox domain 2015-06-29 03:16:09 -04:00
374b78c763 manually fix merge conflicts 2015-06-29 03:11:21 -04:00
409e4ddd96 Merge pull request #340 from Ansa89/update_travis_deps
travis.yml: update dependencies
2015-06-12 18:23:22 +02:00
1beb35025b travis.yml: update dependencies 2015-06-12 18:22:08 +02:00
51a1c660b4 Add localization system (gettext) 2015-05-30 11:55:59 +02:00
85d3c18ba6 Add localization system (gettext) 2015-05-28 15:50:55 +02:00
d0a7ca17d2 separate bootstrapping and adding TCP relays per toxcore API changes 2015-05-24 17:56:30 -04:00
36640224af toxcore API changes to tox_new 2015-05-24 17:36:13 -04:00
231078b6b9 default tox options on initialization 2015-05-18 19:52:22 -04:00
414f58d896 correctly handle tox_new errors 2015-04-14 17:18:09 -04:00
4d73f8b241 not clear which error message is given for ipv6 failure 2015-04-13 00:58:33 -04:00
82e76a3b5b try to fall back to ipv4 if tox fails to init with ipv6 2015-04-13 00:32:35 -04:00
0bc610e18d null terminate status message 2015-04-10 00:16:01 -04:00
02e6d2db3c fix possible segfault 2015-04-09 02:14:23 -04:00
5a2c341259 Makefile: try to fix Tox/toxic#307
@henriqueleng please test it and report back if it works for you.
2015-04-06 11:44:02 +02:00
1a7eaeddba fix a few avatar bugs 2015-04-04 21:15:34 -04:00
f656d0a722 Update .travis.yml 2015-04-04 03:42:43 -04:00
09c1ad4566 Merge branch 'master' of https://github.com/Tox/toxic 2015-04-04 03:27:27 -04:00
8b9e34db75 Merge branch 'master' of https://github.com/JFreegman/toxic 2015-04-04 03:27:01 -04:00
dd9186e834 re-implement avatar setting 2015-04-04 03:26:38 -04:00
5ff1517b28 Merge pull request #322 from Ansa89/trivial-fix
Makefile: add uninstall target
2015-04-03 15:43:18 +02:00
bbb639c5aa Makefile: add uninstall target 2015-04-03 13:04:28 +02:00
860db2f612 Update .travis.yml 2015-04-02 22:44:19 -04:00
523f205646 re-implement friendlist last seen 2015-04-02 22:19:09 -04:00
e998c8a866 fix encryption API breakage 2015-03-31 21:56:11 -04:00
eaea68c33e fix bug where contacts would appear online twice in a row 2015-03-31 18:39:42 -04:00
4780cfeafc remove non-existant group commands 2015-03-31 17:11:43 -04:00
bdb0951c84 a few small filetransfer fixes 2015-03-29 19:29:38 -04:00
e3130c92c0 small fix 2015-03-29 19:26:16 -04:00
12c880ab51 fix bootstrapping 2015-03-29 19:05:24 -04:00
522aabd4e4 Refactor and clean up file transfers
(No longer rely on undefined core filenumber property for indexing)
2015-03-29 18:33:51 -04:00
bf09b3b6c4 Merge branch 'master' of https://github.com/Tox/toxic 2015-03-28 02:58:24 -04:00
2d3c5c9450 Mostly finished with new API port
- File transfers currently don't support pausing/resuming
- Avatars are not yet done
2015-03-28 02:56:54 -04:00
ae87b2eb2d begin port to new API 2015-03-25 22:56:45 -04:00
c34ecc8dfd Merge pull request #318 from Ansa89/trivial-fix
README.md: fix typo
2015-03-23 15:44:19 +01:00
2c2938c647 README.md: fix typo 2015-03-23 15:36:58 +01:00
22dd883f28 Merge pull request #316 from Ansa89/trivial-fix
Makefile: be less aggressive when cleaning
2015-03-21 14:32:23 -04:00
dfbb1338a5 Makefile: be less aggressive when cleaning 2015-03-21 19:31:00 +01:00
f8dc82516e Merge pull request #315 from Ansa89/trivial-fix
Move makefile into root directory
2015-03-21 19:25:05 +01:00
59b16f7760 Fix travis build 2015-03-21 18:38:28 +01:00
a11289de79 Move makefile into root directory
Requested by @mannol.
2015-03-21 18:35:40 +01:00
a64b8cae89 Merge branch 'hardlyeven-master' 2015-03-18 15:51:18 -04:00
470eaeb97b Merge branch 'master' of https://github.com/hardlyeven/toxic into hardlyeven-master 2015-03-18 15:45:37 -04:00
6503349ed3 Merge pull request #314 from al42and/fd_leak
Fixing couple leaking file descriptors
2015-03-18 15:38:40 -04:00
ec23cedc3a Fixing couple leaking file descriptors 2015-03-18 19:28:04 +03:00
jlo
ce1ae1d7dc added tab autocomplete for "/status o" => "/status online" 2015-03-17 14:25:15 -05:00
6669d5632f Merge pull request #310 from Ansa89/trivial-fix
Some cosmetics changes
2015-03-16 13:26:17 +01:00
59e1114997 Some cosmetics changes 2015-03-16 13:16:03 +01:00
c20510e5aa Merge pull request #308 from henriqueleng/openbsd
Openbsd
2015-03-15 15:52:37 -04:00
2b2e746549 added gnumake as dep., because you can't compile with *BSDmake 2015-03-15 16:34:56 -03:00
dc5a8d44e5 Add OpenBSD option to Makefile 2015-03-15 16:27:00 -03:00
090d3339a0 fix auto-away bugs
Manually set aways no longer unaway when they shouldn't, and busy status is no longer overridden
2015-03-13 20:33:23 -04:00
442d9e22b4 use pthread for mplex detach polling for better portability 2015-03-11 18:38:07 -04:00
0c39e7b158 Add support for auto-away based on screen attach/detach 2015-03-09 01:38:30 +02:00
3e3f2614b5 Merge pull request #303 from louipc/interface
Add support for custom timestamps in chat and logs.
2015-02-23 22:38:50 -05:00
53e4b2c971 Add support for custom timestamps in chat and logs.
Internal representations of the time_format setting are replaced by timestamp format strings.
time_format is only used in the setup.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2015-02-23 00:46:33 -05:00
d6c57c7aa3 Merge pull request #302 from Ansa89/trivial-fix
README.md: update download section
2015-02-19 12:49:50 +01:00
3efc984ae9 README.md: update download section 2015-02-18 15:56:19 +01:00
7618a0871a Merge pull request #301 from Ansa89/trivial-fix
Add INSTALL.md
2015-02-17 14:37:17 -05:00
b87f73cc47 Add INSTALL.md 2015-02-17 11:12:58 +01:00
785d39d78f Merge pull request #296 from louipc/interface
Interface
2015-02-13 14:23:44 -05:00
38a0f6fae4 Make little action indicators on each output line configurable.
Also added a new DISCONNECTION line info type.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2015-02-13 02:09:40 -05:00
710be51cad Merge pull request #298 from Ansa89/trivial-fix
travis.yml: use latest libsodium stable
2015-02-11 19:19:47 -05:00
50438425e5 Update README.md 2015-02-11 19:06:40 -05:00
4b4bfe8876 travis.yml: use latest libsodium stable 2015-02-11 10:12:05 +01:00
67da4bdd5b Merge pull request #297 from urras/patch-1
Travis should build with Libsodium stable, fix clang
2015-02-10 14:27:13 -05:00
e230badb47 Fix Clang
I didn't expect this to work, but it is and I'm not complaining.
2015-02-10 10:01:44 -05:00
d48d9ed4dc Travis should build with Libsodium stable 2015-02-10 09:47:06 -05:00
b9fe6bfa10 Merge pull request #280 from DomT4/darwin
Darwin Build
2015-02-09 21:05:10 -08:00
5cbbb62ce2 Fix whitespace
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2015-02-09 23:33:49 -05:00
3369c9d808 Merge pull request #293 from Spagy/patch-1
Correct filename comment from main.c to toxic.c
2015-02-04 15:47:58 -05:00
dfc594f949 Correct filename comment from main.c to toxic.c 2015-02-04 13:56:31 +00:00
d714cda145 Vital commit fixing serious Toxic bug 2015-02-01 17:10:44 -08:00
428e1e4100 Merge pull request #292 from Ansa89/trivial-fix
Update for toxcore API break
2015-02-01 15:16:29 -05:00
2b19f56e63 Update for toxcore API break 2015-02-01 21:09:48 +01:00
4badc983ea Merge pull request #291 from dantok/master
Fix some edge cases when obtaining paths
2015-01-25 15:54:27 -05:00
c8a4f88ff3 Update configdir.c 2015-01-25 21:53:13 +01:00
eeeaf8d707 Update autocomplete.c 2015-01-25 21:52:07 +01:00
37b3b5a5ed Fix an edge case when obtaining home directory.
Make the path to home directory empty before calling get_home_dir(), otherwise if the call fails, the contents are undefined.
2015-01-25 20:49:52 +01:00
a561ef8c49 Fixed emptying avatar_path if the path is too long. 2015-01-25 20:17:32 +01:00
89f200e870 Merge pull request #290 from urras/master
Update DHT nodes again
2015-01-11 15:11:04 -05:00
2823115a6c Update DHT nodes again 2015-01-11 15:06:15 -05:00
5599d73760 remove invalid node from nodes list 2015-01-11 14:28:52 -05:00
bac66cb5ad Merge pull request #289 from urras/master
Update DHT node list
2015-01-11 14:16:50 -05:00
61c50972e3 Update DHT node list 2015-01-11 14:06:33 -05:00
ff0fbbc379 small fix 2015-01-01 12:50:51 -05:00
4a124dea43 Merge branch 'flussence-master' 2015-01-01 01:56:31 -05:00
e722b665d1 Make "Last seen" handle year rollover correctly 2015-01-01 05:44:18 +00:00
4365b8d5ad update man page 2014-12-27 13:17:05 -05:00
e55e5f3f7e add HTTP proxy support 2014-12-27 13:12:16 -05:00
d1036c8538 Darwin Build
Explains/Better Enables building on the OS X Platform. I’ve written a
Darwin.mk file for the purpose, given one is referenced in the Makefile
but doesn’t actually exist yet. I presume this is due to Toxic’s recent
move away from configure scripts?

Anyhow. It’s not perfect, and it could be prettier, but it should fix
2014-12-18 03:49:52 +00:00
9240f62829 Merge branch 'jdp5087-tour' 2014-12-17 17:35:01 -05:00
1b89bc9051 Made the keys section of settings_load more readable in settings.c 2014-12-17 12:15:18 -05:00
7700ef83e0 disable broken callback 2014-12-09 20:30:13 -05:00
9922b3a4f3 forgot IFDEFs 2014-12-09 18:55:14 -05:00
d561d2e1ac fix 2014-12-09 18:35:14 -05:00
7865cea284 group audio stuff 2014-12-09 18:29:07 -05:00
424189cad9 small fix 2014-12-07 21:48:29 -05:00
82aa64e8f7 properly close all groupchats on exit 2014-12-07 13:51:12 -05:00
a0418520a2 Merge branch 'master' of https://github.com/Tox/toxic 2014-12-07 12:19:14 -05:00
f451d961bc close output device on group exit 2014-12-07 12:16:49 -05:00
a4da9fd49e "Refactor" this super important file 2014-12-07 01:50:39 -08:00
0a0891fa98 fix building without audio 2014-12-06 13:40:45 -05:00
9464b369a4 fix possible crash 2014-12-06 13:26:27 -05:00
47692edee4 update DHTnodes for real 2014-12-05 20:33:13 -05:00
73c94b25ba update DHTnodes, fix comment 2014-12-05 20:26:10 -05:00
ab2ea5936d correct value 2014-12-05 13:47:47 -05:00
90985af007 properly handle file pausing 2014-12-05 13:23:45 -05:00
5aad8764b1 ensure messages in queue are always delivered in order 2014-12-03 22:10:21 -05:00
5a175f374a fix file statusbar draw bug 2014-12-03 21:38:37 -05:00
4acfe84171 remove spammy connection messages 2014-11-30 12:20:01 -05:00
e995a1cb69 AV api changes 2014-11-30 09:27:45 -05:00
867f041c23 more group stuff 2014-11-29 09:39:55 -05:00
7e49ba92b2 Merge pull request #283 from stal888/master
Destroy AL context before closing dhndl
2014-11-29 08:18:56 -05:00
2fa53c0531 Destroy AL context before closing dhndl
fixes seggy on os x, i think
2014-11-28 22:08:31 -08:00
673800c947 forgot something 2014-11-28 23:51:32 -05:00
835b821b75 put toxav loop in separate thread 2014-11-28 23:47:22 -05:00
78587ad20b disable group audio callback until it works properly 2014-11-26 17:39:02 -05:00
09bbec79cf group audio almost works 2014-11-26 15:22:34 -05:00
751b5f9943 only include audio_call.h if audio is defined 2014-11-26 12:24:52 -05:00
4a337ae3cb update for core audio refactor 2014-11-26 00:57:02 -05:00
1baeb15073 update DHTnodes 2014-11-20 02:57:42 -05:00
141b36af04 handle errors for name functions 2014-11-15 22:39:24 -05:00
4238c20e72 api update 2014-11-15 15:59:19 -05:00
4e177d60b0 group title fixes and api update 2014-11-15 15:55:45 -05:00
1bd880708b a couple formatting fixes 2014-11-14 22:35:23 -05:00
76c21c8b34 implement group titles 2014-11-14 22:15:59 -05:00
dd8c2caac7 more prep for audio groups 2014-11-14 20:13:08 -05:00
7a7e8a7f8d prep for audio groups 2014-11-11 20:49:05 -05:00
43f45d67a4 core API update 2014-11-11 18:30:23 -05:00
adb36a39bb minor visual adjustment 2014-11-05 18:46:18 -05:00
5a0d9f5e9f Merge pull request #278 from Ansa89/trivial-fix
Fix Tox/toxic#276
2014-10-30 15:41:17 +01:00
a4e8cb3971 Fix Tox/toxic#276 2014-10-30 15:23:47 +01:00
e22b7a336c Merge pull request #274 from Ansa89/trivial-fix
Makefile: revert back to mkdir
2014-10-21 06:20:51 -07:00
317fa42b20 Makefile: revert back to mkdir 2014-10-21 11:51:02 +02:00
884f8dda37 Merge pull request #273 from Ansa89/trivial-fix
Makefile: add toxic.desktop to install target
2014-10-21 01:38:29 -07:00
f5090532fb Makefile: add toxic.desktop to install target 2014-10-21 10:31:30 +02:00
ae04dd8fa5 Create toxic.desktop 2014-10-20 13:00:14 -07:00
00e4075937 Merge pull request #271 from Ansa89/trivial-fix
Toxic.conf.exmaple: fix sound namefile
2014-10-20 15:35:52 -04:00
d65f3ea58d Fix sound namefile 2014-10-20 10:55:06 +02:00
008163bf6c fix 2014-10-18 17:29:23 -04:00
f09002a49a Merge branch 'Ansa89-trivial-fix' 2014-10-16 14:27:58 -04:00
431290d47a Version: fix revision calculation 2014-10-16 20:26:00 +02:00
b66874b7b3 Merge pull request #262 from Ansa89/trivial-fix
Version: add revision only if git is available
2014-10-15 14:26:54 +02:00
1b9fd7f936 Install: check if manpages exist 2014-10-15 14:25:14 +02:00
0a1457acde Version: add revision only if git is available 2014-10-15 10:39:49 +02:00
d2008aa92f Merge branch 'louipc-new' 2014-10-13 00:16:05 -04:00
e83356faef Merge branch 'new' of https://github.com/louipc/toxic into louipc-new 2014-10-13 00:14:29 -04:00
fd4161832b travis.yml: Remove asciidoc
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-10-12 23:35:48 -04:00
0a132b0eb5 doc: Unlink docs from the rest of the build process.
Since generated man pages are also included, we can't
guarantee proper timestamps. This should fix issues that trigger doc
building when it isn't needed.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-10-12 23:21:48 -04:00
9c7ac9043a prompt: Add version line to startup message.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-10-12 23:12:56 -04:00
b86c0d357f Update toxencryptsave api change.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-10-12 23:04:30 -04:00
75dd26518f Finished drag and drop support 2014-10-12 23:26:28 +02:00
2cc261c619 Some random fixups 2014-10-12 22:54:18 +02:00
f7d46f1100 possibly fix sound notification bug 2014-10-12 01:49:56 -04:00
be264528d2 possibly fix sound notification bug 2014-10-12 00:28:28 -04:00
c825adc1e3 Dnd works 2014-10-11 23:53:02 +02:00
4e9f125e95 core API function name change 2014-10-10 22:44:05 -04:00
d26c8fe447 Merge pull request #264 from zetok/indicator
Change action messages indicator
2014-10-09 16:46:51 -04:00
e42d635195 non-critical thread failures shouldn't be fatal 2014-10-09 16:39:01 -04:00
a32cd1c19b Change action messages indicator 2014-10-09 21:36:42 +01:00
14dc02ac83 fix segfault 2014-10-09 15:47:48 -04:00
e4a28d1839 make groupchat announcements behave properly 2014-10-09 01:39:22 -04:00
0908920b51 fix segfault 2014-10-08 18:06:15 -04:00
8a882916fb fix setting custom keybinding 2014-10-08 15:22:49 -04:00
55ada8ad2f fix groupchat resizing when peerlist is off 2014-10-08 14:53:09 -04:00
2094186c0f update DHTnodes 2014-10-08 14:44:15 -04:00
d3a489b756 update settings and docs with peerlist-toggle keybinding 2014-10-08 03:08:08 -04:00
e6b18231c0 add ability to toggle groupchat peerlist with ctrl-b 2014-10-08 02:45:08 -04:00
cc0145d561 reduce system calls, increase time between message queue re-send attempts 2014-10-08 01:50:34 -04:00
9f0daca5eb filter escape sequences from all inbound nicks and status messages 2014-10-07 16:18:06 -04:00
1f2bd44dce don't allow newlines and tabs in nicks 2014-10-07 00:43:03 -04:00
6492bd12f9 escape newlines in contact names/status messages 2014-10-06 16:23:43 -04:00
43552161f9 implement word deletion via ^W 2014-10-05 23:12:58 -04:00
e5d45fdf1d correct return code check 2014-10-05 02:29:40 -04:00
bd69c8da18 small fix 2014-10-04 17:01:02 -04:00
8c3e3ebe24 fix blocklist saving bug 2014-10-03 23:52:54 -04:00
7eebbd982d fix 2014-10-03 21:12:59 -04:00
5c66f5c161 fixes 2014-10-03 19:29:12 -04:00
40f70fc1e3 groupchat fixes 2014-10-03 18:57:32 -04:00
9cf4427375 core groupchat names should be working 2014-10-03 17:55:36 -04:00
23cf9686cb safer string handling 2014-10-03 17:53:50 -04:00
70add920fe Making progress with dnd 2014-10-03 16:59:32 +02:00
c56c6cc219 some temporary fixes for new wip groupchats 2014-10-02 23:22:37 -04:00
e9a0296851 ignore tox_load errors until toxcore is fixed 2014-10-02 22:25:21 -04:00
de30433e26 better data operation error handling 2014-10-02 02:07:54 -04:00
fa64fa8b93 replace call sounds
Signed-off-by: Jfreegman <jfreegman@gmail.com>
2014-10-01 19:38:09 -04:00
50c7942cb5 Started working on dnd for toxic 2014-10-01 23:28:34 +02:00
e7697b8fba make ctrl-L force refresh the window 2014-10-01 16:24:36 -04:00
b46a77f977 forced end of page is not working out 2014-10-01 15:01:23 -04:00
38909afa89 refine a couple sound effects 2014-10-01 13:46:19 -04:00
5af561c811 new default sounds; rm unused sounds 2014-10-01 01:16:17 -04:00
ae984d4f04 don't show version in default status message 2014-09-30 17:02:03 -04:00
97a8ecd115 small fix and bump version to 0.5.2 2014-09-29 13:56:17 -04:00
64d782569a add asciidoc and libnotify-dev to install script 2014-09-29 01:54:53 -04:00
6248baf98b fix segfault 2014-09-29 01:30:22 -04:00
33cfca7ecc bug fixes and code cleanup 2014-09-28 17:49:48 -04:00
a01cc35368 Merge branch 'master' of github.com:Tox/toxic 2014-09-28 16:48:09 +02:00
b10eebd77e This should fix audio problem 2014-09-28 16:47:31 +02:00
05661ca9b6 core API update and refactor group invites a bit 2014-09-27 22:50:20 -04:00
784883f773 What if, like, photosynthesis is a lie?! 2014-09-28 00:13:45 +02:00
a9e5723ca4 a couple fixes 2014-09-27 03:08:19 -04:00
95dfea8d29 keep chatlog names consistent with friend name changes 2014-09-27 02:28:11 -04:00
e574af7d68 fix CPU usage issue regarding audio drivers, courtesy of mannol 2014-09-26 20:32:48 -04:00
2918ca45a2 Merge pull request #255 from Ansa89/trivial-fix
Fix "error: unknown type name 'off_t'"
2014-09-26 13:01:44 -04:00
6ad744f770 Add stdlib.h header to allow off_t type 2014-09-26 10:50:42 +02:00
5b394e6f35 notify.c: better headers order 2014-09-26 10:46:14 +02:00
940af2c711 a few fixes, update example config file 2014-09-26 03:39:36 -04:00
544c402f78 implement avatars (setting only) and generalize path tab-complete 2014-09-26 03:10:44 -04:00
cee9e624b8 more UI changes 2014-09-25 15:23:50 -04:00
2e65ee3609 a few UI changes 2014-09-25 04:31:45 -04:00
3a176e1cab move to page end after pressing return 2014-09-25 00:42:08 -04:00
00cccad22c a few general fixes 2014-09-24 15:20:15 -04:00
a432d733d7 use 64-bit off_t for file sizes 2014-09-24 14:23:08 -04:00
893e88294b more succinct way to get file sizes 2014-09-24 00:06:02 -04:00
b071a9e992 more thorough error checking 2014-09-23 22:51:56 -04:00
48cf4ebf02 fix for issue #254 2014-09-23 21:32:05 -04:00
773a75b948 update makefile checks 2014-09-22 21:51:55 -04:00
133c0e8d63 rename reserved identifiers per C standard 2014-09-22 21:24:45 -04:00
bf54cb36ef set signal handlers at more appropriate places 2014-09-22 20:00:36 -04:00
032853b5c9 Merge branch 'Pyrohh-master' 2014-09-22 19:41:23 -04:00
650c13ca7a There's no need for rm -rf, just rm -f 2014-09-22 18:45:45 -04:00
9d5fe03285 small fix 2014-09-22 18:38:46 -04:00
c3f68b60d3 bigger log identifiers to reduce chance of collision 2014-09-22 17:34:30 -04:00
1c16467eb9 don't share chatlogs across data files (changes log naming convention) 2014-09-22 17:09:39 -04:00
3c74385f5c use proper variable type for sig handler flags 2014-09-22 14:27:33 -04:00
c07c0028bb increase line_info msg buffer size so won't cut off long log lines 2014-09-22 13:49:09 -04:00
dc3b2e04ab load chatlog history when opening a chatwindow 2014-09-22 04:29:28 -04:00
7fd3aa9164 Merge pull request #246 from urras/patch-2
Update screenshot
2014-09-21 13:17:13 -04:00
4c60312e2d Update screenshot 2014-09-21 12:42:04 -04:00
16e29aa4e0 Merge pull request #243 from Ansa89/trivial-fix
Makefile: use single quotes also for PACKAGE_DATADIR
2014-09-19 12:28:32 -04:00
bd7b073155 Makefile: fix typo 2014-09-19 10:47:25 +02:00
f25cf870e6 Makefile: use single quotes also for PACKAGE_DATADIR 2014-09-19 10:45:27 +02:00
13291d0365 bump version to 0.5.1 2014-09-19 01:24:39 -04:00
9ee7a48910 add setting to disable welcome message 2014-09-19 01:11:23 -04:00
daf4614ba6 improve behaviour of misused encryption options 2014-09-19 00:29:30 -04:00
919d36369c add option to unencrypt an encrypted data file 2014-09-18 23:50:51 -04:00
618704df76 remove duplicate DHT node 2014-09-18 22:52:05 -04:00
9a70dd9651 possibly fix display bug on some platforms 2014-09-18 13:14:15 -04:00
e2d310b10f Add TCP nodes on 443 2014-09-17 14:00:41 -07:00
a1015a366a update DHTnodes, small fixes 2014-09-17 13:52:27 -04:00
913ec7b3fe Merge pull request #242 from Ansa89/trivial-fix
Usage help: add missing comma
2014-09-16 13:55:20 +02:00
4a52b06954 Usage help: add missing comma 2014-09-16 11:54:58 +02:00
89f9c07b9e add confirmation when creating new password 2014-09-15 19:00:36 -04:00
388d78d11e add option to encrypt an existing unencrypted data file 2014-09-15 16:17:58 -04:00
a2a23b3932 password prompt fixes 2014-09-15 04:13:12 -04:00
f405ae8b42 improvements to password entry screen 2014-09-14 21:49:38 -04:00
cf3f6750eb small fix 2014-09-14 18:25:13 -04:00
4de22d067a Update .travis.yml 2014-09-14 18:08:42 -04:00
51e274ea38 implement data file encryption 2014-09-14 17:46:28 -04:00
0a6ce62363 don't write unsent messages to log 2014-09-11 01:36:33 -04:00
13c5de5531 increase time between message send retries 2014-09-10 16:18:37 -04:00
21f8e7f398 couple small fixes 2014-09-09 15:16:27 -04:00
bcf4a5af90 message queue improvements 2014-09-09 14:06:28 -04:00
09f90d095b properly flag lines with unread mark 2014-09-07 22:28:54 -04:00
416ebc9ab8 another fix 2014-09-07 22:05:17 -04:00
3ca22aa714 fix 2014-09-07 21:43:16 -04:00
8dd25e1f0b code cleanup, add delay for unread message notification 2014-09-07 15:08:01 -04:00
5b9bd603ea implement read receipts 2014-09-07 02:43:53 -04:00
3c2c1f15ce message sending queue for fake offline messaging 2014-09-06 13:18:42 -04:00
6876df4a45 Merge pull request #240 from s3erios/master
Fix some 'clang --analyze' warnings
2014-09-05 13:16:43 -04:00
1ff97161fb temporarily revert a862874740. 2014-09-05 14:15:25 +03:00
667410e879 fix another potential memory leak 2014-09-05 13:17:10 +03:00
a862874740 mark exit_toxic_* functions as noreturn 2014-09-05 13:15:56 +03:00
79bde4e5bf fix potential memory leak and move cleanup to the end of the function 2014-09-05 13:02:26 +03:00
833b724e9f fix bug 2014-09-04 18:48:55 -04:00
96b68058bb code cleanup and fix bug that sometimes prevented tab notifications from working 2014-09-04 18:28:20 -04:00
e823233149 Merge pull request #238 from Ansa89/trivial-fix
Addition to Tox/toxic#235
2014-09-04 13:23:33 -04:00
3ac22fafe4 Add info about DISABLE_X11 usage 2014-09-04 19:20:51 +02:00
71f2ac170c Merge pull request #235 from s3erios/master_cfg
Add X11 option
2014-09-04 13:18:46 -04:00
0ef888eea3 Merge pull request #236 from s3erios/master
Some code simplification
2014-09-04 11:10:55 +02:00
a9b0028a15 move some code inside _X11 ifdef 2014-09-04 01:41:02 +03:00
b18e6cff5a move duplicate code into separate function 2014-09-04 01:36:37 +03:00
424a1c94d9 Add X11 option 2014-09-04 01:19:32 +03:00
009095af24 slight simplification for command list iteration 2014-09-02 02:23:44 -04:00
159 changed files with 27598 additions and 6706 deletions

13
.cirrus.yml Normal file
View File

@ -0,0 +1,13 @@
---
cirrus-ci_task:
container:
image: toxchat/toktok-stack:0.0.31-third_party
cpu: 2
memory: 2G
configure_script:
- /src/workspace/tools/inject-repo toxic
test_all_script:
- cd /src/workspace && bazel test -k
--remote_http_cache=http://$CIRRUS_HTTP_CACHE_HOST
--config=release
//toxic/...

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
/.github/ @TokTok/admins

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
---
github: [JFreegman]

18
.github/settings.yml vendored Normal file
View File

@ -0,0 +1,18 @@
---
_extends: .github
repository:
name: toxic
description: An ncurses-based Tox client
topics: tox, console, chat
branches:
- name: "master"
protection:
required_status_checks:
contexts:
- build
- cirrus-ci
- Codacy Static Code Analysis
- code-review/reviewable
- infer

106
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,106 @@
name: ci
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run:
sudo apt-get update &&
sudo apt-get install -y --no-install-recommends
libalut-dev
libconfig-dev
libcurl4-gnutls-dev
libnotify-dev
libopenal-dev
libopus-dev
libqrencode-dev
libsodium-dev
libvpx-dev
libx11-dev
python3-dev
pkg-config &&
git clone --depth=1 https://github.com/TokTok/c-toxcore &&
cd c-toxcore &&
cmake . -B_build -DBOOTSTRAP_DAEMON=OFF &&
cd _build &&
make -j4 &&
sudo make install
- name: Build toxic
run: make -j4
infer:
runs-on: ubuntu-latest
container: toxchat/infer
steps:
- name: Install git
run:
apt-get update &&
DEBIAN_FRONTEND=noninteractive
apt-get install -y --no-install-recommends
git
- name: Install dependencies
run:
apt-get update &&
apt-get install -y --no-install-recommends
cmake
g++
libalut-dev
libconfig-dev
libcurl4-gnutls-dev
libncurses-dev
libnotify-dev
libopenal-dev
libopus-dev
libqrencode-dev
libsodium-dev
libvpx-dev
libx11-dev
make
python3-dev
pkg-config &&
git clone --depth=1 https://github.com/TokTok/c-toxcore &&
cd c-toxcore &&
cmake . -B_build -DBOOTSTRAP_DAEMON=OFF &&
cd _build &&
make -j4 &&
make install
- uses: actions/checkout@v2
- name: Run infer
run:
infer --no-progress-bar -- cc src/*.c
-fsyntax-only
$(python3-config --includes --ldflags)
$(pkg-config --cflags --libs
freealut
libconfig
libcurl
libnotify
libpng
libqrencode
ncurses
openal
python3
toxcore
vpx
x11)
-DAUDIO
-DBOX_NOTIFY
-DGAMES
-DPACKAGE_DATADIR='""'
-DPYTHON
-DQRCODE
-DSOUND_NOTIFY
-DVIDEO
- name: Print log
run:
cat /__w/toxic/toxic/infer-out/report.txt

4
.gitignore vendored
View File

@ -16,3 +16,7 @@ stamp-h1
build/toxic
build/*.o
build/*.d
apidoc/python/build
*.vim
*.tox
*.nvim*

4
.restyled.yaml Normal file
View File

@ -0,0 +1,4 @@
---
restylers:
- astyle:
arguments: ["--options=astylerc"]

View File

@ -1,53 +0,0 @@
language: c
compiler:
- gcc
# - clang # Fix me
before_script:
# Installing yasm (needed for compiling vpx) and openal
- sudo apt-get -yq install yasm libopenal-dev libconfig-dev libalut-dev
# Installing libsodium, needed for toxcore
- git clone https://github.com/jedisct1/libsodium.git libsodium
- cd libsodium
- git checkout tags/0.4.2 > /dev/null
- ./autogen.sh > /dev/null
- ./configure > /dev/null
- make check -j2 || make check || exit 1 > /dev/null
- sudo make install > /dev/null
- cd ..
# Installing libopus, needed for audio encoding/decoding
- wget http://downloads.xiph.org/releases/opus/opus-1.0.3.tar.gz
- tar xzf opus-1.0.3.tar.gz > /dev/null
- cd opus-1.0.3
- ./configure > /dev/null
- make -j2 || make || exit 1 > /dev/null
- sudo make install > /dev/null
- cd ..
# Installing vpx
- git clone http://git.chromium.org/webm/libvpx.git libvpx
- cd libvpx
- ./configure --enable-shared > /dev/null
- make -j2 || make || exit 1 > /dev/null
- sudo make install > /dev/null
- cd ..
# Creating libraries links and updating cache
- sudo ldconfig > /dev/null
# Installing toxcore
- git clone https://github.com/irungentoo/toxcore.git toxcore
- cd toxcore
- autoreconf -i
- ./configure --disable-tests --disable-ntox --disable-daemon --enable-av
- make -j2 || make || exit 1
- sudo make install
- cd ..
script:
- cd build
- make -j2 || make || exit 1
notifications:
email: false
irc:
channels:
- "chat.freenode.net#tox-dev"
on_success: always
on_failure: always

49
BUILD.bazel Normal file
View File

@ -0,0 +1,49 @@
load("@rules_cc//cc:defs.bzl", "cc_binary")
load("//tools/project:build_defs.bzl", "project")
project()
cc_binary(
name = "toxic",
srcs = glob(
[
"src/*.c",
"src/*.h",
],
exclude = ["src/video*"],
) + select({
"//tools/config:linux": glob(["src/video*"]),
"//tools/config:osx": [],
}),
copts = [
"-std=gnu99",
"-DAUDIO",
"-DGAMES",
"-DPACKAGE_DATADIR='\"data\"'",
"-DPYTHON",
"-DQRCODE",
] + select({
"//tools/config:linux": ["-DVIDEO"],
"//tools/config:osx": [],
}),
deps = [
"//c-toxcore",
"@curl",
"@libconfig",
"@libqrencode",
"@libvpx",
"@ncurses",
"@openal",
"@python3//:python",
] + select({
"//tools/config:linux": ["@x11"],
"//tools/config:osx": [],
}),
)
sh_test(
name = "toxic_test",
size = "small",
srcs = [":toxic"],
args = ["--help"],
)

71
INSTALL.md Normal file
View File

@ -0,0 +1,71 @@
# Installation
* [Dependencies](#dependencies)
* [OS X Notes](#os-x-notes)
* [Compiling](#compiling)
* [Documentation](#documentation)
* [Notes](#notes)
* [Compilation variables](#compilation-variables)
* [Environment variables](#environment-variables)
## Dependencies
| Name | Needed by | Debian package |
|------------------------------------------------------|----------------------------|---------------------|
| [Tox Core](https://github.com/toktok/c-toxcore) | BASE | libtoxcore-dev |
| [NCurses](https://www.gnu.org/software/ncurses) | BASE | libncursesw5-dev |
| [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev |
| [GNUmake](https://www.gnu.org/software/make) | BASE | make |
| [libcurl](http://curl.haxx.se/) | BASE | libcurl4-openssl-dev|
| [libqrencode](https://fukuchi.org/works/qrencode/) | QRCODE | libqrencode-dev |
| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
| [Python 3](http://www.python.org/) | PYTHON | python3-dev |
| [AsciiDoc](http://asciidoc.org/index.html) | DOCUMENTATION<sup>1</sup> | asciidoc |
<sup>1</sup>: see [Documentation](#documentation)
#### OS X Notes
Using [Homebrew](http://brew.sh):
```
brew install curl qrencode openal-soft freealut libconfig libpng
brew install --HEAD https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/libtoxcore.rb
brew install libnotify
export PKG_CONFIG_PATH=/usr/local/opt/openal-soft/lib/pkgconfig
make
```
You can omit `libnotify` if you intend to build without desktop notifications enabled.
## Compiling
```
make
sudo make install
```
#### Documentation
Run `make doc` in the build directory after editing the asciidoc files to regenerate the manpages.<br />
**Note for developers**: asciidoc files and generated manpages will need to be committed together.<br />
**Note for everyone**: [asciidoc](http://asciidoc.org/index.html) (and this step) is only required for regenerating manpages when you modify them.
## Notes
#### Compilation variables
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and `USER_LDFLAGS=""` passed as arguments to make, or as environment variables
* Default compile options can be overridden by using special variables:
* `DISABLE_X11=1` → Disable X11 support (needed for focus tracking)
* `DISABLE_AV=1` → Disable audio call support
* `DISABLE_SOUND_NOTIFY=1` → Disable sound notifications support
* `DISABLE_QRCODE=1` → Disable QR exporting support
* `DISABLE_QRPNG=1` → Disable support for exporting QR as PNG
* `DISABLE_DESKTOP_NOTIFY=1` → Disable desktop notifications support
* `DISABLE_GAMES=1` → Disable support for games
* `ENABLE_PYTHON=1` → Build toxic with Python scripting support
* `ENABLE_RELEASE=1` → Build toxic without debug symbols and with full compiler optimizations
* `ENABLE_ASAN=1` → Build toxic with LLVM Address Sanitizer enabled
* `DESTDIR=""` Specifies the base install directory for binaries and data files (e.g.: DESTDIR="/tmp/build/pkg")
#### Environment variables
* You can use the `CFLAGS` and `LDFLAGS` environment variables to add specific flags to the Makefile
* The `PREFIX` environment variable specifies a base install directory for binaries and data files. This is interchangeable with the `DESTDIR` variable, and is generally used by systems that have the `PREFIX` environment variable set by default.<br />
**Note**: `sudo` does not preserve user environment variables by default on some systems. See the `sudoers` manual for more information.

View File

97
Makefile Normal file
View File

@ -0,0 +1,97 @@
BASE_DIR = $(shell pwd -P)
CFG_DIR = $(BASE_DIR)/cfg
-include $(CFG_DIR)/global_vars.mk
LIBS = toxcore ncursesw libconfig libcurl
CFLAGS ?= -std=c99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all -Wvla -Wno-missing-braces
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
CFLAGS += ${USER_CFLAGS}
LDFLAGS ?=
LDFLAGS += ${USER_LDFLAGS}
OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o
OBJ += file_transfers.o friendlist.o global_commands.o conference_commands.o conference.o help.o input.o line_info.o
OBJ += log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
# Check if debug build is enabled
RELEASE := $(shell if [ -z "$(ENABLE_RELEASE)" ] || [ "$(ENABLE_RELEASE)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
ifneq ($(RELEASE), enabled)
CFLAGS += -O0 -g -DDEBUG
LDFLAGS += -O0
else
CFLAGS += -O2 -flto
LDFLAGS += -O2 -flto
endif
# Check if LLVM Address Sanitizer is enabled
ASAN := $(shell if [ -z "$(ENABLE_ASAN)" ] || [ "$(ENABLE_ASAN)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
ifneq ($(ASAN), disabled)
CFLAGS += -fsanitize=address -fno-omit-frame-pointer
endif
# Check on wich system we are running
UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S), Linux)
LDFLAGS += -ldl -lrt
endif
ifeq ($(UNAME_S), OpenBSD)
LIBS := $(filter-out ncursesw, $(LIBS))
LDFLAGS += -lncursesw
endif
ifeq ($(UNAME_S), NetBSD)
LIBS := $(filter-out ncursesw, $(LIBS))
LDFLAGS += -lncursesw
endif
ifeq ($(UNAME_S), Darwin)
-include $(CFG_DIR)/systems/Darwin.mk
endif
# Check on which platform we are running
UNAME_M = $(shell uname -m)
ifeq ($(UNAME_M), x86_64)
-include $(CFG_DIR)/platforms/x86_64.mk
endif
ifneq ($(filter %86, $(UNAME_M)),)
-include $(CFG_DIR)/platforms/x86.mk
endif
ifneq ($(filter arm%, $(UNAME_M)),)
-include $(CFG_DIR)/platforms/arm.mk
endif
# Include all needed checks
-include $(CFG_DIR)/checks/check_features.mk
# Fix path for object files
OBJ := $(addprefix $(BUILD_DIR)/, $(OBJ))
# Targets
all: $(BUILD_DIR)/toxic
$(BUILD_DIR)/toxic: $(OBJ)
@echo " LD $(@:$(BUILD_DIR)/%=%)"
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/toxic $(OBJ) $(LDFLAGS)
$(BUILD_DIR)/osx_video.o: $(SRC_DIR)/$(OSX_VIDEO)
@echo " CC $(@:$(BUILD_DIR)/)osx_video.o"
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/osx_video.o -c $(SRC_DIR)/$(OSX_VIDEO)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
@if [ ! -e $(BUILD_DIR) ]; then \
mkdir -p $(BUILD_DIR) ;\
fi
@echo " CC $(@:$(BUILD_DIR)/%=%)"
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/$*.o -c $(SRC_DIR)/$*.c
@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c >$(BUILD_DIR)/$*.d
clean:
rm -f $(BUILD_DIR)/*.d $(BUILD_DIR)/*.o $(BUILD_DIR)/toxic
-include $(BUILD_DIR)/$(OBJ:.o=.d)
-include $(CFG_DIR)/targets/*.mk
.PHONY: clean all

View File

@ -1,52 +1,20 @@
# Toxic [![Build Status](https://travis-ci.org/Tox/toxic.png?branch=master)](https://travis-ci.org/Tox/toxic)
Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application.
<a href="https://scan.coverity.com/projects/toxic-tox">
<img alt="Coverity Scan Build Status"
src="https://scan.coverity.com/projects/4975/badge.svg"/>
</a>
![Toxic Screenshot](https://i.imgur.com/ryaEmQZ.png "Home Screen")
Toxic is a [Tox](https://tox.chat)-based instant messaging and video chat client.
[![Toxic Screenshot](https://i.imgur.com/TwYA8L0.png "Toxic Home Screen")](https://i.imgur.com/TwYA8L0.png)
## Installation
[See the install instructions](/INSTALL.md)
### Dependencies
##### Base
* [libtoxcore](https://github.com/irungentoo/toxcore)
* [ncurses](https://www.gnu.org/software/ncurses) (for Debian based systems, 'libncursesw5-dev')
* [libconfig](http://www.hyperrealm.com/libconfig) (for Debian based systems, 'libconfig-dev')
## Settings
Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more.
You can view our example config file [here](misc/toxic.conf.example).
##### Audio
* libtoxav ([libtoxcore](https://github.com/irungentoo/toxcore) compiled with audio support)
* [openal](http://openal.org) (for Debian based systems, 'libopenal-dev')
##### Sound notifications
* [openal](http://openal.org) (for Debian based systems, 'libopenal-dev')
* [openalut](http://openal.org) (for Debian based systems, 'libalut-dev')
##### Desktop notifications
* [libnotify](https://developer.gnome.org/libnotify) (for Debian based systems, 'libnotify-dev')
##### Documentation
* [Asciidoc](http://asciidoc.org/index.html) (only required for regenerating manpages)
* Run `make doc` after editing the asciidoc files to regenerate the manpages.
* **NOTE FOR DEVELOPERS**: asciidoc files and generated manpages will need to be commited together.
### Compiling
1. `cd build/`
2. `make PREFIX="/where/to/install"`
3. `sudo make install PREFIX="/where/to/install"`
### Compilation Notes
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and/or `USER_LDFLAGS=""`
* You can pass your own flags to the Makefile with `CFLAGS=""` and/or `LDFLAGS=""` (this will supersede the default ones)
* Additional features are automatically enabled if all dependencies are found, but you can disable them by using special variables:
* `DISABLE_AV=1` → build toxic without audio call support
* `DISABLE_SOUND_NOTIFY=1` → build toxic without sound notifications support
* `DISABLE_DESKTOP_NOTIFY=1` → build toxic without desktop notifications support
### Packaging
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files
* `DESTDIR=""` can be used in addition to `PREFIX=""`:
* `DESTDIR=""` is meant to specify a directory where to store installed files (ex: "/tmp/build/pkg")
* `PREFIX=""` is meant to specify a prefix directory for binaries and data files (ex: "/usr/local")
### Troubleshooting
## Troubleshooting
If your default prefix is "/usr/local" and you receive the following:
```
error while loading shared libraries: libtoxcore.so.0: cannot open shared object file: No such file or directory
@ -57,12 +25,3 @@ echo '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf.d/locallib.conf
sudo ldconfig
```
## Precompiled binaries
You can download precompiled binaries from [jenkins](https://jenkins.libtoxcore.so):
* [Linux 32 bit](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz)
* [Linux 64 bit](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz)
## Settings
Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more.
You can view our example config file [here](misc/toxic.conf.example).

20
apidoc/python/Makefile Normal file
View File

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = toxic_api
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# toxic_api documentation build configuration file, created by
# sphinx-quickstart on Tue May 16 08:58:24 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'toxic_api'
copyright = '2017, Jakob Kreuze'
author = 'Jakob Kreuze'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.11.3'
# The full version, including alpha/beta/rc tags.
release = '0.11.3'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'toxic_apidoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'toxic_api.tex', 'toxic\\_api Documentation',
'Jakob Kreuze', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'toxic_api', 'toxic_api Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'toxic_api', 'toxic_api Documentation',
author, 'toxic_api', 'One line description of project.',
'Miscellaneous'),
]

View File

@ -0,0 +1,8 @@
============
API Examples
============
Fortune
=======
.. literalinclude:: fortune.py
:language: python

View File

@ -0,0 +1,37 @@
import toxic_api
import random
FORTUNES = [
"A bug in the code is worth two in the documentation.",
"A bug in the hand is better than one as yet undetected.",
"\"A debugged program is one for which you have not yet found the "
"conditions that make it fail.\" -- Jerry Ogdin"
]
def send_fortune(args):
"""Callback function that sends the contact of the current window a
given number of random fortunes.
"""
if len(args) != 1:
toxic_api.display("Only one argument allowed!")
return
try:
count = int(args[0])
except ValueError:
toxic_api.display("Argument must be a number!")
return
if count < 0 or count > 20:
toxic_api.display("Argument is too large!")
return
name = toxic_api.get_nick()
toxic_api.send("%s has decided to send you %d fortunes:" % (name, count))
for _ in range(count):
toxic_api.send(random.choice(FORTUNES))
toxic_api.register("/fortune", "Send a fortune to the contact of the current "
"window", send_fortune)

View File

@ -0,0 +1,9 @@
Toxic Scripting Interface Documentation
=======================================
.. toctree::
:maxdepth: 2
intro
reference
examples

View File

@ -0,0 +1,12 @@
=========================
Toxic Scripting Interface
=========================
A Python scripting interface to `Toxic <https://github.com/JFreegman/toxic>`_.
Getting Started
===============
Toxic is compiled with Python support by default. To access the scripting interface, simply import "toxic_api" in your script.
Scripts can be run by issuing "/run <path>" from toxic, or placing them in the "autorun_path" from your toxic configuration file.

View File

@ -0,0 +1,73 @@
=============
API Reference
=============
Messages
========
.. function:: display(msg)
Display a message to the user through the current window.
:param msg: The message to display.
:type msg: string
:rtype: none
.. function:: send(msg)
Send a message to the user specified by the currently open conversation.
:param msg: The message to display.
:type msg: string
:rtype: none
State
=====
.. function:: get_nick()
Return the user's current nickname.
:rtype: string
.. function:: get_status()
Return a string representing the user's current status. Can be either "online", "away", or "busy".
:rtype: string
.. function:: get_status_message()
Return the user's current status message.
:rtype: string
.. function:: get_all_friends()
Return a list of all the user's friends.
:rtype: list of (string, string) tuples containing the nickname followed by their public key
Commands
========
.. function:: execute(command, class)
Executes the given command. The API exports three constants for the class parameter; GLOBAL_COMMAND, CHAT_COMMAND, and GROUPCHAT_COMMAND.
:param command: The command to execute.
:type command: string
:param class: The class of the command.
:type class: int
:rtype: none
.. function:: register(command, help, callback)
Register a callback to be executed whenever command is run. The callback function will be called with one argument, a list of arguments from when the user calls the command.
:param command: The command to listen for.
:type command: string
:param help: A description of the command to be shown in the help menu.
:type help: string
:param callback: The function to be called.
:type callback: callable
:rtype: none

26
astylerc Normal file
View File

@ -0,0 +1,26 @@
# Bracket Style Options
--style=kr
# Tab Options
--indent=spaces=4
# Indentation Options
--indent-switches
# Padding Options
--pad-header
--break-blocks
--pad-oper
--unpad-paren
--align-pointer=name
--align-reference=name
# Formatting Options
--add-brackets
--convert-tabs
--max-code-length=120
# Other Options
--preserve-date
--formatted
--lineend=linux

View File

@ -1,67 +0,0 @@
BASE_DIR = $(shell cd .. && pwd -P)
CFG_DIR = $(BASE_DIR)/cfg
-include $(CFG_DIR)/global_vars.mk
LIBS = libtoxcore ncursesw libconfig
CFLAGS = -std=gnu99 -pthread -Wall -g
CFLAGS += -DTOXICVER="\"$(VERSION)\"" -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED
CFLAGS += -DPACKAGE_DATADIR="\"$(abspath $(DATADIR))\""
CFLAGS += $(USER_CFLAGS)
LDFLAGS = $(USER_LDFLAGS)
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o notify.o
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o
# Check on wich system we are running
UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S), Linux)
-include $(CFG_DIR)/systems/Linux.mk
endif
ifeq ($(UNAME_S), FreeBSD)
-include $(CFG_DIR)/systems/FreeBSD.mk
endif
ifeq ($(UNAME_S), Darwin)
-include $(CFG_DIR)/systems/Darwin.mk
endif
ifeq ($(UNAME_S), Solaris)
-include $(CFG_DIR)/systems/Solaris.mk
endif
# Check on which platform we are running
UNAME_M = $(shell uname -m)
ifeq ($(UNAME_M), x86_64)
-include $(CFG_DIR)/platforms/x86_64.mk
endif
ifneq ($(filter %86, $(UNAME_M)),)
-include $(CFG_DIR)/platforms/x86.mk
endif
ifneq ($(filter arm%, $(UNAME_M)),)
-include $(CFG_DIR)/platforms/arm.mk
endif
# Include all needed checks
-include $(CFG_DIR)/checks/check_features.mk
# Targets
all: toxic doc
toxic: $(OBJ)
@echo " LD $@"
@$(CC) $(CFLAGS) -o toxic $(OBJ) $(LDFLAGS)
%.o: $(SRC_DIR)/%.c
@echo " CC $@"
@$(CC) $(CFLAGS) -o $*.o -c $(SRC_DIR)/$*.c
@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c > $*.d
clean:
rm -rf *.d *.o toxic
-include $(OBJ:.o=.d)
-include $(CFG_DIR)/targets/*.mk
.PHONY: clean all

22
cfg/checks/audio.mk Normal file
View File

@ -0,0 +1,22 @@
# Variables for audio call support
AUDIO_LIBS = openal
AUDIO_CFLAGS = -DAUDIO
ifneq (, $(findstring audio_device.o, $(OBJ)))
AUDIO_OBJ = audio_call.o
else
AUDIO_OBJ = audio_call.o audio_device.o
endif
# Check if we can build audio support
CHECK_AUDIO_LIBS := $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
ifneq ($(CHECK_AUDIO_LIBS), error)
LIBS += $(AUDIO_LIBS)
LDFLAGS += -lm
CFLAGS += $(AUDIO_CFLAGS)
OBJ += $(AUDIO_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_AUDIO_LIBS := $(shell for lib in $(AUDIO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without audio support)
$(warning WARNING -- You need these libraries for audio support)
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
endif

View File

@ -1,23 +0,0 @@
# Variables for audio call support
AUDIO_LIBS = libtoxav openal
AUDIO_CFLAGS = -D_AUDIO
ifneq (, $(findstring device.o, $(OBJ)))
AUDIO_OBJ = audio_call.o
else
AUDIO_OBJ = audio_call.o device.o
endif
# Check if we can build audio support
CHECK_AUDIO_LIBS = $(shell pkg-config --exists $(AUDIO_LIBS) || echo -n "error")
ifneq ($(CHECK_AUDIO_LIBS), error)
LIBS += $(AUDIO_LIBS)
CFLAGS += $(AUDIO_CFLAGS)
OBJ += $(AUDIO_OBJ)
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_AUDIO_LIBS = $(shell for lib in $(AUDIO_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without audio support)
$(warning WARNING -- You need these libraries for audio support)
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
endif
endif

View File

@ -1,41 +1,72 @@
CHECKS_DIR = $(CFG_DIR)/checks
# Check if we can use X11
CHECK_X11_LIBS = $(shell pkg-config --exists x11 || echo -n "error")
ifneq ($(CHECK_X11_LIBS), error)
LIBS += x11
CFLAGS += -D_X11
# Check if we want build X11 support
X11 := $(shell if [ -z "$(DISABLE_X11)" ] || [ "$(DISABLE_X11)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(X11), disabled)
-include $(CHECKS_DIR)/x11.mk
endif
# Check if we want build audio support
AUDIO = $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
AUDIO := $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(AUDIO), disabled)
-include $(CHECKS_DIR)/av.mk
-include $(CHECKS_DIR)/audio.mk
endif
# Check if we want build video support
VIDEO := $(shell if [ -z "$(DISABLE_VI)" ] || [ "$(DISABLE_VI)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(X11), disabled)
ifneq ($(AUDIO), disabled)
ifneq ($(VIDEO), disabled)
-include $(CHECKS_DIR)/video.mk
endif
endif
endif
#check if we want to build with game support
GAMES := $(shell if [ -z "$(DISABLE_GAMES)" ] || [ "$(DISABLE_GAMES)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(GAMES), disabled)
-include $(CHECKS_DIR)/games.mk
endif
# Check if we want build sound notifications support
SND_NOTIFY = $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
SND_NOTIFY := $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(SND_NOTIFY), disabled)
-include $(CHECKS_DIR)/sound_notifications.mk
-include $(CHECKS_DIR)/sound_notifications.mk
endif
# Check if we want build desktop notifications support
DESK_NOTIFY = $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
DESK_NOTIFY := $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(DESK_NOTIFY), disabled)
-include $(CHECKS_DIR)/desktop_notifications.mk
-include $(CHECKS_DIR)/desktop_notifications.mk
endif
# Check if we want build QR export support
QR_CODE := $(shell if [ -z "$(DISABLE_QRCODE)" ] || [ "$(DISABLE_QRCODE)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(QR_CODE), disabled)
-include $(CHECKS_DIR)/qr.mk
endif
# Check if we want build QR exported as PNG support
QR_PNG := $(shell if [ -z "$(DISABLE_QRPNG)" ] || [ "$(DISABLE_QRPNG)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(QR_PNG), disabled)
-include $(CHECKS_DIR)/qr_png.mk
endif
# Check if we want build Python scripting support
PYTHON := $(shell if [ -z "$(ENABLE_PYTHON)" ] || [ "$(ENABLE_PYTHON)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
ifneq ($(PYTHON), disabled)
-include $(CHECKS_DIR)/python.mk
endif
# Check if we can build Toxic
CHECK_LIBS = $(shell pkg-config --exists $(LIBS) || echo -n "error")
CHECK_LIBS := $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
ifneq ($(CHECK_LIBS), error)
CFLAGS += $(shell pkg-config --cflags $(LIBS))
LDFLAGS += $(shell pkg-config --libs $(LIBS))
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_LIBS = $(shell for lib in $(LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
$(warning ERROR -- Cannot compile Toxic)
$(warning ERROR -- You need these libraries)
$(warning ERROR -- $(MISSING_LIBS))
$(error ERROR)
endif
CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBS))
LDFLAGS += $(shell $(PKG_CONFIG) --libs $(LIBS))
else ifneq ($(MAKECMDGOALS), clean)
MISSING_LIBS := $(shell for lib in $(LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning ERROR -- Cannot compile Toxic)
$(warning ERROR -- You need these libraries)
$(warning ERROR -- $(MISSING_LIBS))
$(error ERROR)
endif

View File

@ -1,17 +1,15 @@
# Variables for desktop notifications support
DESK_NOTIFY_LIBS = libnotify
DESK_NOTIFY_CFLAGS = -D_BOX_NOTIFY
DESK_NOTIFY_CFLAGS = -DBOX_NOTIFY
# Check if we can build desktop notifications support
CHECK_DESK_NOTIFY_LIBS = $(shell pkg-config --exists $(DESK_NOTIFY_LIBS) || echo -n "error")
CHECK_DESK_NOTIFY_LIBS := $(shell $(PKG_CONFIG) --exists $(DESK_NOTIFY_LIBS) || echo -n "error")
ifneq ($(CHECK_DESK_NOTIFY_LIBS), error)
LIBS += $(DESK_NOTIFY_LIBS)
CFLAGS += $(DESK_NOTIFY_CFLAGS)
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_DESK_NOTIFY_LIBS = $(shell for lib in $(DESK_NOTIFY_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without desktop notifications support)
$(warning WARNING -- You need these libraries for desktop notifications support)
$(warning WARNING -- $(MISSING_DESK_NOTIFY_LIBS))
endif
LIBS += $(DESK_NOTIFY_LIBS)
CFLAGS += $(DESK_NOTIFY_CFLAGS)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_DESK_NOTIFY_LIBS := $(shell for lib in $(DESK_NOTIFY_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without desktop notifications support)
$(warning WARNING -- You need these libraries for desktop notifications support)
$(warning WARNING -- $(MISSING_DESK_NOTIFY_LIBS))
endif

5
cfg/checks/games.mk Normal file
View File

@ -0,0 +1,5 @@
# Variables for game support
GAMES_CFLAGS = -DGAMES
GAMES_OBJ = game_base.o game_centipede.o game_chess.o game_life.o game_util.o game_snake.o
CFLAGS += $(GAMES_CFLAGS)
OBJ += $(GAMES_OBJ)

15
cfg/checks/python.mk Normal file
View File

@ -0,0 +1,15 @@
# Variables for Python scripting support
PYTHON3_LIBS = python3
PYTHON_CFLAGS = -DPYTHON
PYTHON_OBJ = api.o python_api.o
# Check if we can build Python scripting support
CHECK_PYTHON3_LIBS = $(shell $(PKG_CONFIG) --exists $(PYTHON3_LIBS) || echo -n "error")
ifneq ($(CHECK_PYTHON3_LIBS), error)
LDFLAGS += $(shell python3-config --ldflags)
CFLAGS += $(PYTHON_CFLAGS) $(shell python3-config --includes)
OBJ += $(PYTHON_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
$(warning WARNING -- Toxic will be compiled without Python scripting support)
$(warning WARNING -- You need python3 installed for Python scripting support)
endif

15
cfg/checks/qr.mk Normal file
View File

@ -0,0 +1,15 @@
# Variables for QR export support
QR_LIBS = libqrencode
QR_CFLAGS = -DQRCODE
# Check if we can build QR export support
CHECK_QR_LIBS = $(shell pkg-config --exists $(QR_LIBS) || echo -n "error")
ifneq ($(CHECK_QR_LIBS), error)
LIBS += $(QR_LIBS)
CFLAGS += $(QR_CFLAGS)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_QR_LIBS = $(shell for lib in $(QR_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without QR export support)
$(warning WARNING -- You need these libraries for QR export support)
$(warning WARNING -- $(MISSING_QR_LIBS))
endif

15
cfg/checks/qr_png.mk Normal file
View File

@ -0,0 +1,15 @@
# Variables for QR exported as PNG support
PNG_LIBS = libpng
PNG_CFLAGS = -DQRPNG
# Check if we can build QR exported as PNG support
CHECK_PNG_LIBS = $(shell pkg-config --exists $(PNG_LIBS) || echo -n "error")
ifneq ($(CHECK_PNG_LIBS), error)
LIBS += $(PNG_LIBS)
CFLAGS += $(PNG_CFLAGS)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_PNG_LIBS = $(shell for lib in $(PNG_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without QR exported as PNG support)
$(warning WARNING -- You need these libraries for QR exported as PNG support)
$(warning WARNING -- $(MISSING_PNG_LIBS))
endif

View File

@ -1,23 +1,21 @@
# Variables for sound notifications support
SND_NOTIFY_LIBS = openal freealut
SND_NOTIFY_CFLAGS = -D_SOUND_NOTIFY
ifneq (, $(findstring device.o, $(OBJ)))
SND_NOTIFY_OBJ =
SND_NOTIFY_CFLAGS = -DSOUND_NOTIFY
ifneq (, $(findstring audio_device.o, $(OBJ)))
SND_NOTIFY_OBJ =
else
SND_NOTIFY_OBJ = device.o
SND_NOTIFY_OBJ = audio_device.o
endif
# Check if we can build sound notifications support
CHECK_SND_NOTIFY_LIBS = $(shell pkg-config --exists $(SND_NOTIFY_LIBS) || echo -n "error")
CHECK_SND_NOTIFY_LIBS = $(shell $(PKG_CONFIG) --exists $(SND_NOTIFY_LIBS) || echo -n "error")
ifneq ($(CHECK_SND_NOTIFY_LIBS), error)
LIBS += $(SND_NOTIFY_LIBS)
CFLAGS += $(SND_NOTIFY_CFLAGS)
OBJ += $(SND_NOTIFY_OBJ)
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_SND_NOTIFY_LIBS = $(shell for lib in $(SND_NOTIFY_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without sound notifications support)
$(warning WARNING -- You need these libraries for sound notifications support)
$(warning WARNING -- $(MISSING_SND_NOTIFY_LIBS))
endif
LIBS += $(SND_NOTIFY_LIBS)
CFLAGS += $(SND_NOTIFY_CFLAGS)
OBJ += $(SND_NOTIFY_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_SND_NOTIFY_LIBS = $(shell for lib in $(SND_NOTIFY_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without sound notifications support)
$(warning WARNING -- You need these libraries for sound notifications support)
$(warning WARNING -- $(MISSING_SND_NOTIFY_LIBS))
endif

21
cfg/checks/video.mk Normal file
View File

@ -0,0 +1,21 @@
# Variables for video call support
VIDEO_LIBS = openal vpx x11
VIDEO_CFLAGS = -DVIDEO
ifneq (, $(findstring video_device.o, $(OBJ)))
VIDEO_OBJ = video_call.o
else
VIDEO_OBJ = video_call.o video_device.o
endif
# Check if we can build video support
CHECK_VIDEO_LIBS = $(shell $(PKG_CONFIG) --exists $(VIDEO_LIBS) || echo -n "error")
ifneq ($(CHECK_VIDEO_LIBS), error)
LIBS += $(VIDEO_LIBS)
CFLAGS += $(VIDEO_CFLAGS)
OBJ += $(VIDEO_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_VIDEO_LIBS = $(shell for lib in $(VIDEO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without video support)
$(warning WARNING -- You will need these libraries for video support)
$(warning WARNING -- $(MISSING_VIDEO_LIBS))
endif

17
cfg/checks/x11.mk Normal file
View File

@ -0,0 +1,17 @@
# Variables for X11 support
X11_LIBS = x11
X11_CFLAGS = -DX11
X11_OBJ = x11focus.o
# Check if we can build X11 support
CHECK_X11_LIBS = $(shell $(PKG_CONFIG) --exists $(X11_LIBS) || echo -n "error")
ifneq ($(CHECK_X11_LIBS), error)
LIBS += $(X11_LIBS)
CFLAGS += $(X11_CFLAGS)
OBJ += $(X11_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_X11_LIBS = $(shell for lib in $(X11_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without x11 support (needed for focus tracking and drag&drop support))
$(warning WARNING -- You need these libraries for x11 support)
$(warning WARNING -- $(MISSING_X11_LIBS))
endif

View File

@ -1,9 +1,14 @@
# Version
TOXIC_VERSION = 0.5.0
REV = $(shell git rev-list HEAD --count)
VERSION = $(TOXIC_VERSION)_r$(REV)
TOXIC_VERSION = 0.11.3
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
ifneq (, $(findstring error, $(REV)))
VERSION = $(TOXIC_VERSION)
else
VERSION = $(TOXIC_VERSION)_r$(REV)
endif
# Project directories
BUILD_DIR = $(BASE_DIR)/build
DOC_DIR = $(BASE_DIR)/doc
SRC_DIR = $(BASE_DIR)/src
SND_DIR = $(BASE_DIR)/sounds
@ -11,13 +16,18 @@ MISC_DIR = $(BASE_DIR)/misc
# Project files
MANFILES = toxic.1 toxic.conf.5
DATAFILES = DHTnodes DNSservers toxic.conf.example
SNDFILES = ContactLogsIn.wav ContactLogsOut.wav Error.wav IncomingCall.wav
SNDFILES += LogIn.wav LogOut.wav NewMessage.wav OutgoingCall.wav
SNDFILES += TransferComplete.wav TransferPending.wav
DATAFILES = nameservers toxic.conf.example
DESKFILE = toxic.desktop
SNDFILES = ToxicContactOnline.wav ToxicContactOffline.wav ToxicError.wav
SNDFILES += ToxicRecvMessage.wav ToxicOutgoingCall.wav ToxicIncomingCall.wav
SNDFILES += ToxicTransferComplete.wav ToxicTransferStart.wav
# Install directories
PREFIX = /usr/local
PREFIX ?= /usr/local
BINDIR = $(PREFIX)/bin
DATADIR = $(PREFIX)/share/toxic
MANDIR = $(PREFIX)/share/man
MANDIR ?= $(PREFIX)/share/man
APPDIR = $(PREFIX)/share/applications
# Platform tools
PKG_CONFIG = pkg-config

18
cfg/systems/Darwin.mk Normal file
View File

@ -0,0 +1,18 @@
# Special options for OS X
# This assumes the use of Homebrew. Change the paths if using MacPorts or Fink.
PKG_CONFIG_PATH = $(shell export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/opt/libconfig/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig)
LIBS := $(filter-out ncursesw, $(LIBS))
# OS X ships a usable, recent version of ncurses, but calls it ncurses not ncursesw.
LDFLAGS += -lncurses -lalut -ltoxcore -lcurl -lconfig -lqrencode -lpng -lopenal -g
CFLAGS += -I/usr/local/opt/freealut/include/AL -I/usr/local/opt/glib/include/glib-2.0 -g
OSX_LIBRARIES = -lobjc -lresolv
OSX_FRAMEWORKS = -framework Foundation -framework CoreFoundation -framework AVFoundation \
-framework QuartzCore -framework CoreMedia
OSX_VIDEO = osx_video.m
LDFLAGS += $(OSX_LIBRARIES) $(OSX_FRAMEWORKS)
OBJ += osx_video.o

View File

@ -1,4 +0,0 @@
# Specials options for freebsd systems
LIBS := $(filter-out ncursesw, $(LIBS))
LDFLAGS += -lncursesw
MANDIR = $(PREFIX)/man

View File

@ -1,4 +0,0 @@
# Specials options for linux systems
CFLAGS +=
LDFLAGS += -ldl -lresolv
MANDIR = $(PREFIX)/share/man

View File

@ -1,10 +1,10 @@
# Doc target
doc: $(MANFILES:%=$(DOC_DIR)/%)
$(DOC_DIR)/%: $(DOC_DIR)/%.asc
@echo " MAN $(@F)"
@a2x -f manpage -a revdate=$(shell git log -1 --date=short --format="%ad" $<) \
-a manmanual="Toxic Manual" -a mansource=toxic \
-a manversion=__VERSION__ -a datadir=__DATADIR__ $<
.PHONY: doc

View File

@ -1,20 +1,38 @@
# Help target
help:
@echo "-- Targets --"
@echo " all: Build toxic and documentation [DEFAULT]"
@echo " toxic: Build toxic"
@echo " doc: Build documentation"
@echo " install: Build toxic and install it in PREFIX (default PREFIX is \"$(abspath $(PREFIX))\")"
@echo " clean: Remove built files"
@echo " help: This help"
@echo " all: Build toxic and documentation [DEFAULT]"
@echo " toxic: Build toxic"
@echo " doc: Build documentation"
@echo " install: Build toxic and install it in PREFIX (default PREFIX is \"$(abspath $(PREFIX))\")"
@echo " uninstall: Remove toxic from PREFIX (default PREFIX is \"$(abspath $(PREFIX))\")"
@echo " clean: Remove built files"
@echo " help: This help"
@echo
@echo "-- Variables --"
@echo " DISABLE_X11: Set to \"1\" to force building without X11 support"
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
@echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support"
@echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
@echo " DISABLE_QRCODE: Set to \"1\" to force building without QR export support"
@echo " DISABLE_QRPNG: Set to \"1\" to force building without QR exported as PNG support"
@echo " DISABLE_GAMES: Set to \"1\" to force building without game support"
@echo " ENABLE_PYTHON: Set to \"1\" to enable building with Python scripting support"
@echo " ENABLE_RELEASE: Set to \"1\" to build without debug symbols and with full compiler optimizations"
@echo " ENABLE_ASAN: Set to \"1\" to build with LLVM address sanitizer enabled.
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
@echo " MANDIR: Specify a directory where to store man pages (default is \"$(abspath $(PREFIX)/share/man)\")"
@echo
@echo "-- Environment Variables --"
@echo " CFLAGS: Add custom flags to default CFLAGS"
@echo " LDFLAGS: Add custom flags to default LDFLAGS"
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
@echo " MANDIR: Specify a directory where to store man pages (default is \"$(abspath $(PREFIX)/share/man)\")"
.PHONY: help

View File

@ -1,32 +1,41 @@
# Install target
install: toxic doc
mkdir -p $(abspath $(DESTDIR)/$(BINDIR))
mkdir -p $(abspath $(DESTDIR)/$(DATADIR))
mkdir -p $(abspath $(DESTDIR)/$(DATADIR))/sounds
mkdir -p $(abspath $(DESTDIR)/$(MANDIR))
install: $(BUILD_DIR)/toxic
@echo "Installing toxic executable"
@install -m 0755 toxic $(abspath $(DESTDIR)/$(BINDIR))
@mkdir -p $(abspath $(DESTDIR)/$(BINDIR))
@install -m 0755 $(BUILD_DIR)/toxic $(abspath $(DESTDIR)/$(BINDIR)/toxic)
@echo "Installing desktop file"
@mkdir -p $(abspath $(DESTDIR)/$(APPDIR))
@install -m 0644 $(MISC_DIR)/$(DESKFILE) $(abspath $(DESTDIR)/$(APPDIR)/$(DESKFILE))
@echo "Installing data files"
@mkdir -p $(abspath $(DESTDIR)/$(DATADIR))
@for f in $(DATAFILES) ; do \
install -m 0644 $(MISC_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)) ;\
file=$(abspath $(DESTDIR)/$(DATADIR))/$$f ;\
sed -i'' -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file ;\
install -m 0644 $(MISC_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)/$$f) ;\
file=$(abspath $(DESTDIR)/$(DATADIR)/$$f) ;\
sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \
mv temp_file $$file ;\
done
@mkdir -p $(abspath $(DESTDIR)/$(DATADIR))/sounds
@for f in $(SNDFILES) ; do \
install -m 0644 $(SND_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR))/sounds ;\
install -m 0644 $(SND_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)/sounds/$$f) ;\
done
@echo "Installing man pages"
@mkdir -p $(abspath $(DESTDIR)/$(MANDIR))
@for f in $(MANFILES) ; do \
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
if [ ! -e "$(DOC_DIR)/$$f" ]; then \
continue ;\
fi ;\
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $${f##*.}` ;\
file=$$section/$$f ;\
mkdir -p $$section ;\
install -m 0644 $(DOC_DIR)/$$f $$file ;\
sed -i'' -e 's:__VERSION__:'$(VERSION)':g' $$file ;\
sed -i'' -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file ;\
gzip -f -9 $$file ;\
sed -e 's:__VERSION__:'$(VERSION)':g' $$file > temp_file && \
mv temp_file $$file ;\
sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \
mv temp_file $$file ;\
gzip -f -n -9 $$file ;\
done
.PHONY: install

24
cfg/targets/uninstall.mk Normal file
View File

@ -0,0 +1,24 @@
# Uninstall target
uninstall:
@echo "Removing toxic executable"
@rm -f $(abspath $(DESTDIR)/$(BINDIR)/toxic)
@echo "Removing desktop file"
@rm -f $(abspath $(DESTDIR)/$(APPDIR)/$(DESKFILE))
@echo "Removing data files"
@for f in $(DATAFILES) ; do \
rm -f $(abspath $(DESTDIR)/$(DATADIR)/$$f) ;\
done
@for f in $(SNDFILES) ; do \
rm -f $(abspath $(DESTDIR)/$(DATADIR)/sounds/$$f) ;\
done
@echo "Removing man pages"
@for f in $(MANFILES) ; do \
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $${f##*.}` ;\
file=$$section/$$f ;\
rm -f $$file $$file.gz ;\
done
.PHONY: uninstall

View File

@ -1,13 +1,13 @@
'\" t
.\" Title: toxic
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2014-08-21
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 2021-05-24
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC" "1" "2014\-08\-21" "toxic __VERSION__" "Toxic Manual"
.TH "TOXIC" "1" "2021\-05\-24" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -55,17 +55,22 @@ instead of
\fI~/\&.config/tox/toxic\&.conf\fR
.RE
.PP
\-d, \-\-default_locale
\-d, \-\-default\-locale
.RS 4
Use default locale
.RE
.PP
\-e, \-\-encrypt\-data
.RS 4
Encrypt an unencrypted data file\&. An error will occur if this option is used with an encrypted data file\&.
.RE
.PP
\-f, \-\-file data\-file
.RS 4
Use specified
\fIdata\-file\fR
instead of
\fI~/\&.config/tox/data\fR
\fI~/\&.config/tox/toxic_profile\&.tox\fR
.RE
.PP
\-h, \-\-help
@ -73,12 +78,17 @@ instead of
Show help message
.RE
.PP
\-l, \-\-logging
.RS 4
Enable toxcore logging to stderr
.RE
.PP
\-n, \-\-nodes nodes\-file
.RS 4
Use specified
\fInodes\-file\fR
for DHT bootstrap nodes, instead of
\fI__DATADIR__/DHTnodes\fR
for DHT bootstrap nodes instead of
\fI~/\&.config/tox/DHTnodes\&.json\fR
.RE
.PP
\-o, \-\-noconnect
@ -86,14 +96,19 @@ for DHT bootstrap nodes, instead of
Do not connect to the DHT network
.RE
.PP
\-p, \-\-proxy
\-p, \-\-SOCKS5\-proxy
.RS 4
Use proxy: Requires [IP] [port]
Use a SOCKS5 proxy: Requires [IP] [port]
.RE
.PP
\-r, \-\-dnslist
\-P, \-\-HTTP\-proxy
.RS 4
Use specified DNSservers file
Use a HTTP proxy: Requires [IP] [port]
.RE
.PP
\-r, \-\-namelist
.RS 4
Use specified nameservers list
.RE
.PP
\-t, \-\-force\-tcp
@ -101,18 +116,25 @@ Use specified DNSservers file
Force TCP connection (use this with proxies)
.RE
.PP
\-x, \-\-nodata
\-T, \-\-tcp\-relay
.RS 4
Ignore data file
Act as a TCP relay server for the network (Note: this uses significantly more bandwidth)
.RE
.PP
\-u, \-\-unencrypt\-data
.RS 4
Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&.
.RE
.SH "FILES"
.PP
__DATADIR__/DHTnodes
~/\&.config/tox/DHTnodes\&.json
.RS 4
Default list of DHT bootstrap nodes\&.
Default location for list of DHT bootstrap nodes (list obtained from
https://nodes\&.tox\&.chat)\&. This list is automatically updated\&. See
\fBtoxic\&.conf\fR(5) for details on controlling the update frequency\&.
.RE
.PP
~/\&.config/tox/data
~/\&.config/tox/toxic_profile\&.tox
.RS 4
Savestate which contains your personal info (nickname, Tox ID, contacts, etc)
.RE
@ -129,7 +151,11 @@ Configuration example\&.
.RE
.SH "BUGS"
.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
\-Screen flickering sometimes occurs on certain terminals\&.
.sp
\-Resizing the terminal window when a game window is open will break things\&.
.SH "AUTHORS"
.sp
JFreegman <JFreegman@gmail\&.com>
@ -138,6 +164,6 @@ JFreegman <JFreegman@gmail\&.com>
\fBtoxic\&.conf\fR(5)
.SH "LINKS"
.sp
Project page: https://github\&.com/Tox/toxic
Project page: https://github\&.com/JFreegman/toxic
.sp
IRC channel: chat\&.freenode\&.net#tox
IRC channel: irc\&.libera\&.chat#tox

View File

@ -27,40 +27,54 @@ OPTIONS
-c, --config config-file::
Use specified 'config-file' instead of '~/.config/tox/toxic.conf'
-d, --default_locale::
-d, --default-locale::
Use default locale
-e, --encrypt-data::
Encrypt an unencrypted data file. An error will occur if this option
is used with an encrypted 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::
Show help message
-l, --logging::
Enable toxcore logging to stderr
-n, --nodes nodes-file::
Use specified 'nodes-file' for DHT bootstrap nodes, instead of
'{datadir}/DHTnodes'
Use specified 'nodes-file' for DHT bootstrap nodes instead of '~/.config/tox/DHTnodes.json'
-o, --noconnect::
Do not connect to the DHT network
-p, --proxy::
Use proxy: Requires [IP] [port]
-p, --SOCKS5-proxy::
Use a SOCKS5 proxy: Requires [IP] [port]
-r, --dnslist::
Use specified DNSservers file
-P, --HTTP-proxy::
Use a HTTP proxy: Requires [IP] [port]
-r, --namelist::
Use specified nameservers list
-t, --force-tcp::
Force TCP connection (use this with proxies)
-x, --nodata::
Ignore data file
-T, --tcp-relay::
Act as a TCP relay server for the network (Note: this uses significantly more bandwidth)
-u, --unencrypt-data::
Unencrypt a data file. A warning will appear if this option is used
with a data file that is already unencrypted.
FILES
-----
{datadir}/DHTnodes::
Default list of DHT bootstrap nodes.
~/.config/tox/DHTnodes.json::
Default location for list of DHT bootstrap nodes (list obtained from https://nodes.tox.chat).
This list is automatically updated. See *toxic.conf*(5) for details on controlling the update frequency.
~/.config/tox/data::
~/.config/tox/toxic_profile.tox::
Savestate which contains your personal info (nickname, Tox ID, contacts,
etc)
@ -72,9 +86,12 @@ FILES
BUGS
----
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.
-Screen flickering sometimes occurs on certain terminals.
-Resizing the terminal window when a game window is open will break things.
AUTHORS
-------
@ -86,6 +103,6 @@ SEE ALSO
LINKS
-----
Project page: <https://github.com/Tox/toxic>
Project page: <https://github.com/JFreegman/toxic>
IRC channel: chat.freenode.net#tox
IRC channel: irc.libera.chat#tox

View File

@ -1,13 +1,13 @@
'\" t
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2014-08-21
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 2021-05-24
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC\&.CONF" "5" "2014\-08\-21" "toxic __VERSION__" "Toxic Manual"
.TH "TOXIC\&.CONF" "5" "2021\-05\-24" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -66,9 +66,26 @@ Configuration related to interface elements\&.
Enable or disable timestamps\&. true or false
.RE
.PP
\fBtime_format\fR
.RS 4
Select between 24 and 12 hour time\&. Specify 24 or 12\&. Setting timestamp_format and log_timestamp_format will override this setting\&.
.RE
.PP
\fBtimestamp_format\fR
.RS 4
Time format string for the interface enclosed by double quotes\&. See
\fBdate\fR(1)
.RE
.PP
\fBlog_timestamp_format\fR
.RS 4
Time format string for logging enclosed by double quotes\&. See
\fBdate\fR(1)
.RE
.PP
\fBalerts\fR
.RS 4
Enable or disable terminal alerts on events\&. true or false
Enable or disable acoustic alerts on events\&. true or false
.RE
.PP
\fBnative_colors\fR
@ -76,16 +93,31 @@ Enable or disable terminal alerts on events\&. true or false
Select between native terminal colors and toxic color theme\&. true or false
.RE
.PP
\fBcolor_bar_bg\fR
.RS 4
set background color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
.RE
.PP
\fBcolor_bar_fg\fR
.RS 4
set foreground (text) color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
.RE
.PP
\fBcolor_bar_accent\fR
.RS 4
set foreground accent color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
.RE
.PP
\fBcolor_bar_notify\fR
.RS 4
set foreground notify (and typing) color in chat status bar\&. (black, white, red, green, blue, cyan, yellow, magenta)
.RE
.PP
\fBautolog\fR
.RS 4
Enable or disable autologging\&. true or false
.RE
.PP
\fBtime_format\fR
.RS 4
Select between 24 and 12 hour time\&. Specify 24 or 12
.RE
.PP
\fBshow_typing_other\fR
.RS 4
Show when others are typing in a 1\-on\-1 chat\&. true or false
@ -96,10 +128,97 @@ Show when others are typing in a 1\-on\-1 chat\&. true or false
Show others when you\(cqre typing in a 1\-on\-1 chat\&. true or false
.RE
.PP
\fBshow_welcome_msg\fR
.RS 4
Show welcome message on startup\&. true or false
.RE
.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\&. (integer; 0 to disable)
.RE
.PP
\fBautosave_freq\fR
.RS 4
How often in seconds to auto\-save the Tox data file\&. (integer; 0 to disable)
.RE
.PP
\fBhistory_size\fR
.RS 4
Maximum lines for chat window history\&. Integer value\&. (for example: 700)
.RE
.PP
\fBnotification_timeout\fR
.RS 4
Time in milliseconds to display a notification\&. Integer value\&. (for example: 3000)
.RE
.PP
\fBline_join\fR
.RS 4
Indicator for when someone connects or joins a group\&. Three characters max for line_ settings\&.
.RE
.PP
\fBline_quit\fR
.RS 4
Indicator for when someone disconnects or leaves a group\&.
.RE
.PP
\fBline_alert\fR
.RS 4
Indicator for alert messages\&.
.RE
.PP
\fBline_normal\fR
.RS 4
Indicator for normal messages\&.
.RE
.PP
\fBmplex_away\fR
.RS 4
Set user status when attaching and detaching from GNU screen or tmux\&. true or false
.RE
.PP
\fBmplex_away_note\fR
.RS 4
Status message to set when status is set to away due to screen/tmux detach\&. When attaching, the status message is set back to the original value\&.
.sp
.if n \{\
.RS 4
.\}
.nf
The following options control whether to output a terminal bell on certain events\&.
Some terminals mark the window as urgent when a bell is received\&. Urgent windows are usually highlighted in the taskbar and some window managers even provide shortcuts to jump to the next urgent window\&.
These options don\*(Aqt affect the "alerts" option\&.
.fi
.if n \{\
.RE
.\}
.RE
.PP
\fBbell_on_message\fR
.RS 4
Enable/Disable the terminal bell when receiving a message\&. true or false
.RE
.PP
\fBbell_on_filetrans\fR
.RS 4
Enable/Disable the terminal bell when receiving a filetransfer\&. true or false
.RE
.PP
\fBbell_on_filetrans_accept\fR
.RS 4
Enable/Disable the terminal bell when a filetransfer was accepted\&. true or false
.RE
.PP
\fBbell_on_invite\fR
.RS 4
Enable/Disable the terminal bell when receiving a group/call invite\&. true or false
.RE
.RE
.PP
\fBaudio\fR
@ -118,9 +237,24 @@ Audio output device\&. Integer value\&. Number corresponds to
/lsdev out
.RE
.PP
\fBVAD_treshold\fR
\fBVAD_threshold\fR
.RS 4
Voice Activity Detection treshold\&. Float value\&. Recommended values are around 40\&.0
Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0\-40\&.0
.RE
.PP
\fBconference_audio_channels\fR
.RS 4
Number of channels for conference audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
.RE
.PP
\fBchat_audio_channels\fR
.RS 4
Number of channels for 1\-on\-1 audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
.RE
.PP
\fBpush_to_talk\fR
.RS 4
Enable/Disable Push\-To\-Talk for conference audio chats (active key is F2)\&. true or false
.RE
.RE
.PP
@ -133,10 +267,25 @@ Configuration related to paths\&.
Default path for downloads\&. String value\&. Absolute path for downloaded files\&.
.RE
.PP
\fBavatar_path\fR
.RS 4
Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
.RE
.PP
\fBautorun_path\fR
.RS 4
Path for any scripts that should be run on startup
.RE
.PP
\fBchatlogs_path\fR
.RS 4
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
.RE
.PP
\fBpassword_eval\fR
.RS 4
Replace password prompt by running this command and using its output as the password\&.
.RE
.RE
.PP
\fBsounds\fR
@ -145,7 +294,7 @@ Configuration related to notification sounds\&. Special value "silent" can be us
Each value is a string which corresponds to the absolute path of a wav sound file\&.
.PP
\fBerror\fR
\fBnotif_error\fR
.RS 4
Sound to play when an error occurs\&.
.RE
@ -237,14 +386,14 @@ Key combination to scroll half page down\&.
Key combination to scroll to page bottom\&.
.RE
.PP
\fBpeer_list_up\fR
\fBtoggle_peerlist\fR
.RS 4
Key combination to scroll contacts list up\&.
Toggle the peer list on and off\&.
.RE
.PP
\fBpeer_list_down\fR
\fBtoggle_paste_mode\fR
.RS 4
Key combination to scroll contacts list down\&.
Toggle treating linebreaks as enter key press\&.
.RE
.RE
.SH "FILES"
@ -263,9 +412,9 @@ Configuration example\&.
\fBtoxic\fR(1)
.SH "RESOURCES"
.sp
Project page: https://github\&.com/Tox/toxic
Project page: https://github\&.com/JFreegman/toxic
.sp
IRC channel: chat\&.freenode\&.net#tox
IRC channel: irc\&.libera\&.chat#tox
.SH "AUTHORS"
.sp
JFreegman <JFreegman@gmail\&.com>

View File

@ -42,27 +42,101 @@ OPTIONS
*timestamps*;;
Enable or disable timestamps. true or false
*time_format*;;
Select between 24 and 12 hour time. Specify 24 or 12. Setting
timestamp_format and log_timestamp_format will override this setting.
*timestamp_format*;;
Time format string for the interface enclosed by double quotes.
See *date*(1)
*log_timestamp_format*;;
Time format string for logging enclosed by double quotes.
See *date*(1)
*alerts*;;
Enable or disable terminal alerts on events. true or false
Enable or disable acoustic alerts on events. true or false
*native_colors*;;
Select between native terminal colors and toxic color theme. true or false
*color_bar_bg*;;
set background color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
*color_bar_fg*;;
set foreground (text) color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
*color_bar_accent*;;
set foreground accent color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
*color_bar_notify*;;
set foreground notify (and typing) color in chat status bar. (black, white, red, green, blue, cyan, yellow, magenta)
*autolog*;;
Enable or disable autologging. true or false
*time_format*;;
Select between 24 and 12 hour time. Specify 24 or 12
*show_typing_other*;;
Show when others are typing in a 1-on-1 chat. true or false
*show_typing_self*;;
Show others when you're typing in a 1-on-1 chat. true or false
*show_welcome_msg*;;
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. (integer; 0 to disable)
*autosave_freq*;;
How often in seconds to auto-save the Tox data file. (integer; 0 to disable)
*history_size*;;
Maximum lines for chat window history. Integer value. (for example: 700)
*notification_timeout*;;
Time in milliseconds to display a notification. Integer value. (for example: 3000)
*line_join*;;
Indicator for when someone connects or joins a group.
Three characters max for line_ settings.
*line_quit*;;
Indicator for when someone disconnects or leaves a group.
*line_alert*;;
Indicator for alert messages.
*line_normal*;;
Indicator for normal messages.
*mplex_away*;;
Set user status when attaching and detaching from GNU screen or tmux.
true or false
*mplex_away_note*;;
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.
The following options control whether to output a terminal bell on certain events.
Some terminals mark the window as urgent when a bell is received. Urgent windows are usually highlighted in the taskbar and some window managers even provide shortcuts to jump to the next urgent window.
These options don't affect the "alerts" option.
*bell_on_message*;;
Enable/Disable the terminal bell when receiving a message. true or false
*bell_on_filetrans*;;
Enable/Disable the terminal bell when receiving a filetransfer. true or false
*bell_on_filetrans_accept*;;
Enable/Disable the terminal bell when a filetransfer was accepted. true or false
*bell_on_invite*;;
Enable/Disable the terminal bell when receiving a group/call invite. true or false
*audio*::
Configuration related to audio devices.
@ -73,9 +147,18 @@ OPTIONS
*output_device*;;
Audio output device. Integer value. Number corresponds to `/lsdev out`
*VAD_treshold*;;
Voice Activity Detection treshold. Float value. Recommended values are
around 40.0
*VAD_threshold*;;
Voice Activity Detection threshold. Float value. Recommended values are
1.0-40.0
*conference_audio_channels*;;
Number of channels for conference audio broadcast. Integer value. 1 (mono) or 2 (stereo)
*chat_audio_channels*;;
Number of channels for 1-on-1 audio broadcast. Integer value. 1 (mono) or 2 (stereo)
*push_to_talk*;;
Enable/Disable Push-To-Talk for conference audio chats (active key is F2). true or false
*tox*::
Configuration related to paths.
@ -84,16 +167,26 @@ OPTIONS
Default path for downloads. String value. Absolute path for downloaded
files.
*avatar_path*;;
Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
*autorun_path*;;
Path for any scripts that should be run on startup
*chatlogs_path*;;
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*::
Configuration related to notification sounds.
Special value "silent" can be used to disable a specific notification. +
Each value is a string which corresponds to the absolute path of a wav
sound file.
*error*;;
*notif_error*;;
Sound to play when an error occurs.
*self_log_in*;;
@ -149,11 +242,11 @@ OPTIONS
*page_bottom*;;
Key combination to scroll to page bottom.
*peer_list_up*;;
Key combination to scroll contacts list up.
*toggle_peerlist*;;
Toggle the peer list on and off.
*peer_list_down*;;
Key combination to scroll contacts list down.
*toggle_paste_mode*;;
Toggle treating linebreaks as enter key press.
FILES
@ -172,9 +265,9 @@ SEE ALSO
RESOURCES
---------
Project page: <https://github.com/Tox/toxic>
Project page: <https://github.com/JFreegman/toxic>
IRC channel: chat.freenode.net#tox
IRC channel: irc.libera.chat#tox
AUTHORS

View File

@ -1,10 +0,0 @@
192.254.75.98 33445 951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F
37.187.46.132 33445 A9D98212B3F972BD11DA52BEB0658C326FCCC1BFD49F347F9C2D3D8B61E1B927
144.76.60.215 33445 04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
54.199.139.199 33445 7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
37.59.102.176 33445 B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B
95.85.13.245 33445 7187969BB10B54C98538BAE94C069CE5C84E650D54F7E596543D8FB1ECF4CF23
178.21.112.187 33445 4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057
76.191.23.96 33445 4BA57660DE3E854C530EED601BF8D54B7EFAE960523B6CFC10210CC08E2CB808

View File

@ -1,2 +0,0 @@
utox.org d3154f65d28a5b41a05d4ac7e4b39c6b1c233cc857fb365c56e8392737462a12
toxme.se 5d72c517df6aec54f1e977a6b6f25914ea4cf7277a85027cd9f5196df17e0b13

1
misc/nameservers Normal file
View File

@ -0,0 +1 @@
toxme.io 1A39E7A5D5FA9CF155C751570A32E625698A60A55F6D88028F949F66144F4F25

View File

@ -5,26 +5,86 @@ ui = {
// true to enable timestamps, false to disable
timestamps=true;
// true to enable terminal alerts on messages, false to disable
// true to enable acoustic alerts on messages, false to disable
alerts=true;
// Output a bell when receiving a message (see manpage)
bell_on_message=true;
// Output a bell when receiving a filetransfer (see manpage)
bell_on_filetrans=true;
// Don't output a bell when a filetransfer was accepted (see manpage)
bell_on_filetrans_accept=false;
// Output a bell when receiving a group/call invite (see manpage)
bell_on_invite=true;
// true to use native terminal colours, false to use toxic default colour theme
native_colors=false;
// set background color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
color_bar_bg="blue";
// set foreground (text) color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
color_bar_fg="white";
// set foreground accent color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
color_bar_accent="cyan";
// set foreground notify (and typing) color in chat status bar (black, white, red, green, blue, cyan, yellow, magenta)
color_bar_notify="yellow";
// true to enable autologging, false to disable
autolog=false;
// 24 or 12 hour time
time_format=24;
// Timestamp format string according to date/strftime format. Overrides time_format setting
timestamp_format="%H:%M";
// true to show you when others are typing a message in 1-on-1 chats
show_typing_other=true;
// true to show others when you're typing a message in 1-on-1 chats
show_typing_self=true;
// true to show the welcome message on startup
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;
// How often in seconds to auto-save the Tox data file. (0 to disable periodic auto-saves)
autosave_freq=600;
// maximum lines for chat window history
history_size=700;
// time in milliseconds to display a notification
notification_timeout=6000;
// Indicator for display when someone connects or joins a group
line_join="-->";
// Indicator for display when someone disconnects or leaves a group
line_quit="<--";
// Indicator for alert messages.
line_alert="-!-";
// Indicator for normal messages.
line_normal="-";
// true to change status based on screen/tmux attach/detach, false to disable
mplex_away=true;
// Status message to use when status set to away due to screen/tmux detach
mplex_away_note="Away from keyboard, be back soon!"
};
audio = {
@ -33,35 +93,48 @@ audio = {
// preferred audio output device; numbers correspond to /lsdev out
output_device=0;
// default VAD treshold; float (recommended values are around 40)
VAD_treshold=40.0;
// default VAD threshold; float (recommended values are 1.0-40.0)
VAD_threshold=5.0;
// Number of channels to use for conference audio broadcasts; 1 for mono, 2 for stereo.
conference_audio_channels=1;
// Number of channels to use for 1-on-1 audio broadcasts; 1 for mono, 2 for stereo.
chat_audio_channels=2;
// toggle conference push-to-talk
push_to_talk=false;
};
tox = {
// Path for downloaded files
// download_path="/home/USERNAME/Downloads/";
// Path for your avatar (file must be a .png and cannot exceed 64 KiB)
// avatar_path="/home/USERNAME/Pictures/youravatar.png";
// Path for scripts that should be run on startup
// autorun_path="/home/USERNAME/toxic_scripts/";
// Path for chatlogs
// chatlogs_path="/home/USERNAME/toxic_chatlogs/";
};
// To disable a sound set the path to "silent"
sounds = {
error="__DATADIR__/sounds/Error.wav";
self_log_in="__DATADIR__/sounds/LogIn.wav";
self_log_out="__DATADIR__/sounds/LogOut.wav";
user_log_in="__DATADIR__/sounds/ContactLogsIn.wav";
user_log_out="__DATADIR__/sounds/ContactLogsOut.wav";
call_incoming="__DATADIR__/sounds/IncomingCall.wav";
call_outgoing="__DATADIR__/sounds/OutgoingCall.wav";
generic_message="__DATADIR__/sounds/NewMessage.wav";
transfer_pending="__DATADIR__/sounds/TransferPending.wav";
transfer_completed="__DATADIR__/sounds/TransferComplete.wav";
error="__DATADIR__/sounds/ToxicError.wav";
user_log_in="__DATADIR__/sounds/ToxicContactOnline.wav";
user_log_out="__DATADIR__/sounds/ToxicContactOffline.wav";
call_incoming="__DATADIR__/sounds/ToxicIncomingCall.wav";
call_outgoing="__DATADIR__/sounds/ToxicOutgoingCall.wav";
generic_message="__DATADIR__/sounds/ToxicRecvMessage.wav";
transfer_pending="__DATADIR__/sounds/ToxicTransferStart.wav";
transfer_completed="__DATADIR__/sounds/ToxicTransferComplete.wav";
};
// 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 = {
next_tab="Ctrl+P";
prev_tab="Ctrl+O";
@ -70,7 +143,6 @@ keys = {
half_page_up="Ctrl+F";
half_page_down="Ctrl+V";
page_bottom="Ctrl+H";
peer_list_up="Ctrl+[";
peer_list_down="Ctrl+]";
toggle_peerlist="Ctrl+B";
toggle_paste_mode="Ctrl+T";
};

11
misc/toxic.desktop Normal file
View File

@ -0,0 +1,11 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=Toxic
Comment=A CLI based Tox client
TryExec=toxic
Exec=toxic
Icon=utilities-terminal
Categories=InstantMessaging;AudioVideo;Network;
Terminal=true
MimeType=x-scheme-handler/tox;

View File

@ -0,0 +1,304 @@
#!/usr/bin/env sh
# MIT License
#
# Copyright (c) 2021 Maxim Biro <nurupo.contributions@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# Script for building a minimal statically compiled Toxic. While it doesn't
# support X11 integration, video/audio calls, desktop & sound notifications, QR
# codes and Python scripting, it is rather portable.
#
# Run as:
#
# sudo docker run -it --rm \
# -v /tmp/artifact:/artifact \
# -v /home/jfreegman/git/toxic:/toxic \
# amd64/alpine:latest \
# /bin/sh /toxic/script/build-minimal-static-toxic.sh
#
# that would use Toxic code from /home/jfreegman/git/toxic and place the build
# artifact at /tmp/artifact.
# You can change between amd64/alpine:latest and i386/alpine:latest, for 64-bit
# and 32-bit builds.
#
# To debug, run:
#
# sudo docker run -it --rm \
# -v /tmp/artifact:/artifact \
# -v /home/jfreegman/git/toxic:/toxic \
# amd64/alpine:latest \
# /bin/sh
# # sh /toxic/script/build-minimal-static-toxic.sh
set -eu
ARTIFACT_DIR="/artifact"
TOXIC_SRC_DIR="/toxic"
# Make sure we run in the expected environment
if ! grep -q 'docker' /proc/1/cgroup
then
echo "Error: This script should be run inside a disposable Docker container as it might modify system files in ways that would break a real system."
exit 1
fi
if [ ! -f /etc/os-release ] || ! grep -qi 'Alpine Linux' /etc/os-release
then
echo "Error: This script expects to be run on Alpine Linux."
exit 1
fi
if [ ! -d "$ARTIFACT_DIR" ] || [ ! -d "$TOXIC_SRC_DIR" ]
then
echo "Error: At least one of $ARTIFACT_DIR or $TOXIC_SRC_DIR directories inside the container is missing."
exit 1
fi
if [ "$(id -u)" != "0" ]
then
echo "Error: This script expects to be run as root."
exit 1
fi
set -x
# Use all cores for building
MAKEFLAGS=j$(nproc)
export MAKEFLAGS
check_sha256()
{
if ! ( echo "$1 $2" | sha256sum -cs - )
then
echo "Error: sha256 of $2 doesn't match the known one."
echo "Expected: $1 $2"
echo "Got: $(sha256sum "$2")"
exit 1
else
echo "sha256 matches the expected one: $1"
fi
}
apk update
apk upgrade
apk add \
brotli-dev \
brotli-static \
build-base \
cmake \
git \
libconfig-dev \
libconfig-static \
libsodium-dev \
libsodium-static \
linux-headers \
ncurses-dev \
ncurses-static \
ncurses-terminfo \
ncurses-terminfo-base \
nghttp2-dev \
nghttp2-static \
openssl-dev \
openssl-libs-static \
pkgconf \
wget \
xz \
zlib-dev \
zlib-static
BUILD_DIR="/tmp/build"
mkdir -p "$BUILD_DIR"
# Build Toxcore
cd "$BUILD_DIR"
# The git hash of the c-toxcore version we're using
TOXCORE_VERSION="v0.2.13"
# The sha256sum of the c-toxcore tarball for TOXCORE_VERSION
TOXCORE_HASH="67114fa57504c58b695f5dce8ef85124d555f2c3c353d0d2615e6d4845114ab8"
TOXCORE_FILENAME="c-toxcore-$TOXCORE_VERSION.tar.gz"
wget --timeout=10 -O "$TOXCORE_FILENAME" "https://github.com/TokTok/c-toxcore/archive/$TOXCORE_VERSION.tar.gz"
check_sha256 "$TOXCORE_HASH" "$TOXCORE_FILENAME"
tar -o -xf "$TOXCORE_FILENAME"
rm "$TOXCORE_FILENAME"
cd c-toxcore*
cmake -B_build -H. \
-DENABLE_STATIC=ON \
-DENABLE_SHARED=OFF \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TOXAV=OFF \
-DBOOTSTRAP_DAEMON=OFF \
-DDHT_BOOTSTRAP=OFF \
-DCMAKE_INSTALL_PREFIX="$BUILD_DIR/prefix-toxcore"
cmake --build _build --target install
# Build cURL
# While Alpine does provide a static cURL build, it's not built with
# --with-ca-fallback, which is needed for better cross-distro portability.
# Basically, some distros put their ca-certificates in different places, and
# with --with-ca-fallback we or the user can provide the cert bundle file
# location with SSL_CERT_FILE env variable.
cd "$BUILD_DIR"
CURL_VERSION="7.80.0"
CURL_HASH="dab997c9b08cb4a636a03f2f7f985eaba33279c1c52692430018fae4a4878dc7"
CURL_FILENAME="curl-$CURL_VERSION.tar.gz"
wget --timeout=10 -O "$CURL_FILENAME" "https://curl.haxx.se/download/$CURL_FILENAME"
check_sha256 "$CURL_HASH" "$CURL_FILENAME"
tar -xf curl*.tar.gz
rm curl*.tar.gz
cd curl*
./configure \
--prefix="$BUILD_DIR/prefix-curl" \
--disable-shared \
--enable-static \
--without-ca-bundle \
--without-ca-path \
--with-ca-fallback \
--with-nghttp2 \
--with-brotli \
--with-openssl
make
make install
sed -i 's|-lbrotlidec |-lbrotlidec-static -lbrotlicommon-static |g' $BUILD_DIR/prefix-curl/lib/pkgconfig/libcurl.pc
# Build Toxic
cd "$BUILD_DIR"
cp -a "$TOXIC_SRC_DIR" toxic
cd toxic
if [ -z "$(git describe --tags --exact-match HEAD)" ]
then
set +x
echo "Didn't find a git tag on the HEAD commit. You seem to be building an in-development release of Toxic rather than a release version." | fold -sw 80
printf "Do you wish to proceed? (y/N): "
read -r answer
if echo "$answer" | grep -v -iq "^y" ; then
echo "Exiting."
exit 1
fi
set -x
fi
sed -i 's|pkg-config|pkg-config --static|' cfg/global_vars.mk
sed -i 's|<limits.h|<linux/limits.h|' src/*
CFLAGS="-static" PKG_CONFIG_PATH="$BUILD_DIR/prefix-toxcore/lib64/pkgconfig:$BUILD_DIR/prefix-toxcore/lib/pkgconfig:$BUILD_DIR/prefix-curl/lib/pkgconfig" PREFIX="$BUILD_DIR/prefix-toxic" make \
DISABLE_X11=1 \
DISABLE_AV=1 \
DISABLE_SOUND_NOTIFY=1 \
DISABLE_QRCODE=1 \
DISABLE_QRPNG=1 \
DISABLE_DESKTOP_NOTIFY=1 \
ENABLE_PYTHON=0 \
ENABLE_RELEASE=1 \
ENABLE_ASAN=0 \
DISABLE_GAMES=0 \
install
# Prepare the build artifact
PREPARE_ARTIFACT_DIR="$BUILD_DIR/artifact"
cp -a "$BUILD_DIR/prefix-toxic/bin" "$PREPARE_ARTIFACT_DIR"
strip "$PREPARE_ARTIFACT_DIR"/*
cp -a "$BUILD_DIR/toxic/misc"/* "$PREPARE_ARTIFACT_DIR"
mv "$PREPARE_ARTIFACT_DIR/toxic.conf.example" "$PREPARE_ARTIFACT_DIR/toxic.conf"
cp -aL /usr/share/terminfo "$PREPARE_ARTIFACT_DIR"
echo "A minimal statically compiled Toxic.
Doesn't support X11 integration, video/audio calls, desktop & sound
notifications, QR codes and Python scripting.
However, it is rather portable.
Toxic $(git -C "$BUILD_DIR/toxic" describe --tags --exact-match HEAD) ($(git -C "$BUILD_DIR/toxic" rev-parse HEAD))
Build date time: $(TZ=UTC date +"%Y-%m-%dT%H:%M:%S%z")
OS:
$(cat /etc/os-release)
List of self-built software statically compiled into Toxic:
libcurl $CURL_VERSION
libtoxcore $TOXCORE_VERSION
List of OS-packaged software statically compiled into Toxic:
$(apk list -I | grep 'static' | sort -i)
List of all packages installed during the build:
$(apk list -I | sort -i)" > "$PREPARE_ARTIFACT_DIR/build_info"
echo '#!/usr/bin/env sh
DEBIAN_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
RHEL_SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt
OPENSUSE_CERT_FILE=/etc/ssl/ca-bundle.pem
if [ ! -f "$SSL_CERT_FILE" ] ; then
if [ -f "$DEBIAN_SSL_CERT_FILE" ] ; then
SSL_CERT_FILE="$DEBIAN_SSL_CERT_FILE"
elif [ -f "$RHEL_SSL_CERT_FILE" ] ; then
SSL_CERT_FILE="$RHEL_SSL_CERT_FILE"
elif [ -f "$OPENSUSE_CERT_FILE" ] ; then
SSL_CERT_FILE="$OPENSUSE_CERT_FILE"
fi
fi
if [ -z "$SSL_CERT_FILE" ] ; then
echo "Warning: Couldn'\''t find the SSL CA certificate store file." | fold -sw 80
echo
echo "Toxic uses HTTPS to download a list of DHT bootstrap nodes in order to connect to the Tox DHT. This functionality is optional, you should be able to use Toxic without it. If you choose to use Toxic without it, you might need to manually enter DHT bootstrap node information using the '\''/connect'\'' command in order to come online." | fold -sw 80
echo
echo "To fix this issue, install SSL CAs as provided by your Linux distribution, e.g. '\''ca-certificates'\'' package on Debian/Ubuntu. If it'\''s already installed and you still see this message, run this script with SSL_CERT_FILE variable set to point to the SSL CA certificate store file location. The file is usually named '\''ca-certificates.crt'\'' or '\''ca-bundle.pem'\''." | fold -sw 80
echo
printf "Do you wish to run Toxic without SSL CA certificate store file found? (y/N): "
read -r answer
if echo "$answer" | grep -v -iq "^y" ; then
echo "Exiting."
exit
fi
fi
cd "$(dirname -- $0)"
SSL_CERT_FILE="$SSL_CERT_FILE" TERMINFO=./terminfo ./toxic -c toxic.conf' > "$PREPARE_ARTIFACT_DIR/run_toxic.sh"
chmod a+x "$PREPARE_ARTIFACT_DIR/run_toxic.sh"
# Tar it
cd "$PREPARE_ARTIFACT_DIR"
cd ..
ARCH="$(tr '_' '-' < /etc/apk/arch)"
ARTIFACT_NAME="toxic-minimal-static-musl_linux_$ARCH"
mv "$PREPARE_ARTIFACT_DIR" "$PREPARE_ARTIFACT_DIR/../$ARTIFACT_NAME"
tar -cJf "$ARTIFACT_NAME.tar.xz" "$ARTIFACT_NAME"
mv "$ARTIFACT_NAME.tar.xz" "$ARTIFACT_DIR"
chmod 777 -R "$ARTIFACT_DIR"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
sounds/ToxicError.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
sounds/ToxicRecvMessage.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1 +1,2 @@
Tox's sounds are licensed under the "Creative Commons Attribution 3.0 Unported", all credit attributed to Adam Reid.
ToxicError.wav, ToxicRecvMessage.wav, ToxicContactOffline.wav, ToxicIncomingCall.wav, ToxicTransferComplete.wav, ToxicContactOnline.wav, ToxicOutgoingCall.wav and ToxicTransferStart.wav
are licensed under the "Creative Commons Attribution 3.0 Unported". All credit attributed to Jfreegman.

214
src/api.c Normal file
View File

@ -0,0 +1,214 @@
/* api.c
*
*
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
*
* 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 <dirent.h>
#include <stdint.h>
#include <tox/tox.h>
#include "execute.h"
#include "friendlist.h"
#include "line_info.h"
#include "message_queue.h"
#include "misc_tools.h"
#include "settings.h"
#include "toxic_strings.h"
#include "windows.h"
#ifdef PYTHON
#include "python_api.h"
Tox *user_tox;
static WINDOW *cur_window;
static ToxWindow *self_window;
void api_display(const char *const msg)
{
if (msg == NULL) {
return;
}
self_window = get_active_window();
line_info_add(self_window, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
}
FriendsList api_get_friendslist(void)
{
return Friends;
}
char *api_get_nick(void)
{
size_t len = tox_self_get_name_size(user_tox);
uint8_t *name = malloc(len + 1);
if (name == NULL) {
return NULL;
}
tox_self_get_name(user_tox, name);
name[len] = '\0';
return (char *) name;
}
Tox_User_Status api_get_status(void)
{
return tox_self_get_status(user_tox);
}
char *api_get_status_message(void)
{
size_t len = tox_self_get_status_message_size(user_tox);
uint8_t *status = malloc(len + 1);
if (status == NULL) {
return NULL;
}
tox_self_get_status_message(user_tox, status);
status[len] = '\0';
return (char *) status;
}
void api_send(const char *msg)
{
if (msg == NULL || self_window->chatwin->cqueue == NULL) {
return;
}
char *name = api_get_nick();
if (name == NULL) {
return;
}
self_window = get_active_window();
snprintf((char *) self_window->chatwin->line, sizeof(self_window->chatwin->line), "%s", msg);
add_line_to_hist(self_window->chatwin);
int id = line_info_add(self_window, true, name, NULL, OUT_MSG, 0, 0, "%s", msg);
cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, id);
free(name);
}
void api_execute(const char *input, int mode)
{
self_window = get_active_window();
execute(cur_window, self_window, user_tox, input, mode);
}
int do_plugin_command(int num_args, char (*args)[MAX_STR_SIZE])
{
return do_python_command(num_args, args);
}
int num_registered_handlers(void)
{
return python_num_registered_handlers();
}
int help_max_width(void)
{
return python_help_max_width();
}
void draw_handler_help(WINDOW *win)
{
python_draw_handler_help(win);
}
void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
FILE *fp;
const char *error_str;
cur_window = window;
self_window = self;
if (argc != 1) {
if (argc < 1) {
error_str = "Path must be specified.";
} else {
error_str = "Only one argument allowed.";
}
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, error_str);
return;
}
fp = fopen(argv[1], "r");
if (fp == NULL) {
error_str = "Path does not exist.";
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, error_str);
return;
}
run_python(fp, argv[1]);
fclose(fp);
}
void invoke_autoruns(WINDOW *window, ToxWindow *self)
{
char abspath_buf[PATH_MAX + 256];
char err_buf[PATH_MAX + 128];
if (user_settings->autorun_path[0] == '\0') {
return;
}
DIR *d = opendir(user_settings->autorun_path);
if (d == NULL) {
snprintf(err_buf, sizeof(err_buf), "Autorun path does not exist: %s", user_settings->autorun_path);
api_display(err_buf);
return;
}
struct dirent *dir = NULL;
cur_window = window;
self_window = self;
while ((dir = readdir(d)) != NULL) {
size_t path_len = strlen(dir->d_name);
if (!strcmp(dir->d_name + path_len - 3, ".py")) {
snprintf(abspath_buf, sizeof(abspath_buf), "%s%s", user_settings->autorun_path, dir->d_name);
FILE *fp = fopen(abspath_buf, "r");
if (fp == NULL) {
snprintf(err_buf, sizeof(err_buf), "Invalid path: %s", abspath_buf);
api_display(err_buf);
continue;
}
run_python(fp, abspath_buf);
fclose(fp);
}
}
closedir(d);
}
#endif /* PYTHON */

43
src/api.h Normal file
View File

@ -0,0 +1,43 @@
/* api.h
*
*
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
*
* 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 API_H
#define API_H
#include "friendlist.h"
#include "windows.h"
void api_display(const char *const msg);
FriendsList api_get_friendslist(void);
char *api_get_nick(void);
Tox_User_Status api_get_status(void);
char *api_get_status_message(void);
void api_send(const char *msg);
void api_execute(const char *input, int mode);
int do_plugin_command(int num_args, char (*args)[MAX_STR_SIZE]);
int num_registered_handlers(void);
int help_max_width(void);
void draw_handler_help(WINDOW *win);
void invoke_autoruns(WINDOW *w, ToxWindow *self);
void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* API_H */

File diff suppressed because it is too large Load Diff

View File

@ -20,26 +20,90 @@
*
*/
#ifndef _audio_h
#define _audio_h
#ifndef AUDIO_CALL_H
#define AUDIO_CALL_H
#include <tox/toxav.h>
#include "device.h"
#include "audio_device.h"
typedef enum _AudioError {
typedef enum AudioError {
ae_None = 0,
ae_StartingCaptureDevice = 1 << 0,
ae_StartingOutputDevice = 1 << 1,
ae_StartingCoreAudio = 1 << 2
} AudioError;
/* You will have to pass pointer to first member of 'windows'
* declared in windows.c otherwise undefined behaviour will
*/
ToxAv *init_audio(ToxWindow *self, Tox *tox);
void terminate_audio();
#ifdef VIDEO
typedef enum VideoError {
ve_None = 0,
ve_StartingCaptureDevice = 1 << 0,
ve_StartingOutputDevice = 1 << 1,
ve_StartingCoreVideo = 1 << 2
} VideoError;
#endif /* VIDEO */
/* Status transitions:
* None -> Pending (call invitation made or received);
* Pending -> None (invitation rejected or failed);
* Pending -> Active (call starts);
* Active -> None (call ends).
*/
typedef enum CallStatus {
cs_None = 0,
cs_Pending,
cs_Active
} CallStatus;
typedef struct Call {
CallStatus status;
uint32_t state; /* ToxAV call state, valid when `status == cs_Active` */
uint32_t in_idx, out_idx; /* Audio device index, or -1 if not open */
uint32_t audio_bit_rate; /* Bit rate for sending audio */
uint32_t vin_idx, vout_idx; /* Video device index, or -1 if not open */
uint32_t video_width, video_height;
uint32_t video_bit_rate; /* Bit rate for sending video; 0 for no video */
} Call;
struct CallControl {
AudioError audio_errors;
#ifdef VIDEO
VideoError video_errors;
#endif /* VIDEO */
ToxAV *av;
ToxWindow *prompt;
Call *calls;
uint32_t max_calls;
bool audio_enabled;
bool video_enabled;
int32_t audio_frame_duration;
uint32_t audio_sample_rate;
uint8_t audio_channels;
uint32_t default_audio_bit_rate;
int32_t video_frame_duration;
uint32_t default_video_width, default_video_height;
uint32_t default_video_bit_rate;
};
extern struct CallControl CallControl;
/* You will have to pass pointer to first member of 'windows' declared in windows.c */
ToxAV *init_audio(ToxWindow *self, Tox *tox);
void terminate_audio(void);
bool init_call(Call *call);
void place_call(ToxWindow *self);
void stop_current_call(ToxWindow *self);
#endif /* _audio_h */
void init_friend_AV(uint32_t index);
void del_friend_AV(uint32_t index);
#endif /* AUDIO_CALL_H */

788
src/audio_device.c Normal file
View File

@ -0,0 +1,788 @@
/* audio_device.c
*
*
* Copyright (C) 2014 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 "audio_device.h"
#include "line_info.h"
#include "misc_tools.h"
#include "settings.h"
#include <AL/al.h>
#include <AL/alc.h>
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif /* ALC_ALL_DEVICES_SPECIFIER */
#include <assert.h>
#include <math.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern struct user_settings *user_settings;
extern struct Winthread Winthread;
typedef struct FrameInfo {
uint32_t samples_per_frame;
uint32_t sample_rate;
bool stereo;
} FrameInfo;
/* A virtual input/output device, abstracting the currently selected openal
* device (which may change during the lifetime of the virtual device).
* We refer to a virtual device as a "device", and refer to an underlying
* openal device as an "al_device".
* Multiple virtual devices may be open at once; the callback of each virtual
* input device has data captured from the input al_device passed to it, and
* each virtual output device acts as a source for the output al_device.
*/
typedef struct Device {
bool active;
bool muted;
FrameInfo frame_info;
// used only by input devices:
DataHandleCallback cb;
void *cb_data;
float VAD_threshold;
uint32_t VAD_samples_remaining;
// used only by output devices:
uint32_t source;
uint32_t buffers[OPENAL_BUFS];
bool source_open;
} Device;
typedef struct AudioState {
ALCdevice *al_device[2];
Device devices[2][MAX_DEVICES];
uint32_t num_devices[2];
FrameInfo capture_frame_info;
float input_volume;
// mutexes to prevent changes to input resp. output devices and al_devices
// during poll_input iterations resp. calls to write_out;
// mutex[input] also used to lock input_volume which poll_input writes to.
pthread_mutex_t mutex[2];
// TODO: unused
const char *default_al_device_name[2]; /* Default devices */
const char *al_device_names[2][MAX_OPENAL_DEVICES]; /* Available devices */
uint32_t num_al_devices[2];
char *current_al_device_name[2];
} AudioState;
static AudioState *audio_state;
static void lock(DeviceType type)
{
pthread_mutex_lock(&audio_state->mutex[type]);
}
static void unlock(DeviceType type)
{
pthread_mutex_unlock(&audio_state->mutex[type]);
}
static bool thread_running = true,
thread_paused = true; /* Thread control */
#ifdef AUDIO
static void *poll_input(void *);
#endif
static uint32_t sound_mode(bool stereo)
{
return stereo ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
}
static uint32_t sample_size(bool stereo)
{
return stereo ? 4 : 2;
}
DeviceError init_devices(void)
{
audio_state = calloc(1, sizeof(AudioState));
if (audio_state == NULL) {
return de_InternalError;
}
get_al_device_names();
for (DeviceType type = input; type <= output; ++type) {
audio_state->al_device[type] = NULL;
if (pthread_mutex_init(&audio_state->mutex[type], NULL) != 0) {
return de_InternalError;
}
}
#ifdef AUDIO
// Start poll thread
pthread_t thread_id;
if (pthread_create(&thread_id, NULL, poll_input, NULL) != 0
|| pthread_detach(thread_id) != 0) {
return de_InternalError;
}
#endif
return de_None;
}
DeviceError terminate_devices(void)
{
lock(input);
thread_running = false;
unlock(input);
sleep_thread(20000L);
for (DeviceType type = input; type <= output; ++type) {
if (pthread_mutex_destroy(&audio_state->mutex[type]) != 0) {
return de_InternalError;
}
if (audio_state->current_al_device_name[type] != NULL) {
free(audio_state->current_al_device_name[type]);
}
}
free(audio_state);
return de_None;
}
void get_al_device_names(void)
{
const char *stringed_device_list;
for (DeviceType type = input; type <= output; ++type) {
audio_state->num_al_devices[type] = 0;
if (type == input) {
stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
} else {
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 != NULL) {
audio_state->default_al_device_name[type] = alcGetString(NULL,
type == input ? ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER : ALC_DEFAULT_DEVICE_SPECIFIER);
for (; *stringed_device_list != '\0'
&& audio_state->num_al_devices[type] < MAX_OPENAL_DEVICES; ++audio_state->num_al_devices[type]) {
audio_state->al_device_names[type][audio_state->num_al_devices[type]] = stringed_device_list;
stringed_device_list += strlen(stringed_device_list) + 1;
}
}
}
}
DeviceError device_mute(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
Device *device = &audio_state->devices[type][device_idx];
if (!device->active) {
return de_DeviceNotActive;
}
lock(type);
device->muted = !device->muted;
unlock(type);
return de_None;
}
bool device_is_muted(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) {
return false;
}
Device *device = &audio_state->devices[type][device_idx];
if (!device->active) {
return false;
}
return device->muted;
}
DeviceError device_set_VAD_threshold(uint32_t device_idx, float value)
{
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
Device *device = &audio_state->devices[input][device_idx];
if (!device->active) {
return de_DeviceNotActive;
}
if (value <= 0.0f) {
value = 0.0f;
}
lock(input);
device->VAD_threshold = value;
unlock(input);
return de_None;
}
float device_get_VAD_threshold(uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) {
return 0.0;
}
Device *device = &audio_state->devices[input][device_idx];
if (!device->active) {
return 0.0;
}
return device->VAD_threshold;
}
DeviceError set_source_position(uint32_t device_idx, float x, float y, float z)
{
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
Device *device = &audio_state->devices[output][device_idx];
if (!device->active) {
return de_DeviceNotActive;
}
lock(output);
alSource3f(device->source, AL_POSITION, x, y, z);
unlock(output);
if (!audio_state->al_device[output] || alcGetError(audio_state->al_device[output]) != AL_NO_ERROR) {
return de_AlError;
}
return de_None;
}
static DeviceError close_al_device(DeviceType type)
{
if (audio_state->al_device[type] == NULL) {
return de_None;
}
if (type == input) {
if (!alcCaptureCloseDevice(audio_state->al_device[type])) {
return de_AlError;
}
thread_paused = true;
} else {
ALCcontext *context = alcGetCurrentContext();
alcMakeContextCurrent(NULL);
alcDestroyContext(context);
if (!alcCloseDevice(audio_state->al_device[type])) {
return de_AlError;
}
}
audio_state->al_device[type] = NULL;
return de_None;
}
static DeviceError open_al_device(DeviceType type, FrameInfo frame_info)
{
audio_state->al_device[type] = type == input
? alcCaptureOpenDevice(audio_state->current_al_device_name[type],
frame_info.sample_rate, sound_mode(frame_info.stereo), frame_info.samples_per_frame * 2)
: alcOpenDevice(audio_state->current_al_device_name[type]);
if (audio_state->al_device[type] == NULL) {
return de_FailedStart;
}
if (type == input) {
alcCaptureStart(audio_state->al_device[type]);
thread_paused = false;
audio_state->capture_frame_info = frame_info;
} else {
alcMakeContextCurrent(alcCreateContext(audio_state->al_device[type], NULL));
}
if (alcGetError(audio_state->al_device[type]) != AL_NO_ERROR) {
close_al_device(type);
return de_AlError;
}
return de_None;
}
static void close_source(Device *device)
{
if (device->source_open) {
alDeleteSources(1, &device->source);
alDeleteBuffers(OPENAL_BUFS, device->buffers);
device->source_open = false;
}
}
static DeviceError open_source(Device *device)
{
alGenBuffers(OPENAL_BUFS, device->buffers);
if (alcGetError(audio_state->al_device[output]) != AL_NO_ERROR) {
return de_FailedStart;
}
alGenSources((uint32_t)1, &device->source);
if (alcGetError(audio_state->al_device[output]) != AL_NO_ERROR) {
alDeleteBuffers(OPENAL_BUFS, device->buffers);
return de_FailedStart;
}
device->source_open = true;
alSourcei(device->source, AL_LOOPING, AL_FALSE);
const uint32_t frame_size = device->frame_info.samples_per_frame * sample_size(device->frame_info.stereo);
size_t zeros_size = frame_size * sizeof(uint16_t);
uint16_t *zeros = calloc(1, zeros_size);
if (zeros == NULL) {
close_source(device);
return de_FailedStart;
}
for (int i = 0; i < OPENAL_BUFS; ++i) {
alBufferData(device->buffers[i], sound_mode(device->frame_info.stereo), zeros,
zeros_size, device->frame_info.sample_rate);
}
free(zeros);
alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
alSourcePlay(device->source);
if (alcGetError(audio_state->al_device[output]) != AL_NO_ERROR) {
close_source(device);
return de_FailedStart;
}
return de_None;
}
DeviceError set_al_device(DeviceType type, int32_t selection)
{
if (audio_state->num_al_devices[type] <= selection || selection < 0) {
return de_InvalidSelection;
}
const char *name = audio_state->al_device_names[type][selection];
char **cur_name = &audio_state->current_al_device_name[type];
if (*cur_name != NULL) {
free(*cur_name);
}
*cur_name = malloc(strlen(name) + 1);
if (*cur_name == NULL) {
return de_InternalError;
}
strcpy(*cur_name, name);
if (audio_state->num_devices[type] > 0) {
// close any existing al_device and try to open new one, reopening existing sources
lock(type);
if (type == output) {
for (int i = 0; i < MAX_DEVICES; i++) {
Device *device = &audio_state->devices[type][i];
if (device->active) {
close_source(device);
}
}
}
close_al_device(type);
DeviceError err = open_al_device(type, audio_state->capture_frame_info);
if (err != de_None) {
unlock(type);
return err;
}
if (type == output) {
for (int i = 0; i < MAX_DEVICES; i++) {
Device *device = &audio_state->devices[type][i];
if (device->active) {
open_source(device);
}
}
}
unlock(type);
}
return de_None;
}
static DeviceError open_device(DeviceType type, uint32_t *device_idx, DataHandleCallback cb, void *cb_data,
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
{
if (channels != 1 && channels != 2) {
return de_UnsupportedMode;
}
const uint32_t samples_per_frame = (sample_rate * frame_duration / 1000);
FrameInfo frame_info = {samples_per_frame, sample_rate, channels == 2};
uint32_t i;
for (i = 0; i < MAX_DEVICES && audio_state->devices[type][i].active; ++i);
if (i == MAX_DEVICES) {
return de_AllDevicesBusy;
}
*device_idx = i;
lock(type);
if (audio_state->al_device[type] == NULL) {
DeviceError err = open_al_device(type, frame_info);
if (err != de_None) {
unlock(type);
return err;
}
} else if (type == input) {
// Use previously set frame info on existing capture device
frame_info = audio_state->capture_frame_info;
}
Device *device = &audio_state->devices[type][i];
device->active = true;
++audio_state->num_devices[type];
device->muted = false;
device->frame_info = frame_info;
if (type == input) {
device->cb = cb;
device->cb_data = cb_data;
#ifdef AUDIO
if (user_settings->VAD_threshold >= 0.0) {
device->VAD_threshold = user_settings->VAD_threshold;
}
#else
device->VAD_threshold = 0.0f;
#endif
} else {
if (open_source(device) != de_None) {
device->active = false;
--audio_state->num_devices[type];
unlock(type);
return de_FailedStart;
}
}
unlock(type);
return de_None;
}
DeviceError open_input_device(uint32_t *device_idx, DataHandleCallback cb, void *cb_data, uint32_t sample_rate,
uint32_t frame_duration, uint8_t channels)
{
return open_device(input, device_idx, cb, cb_data, sample_rate, frame_duration, channels);
}
DeviceError open_output_device(uint32_t *device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
{
return open_device(output, device_idx, 0, 0, sample_rate, frame_duration, channels);
}
DeviceError close_device(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
lock(type);
Device *device = &audio_state->devices[type][device_idx];
if (!device->active) {
unlock(type);
return de_DeviceNotActive;
}
if (type == output) {
close_source(device);
}
device->active = false;
--audio_state->num_devices[type];
DeviceError err = de_None;
if (audio_state->num_devices[type] == 0) {
err = close_al_device(type);
}
unlock(type);
return err;
}
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;
}
lock(output);
Device *device = &audio_state->devices[output][device_idx];
if (!device->active || device->muted) {
unlock(output);
return de_DeviceNotActive;
}
ALuint bufid;
ALint processed, queued;
alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed);
alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
if (audio_state->al_device[output] == NULL || alcGetError(audio_state->al_device[output]) != AL_NO_ERROR) {
unlock(output);
return de_AlError;
}
if (processed) {
ALuint *bufids = malloc(processed * sizeof(ALuint));
if (bufids == NULL) {
unlock(output);
return de_InternalError;
}
alSourceUnqueueBuffers(device->source, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
free(bufids);
} else if (queued < 16) {
alGenBuffers(1, &bufid);
} else {
unlock(output);
return de_Busy;
}
const bool stereo = channels == 2;
alBufferData(bufid, sound_mode(stereo), data,
sample_count * sample_size(stereo),
sample_rate);
alSourceQueueBuffers(device->source, 1, &bufid);
ALint state;
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
if (state != AL_PLAYING) {
alSourcePlay(device->source);
}
unlock(output);
return de_None;
}
#ifdef AUDIO
/* Adapted from qtox,
* Copyright © 2014-2019 by The qTox Project Contributors
*
* return normalized volume of buffer in range 0.0-100.0
*/
float volume(int16_t *frame, uint32_t samples)
{
float sum_of_squares = 0;
for (uint32_t i = 0; i < samples; i++) {
const float sample = (float)(frame[i]) / INT16_MAX;
sum_of_squares += powf(sample, 2);
}
const float root_mean_square = sqrtf(sum_of_squares / samples);
const float root_two = 1.414213562;
// normalizedVolume == 1.0 corresponds to a sine wave of maximal amplitude
const float normalized_volume = root_mean_square * root_two;
return 100.0f * fminf(1.0f, normalized_volume);
}
// Time in ms for which we continue to capture audio after VAD is triggered:
#define VAD_TIME 250
#define FRAME_BUF_SIZE 16000
static void *poll_input(void *arg)
{
UNUSED_VAR(arg);
int16_t *frame_buf = malloc(FRAME_BUF_SIZE * sizeof(int16_t));
if (frame_buf == NULL) {
exit_toxic_err("failed in thread_poll", FATALERR_MEMORY);
}
while (1) {
lock(input);
if (!thread_running) {
free(frame_buf);
unlock(input);
break;
}
if (thread_paused) {
unlock(input);
sleep_thread(10000L);
continue;
}
if (audio_state->al_device[input] != NULL) {
int32_t available_samples;
alcGetIntegerv(audio_state->al_device[input], ALC_CAPTURE_SAMPLES, sizeof(int32_t), &available_samples);
const uint32_t f_size = audio_state->capture_frame_info.samples_per_frame;
if (available_samples >= f_size && f_size <= FRAME_BUF_SIZE) {
alcCaptureSamples(audio_state->al_device[input], frame_buf, f_size);
unlock(input);
pthread_mutex_lock(&Winthread.lock);
lock(input);
float frame_volume = volume(frame_buf, f_size);
audio_state->input_volume = frame_volume;
for (int i = 0; i < MAX_DEVICES; i++) {
Device *device = &audio_state->devices[input][i];
if (device->VAD_threshold != 0.0f) {
if (frame_volume >= device->VAD_threshold) {
device->VAD_samples_remaining = VAD_TIME * (audio_state->capture_frame_info.sample_rate / 1000);
} else if (device->VAD_samples_remaining < f_size) {
continue;
} else {
device->VAD_samples_remaining -= f_size;
}
}
if (device->active && !device->muted && device->cb) {
device->cb(frame_buf, f_size, device->cb_data);
}
}
pthread_mutex_unlock(&Winthread.lock);
}
}
unlock(input);
sleep_thread(5000L);
}
pthread_exit(NULL);
}
#endif
float get_input_volume(void)
{
float ret = 0.0f;
if (audio_state->al_device[input] != NULL) {
lock(input);
ret = audio_state->input_volume;
unlock(input);
}
return ret;
}
void print_al_devices(ToxWindow *self, DeviceType type)
{
for (int i = 0; i < audio_state->num_al_devices[type]; ++i) {
line_info_add(self, false, NULL, NULL, SYS_MSG,
audio_state->current_al_device_name[type]
&& strcmp(audio_state->current_al_device_name[type], audio_state->al_device_names[type][i]) == 0 ? 1 : 0,
0, "%d: %s", i, audio_state->al_device_names[type][i]);
}
return;
}
DeviceError selection_valid(DeviceType type, int32_t selection)
{
return (audio_state->num_al_devices[type] <= selection || selection < 0) ? de_InvalidSelection : de_None;
}

View File

@ -1,4 +1,4 @@
/* device.h
/* audio_device.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
@ -22,19 +22,18 @@
/*
* 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.
*/
#ifndef _device_h
#define _device_h
#ifndef AUDIO_DEVICE_H
#define AUDIO_DEVICE_H
#define OPENAL_BUFS 5
#define MAX_OPENAL_DEVICES 32
#define MAX_DEVICES 32
#include <inttypes.h>
#include "windows.h"
#define _True 1
#define _False 0
#include "windows.h"
typedef enum DeviceType {
input,
@ -54,39 +53,43 @@ typedef enum DeviceError {
de_AlError = -9,
} DeviceError;
typedef void (*DataHandleCallback) (const int16_t*, uint32_t size, void* data);
typedef void (*DataHandleCallback)(const int16_t *, uint32_t size, void *data);
#ifdef _AUDIO
DeviceError init_devices(ToxAv* av);
#else
DeviceError init_devices();
#endif /* _AUDIO */
DeviceError init_devices(void);
DeviceError terminate_devices();
/* Callback handles ready data from INPUT device */
DeviceError register_device_callback(int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, _Bool enable_VAD);
void* get_device_callback_data(uint32_t device_idx);
void get_al_device_names(void);
DeviceError terminate_devices(void);
/* toggle device mute */
DeviceError device_mute(DeviceType type, uint32_t device_idx);
#ifdef _AUDIO
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
#endif
bool device_is_muted(DeviceType type, uint32_t device_idx);
DeviceError device_set_VAD_threshold(uint32_t device_idx, float value);
float device_get_VAD_threshold(uint32_t device_idx);
DeviceError set_source_position(uint32_t device_idx, float x, float y, float z);
DeviceError set_al_device(DeviceType type, int32_t selection);
DeviceError set_primary_device(DeviceType type, int32_t selection);
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
/* Start device */
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
DeviceError open_input_device(uint32_t *device_idx, DataHandleCallback cb, void *cb_data,
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
DeviceError open_output_device(uint32_t *device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
/* Stop device */
DeviceError close_device(DeviceType type, uint32_t device_idx);
/* Write data to device */
DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t lenght, uint8_t channels);
/* Write data to output device */
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);
/* return current input volume as float in range 0.0-100.0 */
float get_input_volume(void);
void print_al_devices(ToxWindow *self, DeviceType type);
DeviceError selection_valid(DeviceType type, int32_t selection);
#endif /* _device_h */
#endif /* AUDIO_DEVICE_H */

View File

@ -20,108 +20,120 @@
*
*/
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifdef __APPLE__
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/types.h>
#include <sys/dir.h>
#else
#include <dirent.h>
#endif /* ifdef __APPLE__ */
#include <dirent.h>
#endif /* __APPLE__ */
#include "windows.h"
#include "toxic.h"
#include "misc_tools.h"
#include "line_info.h"
#include "execute.h"
#include "configdir.h"
#include "execute.h"
#include "line_info.h"
#include "misc_tools.h"
#include "toxic.h"
#include "windows.h"
static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items, int size)
static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matches)
{
if (m)
if (m) {
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
}
const char *L = (char *) list;
int i;
for (size_t i = 0; i < n_matches; ++i) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", list[i]);
}
for (i = 0; i < n_items; ++i)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); /* formatting */
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
}
/* 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. */
static void get_str_match(ToxWindow *self, char *match, char (*matches)[MAX_STR_SIZE], int n)
* e.g. if matches contains: [foo, foobar, foe] we put fo in match.
*
* Returns the length of the match.
*/
static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, const char *const *matches, size_t n_items,
size_t max_size)
{
if (n == 1) {
strcpy(match, matches[0]);
return;
UNUSED_VAR(self);
if (n_items == 1) {
return snprintf(match, match_sz, "%s", matches[0]);
}
int i;
for (i = 0; i < MAX_STR_SIZE; ++i) {
for (size_t i = 0; i < max_size; ++i) {
char ch1 = matches[0][i];
int j;
for (j = 0; j < n; ++j) {
for (size_t j = 0; j < n_items; ++j) {
char ch2 = matches[j][i];
if (ch1 != ch2 || !ch1) {
strcpy(match, matches[0]);
snprintf(match, match_sz, "%s", matches[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,
then fills line with the complete word. e.g. "Hello jo" would complete the line
with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size)
/*
* Looks for all instances in list that begin with the last entered word in line according to pos,
* then fills line with the complete word. e.g. "Hello jo" would complete the line
* with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
*
* `list` is a pointer to `n_items` strings. Each string in the list must be <= MAX_STR_SIZE.
*
* dir_search should be true if the line being completed is a file path.
*
* Returns the difference between the old len and new len of line on success.
* Returns -1 on error.
*
* Note: This function should not be called directly. Use complete_line() and complete_path() instead.
*/
static int complete_line_helper(ToxWindow *self, const char *const *list, const size_t n_items, bool dir_search)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE)
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->pos > ctx->len) {
return -1;
}
if (ctx->len >= MAX_STR_SIZE) {
return -1;
}
const char *L = (char *) list;
const char *endchrs = " ";
char ubuf[MAX_STR_SIZE];
/* work with multibyte string copy of buf for simplicity */
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1) {
return -1;
bool dir_search = strncmp(ubuf, "/sendfile", strlen("/sendfile")) == 0;
}
/* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", ubuf);
tmp[ctx->pos] = '\0';
memcpy(tmp, ubuf, ctx->pos);
tmp[ctx->pos] = 0;
const char *s = dir_search ? strchr(tmp, '\"') : strrchr(tmp, ' ');
char *sub = malloc(strlen(ubuf) + 1);
const char *s = dir_search ? strchr(tmp, ' ') : strrchr(tmp, ' ');
char *sub = calloc(1, strlen(ubuf) + 1);
if (sub == NULL)
exit_toxic_err("failed in complete_line", FATALERR_MEMORY);
if (sub == NULL) {
exit_toxic_err("failed in complete_line_helper", FATALERR_MEMORY);
}
if (!s && !dir_search) {
strcpy(sub, tmp);
if (sub[0] != '/')
if (sub[0] != '/') {
endchrs = ": ";
}
} else if (s) {
strcpy(sub, &s[1]);
@ -129,70 +141,115 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
int sub_len = strlen(sub);
int si = char_rfind(sub, '/', sub_len);
if (si || *sub == '/')
if (si || *sub == '/') {
memmove(sub, &sub[si + 1], sub_len - si);
}
}
}
if (string_is_empty(sub)) {
if (!sub[0] && !(dir_search && n_items == 1)) {
free(sub);
return 0;
}
int s_len = strlen(sub);
size_t n_matches = 0;
char **matches = (char **) malloc_ptr_array(n_items, MAX_STR_SIZE);
if (matches == NULL) {
free(sub);
return -1;
}
int s_len = strlen(sub);
const char *str;
int n_matches = 0;
char matches[n_items][MAX_STR_SIZE];
int i = 0;
/* put all list matches in matches array */
for (i = 0; i < n_items; ++i) {
str = &L[i * size];
if (strncasecmp(str, sub, s_len) == 0)
strcpy(matches[n_matches++], str);
for (size_t i = 0; i < n_items; ++i) {
if (strncmp(list[i], sub, s_len) == 0) {
snprintf(matches[n_matches++], MAX_STR_SIZE, "%s", list[i]);
}
}
free(sub);
if (!n_matches)
if (!n_matches) {
free_ptr_array((void **) matches);
return -1;
}
if (!dir_search && n_matches > 1)
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
if (!dir_search && n_matches > 1) {
print_ac_matches(self, NULL, matches, n_matches);
}
char match[MAX_STR_SIZE];
get_str_match(self, match, matches, n_matches);
size_t match_len = get_str_match(self, match, sizeof(match), (const char *const *) matches, n_matches, MAX_STR_SIZE);
free_ptr_array((void **) matches);
if (match_len == 0) {
return 0;
}
if (dir_search) {
if (n_matches == 1)
endchrs = char_rfind(match, '.', strlen(match)) ? "\"" : "/";
else
if (n_matches == 1) {
endchrs = char_rfind(match, '.', match_len) ? "" : "/";
} else {
endchrs = "";
}
} else if (n_matches > 1) {
endchrs = "";
}
/* put match in correct spot in buf and append endchars */
int n_endchrs = strlen(endchrs);
int m_len = strlen(match);
int strt = ctx->pos - s_len;
int diff = m_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;
}
char tmpend[MAX_STR_SIZE];
strcpy(tmpend, &ubuf[ctx->pos]);
snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
if (match_len + n_endchrs + strlen(tmpend) >= sizeof(ubuf)) {
return -1;
}
strcpy(&ubuf[strt], match);
strcpy(&ubuf[strt + m_len], endchrs);
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
/* If path points to a file with no extension don't append a forward slash */
if (dir_search && *endchrs == '/') {
const char *path_start = strchr(ubuf + 1, '/');
if (!path_start) {
path_start = strchr(ubuf + 1, ' ');
if (!path_start) {
return -1;
}
}
if (strlen(path_start) < 2) {
return -1;
}
++path_start;
if (file_type(path_start) == FILE_TYPE_REGULAR) {
endchrs = "";
diff -= n_endchrs;
}
}
strcpy(&ubuf[strt + match_len], endchrs);
strcpy(&ubuf[strt + match_len + n_endchrs], tmpend);
/* convert to widechar and copy back to original buf */
wchar_t newbuf[MAX_STR_SIZE];
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
if (mbs_to_wcs_buf(newbuf, ubuf, sizeof(newbuf) / sizeof(wchar_t)) == -1) {
return -1;
}
wcscpy(ctx->line, newbuf);
@ -202,90 +259,135 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
return diff;
}
/* transforms a sendfile tab complete contaning the shorthand "~/" into the full home directory.*/
static void complt_home_dir(ToxWindow *self, char *path, int pathsize)
int complete_line(ToxWindow *self, const char *const *list, size_t n_items)
{
return complete_line_helper(self, list, n_items, false);
}
static int complete_path(ToxWindow *self, const char *const *list, const size_t n_items)
{
return complete_line_helper(self, list, n_items, true);
}
/* Transforms a tab complete starting with the shorthand "~" into the full home directory. */
static void complete_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
{
ChatContext *ctx = self->chatwin;
char homedir[MAX_STR_SIZE];
char homedir[MAX_STR_SIZE] = {0};
get_home_dir(homedir, sizeof(homedir));
char newline[MAX_STR_SIZE];
snprintf(newline, sizeof(newline), "/sendfile \"%s%s", homedir, path + 1);
snprintf(path, pathsize, "%s", &newline[11]);
char newline[MAX_STR_SIZE + 1];
snprintf(newline, sizeof(newline), "%s %s%s", cmd, homedir, path + 1);
snprintf(path, pathsize, "%s", &newline[cmdlen - 1]);
wchar_t wline[MAX_STR_SIZE];
if (mbs_to_wcs_buf(wline, newline, sizeof(wline)) == -1)
if (mbs_to_wcs_buf(wline, newline, sizeof(wline) / sizeof(wchar_t)) == -1) {
return;
}
int newlen = wcslen(wline);
if (ctx->len + newlen >= MAX_STR_SIZE)
if (ctx->len + newlen >= MAX_STR_SIZE) {
return;
}
wmemcpy(ctx->line, wline, newlen + 1);
ctx->pos = newlen;
ctx->len = ctx->pos;
}
/* attempts to match /sendfile "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
#define MAX_DIRS 512
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line)
/*
* Return true if the first `p_len` chars in `s` are equal to `p` and `s` is a valid directory name.
*/
static bool is_partial_match(const char *s, const char *p, size_t p_len)
{
char b_path[MAX_STR_SIZE];
char b_name[MAX_STR_SIZE];
const wchar_t *tmpline = &line[11]; /* start after "/sendfile \"" */
if (s == NULL || p == NULL) {
return false;
}
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
return -1;
return strncmp(s, p, p_len) == 0 && strcmp(".", s) != 0 && strcmp("..", s) != 0;
}
if (b_path[0] == '~')
complt_home_dir(self, b_path, sizeof(b_path));
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
* If there is only one match the line is auto-completed.
*
* Returns the diff between old len and new len of ctx->line on success.
* Returns -1 if no matches or more than one match.
*/
#define MAX_DIRS 75
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
{
char b_path[MAX_STR_SIZE + 1];
char b_name[MAX_STR_SIZE + 1];
char b_cmd[MAX_STR_SIZE];
const wchar_t *tmpline = &line[wcslen(cmd) + 1]; /* start after "/command " */
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path) - 1) == -1) {
return -1;
}
if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1) {
return -1;
}
if (b_path[0] == '~') {
complete_home_dir(self, b_path, sizeof(b_path) - 1, b_cmd, strlen(b_cmd) + 2);
}
int si = char_rfind(b_path, '/', strlen(b_path));
if (!b_path[0]) { /* list everything in pwd */
b_path[0] = '.';
b_path[1] = '\0';
b_path[1] = '\0';
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), ".%s", b_path);
strcpy(b_path, tmp);
memmove(b_path + 1, b_path, sizeof(b_path) - 1);
b_path[0] = '.';
}
strcpy(b_name, &b_path[si + 1]);
snprintf(b_name, sizeof(b_name), "%s", &b_path[si + 1]);
b_path[si + 1] = '\0';
int b_name_len = strlen(b_name);
size_t b_name_len = strlen(b_name);
DIR *dp = opendir(b_path);
if (dp == NULL)
if (dp == NULL) {
return -1;
}
char **dirnames = (char **) malloc_ptr_array(MAX_DIRS, NAME_MAX + 1);
if (dirnames == NULL) {
closedir(dp);
return -1;
}
char dirnames[MAX_DIRS][NAME_MAX];
struct dirent *entry;
int dircount = 0;
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
if (strncmp(entry->d_name, b_name, b_name_len) == 0
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
if (is_partial_match(entry->d_name, b_name, b_name_len)) {
snprintf(dirnames[dircount], NAME_MAX + 1, "%s", entry->d_name);
++dircount;
}
}
if (dircount == 0)
return -1;
closedir(dp);
if (dircount > 1) {
qsort(dirnames, dircount, NAME_MAX, qsort_strcasecmp_hlpr);
print_matches(self, m, dirnames, dircount, NAME_MAX);
if (dircount == 0) {
free_ptr_array((void **) dirnames);
return -1;
}
return complete_line(self, dirnames, dircount, NAME_MAX);
if (dircount > 1) {
qsort(dirnames, dircount, sizeof(char *), qsort_ptr_char_array_helper);
print_ac_matches(self, m, dirnames, dircount);
}
int ret = complete_path(self, (const char *const *) dirnames, dircount);
free_ptr_array((void **) dirnames);
return ret;
}

View File

@ -20,23 +20,33 @@
*
*/
#ifndef _autocomplete_h
#define _autocomplete_h
#ifndef AUTOCOMPLETE_H
#define AUTOCOMPLETE_H
/* looks for all instances in list that begin with the last entered word in line according to pos,
then fills line with the complete word. e.g. "Hello jo" would complete the line
with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
#include "windows.h"
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
/*
* Looks for all instances in list that begin with the last entered word in line according to pos,
* then fills line with the complete word. e.g. "Hello jo" would complete the line
* with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
*
* `list` is a pointer to `n_items` strings.
*
* dir_search should be true if the line being completed is a file path.
*
* Returns the difference between the old len and new len of line on success.
* Returns -1 on error.
*
* Note: This function should not be called directly. Use complete_line() and complete_path() instead.
*/
int complete_line(ToxWindow *self, const char **list, size_t n_items);
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size);
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
* If there is only one match the line is auto-completed.
*
* Returns the diff between old len and new len of ctx->line on success.
* Returns -1 if no matches or more than one match.
*/
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd);
/* attempts to match /sendfile "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line);
#endif /* #define _autocomplete_h */
#endif /* AUTOCOMPLETE_H */

262
src/avatars.c Normal file
View File

@ -0,0 +1,262 @@
/* avatars.c
*
*
* Copyright (C) 2015 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "avatars.h"
#include "file_transfers.h"
#include "friendlist.h"
#include "misc_tools.h"
extern FriendsList Friends;
static struct Avatar {
char name[TOX_MAX_FILENAME_LENGTH + 1];
size_t name_len;
char path[PATH_MAX + 1];
size_t path_len;
off_t size;
} Avatar;
/* Compares the first size bytes of fp to signature.
*
* Returns 0 if they are the same
* Returns 1 if they differ
* Returns -1 on error.
*
* On success this function will seek back to the beginning of fp.
*/
static int check_file_signature(const unsigned char *signature, size_t size, FILE *fp)
{
char *buf = malloc(size);
if (buf == NULL) {
return -1;
}
if (fread(buf, size, 1, fp) != 1) {
free(buf);
return -1;
}
int ret = memcmp(signature, buf, size);
free(buf);
if (fseek(fp, 0L, SEEK_SET) == -1) {
return -1;
}
return ret == 0 ? 0 : 1;
}
static void avatar_clear(void)
{
Avatar = (struct Avatar) {
0
};
}
/* Sends avatar to friendnumber.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int avatar_send(Tox *m, uint32_t friendnumber)
{
Tox_Err_File_Send err;
uint32_t filenumber = tox_file_send(m, friendnumber, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
if (Avatar.size == 0) {
return 0;
}
if (err != TOX_ERR_FILE_SEND_OK) {
fprintf(stderr, "tox_file_send failed for friendnumber %u (error %d)\n", friendnumber, err);
return -1;
}
struct FileTransfer *ft = new_file_transfer(NULL, friendnumber, filenumber, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR);
if (!ft) {
return -1;
}
ft->file = fopen(Avatar.path, "r");
if (ft->file == NULL) {
return -1;
}
snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name);
ft->file_size = Avatar.size;
return 0;
}
/* Sends avatar to all friends */
static void avatar_send_all(Tox *m)
{
for (size_t i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].connection_status != TOX_CONNECTION_NONE) {
avatar_send(m, Friends.list[i].num);
}
}
}
/* Sets avatar to path and sends it to all online contacts.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int avatar_set(Tox *m, const char *path, size_t path_len)
{
if (path_len == 0 || path_len >= sizeof(Avatar.path)) {
return -1;
}
FILE *fp = fopen(path, "rb");
if (fp == NULL) {
return -1;
}
unsigned char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) {
fclose(fp);
return -1;
}
fclose(fp);
off_t size = file_size(path);
if (size == 0 || size > MAX_AVATAR_FILE_SIZE) {
return -1;
}
get_file_name(Avatar.name, sizeof(Avatar.name), path);
Avatar.name_len = strlen(Avatar.name);
snprintf(Avatar.path, sizeof(Avatar.path), "%s", path);
Avatar.path_len = path_len;
Avatar.size = size;
avatar_send_all(m);
return 0;
}
/* Unsets avatar and sends to all online contacts.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
void avatar_unset(Tox *m)
{
avatar_clear();
avatar_send_all(m);
}
void on_avatar_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status)
{
if (connection_status == TOX_CONNECTION_NONE) {
kill_avatar_file_transfers_friend(m, friendnumber);
}
}
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control)
{
switch (control) {
case TOX_FILE_CONTROL_RESUME:
if (ft->state == FILE_TRANSFER_PENDING) {
ft->state = FILE_TRANSFER_STARTED;
} else if (ft->state == FILE_TRANSFER_PAUSED) {
ft->state = FILE_TRANSFER_STARTED;
}
break;
case TOX_FILE_CONTROL_PAUSE:
ft->state = FILE_TRANSFER_PAUSED;
break;
case TOX_FILE_CONTROL_CANCEL:
close_file_transfer(NULL, m, ft, -1, NULL, silent);
break;
}
}
void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length)
{
if (ft->state != FILE_TRANSFER_STARTED) {
return;
}
if (length == 0) {
close_file_transfer(NULL, m, ft, -1, NULL, silent);
return;
}
if (ft->file == NULL) {
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
return;
}
if (ft->position != position) {
if (fseek(ft->file, position, SEEK_SET) == -1) {
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
return;
}
ft->position = position;
}
uint8_t *send_data = malloc(length);
if (send_data == NULL) {
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
return;
}
size_t send_length = fread(send_data, 1, length, ft->file);
if (send_length != length) {
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
free(send_data);
return;
}
Tox_Err_File_Send_Chunk err;
tox_file_send_chunk(m, ft->friendnumber, ft->filenumber, position, send_data, send_length, &err);
free(send_data);
if (err != TOX_ERR_FILE_SEND_CHUNK_OK) {
fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
}
ft->position += send_length;
}

55
src/avatars.h Normal file
View File

@ -0,0 +1,55 @@
/* avatars.h
*
*
* Copyright (C) 2015 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 AVATARS_H
#define AVATARS_H
#include "file_transfers.h"
#define MAX_AVATAR_FILE_SIZE 65536
/* Sends avatar to friendnum.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int avatar_send(Tox *m, uint32_t friendnum);
/* Sets avatar to path and sends it to all online contacts.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int avatar_set(Tox *m, const char *path, size_t length);
/* Unsets avatar and sends to all online contacts.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
void avatar_unset(Tox *m);
void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length);
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control);
void on_avatar_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status);
#endif /* AVATARS_H */

635
src/bootstrap.c Normal file
View File

@ -0,0 +1,635 @@
/* 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 <arpa/inet.h>
#include <limits.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <curl/curl.h>
#include <tox/tox.h>
#include "configdir.h"
#include "curl_util.h"
#include "line_info.h"
#include "misc_tools.h"
#include "prompt.h"
#include "settings.h"
#include "windows.h"
extern struct user_settings *user_settings;
/* 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 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;
/* Return true if address appears to be a valid ipv4 address. */
static 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).
*/
static bool is_ip6_address(const char *address)
{
size_t num_colons = 0;
char ch = 0;
for (size_t i = 0; (ch = address[i]); ++i) {
if (ch == '.') {
return false;
}
if (ch == ':') {
++num_colons;
}
}
return num_colons > 1 && num_colons < 8;
}
/* Determine if a node is offline by comparing the age of the nodeslist
* to the last time the node was successfully pinged.
*/
static bool node_is_offline(unsigned long long int last_ping)
{
return 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.
* Return -5 if memory allocation fails.
*/
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 = calloc(1, sizeof(struct Recv_Curl_Data));
if (recv_data == NULL) {
fclose(fp);
return -5;
}
if (curl_fetch_nodes_JSON(recv_data) == -1) {
free(recv_data);
fclose(fp);
return -2;
}
if (recv_data->length == 0) {
free(recv_data);
fclose(fp);
return -3;
}
if (fwrite(recv_data->data, recv_data->length, 1, fp) != 1) {
free(recv_data);
fclose(fp);
return -4;
}
free(recv_data);
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, size_t buf_length)
{
if (buf_length < TOX_PUBLIC_KEY_SIZE * 2 + 1) {
return -1;
}
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(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, sizeof(key_string));
if (key_len == -1) {
return -6;
}
if (tox_pk_string_to_bytes(key_string, key_len, node->key, sizeof(node->key)) == -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)
{
UNUSED_VAR(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 (Nodes.count == 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 = prompt_selfConnectionStatus() != TOX_CONNECTION_NONE;
if (!connected && timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL)) {
DHT_bootstrap(m);
last_bootstrap_time = get_unix_time();
}
}

42
src/bootstrap.h Normal file
View File

@ -0,0 +1,42 @@
/* bootstrap.h
*
*
* Copyright (C) 2016 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BOOTSTRAP_H
#define BOOTSTRAP_H
/* Manages connection to the Tox DHT network. */
void do_tox_connection(Tox *m);
/* Creates a new thread that will load the DHT nodeslist to memory
* from json encoded nodes file obtained at NODES_LIST_URL. Only one
* thread may run at a time.
*
* Return 0 on success.
* Return -1 if a thread is already active.
* Return -2 if mutex fails to init.
* Return -3 if pthread attribute fails to init.
* Return -4 if pthread fails to set detached state.
* Return -5 if thread creation fails.
*/
int load_DHT_nodeslist(void);
#endif /* BOOTSTRAP_H */

1854
src/chat.c

File diff suppressed because it is too large Load Diff

View File

@ -20,16 +20,16 @@
*
*/
#ifndef CHAT_H_6489PZ13
#define CHAT_H_6489PZ13
#ifndef CHAT_H
#define CHAT_H
#include "windows.h"
#include "toxic.h"
#include "windows.h"
/* set CTRL to -1 if we don't want to send a control signal.
set msg to NULL if we don't want to display a message */
void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL);
void kill_chat_window(ToxWindow *self, Tox *m);
ToxWindow new_chat(Tox *m, int32_t friendnum);
ToxWindow *new_chat(Tox *m, int32_t friendnum);
#endif /* end of include guard: CHAT_H_6489PZ13 */
#endif /* end of include guard: CHAT_H */

View File

@ -23,248 +23,412 @@
#include <stdlib.h>
#include <string.h>
#include "chat.h"
#include "conference.h"
#include "execute.h"
#include "file_transfers.h"
#include "friendlist.h"
#include "line_info.h"
#include "misc_tools.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "friendlist.h"
#include "execute.h"
#include "line_info.h"
#include "groupchat.h"
#include "chat.h"
#include "file_senders.h"
extern ToxWindow *prompt;
extern _Friends Friends;
extern FileSender file_senders[MAX_FILES];
extern uint8_t max_file_senders_index;
extern uint8_t num_active_file_senders;
extern FriendsList Friends;
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
if (argc < 2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID.");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID.");
return;
}
char msg[MAX_STR_SIZE];
const char *inoutstr = argv[1];
int filenum = atoi(argv[2]);
long int idx = strtol(argv[2], NULL, 10);
if (filenum >= MAX_FILES || filenum < 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
if ((idx == 0 && strcmp(argv[2], "0")) || idx >= MAX_FILES || idx < 0) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */
if (!Friends.list[self->num].file_receiver[filenum].active) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
const char *filepath = Friends.list[self->num].file_receiver[filenum].filename;
char name[MAX_STR_SIZE];
get_file_name(name, sizeof(name), filepath);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer for '%s' canceled.", name);
chat_close_file_receiver(m, filenum, self->num, TOX_FILECONTROL_KILL);
// first check transfer queue
if (file_send_queue_remove(self->num, idx) == 0) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Pending file transfer removed from queue");
return;
} else if (strcasecmp(inoutstr, "out") == 0) { /* cancel an outgoing file transfer */
int i;
bool match = false;
}
for (i = 0; i < MAX_FILES; ++i) {
if (file_senders[i].active && file_senders[i].filenum == filenum) {
match = true;
break;
}
}
FileTransfer *ft = NULL;
if (!match) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
const char *filename = file_senders[i].filename;
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", filename);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, self->num);
return;
/* cancel an incoming file transfer */
if (strcasecmp(inoutstr, "in") == 0) {
ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
} else if (strcasecmp(inoutstr, "out") == 0) {
ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_SEND);
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
return;
}
if (!ft) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
if (ft->state == FILE_TRANSFER_INACTIVE) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
snprintf(msg, sizeof(msg), "File transfer for '%s' aborted.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, silent);
}
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
void cmd_conference_invite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group number required.");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference number required.");
return;
}
int groupnum = atoi(argv[1]);
long int conferencenum = strtol(argv[1], NULL, 10);
if (groupnum == 0 && strcmp(argv[1], "0")) { /* atoi returns 0 value on invalid input */
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid group number.");
if ((conferencenum == 0 && strcmp(argv[1], "0")) || conferencenum < 0 || conferencenum == LONG_MAX) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid conference number.");
return;
}
if (tox_invite_friend(m, self->num, groupnum) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group.");
Tox_Err_Conference_Invite err;
if (!tox_conference_invite(m, self->num, conferencenum, &err)) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to conference (error %d)", err);
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Group %d.", groupnum);
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Conference %ld.", conferencenum);
}
void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(argc);
UNUSED_VAR(argv);
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return;
}
const char *groupkey = Friends.list[self->num].groupchat_key;
const char *conferencekey = Friends.list[self->num].conference_invite.key;
uint16_t length = Friends.list[self->num].conference_invite.length;
uint8_t type = Friends.list[self->num].conference_invite.type;
if (!Friends.list[self->num].groupchat_pending) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite.");
if (!Friends.list[self->num].conference_invite.pending) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending conference invite.");
return;
}
int groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey);
uint32_t conferencenum;
if (groupnum == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
if (type == TOX_CONFERENCE_TYPE_TEXT) {
Tox_Err_Conference_Join err;
conferencenum = tox_conference_join(m, self->num, (const uint8_t *) conferencekey, length, &err);
if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
return;
}
} else if (type == TOX_CONFERENCE_TYPE_AV) {
#ifdef AUDIO
conferencenum = toxav_join_av_groupchat(m, self->num, (const uint8_t *) conferencekey, length,
audio_conference_callback, NULL);
if (conferencenum == (uint32_t) -1) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
return;
}
#else
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
return;
#endif
} else {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
return;
}
if (init_groupchat_win(prompt, m, groupnum) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_del_groupchat(m, groupnum);
if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
tox_conference_delete(m, conferencenum, NULL);
return;
}
#ifdef AUDIO
if (type == TOX_CONFERENCE_TYPE_AV) {
if (!init_conference_audio_input(m, conferencenum)) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
}
}
#endif
}
#ifdef GAMES
void cmd_game_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
if (!Friends.list[self->num].game_invite.pending) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending game invite.");
return;
}
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return;
}
GameType type = Friends.list[self->num].game_invite.type;
uint32_t id = Friends.list[self->num].game_invite.id;
uint8_t *data = Friends.list[self->num].game_invite.data;
size_t length = Friends.list[self->num].game_invite.data_length;
int ret = game_initialize(self, m, type, id, data, length);
switch (ret) {
case 0: {
free(data);
Friends.list[self->num].game_invite.data = NULL;
Friends.list[self->num].game_invite.pending = false;
break;
}
case -1: {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Window is too small. Try enlarging your window.");
return;
}
case -2: {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Game failed to initialize (network error)");
return;
}
default: {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Game failed to initialize (error %d)", ret);
return;
}
}
}
#endif // GAMES
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File ID required.");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File ID required.");
return;
}
uint8_t filenum = atoi(argv[1]);
long int idx = strtol(argv[1], NULL, 10);
if ((filenum == 0 && strcmp(argv[1], "0")) || filenum >= MAX_FILES) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
if ((idx == 0 && strcmp(argv[1], "0")) || idx < 0 || idx >= MAX_FILES) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return;
}
if (!Friends.list[self->num].file_receiver[filenum].pending) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
if (!ft) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return;
}
const char *filename = Friends.list[self->num].file_receiver[filenum].filename;
if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", filenum, filename);
/* prep progress bar line */
char progline[MAX_STR_SIZE];
prep_prog_line(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
Friends.list[self->num].file_receiver[filenum].line_id = self->chatwin->hst->line_end->id + 2;
if ((Friends.list[self->num].file_receiver[filenum].file = fopen(filename, "a")) == NULL) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Error writing to file.");
tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
} else {
Friends.list[self->num].file_receiver[filenum].active = true;
++Friends.list[self->num].active_file_receivers;
}
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed.");
if (ft->state != FILE_TRANSFER_PENDING) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return;
}
Friends.list[self->num].file_receiver[filenum].pending = false;
if ((ft->file = fopen(ft->file_path, "a")) == NULL) {
const char *msg = "File transfer failed: Invalid download path.";
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
Tox_Err_File_Control err;
tox_file_control(m, self->num, ft->filenumber, TOX_FILE_CONTROL_RESUME, &err);
if (err != TOX_ERR_FILE_CONTROL_OK) {
goto on_recv_error;
}
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%ld] as: '%s'", idx, ft->file_path);
/* prep progress bar line */
char progline[MAX_STR_SIZE];
init_progress_bar(progline);
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
ft->line_id = self->chatwin->hst->line_end->id + 2;
ft->state = FILE_TRANSFER_STARTED;
return;
on_recv_error:
switch (err) {
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
return;
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED:
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online.");
return;
case TOX_ERR_FILE_CONTROL_NOT_FOUND:
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber.");
return;
case TOX_ERR_FILE_CONTROL_SENDQ:
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error.");
return;
default:
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err);
return;
}
}
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (max_file_senders_index >= (MAX_FILES - 1)) {
const char *errmsg = "Please wait for some of your outgoing file transfers to complete.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
UNUSED_VAR(window);
const char *errmsg = NULL;
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
return;
}
if (argv[1][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path must be enclosed in quotes.");
return;
}
/* remove opening and closing quotes */
char path[MAX_STR_SIZE];
snprintf(path, sizeof(path), "%s", &argv[1][1]);
int path_len = strlen(path) - 1;
path[path_len] = '\0';
snprintf(path, sizeof(path), "%s", argv[1]);
int path_len = strlen(path);
if (path_len >= MAX_STR_SIZE) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
return;
}
FILE *file_to_send = fopen(path, "r");
if (file_to_send == NULL) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File not found.");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File `%s` not found.", path);
return;
}
fseek(file_to_send, 0, SEEK_END);
uint64_t filesize = ftell(file_to_send);
fseek(file_to_send, 0, SEEK_SET);
off_t filesize = file_size(path);
char filename[MAX_STR_SIZE] = {0};
get_file_name(filename, sizeof(filename), path);
int namelen = strlen(filename);
int filenum = tox_new_file_sender(m, self->num, filesize, (const uint8_t *) filename, namelen);
if (filenum == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error sending file.");
if (filesize == 0) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file.");
fclose(file_to_send);
return;
}
int i;
char file_name[TOX_MAX_FILENAME_LENGTH];
size_t namelen = get_file_name(file_name, sizeof(file_name), path);
for (i = 0; i < MAX_FILES; ++i) {
if (!file_senders[i].active) {
memcpy(file_senders[i].filename, filename, namelen + 1);
file_senders[i].active = true;
file_senders[i].toxwin = self;
file_senders[i].file = file_to_send;
file_senders[i].filenum = filenum;
file_senders[i].friendnum = self->num;
file_senders[i].timestamp = get_unix_time();
file_senders[i].size = filesize;
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
tox_file_data_size(m, self->num), file_to_send);
Tox_Err_File_Send err;
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
(uint8_t *) file_name, namelen, &err);
char sizestr[32];
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
"Sending file [%d]: '%s' (%s)", filenum, filename, sizestr);
if (err != TOX_ERR_FILE_SEND_OK) {
goto on_send_error;
}
++num_active_file_senders;
FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);
if (i == max_file_senders_index)
++max_file_senders_index;
if (!ft) {
err = TOX_ERR_FILE_SEND_TOO_MANY;
goto on_send_error;
}
memcpy(ft->file_name, file_name, namelen + 1);
ft->file = file_to_send;
ft->file_size = filesize;
tox_file_get_file_id(m, self->num, filenum, ft->file_id, NULL);
char sizestr[32];
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", filenum, file_name, sizestr);
return;
on_send_error:
fclose(file_to_send);
switch (err) {
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: {
errmsg = "File transfer failed: Invalid friend.";
break;
}
case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED: {
int queue_idx = file_send_queue_add(self->num, path, path_len);
char msg[MAX_STR_SIZE];
switch (queue_idx) {
case -1: {
snprintf(msg, sizeof(msg), "Invalid file name: path is null or length is zero.");
break;
}
case -2: {
snprintf(msg, sizeof(msg), "File name is too long.");
break;
}
case -3: {
snprintf(msg, sizeof(msg), "File send queue is full.");
break;
}
default: {
snprintf(msg, sizeof(msg), "File transfer queued. Type \"/cancel out %d\" to cancel.", queue_idx);
break;
}
}
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
reset_file_sender_queue();
return;
}
case TOX_ERR_FILE_SEND_NAME_TOO_LONG: {
errmsg = "File transfer failed: Filename is too long.";
break;
}
case TOX_ERR_FILE_SEND_TOO_MANY: {
errmsg = "File transfer failed: Too many concurrent file transfers.";
break;
}
default: {
errmsg = "File transfer failed.";
break;
}
}
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg);
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
}

View File

@ -20,19 +20,20 @@
*
*/
#ifndef _chat_commands_h
#define _chat_commands_h
#ifndef CHAT_COMMANDS_H
#define CHAT_COMMANDS_H
#include "windows.h"
#include "toxic.h"
#include "windows.h"
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_conference_invite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_conference_join(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_game_join(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#ifdef _AUDIO
#ifdef AUDIO
void cmd_call(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_answer(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_reject(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@ -41,6 +42,13 @@ void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* _AUDIO */
void cmd_bitrate(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* AUDIO */
#endif /* #define _chat_commands_h */
#ifdef VIDEO
void cmd_vcall(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_video(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_res(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* VIDEO */
#endif /* CHAT_COMMANDS_H */

1430
src/conference.c Normal file

File diff suppressed because it is too large Load Diff

118
src/conference.h Normal file
View File

@ -0,0 +1,118 @@
/* conference.h
*
*
* Copyright (C) 2014 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 CONFERENCE_H
#define CONFERENCE_H
#include "toxic.h"
#include "windows.h"
#define CONFERENCE_MAX_TITLE_LENGTH TOX_MAX_NAME_LENGTH
#define SIDEBAR_WIDTH 16
typedef struct ConferencePeer {
bool active;
uint8_t pubkey[TOX_PUBLIC_KEY_SIZE];
uint32_t peernum; /* index in chat->peer_list */
char name[TOX_MAX_NAME_LENGTH];
size_t name_length;
bool sending_audio;
uint32_t audio_out_idx;
time_t last_audio_time;
} ConferencePeer;
typedef struct AudioInputCallbackData {
Tox *tox;
uint32_t conferencenum;
} AudioInputCallbackData;
#define PUBKEY_STRING_SIZE (2 * TOX_PUBLIC_KEY_SIZE + 1)
typedef struct NameListEntry {
char name[TOX_MAX_NAME_LENGTH];
char pubkey_str[PUBKEY_STRING_SIZE];
uint32_t peernum;
} NameListEntry;
typedef struct {
int chatwin;
bool active;
uint8_t type;
int side_pos; /* current position of the sidebar - used for scrolling up and down */
time_t start_time;
char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
size_t title_length;
ConferencePeer *peer_list;
uint32_t max_idx;
NameListEntry *name_list;
uint32_t num_peers;
bool push_to_talk_enabled;
time_t ptt_last_pushed;
bool audio_enabled;
time_t last_sent_audio;
uint32_t audio_in_idx;
AudioInputCallbackData audio_input_callback_data;
} ConferenceChat;
/* Frees all Toxic associated data structures for a conference (does not call tox_conference_delete() ) */
void free_conference(ToxWindow *self, uint32_t conferencenum);
int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t length);
/* destroys and re-creates conference window with or without the peerlist */
void redraw_conference_win(ToxWindow *self);
void conference_set_title(ToxWindow *self, uint32_t conferencesnum, const char *title, size_t length);
void conference_rename_log_path(Tox *m, uint32_t conferencenum, const char *new_title);
int conference_enable_logging(ToxWindow *self, Tox *m, uint32_t conferencenum, struct chatlog *log);
/* Puts `(NameListEntry *)`s in `entries` for each matched peer, up to a maximum
* of `maxpeers`.
* Maches each peer whose name or pubkey begins with `prefix`.
* If `prefix` is exactly the pubkey of a peer, matches only that peer.
* return number of entries placed in `entries`.
*/
uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *prefix, NameListEntry **entries,
uint32_t maxpeers);
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum);
bool enable_conference_audio(ToxWindow *self, Tox *tox, uint32_t conferencenum);
bool disable_conference_audio(ToxWindow *self, Tox *tox, uint32_t conferencenum);
bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled);
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
sample_rate, void *userdata);
bool conference_mute_self(uint32_t conferencenum);
bool conference_mute_peer(const Tox *m, uint32_t conferencenum, uint32_t peernum);
bool conference_set_VAD_threshold(uint32_t conferencenum, float threshold);
float conference_get_VAD_threshold(uint32_t conferencenum);
#endif /* CONFERENCE_H */

210
src/conference_commands.c Normal file
View File

@ -0,0 +1,210 @@
/* conference_commands.c
*
*
* Copyright (C) 2014 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 "conference.h"
#include "line_info.h"
#include "log.h"
#include "misc_tools.h"
#include "toxic.h"
#include "windows.h"
static void print_err(ToxWindow *self, const char *error_str)
{
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
}
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
Tox_Err_Conference_Title err;
char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
if (argc < 1) {
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
if (err != TOX_ERR_CONFERENCE_TITLE_OK || tlen >= sizeof(title)) {
print_err(self, "Title is not set");
return;
}
if (!tox_conference_get_title(m, self->num, (uint8_t *) title, &err)) {
print_err(self, "Title is not set");
return;
}
title[tlen] = '\0';
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
return;
}
size_t len = strlen(argv[1]);
if (len >= sizeof(title)) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title: max length exceeded.");
return;
}
snprintf(title, sizeof(title), "%s", argv[1]);
if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
return;
}
conference_rename_log_path(m, self->num, title); // must be called first
conference_set_title(self, self->num, title, len);
char selfnick[TOX_MAX_NAME_LENGTH];
tox_self_get_name(m, (uint8_t *) selfnick);
size_t sn_len = tox_self_get_name_size(m);
selfnick[sn_len] = '\0';
line_info_add(self, true, selfnick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title);
char tmp_event[MAX_STR_SIZE + 20];
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
write_to_log(tmp_event, selfnick, self->chatwin->log, true);
}
#ifdef AUDIO
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
bool enable;
if (argc == 1 && !strcasecmp(argv[1], "on")) {
enable = true;
} else if (argc == 1 && !strcasecmp(argv[1], "off")) {
enable = false;
} else {
print_err(self, "Please specify: on | off");
return;
}
if (enable ? enable_conference_audio(self, m, self->num) : disable_conference_audio(self, m, self->num)) {
print_err(self, enable ? "Enabled conference audio. Use the '/ptt' command to toggle Push-To-Talk."
: "Disabled conference audio");
} else {
print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio");
}
}
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
if (argc < 1) {
if (conference_mute_self(self->num)) {
print_err(self, "Toggled self audio mute status");
} else {
print_err(self, "No audio input to mute");
}
} else {
NameListEntry *entries[16];
uint32_t n = get_name_list_entries_by_prefix(self->num, argv[1], entries, 16);
if (n == 0) {
print_err(self, "No such peer");
return;
}
if (n > 1) {
print_err(self, "Multiple matching peers (use /mute [public key] to disambiguate):");
for (uint32_t i = 0; i < n; ++i) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s: %s", entries[i]->pubkey_str, entries[i]->name);
}
return;
}
if (conference_mute_peer(m, self->num, entries[0]->peernum)) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Toggled audio mute status of %s", entries[0]->name);
} else {
print_err(self, "Peer is not on the call");
}
}
}
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
if (argc == 0) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Current VAD threshold: %.1f",
(double) conference_get_VAD_threshold(self->num));
return;
}
if (argc > 1) {
print_err(self, "Only one argument allowed.");
return;
}
char *end;
float value = strtof(argv[1], &end);
if (*end) {
print_err(self, "Invalid input");
return;
}
if (conference_set_VAD_threshold(self->num, value)) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Set VAD threshold to %.1f", (double) value);
} else {
print_err(self, "Failed to set conference audio input sensitivity.");
}
}
void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
bool enable;
if (argc == 1 && !strcasecmp(argv[1], "on")) {
enable = true;
} else if (argc == 1 && !strcasecmp(argv[1], "off")) {
enable = false;
} else {
print_err(self, "Please specify: on | off");
return;
}
if (!toggle_conference_push_to_talk(self->num, enable)) {
print_err(self, "Failed to toggle push to talk.");
return;
}
print_err(self, enable ? "Push-To-Talk is enabled. Push F2 to activate" : "Push-To-Talk is disabled");
}
#endif /* AUDIO */

View File

@ -1,4 +1,4 @@
/* groupchat.h
/* conference_commands.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
@ -20,29 +20,16 @@
*
*/
#ifndef _groupchat_h
#define _groupchat_h
#ifndef CONFERENCE_COMMANDS_H
#define CONFERENCE_COMMANDS_H
#include "toxic.h"
#include "windows.h"
#define SIDEBAR_WIDTH 16
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
typedef struct {
int chatwin;
bool active;
int num_peers;
int side_pos; /* current position of the sidebar - used for scrolling up and down */
uint8_t *peer_names;
uint8_t *oldpeer_names;
uint16_t *peer_name_lengths;
uint16_t *oldpeer_name_lengths;
} GroupChat;
void kill_groupchat_window(ToxWindow *self);
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum);
ToxWindow new_group_chat(Tox *m, int groupnum);
#endif /* #define _groupchat_h */
#endif /* CONFERENCE_COMMANDS_H */

View File

@ -20,19 +20,20 @@
*
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "toxic.h"
#include "configdir.h"
#include "misc_tools.h"
#include "toxic.h"
/* get the user's home directory */
/* get the user's home directory. */
void get_home_dir(char *home, int size)
{
struct passwd pwd;
@ -47,8 +48,9 @@ void get_home_dir(char *home, int size)
} else {
hmstr = getenv("HOME");
if (hmstr == NULL)
if (hmstr == NULL) {
return;
}
snprintf(buf, sizeof(buf), "%s", hmstr);
hmstr = buf;
@ -66,30 +68,32 @@ void get_home_dir(char *home, int size)
*/
char *get_user_config_dir(void)
{
char home[NSS_BUFLEN_PASSWD];
char home[NSS_BUFLEN_PASSWD] = {0};
get_home_dir(home, sizeof(home));
char *user_config_dir;
size_t len;
char *user_config_dir = NULL;
size_t len = 0;
# if defined(__APPLE__)
len = strlen(home) + strlen("/Library/Application Support") + 1;
user_config_dir = malloc(len);
if (user_config_dir == NULL)
if (user_config_dir == NULL) {
return NULL;
}
snprintf(user_config_dir, len, "%s/Library/Application Support", home);
# else /* __APPLE__ */
const char *tmp;
const char *tmp = getenv("XDG_CONFIG_HOME");
if (!(tmp = getenv("XDG_CONFIG_HOME"))) {
if (tmp == NULL) {
len = strlen(home) + strlen("/.config") + 1;
user_config_dir = malloc(len);
if (user_config_dir == NULL)
if (user_config_dir == NULL) {
return NULL;
}
snprintf(user_config_dir, len, "%s/.config", home);
} else {
@ -101,22 +105,26 @@ char *get_user_config_dir(void)
return user_config_dir;
}
/*
* Creates the config and chatlog directories.
/* Creates the config and chatlog directories.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int create_user_config_dirs(char *path)
{
struct stat buf;
int mkdir_err = mkdir(path, 0700);
if (mkdir_err && (errno != EEXIST || stat(path, &buf) || !S_ISDIR(buf.st_mode)))
if (mkdir_err && (errno != EEXIST || stat(path, &buf) || !S_ISDIR(buf.st_mode))) {
return -1;
}
char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
char *logpath = malloc(strlen(path) + strlen(LOGDIR) + 1);
if (fullpath == NULL || logpath == NULL)
if (fullpath == NULL || logpath == NULL) {
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
}
strcpy(fullpath, path);
strcat(fullpath, CONFIGDIR);

View File

@ -20,8 +20,8 @@
*
*/
#ifndef _configdir_h
#define _configdir_h
#ifndef CONFIGDIR_H
#define CONFIGDIR_H
#ifndef NSS_BUFLEN_PASSWD
#define NSS_BUFLEN_PASSWD 4096
@ -34,8 +34,23 @@
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
/**
* @brief Get the user's config directory.
*
* This is without a trailing slash. Resulting string must be freed.
*
* @return The users config dir or NULL on error.
*/
char *get_user_config_dir(void);
/* get the user's home directory. */
void get_home_dir(char *home, int size);
/* Creates the config and chatlog directories.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int create_user_config_dirs(char *path);
#endif /* #define _configdir_h */
#endif /* CONFIGDIR_H */

94
src/curl_util.c Normal file
View File

@ -0,0 +1,94 @@
/* 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;
}

57
src/curl_util.h Normal file
View File

@ -0,0 +1,57 @@
/* 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
#include <stdint.h>
/* List based on Mozilla's recommended configurations for modern browsers */
#define TLS_CIPHER_SUITE_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
/* Max size of an http response that we can store in Recv_Data */
#define MAX_RECV_CURL_DATA_SIZE 32767
/* Holds data received from curl lookup */
struct Recv_Curl_Data {
char data[MAX_RECV_CURL_DATA_SIZE + 1]; /* Data received from curl write data callback */
size_t length; /* Total number of bytes written to data buffer (doesn't include null) */
};
/* Sets proxy info for given CURL handler.
*
* Returns 0 on success or if no proxy is set by the client.
* Returns -1 if proxy info is invalid.
* Returns an int > 0 on curl error (see: https://curl.haxx.se/libcurl/c/libcurl-errors.html)
*/
int set_curl_proxy(CURL *c_handle, const char *proxy_address, uint16_t port, uint8_t proxy_type);
/* Callback function for CURL to write received data.
*
* This function will append data from an http request to the data buffer
* until the request is complete or the buffer is full. Buffer will be null terminated.
*
* Returns size of bytes written to the data buffer.
*/
size_t curl_cb_write_data(void *data, size_t size, size_t nmemb, void *user_pointer);
#endif /* CURL_UTIL_H */

View File

@ -1,467 +0,0 @@
/* device.c
*
*
* Copyright (C) 2014 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 "device.h"
#ifdef _AUDIO
#include "audio_call.h"
#endif
#include "line_info.h"
#include "settings.h"
#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif
#endif
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#define OPENAL_BUFS 5
#define inline__ inline __attribute__((always_inline))
extern struct user_settings *user_settings_;
typedef struct _Device {
ALCdevice *dhndl; /* Handle of device selected/opened */
ALCcontext *ctx; /* Device context */
DataHandleCallback cb; /* Use this to handle data from input device usually */
void* cb_data; /* Data to be passed to callback */
int32_t call_idx; /* ToxAv call index */
uint32_t source, buffers[OPENAL_BUFS]; /* Playback source/buffers */
size_t ref_count;
int32_t selection;
_Bool enable_VAD;
_Bool muted;
pthread_mutex_t mutex[1];
uint32_t sample_rate;
uint32_t frame_duration;
int32_t sound_mode;
#ifdef _AUDIO
float VAD_treshold; /* 40 is usually recommended value */
#endif
} Device;
const char *ddevice_names[2]; /* Default device */
const char *devices_names[2][MAX_DEVICES]; /* Container of available devices */
static int size[2]; /* Size of above containers */
Device *running[2][MAX_DEVICES]; /* Running devices */
uint32_t primary_device[2]; /* Primary device */
#ifdef _AUDIO
static ToxAv* av = NULL;
#endif /* _AUDIO */
/* q_mutex */
#define lock pthread_mutex_lock(&mutex)
#define unlock pthread_mutex_unlock(&mutex)
pthread_mutex_t mutex;
_Bool thread_running = _True,
thread_paused = _True; /* Thread control */
void* thread_poll(void*);
/* Meet devices */
#ifdef _AUDIO
DeviceError init_devices(ToxAv* av_)
#else
DeviceError init_devices()
#endif /* _AUDIO */
{
const char *stringed_device_list;
size[input] = 0;
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[input] < MAX_DEVICES; ++size[input] ) {
devices_names[input][size[input]] = stringed_device_list;
stringed_device_list += strlen( stringed_device_list ) + 1;
}
}
size[output] = 0;
if ( (stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER)) ) {
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output] ) {
devices_names[output][size[output]] = stringed_device_list;
stringed_device_list += strlen( stringed_device_list ) + 1;
}
}
// Start poll thread
pthread_mutex_init(&mutex, NULL);
pthread_t thread_id;
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
return de_InternalError;
#ifdef _AUDIO
av = av_;
#endif /* _AUDIO */
return (DeviceError) de_None;
}
DeviceError terminate_devices()
{
/* Cleanup if needed */
thread_running = false;
usleep(20000);
pthread_mutex_destroy(&mutex);
return (DeviceError) de_None;
}
DeviceError device_mute(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
Device* device = running[type][device_idx];
if (!device) {
unlock;
return de_DeviceNotActive;
}
device->muted = !device->muted;
unlock;
return de_None;
}
#ifdef _AUDIO
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
Device* device = running[input][device_idx];
if (!device) {
unlock;
return de_DeviceNotActive;
}
device->VAD_treshold = value;
unlock;
return de_None;
}
#endif
DeviceError set_primary_device(DeviceType type, int32_t selection)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
primary_device[type] = selection;
return de_None;
}
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
{
return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration, channels);
}
// TODO: generate buffers separately
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
if (channels != 1 && channels != 2) return de_UnsupportedMode;
lock;
const uint32_t frame_size = (sample_rate * frame_duration / 1000);
uint32_t i;
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; i ++);
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; }
else *device_idx = i;
Device* device = running[type][*device_idx] = calloc(1, sizeof(Device));
device->selection = selection;
device->sample_rate = sample_rate;
device->frame_duration = frame_duration;
device->sound_mode = channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
for (i = 0; i < *device_idx; i ++) { /* Check if any previous has the same selection */
if ( running[type][i]->selection == selection ) {
device->dhndl = running[type][i]->dhndl;
if (type == output) {
device->ctx = running[type][i]->ctx;
memcpy(device->buffers, running[type][i]->buffers, sizeof(running[type][i]->buffers));
device->source = running[type][i]->source;
}
device->ref_count++;
pthread_mutex_init(device->mutex, NULL);
unlock;
return de_None;
}
}
if (type == input) {
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
sample_rate, device->sound_mode, frame_size * 2);
#ifdef _AUDIO
device->VAD_treshold = user_settings_->VAD_treshold;
#endif
}
else {
device->dhndl = alcOpenDevice(devices_names[type][selection]);
if ( !device->dhndl ) {
free(device);
running[type][*device_idx] = NULL;
unlock;
return de_FailedStart;
}
device->ctx = alcCreateContext(device->dhndl, NULL);
alcMakeContextCurrent(device->ctx);
alGenBuffers(OPENAL_BUFS, device->buffers);
alGenSources((uint32_t)1, &device->source);
alSourcei(device->source, AL_LOOPING, AL_FALSE);
uint16_t zeros[frame_size];
memset(zeros, 0, frame_size*2);
for ( i =0; i < OPENAL_BUFS; ++i) {
alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size*2, sample_rate);
}
alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
alSourcePlay(device->source);
}
if (alcGetError(device->dhndl) != AL_NO_ERROR) {
free(device);
running[type][*device_idx] = NULL;
unlock;
return de_FailedStart;
}
if (type == input) {
alcCaptureStart(device->dhndl);
thread_paused = _False;
}
pthread_mutex_init(device->mutex, NULL);
unlock;
return de_None;
}
DeviceError close_device(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
Device* device = running[type][device_idx];
if (!device) {
unlock;
return de_DeviceNotActive;
}
if ( !(device->ref_count--) ) {
running[type][device_idx] = NULL;
unlock;
DeviceError rc = de_None;
if (type == input) {
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
}
else {
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
alDeleteSources(1, &device->source);
alDeleteBuffers(OPENAL_BUFS, device->buffers);
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
alcMakeContextCurrent(NULL);
if ( device->ctx ) alcDestroyContext(device->ctx);
}
free(device);
return rc;
}
unlock;
return de_None;
}
DeviceError register_device_callback( int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, _Bool enable_VAD)
{
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return de_InvalidSelection;
lock;
running[input][device_idx]->cb = callback;
running[input][device_idx]->cb_data = data;
running[input][device_idx]->enable_VAD = enable_VAD;
running[input][device_idx]->call_idx = call_idx;
unlock;
return de_None;
}
inline__ DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t lenght, uint8_t channels)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
Device* device = running[output][device_idx];
if (!device || device->muted) return de_DeviceNotActive;
pthread_mutex_lock(device->mutex);
ALuint bufid;
ALint processed, queued;
alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed);
alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
if(processed) {
ALuint bufids[processed];
alSourceUnqueueBuffers(device->source, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
}
else if(queued < 16) alGenBuffers(1, &bufid);
else {
pthread_mutex_unlock(device->mutex);
return de_Busy;
}
alBufferData(bufid, device->sound_mode, data, lenght * 2 * channels, device->sample_rate);
alSourceQueueBuffers(device->source, 1, &bufid);
ALint state;
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
if(state != AL_PLAYING) alSourcePlay(device->source);
pthread_mutex_unlock(device->mutex);
return de_None;
}
void* thread_poll (void* arg) // TODO: maybe use thread for every input source
{
/*
* NOTE: We only need to poll input devices for data.
*/
(void)arg;
uint32_t i;
int32_t sample = 0;
while (thread_running)
{
if (thread_paused) usleep(10000); /* Wait for unpause. */
else
{
for (i = 0; i < size[input]; i ++)
{
lock;
if (running[input][i] != NULL)
{
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample);
int f_size = (running[input][i]->sample_rate * running[input][i]->frame_duration / 1000);
if (sample < f_size) {
unlock;
continue;
}
Device* device = running[input][i];
int16_t frame[16000];
alcCaptureSamples(device->dhndl, frame, f_size);
if ( device->muted
#ifdef _AUDIO
|| (device->enable_VAD && !toxav_has_activity(av, device->call_idx, frame, f_size, device->VAD_treshold))
#endif /* _AUDIO */
)
{ unlock; continue; } /* Skip if no voice activity */
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
}
unlock;
}
usleep(5000);
}
}
pthread_exit(NULL);
}
void print_devices(ToxWindow* self, DeviceType type)
{
int i = 0;
for ( ; i < size[type]; i ++)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, devices_names[type][i]);
return;
}
DeviceError selection_valid(DeviceType type, int32_t selection)
{
return (size[type] <= selection || selection < 0) ? de_InvalidSelection : de_None;
}
void* get_device_callback_data(uint32_t device_idx)
{
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return NULL;
return running[input][device_idx]->cb_data;
}

418
src/dns.c
View File

@ -1,418 +0,0 @@
/* dns.c
*
*
* Copyright (C) 2014 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 <sys/types.h> /* for u_char */
#include <netinet/in.h>
#include <resolv.h>
#ifdef __APPLE__
#include <arpa/nameser_compat.h>
#else
#include <arpa/nameser.h>
#endif /* ifdef __APPLE__ */
#include <tox/toxdns.h>
#include "toxic.h"
#include "windows.h"
#include "line_info.h"
#include "dns.h"
#include "global_commands.h"
#include "misc_tools.h"
#include "configdir.h"
#define DNS3_KEY_SIZE 32
#define MAX_DNS_REQST_SIZE 255
#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
extern struct _Winthread Winthread;
extern struct _dns3_servers dns3_servers;
extern struct arg_opts arg_opts;
#define NUM_DNS3_BACKUP_SERVERS 2
/* Hardcoded backup in case domain list is not loaded */
static struct dns3_server_backup {
const char *name;
char key[DNS3_KEY_SIZE];
} dns3_servers_backup[] = {
{
"utox.org",
{
0xD3, 0x15, 0x4F, 0x65, 0xD2, 0x8A, 0x5B, 0x41, 0xA0, 0x5D, 0x4A, 0xC7, 0xE4, 0xB3, 0x9C, 0x6B,
0x1C, 0x23, 0x3C, 0xC8, 0x57, 0xFB, 0x36, 0x5C, 0x56, 0xE8, 0x39, 0x27, 0x37, 0x46, 0x2A, 0x12
}
},
{
"toxme.se",
{
0x5D, 0x72, 0xC5, 0x17, 0xDF, 0x6A, 0xEC, 0x54, 0xF1, 0xE9, 0x77, 0xA6, 0xB6, 0xF2, 0x59, 0x14,
0xEA, 0x4C, 0xF7, 0x27, 0x7A, 0x85, 0x02, 0x7C, 0xD9, 0xF5, 0x19, 0x6D, 0xF1, 0x7E, 0x0B, 0x13
}
},
};
static struct _thread_data {
ToxWindow *self;
char id_bin[TOX_FRIEND_ADDRESS_SIZE];
char addr[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
uint8_t busy;
Tox *m;
} t_data;
static struct _dns_thread {
pthread_t tid;
pthread_attr_t attr;
} dns_thread;
#define MAX_DNS_SERVERS 50
#define MAX_DOMAIN_SIZE 32
#define MAX_DNS_LINE MAX_DOMAIN_SIZE + (DNS3_KEY_SIZE * 2) + 3
struct _dns3_servers {
bool loaded;
int lines;
char names[MAX_DNS_SERVERS][MAX_DOMAIN_SIZE];
char keys[MAX_DNS_SERVERS][DNS3_KEY_SIZE];
} dns3_servers;
static int load_dns_domainlist(const char *path)
{
FILE *fp = fopen(path, "r");
if (fp == NULL)
return -1;
char line[MAX_DNS_LINE];
while (fgets(line, sizeof(line), fp) && dns3_servers.lines < MAX_DNS_SERVERS) {
int linelen = strlen(line);
if (linelen < DNS3_KEY_SIZE * 2 + 5)
continue;
if (line[linelen - 1] == '\n')
line[--linelen] = '\0';
const char *name = strtok(line, " ");
const char *keystr = strtok(NULL, " ");
if (name == NULL || keystr == NULL)
continue;
if (strlen(keystr) != DNS3_KEY_SIZE * 2)
continue;
snprintf(dns3_servers.names[dns3_servers.lines], sizeof(dns3_servers.names[dns3_servers.lines]), "%s", name);
int res = hex_string_to_bytes(dns3_servers.keys[dns3_servers.lines], DNS3_KEY_SIZE, keystr);
if (res == -1)
continue;
++dns3_servers.lines;
}
fclose(fp);
if (dns3_servers.lines < 1)
return -2;
return 0;
}
static int dns_error(ToxWindow *self, const char *errmsg)
{
pthread_mutex_lock(&Winthread.lock);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "User lookup failed: %s", errmsg);
pthread_mutex_unlock(&Winthread.lock);
return -1;
}
static void kill_dns_thread(void *dns_obj)
{
if (dns_obj)
tox_dns3_kill(dns_obj);
memset(&t_data, 0, sizeof(struct _thread_data));
pthread_attr_destroy(&dns_thread.attr);
pthread_exit(NULL);
}
/* puts TXT from dns response in buf. Returns length of TXT on success, -1 on fail.*/
static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char *buf)
{
uint8_t *ans_pt = answer + sizeof(HEADER);
uint8_t *ans_end = answer + ans_len;
char exp_ans[PACKETSZ];
int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
if (len == -1)
return dns_error(self, "dn_expand failed.");
ans_pt += len;
if (ans_pt > ans_end - 4)
return dns_error(self, "DNS reply was too short.");
int type;
GETSHORT(type, ans_pt);
if (type != T_TXT)
return dns_error(self, "Broken DNS reply.");
ans_pt += INT16SZ; /* class */
uint32_t size = 0;
/* recurse through CNAME rr's */
do {
ans_pt += size;
len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
if (len == -1)
return dns_error(self, "Second dn_expand failed.");
ans_pt += len;
if (ans_pt > ans_end - 10)
return dns_error(self, "DNS reply was too short.");
GETSHORT(type, ans_pt);
ans_pt += INT16SZ;
ans_pt += 4;
GETSHORT(size, ans_pt);
if (ans_pt + size < answer || ans_pt + size > ans_end)
return dns_error(self, "RR overflow.");
} while (type == T_CNAME);
if (type != T_TXT)
return dns_error(self, "DNS response failed.");
uint32_t txt_len = *ans_pt;
if (!size || txt_len >= size || !txt_len)
return dns_error(self, "No record found.");
if (txt_len > MAX_DNS_REQST_SIZE)
return dns_error(self, "Invalid DNS response.");
ans_pt++;
ans_pt[txt_len] = '\0';
memcpy(buf, ans_pt, txt_len + 1);
return txt_len;
}
/* Takes address addr in the form "username@domain", puts the username in namebuf,
and the domain in dombuf.
return length of username on success, -1 on failure */
static int parse_addr(const char *addr, char *namebuf, char *dombuf)
{
char tmpaddr[MAX_STR_SIZE];
char *tmpname, *tmpdom;
strcpy(tmpaddr, addr);
tmpname = strtok(tmpaddr, "@");
tmpdom = strtok(NULL, "");
if (tmpname == NULL || tmpdom == NULL)
return -1;
str_to_lower(tmpdom);
strcpy(namebuf, tmpname);
strcpy(dombuf, tmpdom);
return strlen(namebuf);
}
/* matches input domain name with domains in list and obtains key. Return 0 on success, -1 on failure */
static int get_domain_match(char *pubkey, char *domain, const char *inputdomain)
{
/* check server list first */
int i;
bool match = false;
for (i = 0; i < dns3_servers.lines; ++i) {
if (strcmp(dns3_servers.names[i], inputdomain) == 0) {
memcpy(pubkey, dns3_servers.keys[i], DNS3_KEY_SIZE);
snprintf(domain, MAX_DOMAIN_SIZE, "%s", dns3_servers.names[i]);
match = true;
break;
}
}
/* fall back to hard-coded domains on server list failure */
if (!match) {
for (i = 0; i < NUM_DNS3_BACKUP_SERVERS; ++i) {
if (strcmp(dns3_servers_backup[i].name, inputdomain) == 0) {
memcpy(pubkey, dns3_servers_backup[i].key, DNS3_KEY_SIZE);
snprintf(domain, MAX_DOMAIN_SIZE, "%s", dns3_servers_backup[i].name);
match = true;
break;
}
}
if (!match)
return -1;
}
return 0;
}
/* Does DNS lookup for addr and puts resulting tox id in id_bin. */
void *dns3_lookup_thread(void *data)
{
ToxWindow *self = t_data.self;
char inputdomain[MAX_STR_SIZE];
char name[MAX_STR_SIZE];
int namelen = parse_addr(t_data.addr, name, inputdomain);
if (namelen == -1) {
dns_error(self, "Must be a Tox ID or an address in the form username@domain");
kill_dns_thread(NULL);
}
char DNS_pubkey[DNS3_KEY_SIZE];
char domain[MAX_DOMAIN_SIZE];
int match = get_domain_match(DNS_pubkey, domain, inputdomain);
if (match == -1) {
dns_error(self, "Domain not found.");
kill_dns_thread(NULL);
}
void *dns_obj = tox_dns3_new((uint8_t *) DNS_pubkey);
if (dns_obj == NULL) {
dns_error(self, "Core failed to create DNS object.");
kill_dns_thread(NULL);
}
char string[MAX_DNS_REQST_SIZE + 1];
uint32_t request_id;
int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id,
(uint8_t *) name, namelen);
if (str_len == -1) {
dns_error(self, "Core failed to generate DNS3 string.");
kill_dns_thread(dns_obj);
}
string[str_len] = '\0';
u_char answer[PACKETSZ];
char d_string[MAX_DOMAIN_SIZE + MAX_DNS_REQST_SIZE + 10];
/* format string and create dns query */
snprintf(d_string, sizeof(d_string), "_%s._tox.%s", string, domain);
int ans_len = res_query(d_string, C_IN, T_TXT, answer, sizeof(answer));
if (ans_len <= 0) {
dns_error(self, "DNS query failed.");
kill_dns_thread(dns_obj);
}
char ans_id[MAX_DNS_REQST_SIZE + 1];
/* extract TXT from DNS response */
if (parse_dns_response(self, answer, ans_len, ans_id) == -1)
kill_dns_thread(dns_obj);
char encrypted_id[MAX_DNS_REQST_SIZE + 1];
int prfx_len = strlen(TOX_DNS3_TXT_PREFIX);
/* extract the encrypted ID from TXT response */
if (strncmp(ans_id, TOX_DNS3_TXT_PREFIX, prfx_len) != 0) {
dns_error(self, "Bad DNS3 TXT response.");
kill_dns_thread(dns_obj);
}
memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len);
if (tox_decrypt_dns3_TXT(dns_obj, (uint8_t *) t_data.id_bin, (uint8_t *) encrypted_id,
strlen(encrypted_id), request_id) == -1) {
dns_error(self, "Core failed to decrypt DNS response.");
kill_dns_thread(dns_obj);
}
pthread_mutex_lock(&Winthread.lock);
cmd_add_helper(self, t_data.m, t_data.id_bin, t_data.msg);
pthread_mutex_unlock(&Winthread.lock);
kill_dns_thread(dns_obj);
return 0;
}
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg)
{
if (arg_opts.use_proxy && arg_opts.force_tcp) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "DNS lookups are disabled.");
return;
}
if (t_data.busy) {
const char *err = "Please wait for previous user lookup to finish.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, err);
return;
}
if (!dns3_servers.loaded) {
const char *path = arg_opts.dns_path[0] ? arg_opts.dns_path : PACKAGE_DATADIR "/DNSservers";
dns3_servers.loaded = true;
int ret = load_dns_domainlist(path);
if (ret < 0) {
const char *errmsg = "DNS server list failed to load with error code %d. Falling back to hard-coded list.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg, ret);
}
}
snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin);
snprintf(t_data.addr, sizeof(t_data.addr), "%s", addr);
snprintf(t_data.msg, sizeof(t_data.msg), "%s", msg);
t_data.self = self;
t_data.m = m;
t_data.busy = 1;
if (pthread_attr_init(&dns_thread.attr) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_ATTR);
if (pthread_attr_setdetachstate(&dns_thread.attr, PTHREAD_CREATE_DETACHED) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_ATTR);
if (pthread_create(&dns_thread.tid, &dns_thread.attr, dns3_lookup_thread, NULL) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_CREATE);
}

View File

@ -20,18 +20,20 @@
*
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "toxic.h"
#include "windows.h"
#include "execute.h"
#include "api.h"
#include "chat_commands.h"
#include "execute.h"
#include "global_commands.h"
#include "conference_commands.h"
#include "line_info.h"
#include "misc_tools.h"
#include "notify.h"
#include "toxic.h"
#include "windows.h"
struct cmd_func {
const char *name;
@ -41,97 +43,178 @@ struct cmd_func {
static struct cmd_func global_commands[] = {
{ "/accept", cmd_accept },
{ "/add", cmd_add },
{ "/avatar", cmd_avatar },
{ "/clear", cmd_clear },
{ "/connect", cmd_connect },
{ "/decline", cmd_decline },
{ "/exit", cmd_quit },
{ "/groupchat", cmd_groupchat },
{ "/conference", cmd_conference },
#ifdef GAMES
{ "/game", cmd_game },
#endif
{ "/help", cmd_prompt_help },
{ "/log", cmd_log },
{ "/myid", cmd_myid },
#ifdef QRCODE
{ "/myqr", cmd_myqr },
#endif /* QRCODE */
{ "/nick", cmd_nick },
{ "/note", cmd_note },
{ "/nospam", cmd_nospam },
{ "/q", cmd_quit },
{ "/quit", cmd_quit },
{ "/requests", cmd_requests },
{ "/status", cmd_status },
#ifdef _AUDIO
#ifdef AUDIO
{ "/lsdev", cmd_list_devices },
{ "/sdev", cmd_change_device },
#endif /* _AUDIO */
#endif /* AUDIO */
#ifdef VIDEO
{ "/lsvdev", cmd_list_video_devices },
{ "/svdev", cmd_change_video_device },
#endif /* VIDEO */
#ifdef PYTHON
{ "/run", cmd_run },
#endif /* PYTHON */
{ NULL, NULL },
};
static struct cmd_func chat_commands[] = {
{ "/cancel", cmd_cancelfile },
{ "/invite", cmd_groupinvite },
{ "/join", cmd_join_group },
{ "/savefile", cmd_savefile },
{ "/sendfile", cmd_sendfile },
#ifdef _AUDIO
{ "/call", cmd_call },
{ "/answer", cmd_answer },
{ "/reject", cmd_reject },
{ "/hangup", cmd_hangup },
{ "/sdev", cmd_ccur_device },
{ "/mute", cmd_mute },
{ "/sense", cmd_sense },
#endif /* _AUDIO */
{ "/cancel", cmd_cancelfile },
{ "/invite", cmd_conference_invite },
{ "/join", cmd_conference_join },
#ifdef GAMES
{ "/play", cmd_game_join },
#endif
{ "/savefile", cmd_savefile },
{ "/sendfile", cmd_sendfile },
#ifdef AUDIO
{ "/call", cmd_call },
{ "/answer", cmd_answer },
{ "/reject", cmd_reject },
{ "/hangup", cmd_hangup },
{ "/mute", cmd_mute },
{ "/sense", cmd_sense },
{ "/bitrate", cmd_bitrate },
#endif /* AUDIO */
#ifdef VIDEO
{ "/vcall", cmd_vcall },
{ "/video", cmd_video },
{ "/res", cmd_res },
#endif /* VIDEO */
{ NULL, NULL },
};
/* Parses input command and puts args into arg array.
Returns number of arguments on success, -1 on failure. */
static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
static struct cmd_func conference_commands[] = {
{ "/title", cmd_conference_set_title },
#ifdef AUDIO
{ "/audio", cmd_enable_audio },
{ "/mute", cmd_conference_mute },
{ "/ptt", cmd_conference_push_to_talk },
{ "/sense", cmd_conference_sense },
#endif /* AUDIO */
{ NULL, NULL },
};
/* Special commands are commands that only take one argument even if it contains spaces */
static const char special_commands[][MAX_CMDNAME_SIZE] = {
"/add",
"/avatar",
"/nick",
"/note",
#ifdef PYTHON
"/run",
#endif /* PYTHON */
"/sendfile",
"/title",
"/mute",
"",
};
/* Returns true if input command is in the special_commands array. */
static bool is_special_command(const char *input)
{
const int s = char_find(0, input, ' ');
for (int i = 0; special_commands[i][0] != '\0'; ++i) {
if (strncmp(input, special_commands[i], s) == 0) {
return true;
}
}
return false;
}
/* Parses commands in the special_commands array. Unlike parse_command, this function
* does not split the input string at spaces.
*
* Returns the number of arguments.
*/
static int parse_special_command(const char *input, char (*args)[MAX_STR_SIZE])
{
int len = strlen(input);
int s = char_find(0, input, ' ');
memcpy(args[0], input, s);
args[0][s++] = '\0'; // increment to remove space after "/command "
if (s >= len) {
return 1; // No additional args
}
memcpy(args[1], input + s, len - s);
args[1][len - s] = '\0';
return 2;
}
/* Parses input command and puts args into arg array.
*
* Returns the number of arguments.
*/
static int parse_command(const char *input, char (*args)[MAX_STR_SIZE])
{
if (is_special_command(input)) {
return parse_special_command(input, args);
}
char *cmd = strdup(input);
if (cmd == NULL)
if (cmd == NULL) {
exit_toxic_err("failed in parse_command", FATALERR_MEMORY);
}
int num_args = 0;
int i = 0; /* index of last char in an argument */
/* characters wrapped in double quotes count as one arg */
while (num_args < MAX_NUM_ARGS) {
int qt_ofst = 0; /* set to 1 to offset index for quote char at end of arg */
int i = char_find(0, cmd, ' '); // index of last char in an argument
memcpy(args[num_args], cmd, i);
args[num_args++][i] = '\0';
if (*cmd == '\"') {
qt_ofst = 1;
i = char_find(1, cmd, '\"');
if (cmd[i] == '\0') {
char *errmsg = "Invalid argument. Did you forget a closing \"?";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
free(cmd);
return -1;
}
} else {
i = char_find(0, cmd, ' ');
}
memcpy(args[num_args], cmd, i + qt_ofst);
args[num_args++][i + qt_ofst] = '\0';
if (cmd[i] == '\0') /* no more args */
if (cmd[i] == '\0') { // no more args
break;
}
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", &cmd[i + 1]);
strcpy(cmd, tmp);
strcpy(cmd, tmp); // tmp will always fit inside cmd
}
free(cmd);
return num_args;
}
/* Matches command to respective function. Returns 0 on match, 1 on no match */
static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, int num_cmds,
struct cmd_func *commands, char (*args)[MAX_STR_SIZE])
/* Matches command to respective function.
*
* Returns 0 on match.
* Returns 1 on no match
*/
static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands,
char (*args)[MAX_STR_SIZE])
{
int i;
for (i = 0; i < num_cmds; ++i) {
for (size_t i = 0; commands[i].name != NULL; ++i) {
if (strcmp(args[0], commands[i].name) == 0) {
(commands[i].func)(w, self, m, num_args - 1, args);
return 0;
@ -143,32 +226,49 @@ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, int num_
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
{
if (string_is_empty(input))
if (string_is_empty(input)) {
return;
}
char args[MAX_NUM_ARGS][MAX_STR_SIZE];
int num_args = parse_command(w, self, input, args);
int num_args = parse_command(input, args);
if (num_args == -1)
if (num_args <= 0) {
return;
}
/* Try to match input command to command functions. If non-global command mode is specified,
try specified mode's commands first, then upon failure try global commands.
Note: Global commands must come last in case of duplicate command names */
* try specified mode's commands first, then upon failure try global commands.
*
* Note: Global commands must come last in case of duplicate command names
*/
switch (mode) {
case CHAT_COMMAND_MODE:
if (do_command(w, self, m, num_args, CHAT_NUM_COMMANDS, chat_commands, args) == 0)
if (do_command(w, self, m, num_args, chat_commands, args) == 0) {
return;
}
break;
case GROUPCHAT_COMMAND_MODE:
case CONFERENCE_COMMAND_MODE:
if (do_command(w, self, m, num_args, conference_commands, args) == 0) {
return;
}
break;
}
if (do_command(w, self, m, num_args, GLOBAL_NUM_COMMANDS, global_commands, args) == 0)
if (do_command(w, self, m, num_args, global_commands, args) == 0) {
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
#ifdef PYTHON
if (do_plugin_command(num_args, args) == 0) {
return;
}
#endif
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
}

View File

@ -20,28 +20,20 @@
*
*/
#ifndef _execute_h
#define _execute_h
#ifndef EXECUTE_H
#define EXECUTE_H
#include "toxic.h"
#include "windows.h"
#define MAX_NUM_ARGS 4 /* Includes command */
#ifdef _AUDIO
#define GLOBAL_NUM_COMMANDS 18
#define CHAT_NUM_COMMANDS 12
#else
#define GLOBAL_NUM_COMMANDS 16
#define CHAT_NUM_COMMANDS 5
#endif /* _AUDIO */
enum {
GLOBAL_COMMAND_MODE,
CHAT_COMMAND_MODE,
GROUPCHAT_COMMAND_MODE,
CONFERENCE_COMMAND_MODE,
};
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode);
#endif /* #define _execute_h */
#endif /* EXECUTE_H */

View File

@ -1,290 +0,0 @@
/* file_senders.c
*
*
* Copyright (C) 2014 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 <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "toxic.h"
#include "windows.h"
#include "friendlist.h"
#include "file_senders.h"
#include "line_info.h"
#include "misc_tools.h"
#include "notify.h"
FileSender file_senders[MAX_FILES];
uint8_t max_file_senders_index;
uint8_t num_active_file_senders;
extern _Friends Friends;
/* creates initial progress line that will be updated during file transfer.
Assumes progline is of size MAX_STR_SIZE */
void prep_prog_line(char *progline)
{
strcpy(progline, "0.0 B/s [");
int i;
for (i = 0; i < NUM_PROG_MARKS; ++i)
strcat(progline, "-");
strcat(progline, "] 0%");
}
/* 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, int idx, int friendnum, double pct_done)
{
double bps;
uint32_t line_id;
if (friendnum < 0) {
bps = file_senders[idx].bps;
line_id = file_senders[idx].line_id;
} else {
bps = Friends.list[friendnum].file_receiver[idx].bps;
line_id = Friends.list[friendnum].file_receiver[idx].line_id;
}
char msg[MAX_STR_SIZE];
bytes_convert_str(msg, sizeof(msg), bps);
strcat(msg, "/s [");
int n = pct_done / (100 / NUM_PROG_MARKS);
int i, j;
for (i = 0; i < n; ++i)
strcat(msg, "#");
for (j = i; j < NUM_PROG_MARKS; ++j)
strcat(msg, "-");
strcat(msg, "] ");
char pctstr[16];
const char *frmt = pct_done == 100 ? "%.f%%" : "%.1f%%";
snprintf(pctstr, sizeof(pctstr), frmt, pct_done);
strcat(msg, pctstr);
line_info_set(self, line_id, msg);
}
/* refreshes active file receiver status bars */
static void refresh_recv_prog(Tox *m)
{
int i;
uint64_t curtime = get_unix_time();
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *toxwin = get_window_ptr(i);
if (toxwin == NULL || !toxwin->is_chat)
continue;
int fnum = toxwin->num;
int j;
for (j = 0; j < MAX_FILES; ++j) {
if (!Friends.list[fnum].file_receiver[j].active)
continue;
int filenum = Friends.list[fnum].file_receiver[j].filenum;
double remain = (double) tox_file_data_remaining(m, fnum, filenum, 1);
/* must be called once per second */
if (timed_out(Friends.list[fnum].file_receiver[filenum].last_progress, curtime, 1)) {
Friends.list[fnum].file_receiver[filenum].last_progress = curtime;
uint64_t size = Friends.list[fnum].file_receiver[filenum].size;
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
print_progress_bar(toxwin, filenum, fnum, pct_done);
Friends.list[fnum].file_receiver[filenum].bps = 0;
}
}
}
}
/* refreshes active file sender status bars */
static void refresh_sender_prog(Tox *m)
{
int i;
uint64_t curtime = get_unix_time();
for (i = 0; i < max_file_senders_index; ++i) {
if (!file_senders[i].active || file_senders[i].finished)
continue;
int filenum = file_senders[i].filenum;
int32_t friendnum = file_senders[i].friendnum;
double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0);
/* must be called once per second */
if (timed_out(file_senders[i].last_progress, curtime, 1)) {
file_senders[i].last_progress = curtime;
double pct_done = remain > 0 ? (1 - (remain / file_senders[i].size)) * 100 : 100;
print_progress_bar(file_senders[i].toxwin, i, -1, pct_done);
file_senders[i].bps = 0;
}
}
}
static void set_max_file_senders_index(void)
{
int j;
for (j = max_file_senders_index; j > 0; --j) {
if (file_senders[j - 1].active)
break;
}
max_file_senders_index = j;
}
/* called whenever a file sender is opened or closed */
void reset_file_sender_queue(void)
{
int i;
int pos = 0;
for (i = 0; i < max_file_senders_index; ++i) {
if (file_senders[i].active)
file_senders[i].queue_pos = pos++;
}
}
/* set CTRL to -1 if we don't want to send a control signal.
set msg to NULL if we don't want to display a message */
void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum)
{
if (msg != NULL)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
if (CTRL > 0)
tox_file_send_control(m, friendnum, 0, filenum, CTRL, 0, 0);
fclose(file_senders[i].file);
memset(&file_senders[i], 0, sizeof(FileSender));
set_max_file_senders_index();
reset_file_sender_queue();
--num_active_file_senders;
}
void close_all_file_senders(Tox *m)
{
int i;
for (i = 0; i < max_file_senders_index; ++i) {
if (file_senders[i].active) {
fclose(file_senders[i].file);
tox_file_send_control(m, file_senders[i].friendnum, 0, file_senders[i].filenum,
TOX_FILECONTROL_KILL, 0, 0);
memset(&file_senders[i], 0, sizeof(FileSender));
}
set_max_file_senders_index();
}
}
static void send_file_data(ToxWindow *self, Tox *m, int i, int32_t friendnum, int filenum, const char *filename)
{
FILE *fp = file_senders[i].file;
while (true) {
if (tox_file_send_data(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece,
file_senders[i].piecelen) == -1)
return;
file_senders[i].timestamp = get_unix_time();
file_senders[i].bps += file_senders[i].piecelen;
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
tox_file_data_size(m, friendnum), fp);
/* note: file sender is closed in chat_onFileControl callback after receiving reply */
if (file_senders[i].piecelen == 0) {
if (feof(fp) != 0) { /* make sure we're really at eof */
print_progress_bar(self, i, -1, 100.0);
tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0);
file_senders[i].finished = true;
} else {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read error.", file_senders[i].filename);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
sound_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, NULL);
if (self->active_box != -1)
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg);
else
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg);
}
return;
}
}
}
void do_file_senders(Tox *m)
{
int i;
for (i = 0; i < max_file_senders_index; ++i) {
if (!file_senders[i].active)
continue;
if (file_senders[i].queue_pos > 0) {
--file_senders[i].queue_pos;
continue;
}
ToxWindow *self = file_senders[i].toxwin;
char *filename = file_senders[i].filename;
int filenum = file_senders[i].filenum;
int32_t friendnum = file_senders[i].friendnum;
/* kill file transfer if chatwindow is closed */
if (self->chatwin == NULL) {
close_file_sender(self, m, i, NULL, TOX_FILECONTROL_KILL, filenum, friendnum);
continue;
}
/* If file transfer has timed out kill transfer and send kill control */
if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)) {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", filename);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
sound_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, NULL);
if (self->active_box != -1)
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg);
else
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg);
continue;
}
if (!file_senders[i].noconnection && !file_senders[i].finished)
send_file_data(self, m, i, friendnum, filenum, filename);
file_senders[i].queue_pos = num_active_file_senders - 1;
}
refresh_sender_prog(m);
refresh_recv_prog(m);
}

View File

@ -1,75 +0,0 @@
/* file_senders.h
*
*
* Copyright (C) 2014 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 _filesenders_h
#define _filesenders_h
#include "toxic.h"
#include "windows.h"
#define KiB 1024
#define MiB 1048576 /* 1024 ^ 2 */
#define GiB 1073741824 /* 1024 ^ 3 */
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
#define MAX_FILES 32
#define TIMEOUT_FILESENDER 120
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
typedef struct {
FILE *file;
ToxWindow *toxwin;
int32_t friendnum;
bool active;
bool noconnection;
bool finished;
int filenum;
char nextpiece[FILE_PIECE_SIZE];
uint16_t piecelen;
char filename[MAX_STR_SIZE];
uint64_t timestamp;
uint64_t last_progress;
double bps;
uint64_t size;
uint32_t line_id;
uint8_t queue_pos;
} FileSender;
/* creates initial progress line that will be updated during file transfer.
Assumes progline is of size MAX_STR_SIZE */
void prep_prog_line(char *progline);
/* 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, int idx, int friendnum, double pct_remain);
/* set CTRL to -1 if we don't want to send a control signal.
set msg to NULL if we don't want to display a message */
void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum);
/* called whenever a file sender is opened or closed */
void reset_file_sender_queue(void);
void close_all_file_senders(Tox *m);
void do_file_senders(Tox *m);
#endif /* #define _filesenders_h */

Some files were not shown because too many files have changed in this diff Show More