1
0
mirror of https://github.com/Tha14/toxic.git synced 2025-06-28 00:16:44 +02:00

Compare commits

..

23 Commits

Author SHA1 Message Date
fd263e3e0a Add config option to show real-time network info in UI 2022-03-20 11:16:46 -04:00
15ab58aa13 Add run time, avg. kb/s and packets/s to netprof log dump 2022-03-20 11:16:46 -04:00
b91f5a8758 Add tox network profiling
Profiling can be enabled with the -s run option
2022-03-20 11:16:11 -04:00
cec96e1ea3 Use calloc instead of malloc for new message queue items
This prevents us from accidentally using uninitialized memory
2022-03-18 12:17:50 -04:00
eb7e6151a2 cleanup: Ensure python_api.c is never completely empty.
C doesn't allow this, there must be at least some declarations in it,
even if no code.
2022-03-17 17:52:37 +00:00
22ca3704d2 Use a small hack to get around an ncurses buffer overread
Patch by iphydf
2022-03-16 16:31:41 -04:00
fdfaaf953f cleanup: Remove all uses of deprecated enum names.
All-caps enum names have been deprecated for a while now and will go
away in 0.3.0.
2022-03-07 19:20:35 +00:00
310cf464d0 Fix bug causing messages containing newline byte to disappear
The wcswidth() function was silently failing when trying to convert
messages containing a newline to a widechar buffer which resulted
in the message showing up as an empty line. we now fall back
to using strlen to get the width of the string, which might still
cause minor display bugs when the message contains unicode, but is
still better than losing messages entirely.
2022-03-02 15:58:21 -05:00
0c11b3121a Update static musl build script
Bump toxcore to v0.2.16 and add new msgpack dependency
2022-02-20 13:12:23 -05:00
1bdf0041bc Bump toxic and curl versions in static build script 2022-02-12 21:17:19 -05:00
6a203fd7bf Make sure we compare wchars to wchars instead of bytes 2022-02-03 13:01:08 -05:00
93b3bbd5f6 chore: Use latest instead of versioned toktok-stack image. 2022-01-30 19:32:00 +00:00
e122c5dbca Use widechars to display strings in the UI
This fixes a bug where printing a bunch of UTF8 chars with glyphs
that have a size > 1 would make the entire chat window disappear.
It also fixes an issue where said UTF8 chars would be truncated
and generally not display correctly.
2022-01-27 15:45:56 -05:00
f6f41a510b Add some simple impersonation detection on friend requests
This will alert the user when the first six bytes of a new
contact's public key is the same as any other contact in
their list. These 6 bytes are used elsewhere in toxic for
unique identification.

Also did a small refactor regarding the KEY_IDENT_BYTES
define
2022-01-23 11:32:57 -05:00
05dbc626e2 Make sure we check for duplicate paths in pending file transfers list
This fixes a bug where if you receive multiple file transfer
requests simultaneously and they have the same path the files
will overwrite each other
2022-01-17 10:53:34 -05:00
ceb175e3f1 chore: Add check that the static build script works.
Otherwise it'll break again in the future and we won't know.
2022-01-13 01:37:24 +00:00
4bd1d9bfee Update libbrotli pc file sed
libbrotli has updated its .pc files since the last sed was written, so
it didn't work anymore, resulting in Toxic build failing. However, the
way they have updated it, it's still broken, so a different sed is
needed.
2022-01-05 15:55:30 -05:00
55944aa5a9 Remove broken Docker check
The Docker detection method doesn't work on cgroup v2 systems, so the
script just keeps erroring out.

There doesn't seem to be a simple way to detect that we are running
inside a Docker container, so it makes sense to drop that check
altogether.
2022-01-05 15:52:57 -05:00
b71c6a3792 Improve static build script documentation 2022-01-05 15:51:52 -05:00
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
33 changed files with 914 additions and 169 deletions

View File

@ -1,7 +1,7 @@
--- ---
cirrus-ci_task: bazel-opt_task:
container: container:
image: toxchat/toktok-stack:0.0.23-third_party image: toxchat/toktok-stack:latest-release
cpu: 2 cpu: 2
memory: 2G memory: 2G
configure_script: configure_script:
@ -9,5 +9,4 @@ cirrus-ci_task:
test_all_script: test_all_script:
- cd /src/workspace && bazel test -k - cd /src/workspace && bazel test -k
--remote_http_cache=http://$CIRRUS_HTTP_CACHE_HOST --remote_http_cache=http://$CIRRUS_HTTP_CACHE_HOST
--config=release
//toxic/... //toxic/...

View File

@ -12,7 +12,8 @@ branches:
required_status_checks: required_status_checks:
contexts: contexts:
- build - build
- cirrus-ci - build-static
- bazel-opt
- Codacy Static Code Analysis - Codacy Static Code Analysis
- code-review/reviewable - code-review/reviewable
- infer - infer

View File

@ -18,6 +18,7 @@ jobs:
libalut-dev libalut-dev
libconfig-dev libconfig-dev
libcurl4-gnutls-dev libcurl4-gnutls-dev
libmsgpack-dev
libnotify-dev libnotify-dev
libopenal-dev libopenal-dev
libopus-dev libopus-dev
@ -37,6 +38,22 @@ jobs:
- name: Build toxic - name: Build toxic
run: make -j4 run: make -j4
build-static:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Build minimal static toxic binary
run: docker run --rm
-v /tmp/artifact:/artifact
-v $PWD:/toxic
amd64/alpine:latest
sh -c 'yes | /toxic/script/build-minimal-static-toxic.sh'
- name: Display binary checksum
run: |
tar Jxf /tmp/artifact/toxic-minimal-static-musl_linux_x86-64.tar.xz
sha256sum toxic-minimal-static-musl_linux_x86-64/toxic
infer: infer:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: toxchat/infer container: toxchat/infer
@ -56,6 +73,7 @@ jobs:
libalut-dev libalut-dev
libconfig-dev libconfig-dev
libcurl4-gnutls-dev libcurl4-gnutls-dev
libmsgpack-dev
libncurses-dev libncurses-dev
libnotify-dev libnotify-dev
libopenal-dev libopenal-dev
@ -87,6 +105,7 @@ jobs:
libnotify libnotify
libpng libpng
libqrencode libqrencode
msgpack
ncurses ncurses
openal openal
python3 python3

View File

@ -1,6 +1,8 @@
load("@rules_cc//cc:defs.bzl", "cc_binary") load("@rules_cc//cc:defs.bzl", "cc_binary")
load("//tools/project:build_defs.bzl", "project") load("//tools/project:build_defs.bzl", "project")
package(features = ["layering_check"])
project() project()
cc_binary( cc_binary(
@ -43,7 +45,7 @@ cc_binary(
sh_test( sh_test(
name = "toxic_test", name = "toxic_test",
size = "small",
srcs = [":toxic"], srcs = [":toxic"],
args = ["--help"], args = ["--help"],
size = "small",
) )

View File

@ -14,7 +14,7 @@ LDFLAGS += ${USER_LDFLAGS}
OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o
OBJ += file_transfers.o friendlist.o global_commands.o conference_commands.o conference.o help.o input.o line_info.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 += log.o message_queue.o misc_tools.o name_lookup.o netprof.o notify.o prompt.o qr_code.o settings.o
OBJ += term_mplex.o toxic.o toxic_strings.o windows.o OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
# Check if debug build is enabled # Check if debug build is enabled

View File

@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.11.2' version = '0.11.3'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.11.2' release = '0.11.3'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -1,5 +1,5 @@
# Version # Version
TOXIC_VERSION = 0.11.2 TOXIC_VERSION = 0.11.3
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error") REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
ifneq (, $(findstring error, $(REV))) ifneq (, $(findstring error, $(REV)))
VERSION = $(TOXIC_VERSION) VERSION = $(TOXIC_VERSION)

View File

@ -138,6 +138,11 @@ Show welcome message on startup\&. true or false
Enable friend connection change notifications\&. true or false Enable friend connection change notifications\&. true or false
.RE .RE
.PP .PP
\fBshow_network_info\fR
.RS 4
Show network information in the UI home window\&. true or false
.RE
.PP
\fBnodelist_update_freq\fR \fBnodelist_update_freq\fR
.RS 4 .RS 4
How often in days to update the DHT nodes list\&. (integer; 0 to disable) How often in days to update the DHT nodes list\&. (integer; 0 to disable)

View File

@ -87,6 +87,9 @@ OPTIONS
*show_connection_msg*;; *show_connection_msg*;;
Enable friend connection change notifications. true or false Enable friend connection change notifications. true or false
*show_network_info*;;
Show network information in the UI home window. true or false
*nodelist_update_freq*;; *nodelist_update_freq*;;
How often in days to update the DHT nodes list. (integer; 0 to disable) How often in days to update the DHT nodes list. (integer; 0 to disable)

View File

@ -56,6 +56,9 @@ ui = {
// true to show friend connection change messages on the home screen // true to show friend connection change messages on the home screen
show_connection_msg=true; show_connection_msg=true;
// true to show network information in the UI home window
show_network_info=true;
// How often in days to update the DHT nodes list. (0 to disable updates) // How often in days to update the DHT nodes list. (0 to disable updates)
nodeslist_update_freq=7; nodeslist_update_freq=7;

View File

@ -2,7 +2,7 @@
# MIT License # MIT License
# #
# Copyright (c) 2021 Maxim Biro <nurupo.contributions@gmail.com> # Copyright (c) 2021-2022 Maxim Biro <nurupo.contributions@gmail.com>
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
@ -36,8 +36,19 @@
# #
# that would use Toxic code from /home/jfreegman/git/toxic and place the build # that would use Toxic code from /home/jfreegman/git/toxic and place the build
# artifact at /tmp/artifact. # artifact at /tmp/artifact.
# You can change between amd64/alpine:latest and i386/alpine:latest, for 64-bit #
# and 32-bit builds. # You can change between:
# amd64/alpine:latest,
# i386/alpine:latest,
# arm64v8/alpine:latest,
# arm32v7/alpine:latest,
# arm32v6/alpine:latest,
# ppc64le/alpine:latest,
# s390x/alpine:latest,
# etc.
# as long as your system can run foreign architecture binaries, e.g. via qemu
# static bins and binfmt (install qemu-user-static package on Debian/Ubuntu).
#
# #
# To debug, run: # To debug, run:
# #
@ -53,13 +64,6 @@ set -eu
ARTIFACT_DIR="/artifact" ARTIFACT_DIR="/artifact"
TOXIC_SRC_DIR="/toxic" 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 if [ ! -f /etc/os-release ] || ! grep -qi 'Alpine Linux' /etc/os-release
then then
echo "Error: This script expects to be run on Alpine Linux." echo "Error: This script expects to be run on Alpine Linux."
@ -110,6 +114,7 @@ apk add \
libsodium-dev \ libsodium-dev \
libsodium-static \ libsodium-static \
linux-headers \ linux-headers \
msgpack-c-dev \
ncurses-dev \ ncurses-dev \
ncurses-static \ ncurses-static \
ncurses-terminfo \ ncurses-terminfo \
@ -132,10 +137,10 @@ mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR" cd "$BUILD_DIR"
# The git hash of the c-toxcore version we're using # The git hash of the c-toxcore version we're using
TOXCORE_VERSION="af1848ed13d2aa3a7fc218de1d0633e99814efec" TOXCORE_VERSION="v0.2.16"
# The sha256sum of the c-toxcore tarball for TOXCORE_VERSION # The sha256sum of the c-toxcore tarball for TOXCORE_VERSION
TOXCORE_HASH="acd1117b752583eb7d97aabc1053275ffa5f92591e166687a17c7267201a2e18" TOXCORE_HASH="653aa42654b607f0940cecfac873e9ce55605119a90d1dc454d1090ff6ca29c0"
TOXCORE_FILENAME="c-toxcore-$TOXCORE_VERSION.tar.gz" TOXCORE_FILENAME="c-toxcore-$TOXCORE_VERSION.tar.gz"
@ -164,8 +169,8 @@ cmake --build _build --target install
# location with SSL_CERT_FILE env variable. # location with SSL_CERT_FILE env variable.
cd "$BUILD_DIR" cd "$BUILD_DIR"
CURL_VERSION="7.80.0" CURL_VERSION="7.81.0"
CURL_HASH="dab997c9b08cb4a636a03f2f7f985eaba33279c1c52692430018fae4a4878dc7" CURL_HASH="ac8e1087711084548d788ef18b9b732c8de887457b81f616fc681d1044b32f98"
CURL_FILENAME="curl-$CURL_VERSION.tar.gz" CURL_FILENAME="curl-$CURL_VERSION.tar.gz"
wget --timeout=10 -O "$CURL_FILENAME" "https://curl.haxx.se/download/$CURL_FILENAME" wget --timeout=10 -O "$CURL_FILENAME" "https://curl.haxx.se/download/$CURL_FILENAME"
@ -186,7 +191,8 @@ cd curl*
--with-openssl --with-openssl
make make
make install make install
sed -i 's|-lbrotlidec |-lbrotlidec-static -lbrotlicommon-static |g' $BUILD_DIR/prefix-curl/lib/pkgconfig/libcurl.pc sed -i 's|-lbrotlidec |-lbrotlidec -lbrotlicommon |g' $BUILD_DIR/prefix-curl/lib/pkgconfig/libcurl.pc
# Build Toxic # Build Toxic
cd "$BUILD_DIR" cd "$BUILD_DIR"
@ -301,4 +307,3 @@ mv "$PREPARE_ARTIFACT_DIR" "$PREPARE_ARTIFACT_DIR/../$ARTIFACT_NAME"
tar -cJf "$ARTIFACT_NAME.tar.xz" "$ARTIFACT_NAME" tar -cJf "$ARTIFACT_NAME.tar.xz" "$ARTIFACT_NAME"
mv "$ARTIFACT_NAME.tar.xz" "$ARTIFACT_DIR" mv "$ARTIFACT_NAME.tar.xz" "$ARTIFACT_DIR"
chmod 777 -R "$ARTIFACT_DIR" chmod 777 -R "$ARTIFACT_DIR"

View File

@ -130,7 +130,7 @@ static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
TOX_ERR_SET_TYPING err; Tox_Err_Set_Typing err;
tox_self_set_typing(m, self->num, is_typing, &err); tox_self_set_typing(m, self->num, is_typing, &err);
if (err != TOX_ERR_SET_TYPING_OK) { if (err != TOX_ERR_SET_TYPING_OK) {
@ -248,6 +248,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
if (prev_status == TOX_CONNECTION_NONE) { if (prev_status == TOX_CONNECTION_NONE) {
chat_resume_file_senders(self, m, num); chat_resume_file_senders(self, m, num);
file_send_queue_check(self, m, self->num);
msg = "has come online"; msg = "has come online";
line_info_add(self, true, nick, NULL, CONNECTION, 0, GREEN, msg); line_info_add(self, true, nick, NULL, CONNECTION, 0, GREEN, msg);
@ -675,8 +676,10 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
FILE *filecheck = NULL; FILE *filecheck = NULL;
int count = 1; int count = 1;
while ((filecheck = fopen(file_path, "r"))) { while ((filecheck = fopen(file_path, "r")) || file_transfer_recv_path_exists(file_path)) {
fclose(filecheck); if (filecheck) {
fclose(filecheck);
}
file_path[path_len] = '\0'; file_path[path_len] = '\0';
char d[5]; char d[5];
@ -1382,7 +1385,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
self->x = x2; self->x = x2;
/* Truncate note if it doesn't fit in statusbar */ /* Truncate note if it doesn't fit in statusbar */
size_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 6; size_t maxlen = x2 - getcurx(statusbar->topline) - KEY_IDENT_BYTES - 6;
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
size_t statusmsg_len = statusbar->statusmsg_len; size_t statusmsg_len = statusbar->statusmsg_len;
@ -1413,10 +1416,10 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
int s_x; int s_x;
getyx(statusbar->topline, s_y, s_x); getyx(statusbar->topline, s_y, s_x);
mvwhline(statusbar->topline, s_y, s_x, ' ', x2 - s_x - (KEY_IDENT_DIGITS * 2) - 3); mvwhline(statusbar->topline, s_y, s_x, ' ', x2 - s_x - KEY_IDENT_BYTES - 3);
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT)); wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3); wmove(statusbar->topline, 0, x2 - KEY_IDENT_BYTES - 3);
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT)); wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "{"); wprintw(statusbar->topline, "{");
@ -1424,7 +1427,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT)); wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
for (size_t i = 0; i < KEY_IDENT_DIGITS; ++i) { for (size_t i = 0; i < KEY_IDENT_BYTES / 2; ++i) {
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff); wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
} }

View File

@ -54,7 +54,13 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
return; return;
} }
struct FileTransfer *ft = NULL; // 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;
}
FileTransfer *ft = NULL;
/* cancel an incoming file transfer */ /* cancel an incoming file transfer */
if (strcasecmp(inoutstr, "in") == 0) { if (strcasecmp(inoutstr, "in") == 0) {
@ -239,7 +245,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return; return;
} }
struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV); FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
if (!ft) { if (!ft) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
@ -324,7 +330,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
FILE *file_to_send = fopen(path, "r"); FILE *file_to_send = fopen(path, "r");
if (file_to_send == NULL) { if (file_to_send == NULL) {
line_info_add(self, false, 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; return;
} }
@ -347,7 +353,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
goto on_send_error; goto on_send_error;
} }
struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA); FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);
if (!ft) { if (!ft) {
err = TOX_ERR_FILE_SEND_TOO_MANY; err = TOX_ERR_FILE_SEND_TOO_MANY;
@ -367,29 +373,62 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
on_send_error: on_send_error:
fclose(file_to_send);
switch (err) { switch (err) {
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: {
errmsg = "File transfer failed: Invalid friend."; errmsg = "File transfer failed: Invalid friend.";
break; break;
}
case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED: case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED: {
errmsg = "File transfer failed: Friend is offline."; int queue_idx = file_send_queue_add(self->num, path, path_len);
break;
case TOX_ERR_FILE_SEND_NAME_TOO_LONG: 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);
return;
}
case TOX_ERR_FILE_SEND_NAME_TOO_LONG: {
errmsg = "File transfer failed: Filename is too long."; errmsg = "File transfer failed: Filename is too long.";
break; break;
}
case TOX_ERR_FILE_SEND_TOO_MANY: case TOX_ERR_FILE_SEND_TOO_MANY: {
errmsg = "File transfer failed: Too many concurrent file transfers."; errmsg = "File transfer failed: Too many concurrent file transfers.";
break; break;
}
default: default: {
errmsg = "File transfer failed."; errmsg = "File transfer failed.";
break; break;
}
} }
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg); 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); tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
fclose(file_to_send);
} }

View File

@ -25,6 +25,7 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include "execute.h"
#include "file_transfers.h" #include "file_transfers.h"
#include "friendlist.h" #include "friendlist.h"
#include "line_info.h" #include "line_info.h"
@ -44,9 +45,8 @@ extern FriendsList Friends;
void init_progress_bar(char *progline) void init_progress_bar(char *progline)
{ {
strcpy(progline, "0% ["); strcpy(progline, "0% [");
int i;
for (i = 0; i < NUM_PROG_MARKS; ++i) { for (size_t i = 0; i < NUM_PROG_MARKS; ++i) {
strcat(progline, "-"); strcat(progline, "-");
} }
@ -98,7 +98,7 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
free(full_line); free(full_line);
} }
static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft) static void refresh_progress_helper(ToxWindow *self, FileTransfer *ft)
{ {
if (ft->state == FILE_TRANSFER_INACTIVE) { if (ft->state == FILE_TRANSFER_INACTIVE) {
return; return;
@ -126,8 +126,8 @@ bool refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber)
bool active = false; bool active = false;
for (size_t i = 0; i < MAX_FILES; ++i) { for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft_r = &Friends.list[friendnumber].file_receiver[i]; FileTransfer *ft_r = &Friends.list[friendnumber].file_receiver[i];
struct FileTransfer *ft_s = &Friends.list[friendnumber].file_sender[i]; FileTransfer *ft_s = &Friends.list[friendnumber].file_sender[i];
refresh_progress_helper(self, ft_r); refresh_progress_helper(self, ft_r);
refresh_progress_helper(self, ft_s); refresh_progress_helper(self, ft_s);
@ -140,9 +140,9 @@ bool refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber)
return active; return active;
} }
static void clear_file_transfer(struct FileTransfer *ft) static void clear_file_transfer(FileTransfer *ft)
{ {
*ft = (struct FileTransfer) { *ft = (FileTransfer) {
0 0
}; };
} }
@ -150,16 +150,16 @@ static void clear_file_transfer(struct FileTransfer *ft)
/* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber. /* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber.
* Returns NULL if filenumber is invalid. * Returns NULL if filenumber is invalid.
*/ */
struct FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t filenumber) FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t filenumber)
{ {
for (size_t i = 0; i < MAX_FILES; ++i) { for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft_send = &Friends.list[friendnumber].file_sender[i]; FileTransfer *ft_send = &Friends.list[friendnumber].file_sender[i];
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenumber == filenumber) { if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenumber == filenumber) {
return ft_send; return ft_send;
} }
struct FileTransfer *ft_recv = &Friends.list[friendnumber].file_receiver[i]; FileTransfer *ft_recv = &Friends.list[friendnumber].file_receiver[i];
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenumber == filenumber) { if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenumber == filenumber) {
return ft_recv; return ft_recv;
@ -172,7 +172,7 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t fi
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified. /* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
* Returns NULL on failure. * Returns NULL on failure.
*/ */
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint32_t index, FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint32_t index,
FILE_TRANSFER_DIRECTION direction) FILE_TRANSFER_DIRECTION direction)
{ {
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND) { if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND) {
@ -180,9 +180,9 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint3
} }
for (size_t i = 0; i < MAX_FILES; ++i) { for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ? FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
&Friends.list[friendnumber].file_sender[i] : &Friends.list[friendnumber].file_sender[i] :
&Friends.list[friendnumber].file_receiver[i]; &Friends.list[friendnumber].file_receiver[i];
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index) { if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index) {
return ft; return ft;
@ -195,10 +195,10 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint3
/* Returns a pointer to an unused file sender. /* Returns a pointer to an unused file sender.
* Returns NULL if all file senders are in use. * Returns NULL if all file senders are in use.
*/ */
static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber, uint8_t type) static FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber, uint8_t type)
{ {
for (size_t i = 0; i < MAX_FILES; ++i) { for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i]; FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
if (ft->state == FILE_TRANSFER_INACTIVE) { if (ft->state == FILE_TRANSFER_INACTIVE) {
clear_file_transfer(ft); clear_file_transfer(ft);
@ -218,11 +218,11 @@ static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnu
/* Returns a pointer to an unused file receiver. /* Returns a pointer to an unused file receiver.
* Returns NULL if all file receivers are in use. * Returns NULL if all file receivers are in use.
*/ */
static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber, static FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
uint8_t type) uint8_t type)
{ {
for (size_t i = 0; i < MAX_FILES; ++i) { for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnumber].file_receiver[i]; FileTransfer *ft = &Friends.list[friendnumber].file_receiver[i];
if (ft->state == FILE_TRANSFER_INACTIVE) { if (ft->state == FILE_TRANSFER_INACTIVE) {
clear_file_transfer(ft); clear_file_transfer(ft);
@ -242,8 +242,8 @@ static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friend
/* Initializes an unused file transfer and returns its pointer. /* Initializes an unused file transfer and returns its pointer.
* Returns NULL on failure. * Returns NULL on failure.
*/ */
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber, FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
FILE_TRANSFER_DIRECTION direction, uint8_t type) FILE_TRANSFER_DIRECTION direction, uint8_t type)
{ {
if (direction == FILE_TRANSFER_RECV) { if (direction == FILE_TRANSFER_RECV) {
return new_file_receiver(window, friendnumber, filenumber, type); return new_file_receiver(window, friendnumber, filenumber, type);
@ -256,13 +256,83 @@ struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber,
return NULL; return NULL;
} }
int file_send_queue_add(uint32_t friendnumber, const char *file_path, size_t length)
{
if (length == 0 || file_path == NULL) {
return -1;
}
if (length > TOX_MAX_FILENAME_LENGTH) {
return -2;
}
for (size_t i = 0; i < MAX_FILES; ++i) {
PendingFileTransfer *pending_slot = &Friends.list[friendnumber].file_send_queue[i];
if (pending_slot->pending) {
continue;
}
pending_slot->pending = true;
memcpy(pending_slot->file_path, file_path, length);
pending_slot->file_path[length] = 0;
pending_slot->length = length;
return i;
}
return -3;
}
#define FILE_TRANSFER_SEND_CMD "/sendfile "
#define FILE_TRANSFER_SEND_LEN (sizeof(FILE_TRANSFER_SEND_CMD) - 1)
void file_send_queue_check(ToxWindow *self, Tox *m, uint32_t friendnumber)
{
for (size_t i = 0; i < MAX_FILES; ++i) {
PendingFileTransfer *pending_slot = &Friends.list[friendnumber].file_send_queue[i];
if (!pending_slot->pending) {
continue;
}
char command[TOX_MAX_FILENAME_LENGTH + FILE_TRANSFER_SEND_LEN + 1];
snprintf(command, sizeof(command), "%s%s", FILE_TRANSFER_SEND_CMD, pending_slot->file_path);
execute(self->window, self, m, command, CHAT_COMMAND_MODE);
*pending_slot = (PendingFileTransfer) {
0,
};
}
}
int file_send_queue_remove(uint32_t friendnumber, size_t index)
{
if (index >= MAX_FILES) {
return -1;
}
PendingFileTransfer *pending_slot = &Friends.list[friendnumber].file_send_queue[index];
if (!pending_slot->pending) {
return -1;
}
*pending_slot = (PendingFileTransfer) {
0,
};
return 0;
}
/* Closes file transfer ft. /* Closes file transfer ft.
* *
* Set CTRL to -1 if we don't want to send a control signal. * Set CTRL to -1 if we don't want to send a control signal.
* Set message or self to NULL if we don't want to display a message. * Set message or self to NULL if we don't want to display a message.
*/ */
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message, void close_file_transfer(ToxWindow *self, Tox *m, FileTransfer *ft, int CTRL, const char *message,
Notification sound_type) Notification sound_type)
{ {
if (!ft) { if (!ft) {
@ -278,7 +348,11 @@ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int C
} }
if (CTRL >= 0) { if (CTRL >= 0) {
tox_file_control(m, ft->friendnumber, ft->filenumber, (Tox_File_Control) CTRL, NULL); Tox_Err_File_Control err;
if (!tox_file_control(m, ft->friendnumber, ft->filenumber, (Tox_File_Control) CTRL, &err)) {
fprintf(stderr, "Failed to cancel file transfer: %d\n", err);
}
} }
if (message && self) { if (message && self) {
@ -298,7 +372,7 @@ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int C
void kill_avatar_file_transfers_friend(Tox *m, uint32_t friendnumber) void kill_avatar_file_transfers_friend(Tox *m, uint32_t friendnumber)
{ {
for (size_t i = 0; i < MAX_FILES; ++i) { for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i]; FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
if (ft->file_type == TOX_FILE_KIND_AVATAR) { if (ft->file_type == TOX_FILE_KIND_AVATAR) {
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent); close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
@ -312,6 +386,7 @@ void kill_all_file_transfers_friend(Tox *m, uint32_t friendnumber)
for (size_t i = 0; i < MAX_FILES; ++i) { for (size_t i = 0; i < MAX_FILES; ++i) {
close_file_transfer(NULL, m, &Friends.list[friendnumber].file_sender[i], TOX_FILE_CONTROL_CANCEL, NULL, silent); close_file_transfer(NULL, m, &Friends.list[friendnumber].file_sender[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
close_file_transfer(NULL, m, &Friends.list[friendnumber].file_receiver[i], TOX_FILE_CONTROL_CANCEL, NULL, silent); close_file_transfer(NULL, m, &Friends.list[friendnumber].file_receiver[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
file_send_queue_remove(friendnumber, i);
} }
} }
@ -321,3 +396,26 @@ void kill_all_file_transfers(Tox *m)
kill_all_file_transfers_friend(m, Friends.list[i].num); kill_all_file_transfers_friend(m, Friends.list[i].num);
} }
} }
bool file_transfer_recv_path_exists(const char *path)
{
for (size_t friendnumber = 0; friendnumber < Friends.max_idx; ++friendnumber) {
if (!Friends.list[friendnumber].active) {
continue;
}
for (size_t i = 0; i < MAX_FILES; ++i) {
FileTransfer *ft = &Friends.list[friendnumber].file_receiver[i];
if (ft->state == FILE_TRANSFER_INACTIVE) {
continue;
}
if (strcmp(path, ft->file_path) == 0) {
return true;
}
}
}
return false;
}

View File

@ -29,9 +29,9 @@
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
#define KiB 1024 #define KiB (uint32_t) 1024
#define MiB 1048576 /* 1024^2 */ #define MiB (uint32_t) (1024 << 10) /* 1024^2 */
#define GiB 1073741824 /* 1024^3 */ #define GiB (uint32_t) (1024 << 20) /* 1024^3 */
#define MAX_FILES 32 #define MAX_FILES 32
@ -47,7 +47,7 @@ typedef enum FILE_TRANSFER_DIRECTION {
FILE_TRANSFER_RECV FILE_TRANSFER_RECV
} FILE_TRANSFER_DIRECTION; } FILE_TRANSFER_DIRECTION;
struct FileTransfer { typedef struct FileTransfer {
ToxWindow *window; ToxWindow *window;
FILE *file; FILE *file;
FILE_TRANSFER_STATE state; FILE_TRANSFER_STATE state;
@ -63,7 +63,15 @@ struct FileTransfer {
time_t last_line_progress; /* The last time we updated the progress bar */ time_t last_line_progress; /* The last time we updated the progress bar */
uint32_t line_id; uint32_t line_id;
uint8_t file_id[TOX_FILE_ID_LENGTH]; uint8_t file_id[TOX_FILE_ID_LENGTH];
}; } FileTransfer;
typedef struct PendingFileTransfer {
char file_path[TOX_MAX_FILENAME_LENGTH + 1];
size_t length;
uint32_t friendnumber;
bool pending;
} PendingFileTransfer;
/* creates initial progress line that will be updated during file transfer. /* creates initial progress line that will be updated during file transfer.
progline must be at lesat MAX_STR_SIZE bytes */ progline must be at lesat MAX_STR_SIZE bytes */
@ -96,6 +104,31 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint3
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber, struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
FILE_TRANSFER_DIRECTION direction, uint8_t type); FILE_TRANSFER_DIRECTION direction, uint8_t type);
/* Adds a file designated by `file_path` of length `length` to the file transfer queue.
*
* Items in this queue will be automatically sent to the contact designated by `friendnumber`
* as soon as they appear online. The item will then be removed from the queue whether
* or not the transfer successfully initiates.
*
* If the ToxWindow associated with this friend is closed, all queued items will be
* discarded.
*
* Return the queue index on success.
* Return -1 if the length is invalid.
* Return -2 if the send queue is full.
*/
int file_send_queue_add(uint32_t friendnumber, const char *file_path, size_t length);
/* Initiates all file transfers from the file send queue for friend designated by `friendnumber`. */
void file_send_queue_check(ToxWindow *self, Tox *m, uint32_t friendnumber);
/* Removes the `index`-th item from the file send queue for `friendnumber`.
*
* Return 0 if a pending transfer was successfully removed
* Return -1 if index does not designate a pending file transfer.
*/
int file_send_queue_remove(uint32_t friendnumber, size_t index);
/* Closes file transfer ft. /* Closes file transfer ft.
* *
* Set CTRL to -1 if we don't want to send a control signal. * Set CTRL to -1 if we don't want to send a control signal.
@ -112,4 +145,7 @@ void kill_all_file_transfers_friend(Tox *m, uint32_t friendnumber);
void kill_all_file_transfers(Tox *m); void kill_all_file_transfers(Tox *m);
/* Return true if any pending or active file receiver has the path `path`. */
bool file_transfer_recv_path_exists(const char *path);
#endif /* FILE_TRANSFERS_H */ #endif /* FILE_TRANSFERS_H */

View File

@ -692,6 +692,9 @@ static void select_friend(wint_t key, int *selected, int num)
static void delete_friend(Tox *m, uint32_t f_num) static void delete_friend(Tox *m, uint32_t f_num)
{ {
kill_all_file_transfers_friend(m, f_num);
kill_avatar_file_transfers_friend(m, f_num);
Tox_Err_Friend_Delete err; Tox_Err_Friend_Delete err;
if (tox_friend_delete(m, f_num, &err) != true) { if (tox_friend_delete(m, f_num, &err) != true) {
@ -840,9 +843,7 @@ void block_friend(Tox *m, uint32_t fnum)
realloc_blocklist(Blocked.max_idx + 1); realloc_blocklist(Blocked.max_idx + 1);
clear_blocklist_index(Blocked.max_idx); clear_blocklist_index(Blocked.max_idx);
int i; for (int i = 0; i <= Blocked.max_idx; ++i) {
for (i = 0; i <= Blocked.max_idx; ++i) {
if (Blocked.list[i].active) { if (Blocked.list[i].active) {
continue; continue;
} }
@ -1107,14 +1108,14 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
/* Determine which portion of friendlist to draw based on current position */ /* Determine which portion of friendlist to draw based on current position */
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
int page = Friends.num_selected / (y2 - FLIST_OFST); const int page = Friends.num_selected / (y2 - FLIST_OFST);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
int start = (y2 - FLIST_OFST) * page; const int start = (y2 - FLIST_OFST) * page;
int end = y2 - FLIST_OFST + start; const int end = y2 - FLIST_OFST + start;
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
size_t num_friends = Friends.num_friends; const size_t num_friends = Friends.num_friends;
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
int i; int i;

View File

@ -79,8 +79,9 @@ typedef struct {
struct GameInvite game_invite; struct GameInvite game_invite;
#endif #endif
struct FileTransfer file_receiver[MAX_FILES]; FileTransfer file_receiver[MAX_FILES];
struct FileTransfer file_sender[MAX_FILES]; FileTransfer file_sender[MAX_FILES];
PendingFileTransfer file_send_queue[MAX_FILES];
} ToxicFriend; } ToxicFriend;
typedef struct { typedef struct {

View File

@ -1129,7 +1129,7 @@ int game_packet_send(const GameData *game, const uint8_t *data, size_t length, G
memcpy(packet + 1 + GAME_PACKET_HEADER_SIZE, data, length); memcpy(packet + 1 + GAME_PACKET_HEADER_SIZE, data, length);
packet_length += length; packet_length += length;
TOX_ERR_FRIEND_CUSTOM_PACKET err; Tox_Err_Friend_Custom_Packet err;
if (!tox_friend_send_lossless_packet(game->tox, game->friend_number, packet, packet_length, &err)) { if (!tox_friend_send_lossless_packet(game->tox, game->friend_number, packet, packet_length, &err)) {
fprintf(stderr, "failed to send game packet: error %d\n", err); fprintf(stderr, "failed to send game packet: error %d\n", err);

View File

@ -20,6 +20,10 @@
* *
*/ */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* needed for wcswidth() */
#endif
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
@ -137,13 +141,16 @@ static struct line_info *line_info_ret_queue(struct history *hst)
* Return 0 if string does not contain a newline byte. * Return 0 if string does not contain a newline byte.
* Return -1 if printing was aborted. * Return -1 if printing was aborted.
*/ */
static int print_n_chars(WINDOW *win, const char *s, size_t n, int max_y) static int print_n_chars(WINDOW *win, const wchar_t *s, size_t n, int max_y)
{ {
// we use an array to represent a single wchar in order to get around an ncurses
// bug with waddnwstr() that overreads the memory address by one byte when
// supplied with a single wchar.
wchar_t ch[2] = {0};
bool newline = false; bool newline = false;
char ch;
for (size_t i = 0; i < n && (ch = s[i]); ++i) { for (size_t i = 0; i < n && (ch[0] = s[i]); ++i) {
if (ch == '\n') { if (ch[0] == L'\n') {
newline = true; newline = true;
int x; int x;
@ -159,7 +166,17 @@ static int print_n_chars(WINDOW *win, const char *s, size_t n, int max_y)
} }
if (win) { if (win) {
wprintw(win, "%c", ch); #ifdef HAVE_WIDECHAR
waddnwstr(win, ch, 1);
#else
char b;
if (wcstombs(&b, ch, sizeof(char)) != 1) {
continue;
}
wprintw(win, "%c", b);
#endif // HAVE_WIDECHAR
} }
} }
@ -169,10 +186,10 @@ static int print_n_chars(WINDOW *win, const char *s, size_t n, int max_y)
/* Returns the index of the last space character in `s` found before `limit`. /* Returns the index of the last space character in `s` found before `limit`.
* Returns -1 if no space is found. * Returns -1 if no space is found.
*/ */
static int rspace_index(const char *s, int limit) static int rspace_index(const wchar_t *s, int limit)
{ {
for (int i = limit; i >= 0; --i) { for (int i = limit; i >= 0; --i) {
if (s[i] == ' ') { if (s[i] == L' ') {
return i; return i;
} }
} }
@ -183,12 +200,12 @@ static int rspace_index(const char *s, int limit)
/* Returns the first index in `s` containing a newline byte found before `limit`. /* Returns the first index in `s` containing a newline byte found before `limit`.
* Returns -1 if no newline is found. * Returns -1 if no newline is found.
*/ */
static int newline_index(const char *s, int limit) static int newline_index(const wchar_t *s, int limit)
{ {
char ch; wchar_t ch;
for (int i = 0; i < limit && (ch = s[i]); ++i) { for (int i = 0; i < limit && (ch = s[i]); ++i) {
if (ch == '\n') { if (ch == L'\n') {
return i; return i;
} }
} }
@ -197,13 +214,13 @@ static int newline_index(const char *s, int limit)
} }
/* Returns the number of newline bytes in `s` */ /* Returns the number of newline bytes in `s` */
static unsigned int newline_count(const char *s) static unsigned int newline_count(const wchar_t *s)
{ {
char ch; wchar_t ch;
unsigned int count = 0; unsigned int count = 0;
for (size_t i = 0; (ch = s[i]); ++i) { for (size_t i = 0; (ch = s[i]); ++i) {
if (ch == '\n') { if (ch == L'\n') {
++count; ++count;
} }
} }
@ -226,10 +243,10 @@ static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
int y; int y;
UNUSED_VAR(y); UNUSED_VAR(y);
const char *msg = line->msg; const wchar_t *msg = line->msg;
uint16_t length = line->msg_len; uint16_t length = line->msg_width;
uint16_t lines = 0; uint16_t lines = 0;
const int x_start = line->len - line->msg_len - 1; // manually keep track of x position because ncurses sucks const int x_start = line->len - line->msg_width - 1; // manually keep track of x position because ncurses sucks
int x_limit = max_x - x_start; int x_limit = max_x - x_start;
if (x_limit <= 1) { if (x_limit <= 1) {
@ -246,7 +263,7 @@ static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
} }
if (length < x_limit) { if (length < x_limit) {
int p_ret = print_n_chars(win, msg, length, max_y); const int p_ret = print_n_chars(win, msg, length, max_y);
if (p_ret == 1) { if (p_ret == 1) {
lines += newline_count(msg); lines += newline_count(msg);
@ -258,7 +275,7 @@ static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
break; break;
} }
int newline_idx = newline_index(msg, x_limit - 1); const int newline_idx = newline_index(msg, x_limit - 1);
if (newline_idx >= 0) { if (newline_idx >= 0) {
if (print_n_chars(win, msg, newline_idx + 1, max_y) == -1) { if (print_n_chars(win, msg, newline_idx + 1, max_y) == -1) {
@ -272,7 +289,7 @@ static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
continue; continue;
} }
int space_idx = rspace_index(msg, x_limit - 1); const int space_idx = rspace_index(msg, x_limit - 1);
if (space_idx >= 1) { if (space_idx >= 1) {
if (print_n_chars(win, msg, space_idx, max_y) == -1) { if (print_n_chars(win, msg, space_idx, max_y) == -1) {
@ -321,6 +338,37 @@ static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
return 0; return 0;
} }
/* Converts `msg` into a widechar string and puts the result in `buf`.
*
* Returns the widechar width of the string.
*/
static uint16_t line_info_add_msg(wchar_t *buf, size_t buf_size, const char *msg)
{
if (msg == NULL || msg[0] == '\0') {
return 0;
}
const wint_t wc_msg_len = mbs_to_wcs_buf(buf, msg, buf_size);
if (wc_msg_len > 0 && wc_msg_len < buf_size) {
buf[wc_msg_len] = L'\0';
int width = wcswidth(buf, wc_msg_len);
if (width == -1) { // the best we can do on failure is to fall back to strlen
width = strlen(msg);
}
return (uint16_t)width;
} else {
fprintf(stderr, "Failed to convert string '%s' to widechar\n", msg);
const wchar_t *err = L"Failed to parse message";
uint16_t width = (uint16_t)wcslen(err);
wmemcpy(buf, err, width);
buf[width] = L'\0';
return width;
}
}
static void line_info_init_line(ToxWindow *self, struct line_info *line) static void line_info_init_line(ToxWindow *self, struct line_info *line)
{ {
int y2; int y2;
@ -409,13 +457,8 @@ int line_info_add(ToxWindow *self, bool show_timestamp, const char *name1, const
break; break;
} }
uint16_t msg_len = 0; const uint16_t msg_width = line_info_add_msg(new_line->msg, sizeof(new_line->msg), frmt_msg);
len += msg_width;
if (frmt_msg[0]) {
snprintf(new_line->msg, sizeof(new_line->msg), "%s", frmt_msg);
msg_len = strlen(new_line->msg);
len += msg_len;
}
if (show_timestamp) { if (show_timestamp) {
get_time_str(new_line->timestr, sizeof(new_line->timestr)); get_time_str(new_line->timestr, sizeof(new_line->timestr));
@ -434,7 +477,7 @@ int line_info_add(ToxWindow *self, bool show_timestamp, const char *name1, const
new_line->id = (hst->line_end->id + 1 + hst->queue_size) % INT_MAX; new_line->id = (hst->line_end->id + 1 + hst->queue_size) % INT_MAX;
new_line->len = len; new_line->len = len;
new_line->msg_len = msg_len; new_line->msg_width = msg_width;
new_line->type = type; new_line->type = type;
new_line->bold = bold; new_line->bold = bold;
new_line->colour = colour; new_line->colour = colour;
@ -518,9 +561,8 @@ void line_info_print(ToxWindow *self)
const int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT; const int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT;
const int max_x = self->show_peerlist ? x2 - 1 - SIDEBAR_WIDTH : x2; const int max_x = self->show_peerlist ? x2 - 1 - SIDEBAR_WIDTH : x2;
uint16_t numlines = line->format_lines; uint16_t numlines = line->format_lines;
int print_ret = 0;
while (line && numlines++ <= max_y && print_ret == 0) { while (line && numlines++ <= max_y) {
int y; int y;
int x; int x;
getyx(win, y, x); getyx(win, y, x);
@ -557,22 +599,22 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1); wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
wattroff(win, COLOR_PAIR(nameclr)); wattroff(win, COLOR_PAIR(nameclr));
if (line->msg[0] == 0) { if (line->msg[0] == L'\0') {
waddch(win, '\n'); waddch(win, '\n');
break; break;
} }
if (line->msg[0] == '>') { if (line->msg[0] == L'>') {
wattron(win, COLOR_PAIR(GREEN)); wattron(win, COLOR_PAIR(GREEN));
} else if (line->msg[0] == '<') { } else if (line->msg[0] == L'<') {
wattron(win, COLOR_PAIR(RED)); wattron(win, COLOR_PAIR(RED));
} }
print_ret = print_wrap(win, line, max_x, max_y); print_wrap(win, line, max_x, max_y);
if (line->msg[0] == '>') { if (line->msg[0] == L'>') {
wattroff(win, COLOR_PAIR(GREEN)); wattroff(win, COLOR_PAIR(GREEN));
} else if (line->msg[0] == '<') { } else if (line->msg[0] == L'<') {
wattroff(win, COLOR_PAIR(RED)); wattroff(win, COLOR_PAIR(RED));
} }
@ -592,7 +634,7 @@ void line_info_print(ToxWindow *self)
wattron(win, COLOR_PAIR(YELLOW)); wattron(win, COLOR_PAIR(YELLOW));
wprintw(win, "%s %s ", user_settings->line_normal, line->name1); wprintw(win, "%s %s ", user_settings->line_normal, line->name1);
print_ret = print_wrap(win, line, max_x, max_y); print_wrap(win, line, max_x, max_y);
wattroff(win, COLOR_PAIR(YELLOW)); wattroff(win, COLOR_PAIR(YELLOW));
waddch(win, '\n'); waddch(win, '\n');
@ -613,7 +655,7 @@ void line_info_print(ToxWindow *self)
wattron(win, COLOR_PAIR(line->colour)); wattron(win, COLOR_PAIR(line->colour));
} }
print_ret = print_wrap(win, line, max_x, max_y); print_wrap(win, line, max_x, max_y);
waddch(win, '\n'); waddch(win, '\n');
if (line->bold) { if (line->bold) {
@ -631,8 +673,8 @@ void line_info_print(ToxWindow *self)
wprintw(win, "$ "); wprintw(win, "$ ");
wattroff(win, COLOR_PAIR(GREEN)); wattroff(win, COLOR_PAIR(GREEN));
if (line->msg[0]) { if (line->msg[0] != L'\0') {
print_ret = print_wrap(win, line, max_x, max_y); print_wrap(win, line, max_x, max_y);
} }
waddch(win, '\n'); waddch(win, '\n');
@ -650,7 +692,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s ", line->name1); wprintw(win, "%s ", line->name1);
wattroff(win, A_BOLD); wattroff(win, A_BOLD);
print_ret = print_wrap(win, line, max_x, max_y); print_wrap(win, line, max_x, max_y);
waddch(win, '\n'); waddch(win, '\n');
wattroff(win, COLOR_PAIR(line->colour)); wattroff(win, COLOR_PAIR(line->colour));
@ -669,7 +711,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s ", line->name1); wprintw(win, "%s ", line->name1);
wattroff(win, A_BOLD); wattroff(win, A_BOLD);
print_ret = print_wrap(win, line, max_x, max_y); print_wrap(win, line, max_x, max_y);
waddch(win, '\n'); waddch(win, '\n');
wattroff(win, COLOR_PAIR(line->colour)); wattroff(win, COLOR_PAIR(line->colour));
@ -687,7 +729,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s", line->name1); wprintw(win, "%s", line->name1);
wattroff(win, A_BOLD); wattroff(win, A_BOLD);
print_ret = print_wrap(win, line, max_x, max_y); print_wrap(win, line, max_x, max_y);
wattron(win, A_BOLD); wattron(win, A_BOLD);
wprintw(win, "%s\n", line->name2); wprintw(win, "%s\n", line->name2);
@ -749,10 +791,9 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
while (line) { while (line) {
if (line->id == id) { if (line->id == id) {
size_t new_len = strlen(msg); const uint16_t new_width = line_info_add_msg(line->msg, sizeof(line->msg), msg);
line->len = line->len - line->msg_len + new_len; line->len = line->len - line->msg_width + new_width;
line->msg_len = new_len; line->msg_width = new_width;
snprintf(line->msg, sizeof(line->msg), "%s", msg);
return; return;
} }

View File

@ -46,11 +46,11 @@ typedef enum LINE_TYPE {
} LINE_TYPE; } LINE_TYPE;
struct line_info { struct line_info {
char timestr[TIME_STR_SIZE]; char timestr[TIME_STR_SIZE];
char name1[TOXIC_MAX_NAME_LENGTH + 1]; char name1[TOXIC_MAX_NAME_LENGTH + 1];
char name2[TOXIC_MAX_NAME_LENGTH + 1]; char name2[TOXIC_MAX_NAME_LENGTH + 1];
char msg[MAX_LINE_INFO_MSG_SIZE]; wchar_t msg[MAX_LINE_INFO_MSG_SIZE];
time_t timestamp; time_t timestamp;
uint8_t type; uint8_t type;
uint8_t bold; uint8_t bold;
uint8_t colour; uint8_t colour;
@ -58,7 +58,7 @@ struct line_info {
bool read_flag; /* true if a message has been flagged as read */ bool read_flag; /* true if a message has been flagged as read */
uint32_t id; uint32_t id;
uint16_t len; /* combined length of entire line */ uint16_t len; /* combined length of entire line */
uint16_t msg_len; /* length of the message */ uint16_t msg_width; /* width of the message */
uint16_t format_lines; /* number of lines the combined string takes up (dynamically set) */ uint16_t format_lines; /* number of lines the combined string takes up (dynamically set) */
struct line_info *prev; struct line_info *prev;

View File

@ -62,21 +62,21 @@ static int get_log_path(char *dest, int destsize, const char *name, const char *
/* first 6 bytes of selfkey */ /* first 6 bytes of selfkey */
char self_id[32] = {0}; char self_id[32] = {0};
path_len += KEY_IDENT_DIGITS * 2; path_len += KEY_IDENT_BYTES;
sprintf(&self_id[0], "%02X", selfkey[0] & 0xff); sprintf(&self_id[0], "%02X", selfkey[0] & 0xff);
sprintf(&self_id[2], "%02X", selfkey[1] & 0xff); sprintf(&self_id[2], "%02X", selfkey[1] & 0xff);
sprintf(&self_id[4], "%02X", selfkey[2] & 0xff); sprintf(&self_id[4], "%02X", selfkey[2] & 0xff);
self_id[KEY_IDENT_DIGITS * 2] = '\0'; self_id[KEY_IDENT_BYTES] = '\0';
char other_id[32] = {0}; char other_id[32] = {0};
if (otherkey) { if (otherkey) {
/* first 6 bytes of otherkey */ /* first 6 bytes of otherkey */
path_len += KEY_IDENT_DIGITS * 2; path_len += KEY_IDENT_BYTES;
sprintf(&other_id[0], "%02X", otherkey[0] & 0xff); sprintf(&other_id[0], "%02X", otherkey[0] & 0xff);
sprintf(&other_id[2], "%02X", otherkey[1] & 0xff); sprintf(&other_id[2], "%02X", otherkey[1] & 0xff);
sprintf(&other_id[4], "%02X", otherkey[2] & 0xff); sprintf(&other_id[4], "%02X", otherkey[2] & 0xff);
other_id[KEY_IDENT_DIGITS * 2] = '\0'; other_id[KEY_IDENT_BYTES] = '\0';
} }
if (path_len >= destsize) { if (path_len >= destsize) {

View File

@ -48,7 +48,7 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type,
return; return;
} }
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg)); struct cqueue_msg *new_m = calloc(1, sizeof(struct cqueue_msg));
if (new_m == NULL) { if (new_m == NULL) {
exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY); exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY);
@ -62,6 +62,7 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type,
new_m->time_added = get_unix_time(); new_m->time_added = get_unix_time();
new_m->receipt = -1; new_m->receipt = -1;
new_m->next = NULL; new_m->next = NULL;
new_m->noread_flag = false;
if (q->root == NULL) { if (q->root == NULL) {
new_m->prev = NULL; new_m->prev = NULL;
@ -203,7 +204,7 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
return; return;
} }
TOX_ERR_FRIEND_SEND_MESSAGE err; Tox_Err_Friend_Send_Message err;
Tox_Message_Type type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION; Tox_Message_Type type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
uint32_t receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, &err); uint32_t receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, &err);

View File

@ -477,10 +477,9 @@ on_error:
returns length of msg, which will be no larger than size-1 */ returns length of msg, which will be no larger than size-1 */
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length) size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
{ {
size_t i;
size_t j = 0; size_t j = 0;
for (i = 0; (i < length) && (j < size - 1); ++i) { for (size_t i = 0; (i < length) && (j < size - 1); ++i) {
if (data[i] != '\r') { if (data[i] != '\r') {
msg[j++] = data[i]; msg[j++] = data[i];
} }

299
src/netprof.c Normal file
View File

@ -0,0 +1,299 @@
/* netprof.c
*
*
* Copyright (C) 2022 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 <stdio.h>
#include "netprof.h"
#include "../../toxcore/toxcore/tox_private.h" // set this to your local toxcore source directory
static void log_tcp_packet_id(FILE *fp, unsigned int id, uint64_t total, uint64_t TCP_id_sent, uint64_t TCP_id_recv)
{
switch (id) {
case TOX_NETPROF_PACKET_ID_ZERO:
case TOX_NETPROF_PACKET_ID_ONE:
case TOX_NETPROF_PACKET_ID_TWO:
case TOX_NETPROF_PACKET_ID_TCP_DISCONNECT:
case TOX_NETPROF_PACKET_ID_FOUR:
case TOX_NETPROF_PACKET_ID_TCP_PONG:
case TOX_NETPROF_PACKET_ID_TCP_OOB_SEND:
case TOX_NETPROF_PACKET_ID_TCP_OOB_RECV:
case TOX_NETPROF_PACKET_ID_TCP_ONION_REQUEST:
case TOX_NETPROF_PACKET_ID_TCP_ONION_RESPONSE:
case TOX_NETPROF_PACKET_ID_TCP_DATA: {
if (TCP_id_recv || TCP_id_sent) {
fprintf(fp, "0x%02x (total): %lu (%.2f%%)\n", id, TCP_id_sent + TCP_id_recv,
((float)TCP_id_recv + TCP_id_sent) / total * 100.0);
}
if (TCP_id_sent) {
fprintf(fp, "0x%02x (sent): %lu (%.2f%%)\n", id, TCP_id_sent, (float)TCP_id_sent / total * 100.0);
}
if (TCP_id_recv) {
fprintf(fp, "0x%02x (recv): %lu (%.2f%%)\n", id, TCP_id_recv, (float)TCP_id_recv / total * 100.0);
}
break;
}
default:
return;
}
}
static void log_udp_packet_id(FILE *fp, unsigned int id, uint64_t total, uint64_t UDP_id_sent, uint64_t UDP_id_recv)
{
switch (id) {
case TOX_NETPROF_PACKET_ID_ZERO:
case TOX_NETPROF_PACKET_ID_ONE:
case TOX_NETPROF_PACKET_ID_TWO:
case TOX_NETPROF_PACKET_ID_FOUR:
case TOX_NETPROF_PACKET_ID_COOKIE_REQUEST:
case TOX_NETPROF_PACKET_ID_COOKIE_RESPONSE:
case TOX_NETPROF_PACKET_ID_CRYPTO_HS:
case TOX_NETPROF_PACKET_ID_CRYPTO_DATA:
case TOX_NETPROF_PACKET_ID_CRYPTO:
case TOX_NETPROF_PACKET_ID_LAN_DISCOVERY:
case TOX_NETPROF_PACKET_ID_ONION_SEND_INITIAL:
case TOX_NETPROF_PACKET_ID_ONION_SEND_1:
case TOX_NETPROF_PACKET_ID_ONION_SEND_2:
case TOX_NETPROF_PACKET_ID_ANNOUNCE_REQUEST:
case TOX_NETPROF_PACKET_ID_ANNOUNCE_RESPONSE:
case TOX_NETPROF_PACKET_ID_ONION_DATA_REQUEST:
case TOX_NETPROF_PACKET_ID_ONION_DATA_RESPONSE:
case TOX_NETPROF_PACKET_ID_ONION_RECV_3:
case TOX_NETPROF_PACKET_ID_ONION_RECV_2:
case TOX_NETPROF_PACKET_ID_ONION_RECV_1:
case TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO: {
if (UDP_id_recv || UDP_id_sent) {
fprintf(fp, "0x%02x (total): %lu (%.2f%%)\n", id, UDP_id_sent + UDP_id_recv,
((float)UDP_id_recv + UDP_id_sent) / total * 100.0);
}
if (UDP_id_sent) {
fprintf(fp, "0x%02x (sent): %lu (%.2f%%)\n", id, UDP_id_sent, (float)UDP_id_sent / total * 100.0);
}
if (UDP_id_recv) {
fprintf(fp, "0x%02x (recv): %lu (%.2f%%)\n", id, UDP_id_recv, (float)UDP_id_recv / total * 100.0);
}
break;
}
default:
return;
}
}
static void dump_packet_id_counts(const Tox *m, FILE *fp, uint64_t total_count, Tox_Netprof_Packet_Type packet_type)
{
if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) {
fprintf(fp, "--- TCP packet counts by packet ID --- \n");
} else {
fprintf(fp, "--- UDP packet counts by packet ID --- \n");
}
for (unsigned long i = TOX_NETPROF_PACKET_ID_ZERO; i <= TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO; ++i) {
const uint64_t id_count_sent = tox_netprof_get_packet_id_count(m, packet_type, i, TOX_NETPROF_DIRECTION_SENT);
const uint64_t id_count_recv = tox_netprof_get_packet_id_count(m, packet_type, i, TOX_NETPROF_DIRECTION_RECV);
if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) {
log_tcp_packet_id(fp, i, total_count, id_count_sent, id_count_recv);
} else {
log_udp_packet_id(fp, i, total_count, id_count_sent, id_count_recv);
}
}
fprintf(fp, "\n\n");
}
static void dump_packet_id_bytes(const Tox *m, FILE *fp, uint64_t total_bytes, Tox_Netprof_Packet_Type packet_type)
{
if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) {
fprintf(fp, "--- TCP byte counts by packet ID --- \n");
} else {
fprintf(fp, "--- UDP byte counts by packet ID --- \n");
}
for (unsigned long i = TOX_NETPROF_PACKET_ID_ZERO; i <= TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO; ++i) {
const uint64_t id_bytes_sent = tox_netprof_get_packet_id_bytes(m, packet_type, i, TOX_NETPROF_DIRECTION_SENT);
const uint64_t id_bytes_recv = tox_netprof_get_packet_id_bytes(m, packet_type, i, TOX_NETPROF_DIRECTION_RECV);
if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) {
log_tcp_packet_id(fp, i, total_bytes, id_bytes_sent, id_bytes_recv);
} else {
log_udp_packet_id(fp, i, total_bytes, id_bytes_sent, id_bytes_recv);
}
}
fprintf(fp, "\n\n");
}
static void dump_packet_count_totals(const Tox *m, FILE *fp, uint64_t total_packet_count,
uint64_t UDP_count_sent, uint64_t UDP_count_recv,
uint64_t TCP_count_sent, uint64_t TCP_count_recv)
{
const uint64_t total_UDP_count = UDP_count_sent + UDP_count_recv;
const uint64_t total_TCP_count = TCP_count_sent + TCP_count_recv;
const uint64_t total_packet_count_sent = UDP_count_sent + TCP_count_sent;
const uint64_t total_packet_count_recv = UDP_count_recv + TCP_count_recv;
fprintf(fp, "--- Total packet counts --- \n");
fprintf(fp, "Total packets: %lu\n", total_packet_count);
fprintf(fp, "Total packets sent: %lu (%.2f%%)\n", total_packet_count_sent,
(float)total_packet_count_sent / total_packet_count * 100.0);
fprintf(fp, "Total packets recv: %lu (%.2f%%)\n", total_packet_count_recv,
(float)total_packet_count_recv / total_packet_count * 100.0);
fprintf(fp, "total UDP packets: %lu (%.2f%%)\n", total_UDP_count,
(float)total_UDP_count / total_packet_count * 100.0);
fprintf(fp, "UDP packets sent: %lu (%.2f%%)\n", UDP_count_sent,
(float)UDP_count_sent / total_packet_count * 100.0);
fprintf(fp, "UDP packets recv: %lu (%.2f%%)\n", UDP_count_recv,
(float)UDP_count_recv / total_packet_count * 100.0);
fprintf(fp, "Total TCP packets: %lu (%.2f%%)\n", total_TCP_count,
(float)total_TCP_count / total_packet_count * 100.0);
fprintf(fp, "TCP packets sent: %lu (%.2f%%)\n", TCP_count_sent,
(float)TCP_count_sent / total_packet_count * 100.0);
fprintf(fp, "TCP packets recv: %lu (%.2f%%)\n", TCP_count_recv,
(float)TCP_count_recv / total_packet_count * 100.0);
fprintf(fp, "\n\n");
}
void dump_packet_bytes_totals(const Tox *m, FILE *fp, const uint64_t total_bytes,
const uint64_t UDP_bytes_sent, const uint64_t UDP_bytes_recv,
const uint64_t TCP_bytes_sent, const uint64_t TCP_bytes_recv)
{
const uint64_t total_UDP_bytes = UDP_bytes_sent + UDP_bytes_recv;
const uint64_t total_TCP_bytes = TCP_bytes_sent + TCP_bytes_recv;
const uint64_t total_bytes_sent = UDP_bytes_sent + TCP_bytes_sent;
const uint64_t total_bytes_recv = UDP_bytes_recv + TCP_bytes_recv;
fprintf(fp, "--- Total byte counts --- \n");
fprintf(fp, "Total bytes: %lu\n", total_bytes);
fprintf(fp, "Total bytes sent: %lu (%.2f%%)\n", total_bytes_sent,
(float)total_bytes_sent / total_bytes * 100.0);
fprintf(fp, "Total bytes recv: %lu (%.2f%%)\n", total_bytes_recv,
(float)total_bytes_recv / total_bytes * 100.0);
fprintf(fp, "Total UDP bytes: %lu (%.2f%%)\n", total_UDP_bytes,
(float)total_UDP_bytes / total_bytes * 100.0);
fprintf(fp, "UDP bytes sent: %lu (%.2f%%)\n", UDP_bytes_sent,
(float)UDP_bytes_sent / total_bytes * 100.0);
fprintf(fp, "UDP bytes recv: %lu (%.2f%%)\n", UDP_bytes_recv,
(float)UDP_bytes_recv / total_bytes * 100.0);
fprintf(fp, "Total TCP bytes: %lu (%.2f%%)\n", total_TCP_bytes,
(float)total_TCP_bytes / total_bytes * 100.0);
fprintf(fp, "TCP bytes sent: %lu (%.2f%%)\n", TCP_bytes_sent,
(float)TCP_bytes_sent / total_bytes * 100.0);
fprintf(fp, "TCP bytes recv: %lu (%.2f%%)\n", TCP_bytes_recv,
(float)TCP_bytes_recv / total_bytes * 100.0);
fprintf(fp, "\n\n");
}
void netprof_log_dump(const Tox *m, FILE *fp, time_t run_time)
{
if (fp == NULL) {
fprintf(stderr, "Failed to dump network statistics: null file pointer\n");
return;
}
const uint64_t UDP_count_sent = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_SENT);
const uint64_t UDP_count_recv = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_RECV);
const uint64_t TCP_count_sent = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_SENT);
const uint64_t TCP_count_recv = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_RECV);
const uint64_t UDP_bytes_sent = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_SENT);
const uint64_t UDP_bytes_recv = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_RECV);
const uint64_t TCP_bytes_sent = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_SENT);
const uint64_t TCP_bytes_recv = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_RECV);
const uint64_t total_count = UDP_count_sent + UDP_count_recv + TCP_count_sent + TCP_count_recv;
const uint64_t total_bytes = UDP_bytes_sent + UDP_bytes_recv + TCP_bytes_sent + TCP_bytes_recv;
fprintf(fp, "--- Tox network profile log dump ---\n");
fprintf(fp, "Run time: %lu seconds\n", run_time);
if (run_time && total_count && total_bytes) {
fprintf(fp, "Average kilobytes per second: %.2f\n", ((float)total_bytes / run_time) / 1000.0);
fprintf(fp, "Average packets per second: %lu\n", total_count / run_time);
fprintf(fp, "Average packet size: %lu bytes\n", total_bytes / total_count);
fprintf(fp, "\n");
}
dump_packet_count_totals(m, fp, total_count, UDP_count_sent, UDP_count_recv, TCP_count_sent, TCP_count_recv);
dump_packet_bytes_totals(m, fp, total_bytes, UDP_bytes_sent, UDP_bytes_recv, TCP_bytes_sent, TCP_bytes_recv);
dump_packet_id_counts(m, fp, total_count, TOX_NETPROF_PACKET_TYPE_TCP);
dump_packet_id_counts(m, fp, total_count, TOX_NETPROF_PACKET_TYPE_UDP);
dump_packet_id_bytes(m, fp, total_bytes, TOX_NETPROF_PACKET_TYPE_TCP);
dump_packet_id_bytes(m, fp, total_bytes, TOX_NETPROF_PACKET_TYPE_UDP);
fflush(fp);
}
uint64_t netprof_get_bytes_up(const Tox *m)
{
const uint64_t UDP_bytes_sent = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_SENT);
const uint64_t TCP_bytes_sent = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_SENT);
return UDP_bytes_sent + TCP_bytes_sent;
}
uint64_t netprof_get_bytes_down(const Tox *m)
{
const uint64_t UDP_bytes_recv = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_RECV);
const uint64_t TCP_bytes_recv = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_RECV);
return UDP_bytes_recv + TCP_bytes_recv;
}

35
src/netprof.h Normal file
View File

@ -0,0 +1,35 @@
/* netprof.h
*
*
* Copyright (C) 2022 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 TOXIC_NETPROF
#define TOXIC_NETPROF
#include <stdio.h>
#include <time.h>
#include <tox/tox.h>
void netprof_log_dump(const Tox *m, FILE *fp, time_t run_time);
uint64_t netprof_get_bytes_down(const Tox *m);
uint64_t netprof_get_bytes_up(const Tox *m);
#endif // TOXIC_NETPROF

View File

@ -36,6 +36,7 @@
#include "line_info.h" #include "line_info.h"
#include "log.h" #include "log.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "netprof.h"
#include "notify.h" #include "notify.h"
#include "prompt.h" #include "prompt.h"
#include "settings.h" #include "settings.h"
@ -175,9 +176,7 @@ static int add_friend_request(const char *public_key, const char *data)
return -1; return -1;
} }
int i; for (int i = 0; i <= FrndRequests.max_idx; ++i) {
for (i = 0; i <= FrndRequests.max_idx; ++i) {
if (!FrndRequests.request[i].active) { if (!FrndRequests.request[i].active) {
FrndRequests.request[i].active = true; FrndRequests.request[i].active = true;
memcpy(FrndRequests.request[i].key, public_key, TOX_PUBLIC_KEY_SIZE); memcpy(FrndRequests.request[i].key, public_key, TOX_PUBLIC_KEY_SIZE);
@ -307,6 +306,77 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
return input_ret; return input_ret;
} }
#define NET_INFO_REFRESH_INTERVAL 1
static void draw_network_info(const Tox *m, StatusBar *stb)
{
WINDOW *win = stb->topline;
wattron(win, COLOR_PAIR(BAR_TEXT));
wprintw(win, "%s", stb->network_info);
wattroff(win, COLOR_PAIR(BAR_TEXT));
if (!timed_out(stb->time_last_refreshed, NET_INFO_REFRESH_INTERVAL)) {
return;
}
stb->time_last_refreshed = get_unix_time();
const uint64_t up_bytes = netprof_get_bytes_up(m);
const uint64_t down_bytes = netprof_get_bytes_down(m);
const uint64_t up_delta = (up_bytes - stb->up_bytes) / NET_INFO_REFRESH_INTERVAL;
const uint64_t down_delta = (down_bytes - stb->down_bytes) / NET_INFO_REFRESH_INTERVAL;
stb->up_bytes = up_bytes;
stb->down_bytes = down_bytes;
float up = up_bytes;
float down = down_bytes;
const char *up_unit = "bytes";
const char *down_unit = "bytes";
if (up_bytes > MiB) {
up /= (float)MiB;
up_unit = "MiB";
} else if (up_bytes > KiB) {
up /= (float)KiB;
up_unit = "KiB";
}
if (down_bytes > MiB) {
down /= (float)MiB;
down_unit = "MiB";
} else if (down_bytes > KiB) {
down /= (float)KiB;
down_unit = "KiB";
}
float up_bps = up_delta;
float down_bps = down_delta;
const char *up_bps_unit = "b/s";
const char *down_bps_unit = "b/s";
if (up_bps > MiB) {
up_bps /= (float)MiB;
up_bps_unit = "MiB/s";
} else if (up_bps > KiB) {
up_bps /= (float)KiB;
up_bps_unit = "KiB/s";
}
if (down_bps > MiB) {
down_bps /= (float)MiB;
down_bps_unit = "MiB/s";
} else if (down_bps > KiB) {
down_bps /= (float)KiB;
down_bps_unit = "KiB/s";
}
snprintf(stb->network_info, sizeof(stb->network_info),
" | [Up: %.1f%s (%.1f%s) | Down: %.1f%s (%.1f%s)]", up, up_unit, up_bps, up_bps_unit,
down, down_unit, down_bps, down_bps_unit);
}
static void prompt_onDraw(ToxWindow *self, Tox *m) static void prompt_onDraw(ToxWindow *self, Tox *m)
{ {
int x2; int x2;
@ -464,6 +534,10 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT)); wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
} }
if (user_settings->show_network_info) {
draw_network_info(m, statusbar);
}
int y; int y;
int x; int x;
getyx(self->window, y, x); getyx(self->window, y, x);
@ -526,6 +600,26 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
} }
} }
/**
* Return true is the first 3 bytes of `key` are identical to any other contact in the contact list.
*/
static bool key_is_similar(const char *key)
{
for (size_t i = 0; i < Friends.max_idx; ++i) {
const ToxicFriend *friend = &Friends.list[i];
if (!friend->active) {
continue;
}
if (memcmp(friend->pub_key, key, KEY_IDENT_BYTES / 2) == 0) {
return true;
}
}
return false;
}
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, size_t length) static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, size_t length)
{ {
UNUSED_VAR(m); UNUSED_VAR(m);
@ -536,6 +630,13 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
line_info_add(self, true, NULL, NULL, SYS_MSG, 0, 0, "Friend request with the message '%s'", data); line_info_add(self, true, NULL, NULL, SYS_MSG, 0, 0, "Friend request with the message '%s'", data);
write_to_log("Friend request with the message '%s'", "", ctx->log, true); write_to_log("Friend request with the message '%s'", "", ctx->log, true);
if (key_is_similar(key)) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED,
"WARNING: This contact's public key is suspiciously similar to that of another contact ");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED,
"in your list. This may be an impersonation attempt, or it may have occurred by chance.");
}
int n = add_friend_request(key, data); int n = add_friend_request(key, data);
if (n == -1) { if (n == -1) {

View File

@ -20,9 +20,10 @@
* *
*/ */
#include "api.h"
#ifdef PYTHON #ifdef PYTHON
#include <Python.h> #include <Python.h>
#include "api.h"
#include "execute.h" #include "execute.h"

View File

@ -63,6 +63,7 @@ static struct ui_strings {
const char *show_typing_other; const char *show_typing_other;
const char *show_welcome_msg; const char *show_welcome_msg;
const char *show_connection_msg; const char *show_connection_msg;
const char *show_network_info;
const char *nodeslist_update_freq; const char *nodeslist_update_freq;
const char *autosave_freq; const char *autosave_freq;
@ -97,6 +98,7 @@ static struct ui_strings {
"show_typing_other", "show_typing_other",
"show_welcome_msg", "show_welcome_msg",
"show_connection_msg", "show_connection_msg",
"show_network_info",
"nodeslist_update_freq", "nodeslist_update_freq",
"autosave_freq", "autosave_freq",
"line_join", "line_join",
@ -130,6 +132,7 @@ static void ui_defaults(struct user_settings *settings)
settings->show_typing_other = SHOW_TYPING_ON; settings->show_typing_other = SHOW_TYPING_ON;
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON; settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
settings->show_connection_msg = SHOW_CONNECTION_MSG_ON; settings->show_connection_msg = SHOW_CONNECTION_MSG_ON;
settings->show_network_info = SHOW_NETWORK_INFO_OFF;
settings->nodeslist_update_freq = 7; settings->nodeslist_update_freq = 7;
settings->autosave_freq = 600; settings->autosave_freq = 600;
@ -398,6 +401,7 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other); config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other);
config_setting_lookup_bool(setting, ui_strings.show_welcome_msg, &s->show_welcome_msg); config_setting_lookup_bool(setting, ui_strings.show_welcome_msg, &s->show_welcome_msg);
config_setting_lookup_bool(setting, ui_strings.show_connection_msg, &s->show_connection_msg); config_setting_lookup_bool(setting, ui_strings.show_connection_msg, &s->show_connection_msg);
config_setting_lookup_bool(setting, ui_strings.show_network_info, &s->show_network_info);
config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size); config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
config_setting_lookup_int(setting, ui_strings.notification_timeout, &s->notification_timeout); config_setting_lookup_int(setting, ui_strings.notification_timeout, &s->notification_timeout);

View File

@ -54,6 +54,7 @@ struct user_settings {
int show_typing_other; /* boolean */ int show_typing_other; /* boolean */
int show_welcome_msg; /* boolean */ int show_welcome_msg; /* boolean */
int show_connection_msg; /* boolean */ int show_connection_msg; /* boolean */
int show_network_info; /* boolean */
int nodeslist_update_freq; /* int (<= 0 to disable updates) */ int nodeslist_update_freq; /* int (<= 0 to disable updates) */
int autosave_freq; /* int (<= 0 to disable autosave) */ int autosave_freq; /* int (<= 0 to disable autosave) */
@ -120,6 +121,9 @@ enum settings_values {
SHOW_CONNECTION_MSG_OFF = 0, SHOW_CONNECTION_MSG_OFF = 0,
SHOW_CONNECTION_MSG_ON = 1, SHOW_CONNECTION_MSG_ON = 1,
SHOW_NETWORK_INFO_OFF = 0,
SHOW_NETWORK_INFO_ON = 1,
DFLT_HST_SIZE = 700, DFLT_HST_SIZE = 700,
MPLEX_OFF = 0, MPLEX_OFF = 0,

View File

@ -58,6 +58,7 @@
#include "message_queue.h" #include "message_queue.h"
#include "misc_tools.h" #include "misc_tools.h"
#include "name_lookup.h" #include "name_lookup.h"
#include "netprof.h"
#include "notify.h" #include "notify.h"
#include "prompt.h" #include "prompt.h"
#include "settings.h" #include "settings.h"
@ -143,6 +144,22 @@ static void catch_SIGSEGV(int sig)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void cb_toxcore_logger(Tox *m, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func,
const char *message, void *user_data)
{
UNUSED_VAR(user_data);
UNUSED_VAR(file);
UNUSED_VAR(m);
if (user_data) {
FILE *fp = (FILE *)user_data;
fprintf(fp, "[%d] %u:%s() - %s\n", level, line, func, message);
fflush(fp);
} else {
fprintf(stderr, "[%d] %u:%s() - %s\n", level, line, func, message);
}
}
static void flag_window_resize(int sig) static void flag_window_resize(int sig)
{ {
UNUSED_VAR(sig); UNUSED_VAR(sig);
@ -177,6 +194,10 @@ void free_global_data(void)
void exit_toxic_success(Tox *m) void exit_toxic_success(Tox *m)
{ {
if (arg_opts.netprof_log_dump) {
netprof_log_dump(m, arg_opts.netprof_fp, get_unix_time() - arg_opts.netprof_start_time);
}
store_data(m, DATA_FILE); store_data(m, DATA_FILE);
user_password = (struct user_password) { user_password = (struct user_password) {
@ -207,6 +228,11 @@ void exit_toxic_success(Tox *m)
arg_opts.log_fp = NULL; arg_opts.log_fp = NULL;
} }
if (arg_opts.netprof_fp != NULL) {
fclose(arg_opts.netprof_fp);
arg_opts.netprof_fp = NULL;
}
endwin(); endwin();
curl_global_cleanup(); curl_global_cleanup();
@ -229,22 +255,6 @@ void exit_toxic_err(const char *errmsg, int errcode)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void cb_toxcore_logger(Tox *m, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func,
const char *message, void *user_data)
{
UNUSED_VAR(user_data);
UNUSED_VAR(file);
UNUSED_VAR(m);
if (user_data) {
FILE *fp = (FILE *)user_data;
fprintf(fp, "[%d] %u:%s() - %s\n", level, line, func, message);
fflush(fp);
} else {
fprintf(stderr, "[%d] %u:%s() - %s\n", level, line, func, message);
}
}
/* Sets ncurses refresh rate. Lower values make it refresh more often. */ /* Sets ncurses refresh rate. Lower values make it refresh more often. */
void set_window_refresh_rate(size_t refresh_rate) void set_window_refresh_rate(size_t refresh_rate)
{ {
@ -1199,6 +1209,7 @@ static void print_usage(void)
fprintf(stderr, " -p, --SOCKS5-proxy Use SOCKS5 proxy: Requires [IP] [port]\n"); fprintf(stderr, " -p, --SOCKS5-proxy Use SOCKS5 proxy: Requires [IP] [port]\n");
fprintf(stderr, " -P, --HTTP-proxy Use HTTP proxy: Requires [IP] [port]\n"); fprintf(stderr, " -P, --HTTP-proxy Use HTTP proxy: Requires [IP] [port]\n");
fprintf(stderr, " -r, --namelist Use specified name lookup server list\n"); fprintf(stderr, " -r, --namelist Use specified name lookup server list\n");
fprintf(stderr, " -s, --netstats Dump network statistic to log on exit: Requires [path]\n");
fprintf(stderr, " -t, --force-tcp Force toxic to use a TCP connection (use with proxies)\n"); fprintf(stderr, " -t, --force-tcp Force toxic to use a TCP connection (use with proxies)\n");
fprintf(stderr, " -T, --tcp-server Act as a TCP relay server: Requires [port]\n"); fprintf(stderr, " -T, --tcp-server Act as a TCP relay server: Requires [port]\n");
fprintf(stderr, " -u, --unencrypt-data Unencrypt an encrypted data file\n"); fprintf(stderr, " -u, --unencrypt-data Unencrypt an encrypted data file\n");
@ -1238,6 +1249,7 @@ static void parse_args(int argc, char *argv[])
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"noconnect", no_argument, 0, 'o'}, {"noconnect", no_argument, 0, 'o'},
{"namelist", required_argument, 0, 'r'}, {"namelist", required_argument, 0, 'r'},
{"netstats", required_argument, 0, 's'},
{"force-tcp", no_argument, 0, 't'}, {"force-tcp", no_argument, 0, 't'},
{"tcp-server", required_argument, 0, 'T'}, {"tcp-server", required_argument, 0, 'T'},
{"SOCKS5-proxy", required_argument, 0, 'p'}, {"SOCKS5-proxy", required_argument, 0, 'p'},
@ -1247,7 +1259,7 @@ static void parse_args(int argc, char *argv[])
{NULL, no_argument, NULL, 0}, {NULL, no_argument, NULL, 0},
}; };
const char *opts_str = "4bdehLotuxvc:f:l:n:r:p:P:T:"; const char *opts_str = "4bdehLotuxvc:f:l:n:r:s:p:P:T:";
int opt = 0; int opt = 0;
int indexptr = 0; int indexptr = 0;
@ -1443,6 +1455,25 @@ static void parse_args(int argc, char *argv[])
break; break;
} }
case 's': {
if (optarg == NULL) {
queue_init_message("Invalid argument for option: %d", opt);
break;
}
arg_opts.netprof_fp = fopen(optarg, "w");
if (arg_opts.netprof_fp != NULL) {
queue_init_message("Network profile logging enabled. Logging to file: '%s'", optarg);
arg_opts.netprof_log_dump = true;
arg_opts.netprof_start_time = time(NULL);
} else {
queue_init_message("Failed to open file '%s' for network profile logging.", optarg);
}
break;
}
case 'u': { case 'u': {
arg_opts.unencrypt_data = 1; arg_opts.unencrypt_data = 1;
break; break;

View File

@ -23,6 +23,10 @@
#ifndef TOXIC_H #ifndef TOXIC_H
#define TOXIC_H #define TOXIC_H
#ifndef NCURSES_WIDECHAR
#define NCURSES_WIDECHAR 1
#endif
#ifndef TOXICVER #ifndef TOXICVER
#define TOXICVER "NOVERS" /* Use the -D flag to set this */ #define TOXICVER "NOVERS" /* Use the -D flag to set this */
#endif #endif
@ -46,7 +50,7 @@
#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH /* must be >= TOX_MAX_MESSAGE_LENGTH */ #define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH /* must be >= TOX_MAX_MESSAGE_LENGTH */
#define MAX_CMDNAME_SIZE 64 #define MAX_CMDNAME_SIZE 64
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */ #define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
#define KEY_IDENT_DIGITS 3 /* number of hex digits to display for the pub-key based identifier */ #define KEY_IDENT_BYTES 6 /* number of hex digits to display for the public key identifier */
#define TIME_STR_SIZE 32 #define TIME_STR_SIZE 32
#define COLOR_STR_SIZE 10 /* should fit every color option */ #define COLOR_STR_SIZE 10 /* should fit every color option */

View File

@ -244,7 +244,7 @@ void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, u
{ {
UNUSED_VAR(userdata); UNUSED_VAR(userdata);
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber); FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft) { if (!ft) {
return; return;
@ -267,7 +267,7 @@ void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint
{ {
UNUSED_VAR(userdata); UNUSED_VAR(userdata);
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber); FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft) { if (!ft) {
return; return;
@ -285,7 +285,7 @@ void on_file_recv_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, To
{ {
UNUSED_VAR(userdata); UNUSED_VAR(userdata);
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber); FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft) { if (!ft) {
return; return;

View File

@ -142,6 +142,10 @@ struct arg_opts {
bool logging; bool logging;
FILE *log_fp; FILE *log_fp;
bool netprof_log_dump;
time_t netprof_start_time;
FILE *netprof_fp;
char proxy_address[256]; char proxy_address[256];
uint8_t proxy_type; uint8_t proxy_type;
uint16_t proxy_port; uint16_t proxy_port;
@ -248,6 +252,12 @@ struct StatusBar {
size_t nick_len; size_t nick_len;
Tox_User_Status status; Tox_User_Status status;
Tox_Connection connection; Tox_Connection connection;
/* network info */
uint64_t up_bytes;
uint64_t down_bytes;
uint64_t time_last_refreshed;
char network_info[MAX_STR_SIZE];
}; };
#ifdef AUDIO #ifdef AUDIO