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

Compare commits

...

54 Commits

Author SHA1 Message Date
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
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
48 changed files with 1676 additions and 1239 deletions

View File

@ -9,22 +9,22 @@ before_script:
# Installing libsodium, needed for toxcore
- git clone https://github.com/jedisct1/libsodium.git libsodium
- cd libsodium
- git checkout tags/1.0.2 > /dev/null
- git checkout tags/1.0.3 > /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
- wget http://downloads.xiph.org/releases/opus/opus-1.1.tar.gz
- tar xzf opus-1.1.tar.gz > /dev/null
- cd opus-1.1
- ./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
- git clone https://chromium.googlesource.com/webm/libvpx libvpx
- cd libvpx
- ./configure --enable-shared > /dev/null
- make -j2 || make || exit 1 > /dev/null

View File

@ -14,7 +14,7 @@ LDFLAGS = $(USER_LDFLAGS)
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_transfers.o notify.o
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o
OBJ += group_commands.o term_mplex.o
OBJ += group_commands.o term_mplex.o avatars.o
# Check on wich system we are running
UNAME_S = $(shell uname -s)

View File

@ -1,26 +1,12 @@
# 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.
Toxic is a [Tox](https://tox.chat)-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.
[![Toxic Screenshot](https://i.imgur.com/san99Z2.png "Home Screen")](https://i.imgur.com/san99Z2.png)
## Installation
[Use our repositories](https://wiki.tox.im/Binaries#Linux)<br />
[Use our repositories](https://wiki.tox.chat/binaries#other_linux)<br />
[Compile it yourself](/INSTALL.md)
## Downloads
If you don't like installation methods listed above, you can still 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) [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_i386/badge/icon)](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) [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz)
* [~~Linux ARMv6~~](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz) **CURRENTLY DISABLED** [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz)
#### DEBs packages
* [toxic-i386.deb](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-i386.deb)
* [toxic-x86_64.deb](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-x86_64.deb)
#### RPMs packages
* [toxic-i386.rpm](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-i386.rpm)
* [toxic-x86_64.rpm](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-x86_64.rpm)
## 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).

View File

@ -8,13 +8,13 @@ else
endif
# Check if we can build audio support
CHECK_AUDIO_LIBS = $(shell pkg-config --exists $(AUDIO_LIBS) || echo -n "error")
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)
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))

View File

@ -25,12 +25,12 @@ ifneq ($(DESK_NOTIFY), disabled)
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))
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)
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))

View File

@ -3,12 +3,12 @@ DESK_NOTIFY_LIBS = libnotify
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)
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))

View File

@ -8,13 +8,13 @@ else
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)
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))

View File

@ -4,13 +4,13 @@ X11_CFLAGS = -DX11
X11_OBJ = xtra.o
# Check if we can build X11 support
CHECK_X11_LIBS = $(shell pkg-config --exists $(X11_LIBS) || echo -n "error")
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)
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))

View File

@ -28,3 +28,6 @@ BINDIR = $(PREFIX)/bin
DATADIR = $(PREFIX)/share/toxic
MANDIR = $(PREFIX)/share/man
APPDIR = $(PREFIX)/share/applications
# Platform tools
PKG_CONFIG = pkg-config

View File

@ -5,6 +5,7 @@ help:
@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

View File

@ -13,7 +13,8 @@ install: $(BUILD_DIR)/toxic
@for f in $(DATAFILES) ; do \
install -m 0644 $(MISC_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)/$$f) ;\
file=$(abspath $(DESTDIR)/$(DATADIR)/$$f) ;\
sed -i'' -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file ;\
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 \
@ -30,8 +31,10 @@ install: $(BUILD_DIR)/toxic
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 ;\
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 -9 $$file ;\
done

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 | rev | cut -d "." -f 1` ;\
file=$$section/$$f ;\
rm -f $$file $$file.gz ;\
done
.PHONY: uninstall

View File

@ -2,12 +2,12 @@
.\" Title: toxic
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2014-12-27
.\" Date: 2015-03-28
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC" "1" "2014\-12\-27" "toxic __VERSION__" "Toxic Manual"
.TH "TOXIC" "1" "2015\-03\-28" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -111,6 +111,11 @@ Use specified DNSservers file
Force TCP connection (use this with proxies)
.RE
.PP
\-T, \-\-tcp\-relay
.RS 4
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\&.

View File

@ -59,6 +59,9 @@ OPTIONS
-t, --force-tcp::
Force TCP connection (use this with proxies)
-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.

View File

@ -2,12 +2,12 @@
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2015-02-26
.\" Date: 2015-03-28
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC\&.CONF" "5" "2015\-02\-26" "toxic __VERSION__" "Toxic Manual"
.TH "TOXIC\&.CONF" "5" "2015\-03\-28" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------

View File

@ -5,7 +5,6 @@
178.21.112.187 33445 4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057
195.154.119.113 33445 E398A69646B8CEACA9F0B84F553726C1C49270558C57DF5F3C368F05A7D71354
192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
104.219.184.206 443 8CD087E31C67568103E8C2A28653337E90E6B8EDA0D765D57C6B5172B4F1F04C
76.191.23.96 33445 93574A3FAB7D612FEA29FD8D67D3DD10DFD07A075A5D62E8AF3DD9F5D0932E11
46.38.239.179 33445 F5A1A38EFB6BD3C2C8AF8B10D85F0F89E931704D349F1D0720C3C4059AF2440A
178.62.250.138 33445 788236D34978D1D5BD822F0A5BEBD2C53C64CC31CD3149350EE27D4D9A2F9B6B
@ -16,5 +15,11 @@
192.3.173.88 33445 3E1FFDEB667BFF549F619EC6737834762124F50A89C8D0DBF1DDF64A2DD6CD1B
205.185.116.116 33445 A179B09749AC826FF01F37A9613F6B57118AE014D4196A0E1105A98F93A54702
198.98.51.198 33445 1D5A5F2F5D6233058BF0259B09622FB40B482E4FA0931EB8FD3AB8E7BF7DAF6F
80.232.246.79 33445 0B8DCEAA7BDDC44BB11173F987CAE3566A2D7057D8DD3CC642BD472B9391002A
80.232.246.79 33445 A7A060D553B017D9D8F038E265C7AFB6C70BAAC55070197F9C007432D0038E0F
108.61.165.198 33445 8E7D0B859922EF569298B4D261A8CCB5FEA14FB91ED412A7603A585A25698832
212.71.252.109 33445 C4CEB8C7AC607C6B374E2E782B3C00EA3A63B80D4910B8649CCACDD19F260819
194.249.212.109 33445 3CEE1F054081E7A011234883BC4FC39F661A55B73637A5AC293DDF1251D9432B
194.249.212.109 443 3CEE1F054081E7A011234883BC4FC39F661A55B73637A5AC293DDF1251D9432B
103.38.216.87 33445 601AEE6FC8C17E8CD8F8F1FFC4D4AD84E59A73BE451F037194E7A404E3795320
185.25.116.107 33445 DA4E4ED4B697F2E9B000EEFE3A34B554ACD3F45F5C96EAEA2516DD7FF9AF7B43
192.99.168.140 33445 6A4D0607A296838434A6A7DDF99F50EF9D60A2C510BBF31FE538A25CB6B4652F

View File

@ -93,7 +93,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
{
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 || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE)
return -1;
const char *L = (char *) list;
@ -136,7 +136,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
}
}
if (string_is_empty(sub)) {
if (!sub[0]) {
free(sub);
return -1;
}
@ -185,7 +185,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
return -1;
char tmpend[MAX_STR_SIZE];
strcpy(tmpend, &ubuf[ctx->pos]);
snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
strcpy(&ubuf[strt], match);
strcpy(&ubuf[strt + m_len], endchrs);
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
@ -193,7 +193,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
/* 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);
@ -218,7 +218,7 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const cha
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);
@ -261,10 +261,10 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
} 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);
snprintf(b_path, sizeof(b_path), "%s", tmp);
}
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);
DIR *dp = opendir(b_path);

205
src/avatars.c Normal file
View File

@ -0,0 +1,205 @@
/* 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "misc_tools.h"
#include "file_transfers.h"
#include "friendlist.h"
#include "avatars.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;
static void avatar_clear(void)
{
memset(&Avatar, 0, sizeof(struct Avatar));
}
/* Sends avatar to friendnum.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int avatar_send(Tox *m, uint32_t friendnum)
{
TOX_ERR_FILE_SEND err;
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
if (Avatar.size == 0)
return 0;
if (err != TOX_ERR_FILE_SEND_OK) {
fprintf(stderr, "tox_file_send failed for friendnumber %d (error %d)\n", friendnum, err);
return -1;
}
struct FileTransfer *ft = new_file_transfer(NULL, friendnum, filenum, 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)
{
size_t i;
for (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;
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_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[length];
size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
if (send_length != length) {
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
return;
}
TOX_ERR_FILE_SEND_CHUNK err;
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
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;
ft->last_keep_alive = get_unix_time();
}

52
src/avatars.h Normal file
View File

@ -0,0 +1,52 @@
/* 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
#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);
#endif /* AVATARS_H */

View File

@ -188,8 +188,8 @@ static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TY
return recv_action_helper(self, m, num, msg, len, nick, timefrmt);
}
static void chat_resume_file_transfers(Tox *m, uint32_t fnum);
static void chat_stop_file_senders(uint32_t friendnum);
static void chat_pause_file_transfers(Tox *m, uint32_t friendnum);
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t fnum);
static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
{
@ -206,28 +206,28 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
statusbar->connection = connection_status;
if (connection_status != TOX_CONNECTION_NONE) {
if (connection_status != TOX_CONNECTION_NONE && statusbar->connection == TOX_CONNECTION_NONE) {
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
? tox_friend_get_typing(m, num, NULL) : false;
chat_resume_file_transfers(m, num);
chat_resume_file_senders(self, m, num);
msg = "has come online";
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
write_to_log(msg, nick, ctx->log, true);
} else {
} else if (connection_status == TOX_CONNECTION_NONE) {
Friends.list[num].is_typing = false;
if (self->chatwin->self_is_typing)
set_self_typingstatus(self, m, 0);
chat_stop_file_senders(num);
chat_pause_file_transfers(m, num);
msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true);
}
statusbar->connection = connection_status;
}
static void chat_onTypingChange(ToxWindow *self, Tox *m, uint32_t num, bool is_typing)
@ -277,196 +277,258 @@ static void chat_onReadReceipt(ToxWindow *self, Tox *m, uint32_t num, uint32_t r
cqueue_remove(self, m, receipt);
}
/* Stops active file senders for this friend. Call when a friend goes offline */
static void chat_stop_file_senders(uint32_t friendnum)
/* Stops active file transfers for this friend. Called when a friend goes offline */
static void chat_pause_file_transfers(Tox *m, uint32_t friendnum)
{
// size_t i;
ToxicFriend *friend = &Friends.list[friendnum];
// for (i = 0; i < MAX_FILES; ++i) {
// if (Friends.list[friendnum].file_sender[i].active)
// Friends.list[friendnum].file_sender[i].noconnection = true;
// }
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
if (friend->file_sender[i].state >= FILE_TRANSFER_STARTED)
friend->file_sender[i].state = FILE_TRANSFER_PAUSED;
if (friend->file_receiver[i].state >= FILE_TRANSFER_STARTED)
friend->file_receiver[i].state = FILE_TRANSFER_PAUSED;
}
}
/* Tries to resume broken file transfers. Call when a friend comes online */
static void chat_resume_file_transfers(Tox *m, uint32_t fnum)
/* Tries to resume broken file senders. Called when a friend comes online */
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum)
{
// size_t i;
size_t i;
// for (i = 0; i < MAX_FILES; ++i) {
// if (Friends.list[fnum].file_receiver[i].active) {
// uint8_t bytes_recv[sizeof(uint64_t)];
// memcpy(bytes_recv, &Friends.list[fnum].file_receiver[i].bytes_recv, sizeof(uint64_t));
// net_to_host(bytes_recv, sizeof(uint64_t));
// uint32_t filenum = Friends.list[fnum].file_receiver[i].filenum;
// tox_file_send_control(m, fnum, 1, filenum, TOX_FILECONTROL_RESUME_BROKEN, bytes_recv, sizeof(uint64_t));
// }
// }
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
if (ft->state != FILE_TRANSFER_PAUSED)
continue;
TOX_ERR_FILE_SEND err;
ft->filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, ft->file_size, ft->file_id,
(uint8_t *) ft->file_name, strlen(ft->file_name), &err);
if (err != TOX_ERR_FILE_SEND_OK) {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "File transfer for '%s' failed.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
continue;
}
}
}
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint64_t position,
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
size_t length)
{
if (num != self->num)
if (friendnum != self->num)
return;
uint32_t idx = get_file_transfer_index(filenum);
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
if (idx >= MAX_FILES)
if (!ft)
return;
if (ft->state != FILE_TRANSFER_STARTED)
return;
char msg[MAX_STR_SIZE];
const char *file_name = Friends.list[num].file_sender[idx].file_name;
FILE *fp = Friends.list[num].file_sender[idx].file;
if (fp == NULL) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Null file pointer.", file_name);
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
if (length == 0) {
snprintf(msg, sizeof(msg), "File '%s' successfully sent.", file_name);
print_progress_bar(self, Friends.list[num].file_sender[idx].bps, 100.0, Friends.list[num].file_sender[idx].line_id);
close_file_transfer(self, m, filenum, num, -1, msg, transfer_completed);
snprintf(msg, sizeof(msg), "File '%s' successfully sent.", ft->file_name);
print_progress_bar(self, ft->bps, 100.0, ft->line_id);
close_file_transfer(self, m, ft, -1, msg, transfer_completed);
return;
}
if (Friends.list[num].file_sender[idx].position != position) {
if (fseek(fp, position, SEEK_SET) == -1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Seek fail.", file_name);
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
if (ft->file == NULL) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Null file pointer.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
Friends.list[num].file_sender[idx].position = position;
if (ft->position != position) {
if (fseek(ft->file, position, SEEK_SET) == -1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Seek fail.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
ft->position = position;
}
uint8_t send_data[length];
size_t send_length = fread(send_data, 1, sizeof(send_data), fp);
size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
if (send_length != length) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", file_name);
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
TOX_ERR_FILE_SEND_CHUNK err;
tox_file_send_chunk(m, num, filenum, position, send_data, send_length, &err);
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
fprintf(stderr, "tox_file_send_chunk failed (error %d)\n", err);
fprintf(stderr, "tox_file_send_chunk failed in chat callback (error %d)\n", err);
Friends.list[num].file_sender[idx].position += send_length;
Friends.list[num].file_sender[idx].bps += send_length;
ft->position += send_length;
ft->bps += send_length;
ft->last_keep_alive = get_unix_time();
}
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint64_t position,
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
const char *data, size_t length)
{
if (num != self->num)
if (friendnum != self->num)
return;
uint32_t idx = get_file_transfer_index(filenum);
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
if (idx >= MAX_FILES)
if (!ft)
return;
if (ft->state != FILE_TRANSFER_STARTED)
return;
char msg[MAX_STR_SIZE];
char file_name[MAX_STR_SIZE];
get_file_name(file_name, sizeof(file_name), Friends.list[num].file_receiver[idx].file_path);
if (length == 0) {
snprintf(msg, sizeof(msg), "File '%s' successfully received.", file_name);
print_progress_bar(self, Friends.list[num].file_receiver[idx].bps, 100.0, Friends.list[num].file_receiver[idx].line_id);
close_file_transfer(self, m, filenum, num, -1, msg, transfer_completed);
snprintf(msg, sizeof(msg), "File '%s' successfully received.", ft->file_name);
print_progress_bar(self, ft->bps, 100.0, ft->line_id);
close_file_transfer(self, m, ft, -1, msg, transfer_completed);
return;
}
FILE *fp = Friends.list[num].file_receiver[idx].file;
if (fp == NULL) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Invalid file pointer.", file_name);
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
if (ft->file == NULL) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Invalid file pointer.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
if (fwrite(data, length, 1, fp) != 1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Write fail.", file_name);
close_file_transfer(self, m, filenum, num, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
if (fwrite(data, length, 1, ft->file) != 1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Write fail.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
Friends.list[num].file_receiver[idx].bps += length;
Friends.list[num].file_receiver[idx].position += length;
ft->bps += length;
ft->position += length;
ft->last_keep_alive = get_unix_time();
}
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, TOX_FILE_CONTROL control)
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, TOX_FILE_CONTROL control)
{
if (self->num != num)
if (friendnum != self->num)
return;
uint32_t idx = get_file_transfer_index(filenum);
bool sending = filenum_is_sending(filenum);
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
if (idx >= MAX_FILES)
if (!ft)
return;
char file_name[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
if (sending && Friends.list[num].file_sender[idx].active) {
snprintf(file_name, sizeof(file_name), "%s", Friends.list[num].file_sender[idx].file_name);
} else if (!sending && Friends.list[num].file_receiver[idx].active) {
get_file_name(file_name, sizeof(file_name), Friends.list[num].file_receiver[idx].file_path);
} else {
return;
}
switch (control) {
case TOX_FILE_CONTROL_RESUME:
case TOX_FILE_CONTROL_RESUME: {
ft->last_keep_alive = get_unix_time();
/* transfer is accepted */
if (sending && !Friends.list[num].file_sender[idx].started) {
Friends.list[num].file_sender[idx].started = true;
if (ft->state == FILE_TRANSFER_PENDING) {
ft->state = FILE_TRANSFER_STARTED;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
idx, file_name);
ft->index, ft->file_name);
char progline[MAX_STR_SIZE];
prep_prog_line(progline);
init_progress_bar(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
Friends.list[num].file_sender[idx].line_id = self->chatwin->hst->line_end->id + 2;
sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
ft->line_id = self->chatwin->hst->line_end->id + 2;
} else if (ft->state == FILE_TRANSFER_PAUSED) { /* transfer is resumed */
ft->state = FILE_TRANSFER_STARTED;
}
break;
case TOX_FILE_CONTROL_PAUSE:
}
case TOX_FILE_CONTROL_PAUSE: {
ft->state = FILE_TRANSFER_PAUSED;
break;
case TOX_FILE_CONTROL_CANCEL:
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", file_name);
close_file_transfer(self, m, filenum, num, -1, msg, notif_error);
}
case TOX_FILE_CONTROL_CANCEL: {
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
close_file_transfer(self, m, ft, -1, msg, notif_error);
break;
}
}
}
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind,
uint64_t file_size, const char *filename, size_t name_length)
/* Attempts to resume a broken inbound file transfer.
*
* Returns true if resume is successful.
*/
static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum)
{
if (self->num != num)
char msg[MAX_STR_SIZE];
uint8_t file_id[TOX_FILE_ID_LENGTH];
if (!tox_file_get_file_id(m, friendnum, filenum, file_id, NULL))
return false;
bool resuming = false;
struct FileTransfer *ft = NULL;
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
ft = &Friends.list[friendnum].file_receiver[i];
if (ft->state == FILE_TRANSFER_INACTIVE)
continue;
if (memcmp(ft->file_id, file_id, TOX_FILE_ID_LENGTH) == 0) {
ft->filenum = filenum;
ft->state = FILE_TRANSFER_STARTED;
ft->last_keep_alive = get_unix_time();
resuming = true;
break;
}
}
if (!resuming || !ft)
return false;
if (!tox_file_seek(m, ft->friendnum, ft->filenum, ft->position, NULL))
goto on_error;
if (!tox_file_control(m, ft->friendnum, ft->filenum, TOX_FILE_CONTROL_RESUME, NULL))
goto on_error;
return true;
on_error:
snprintf(msg, sizeof(msg), "File transfer for '%s' failed.", ft->file_name);
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return false;
}
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t file_size,
const char *filename, size_t name_length)
{
if (self->num != friendnum)
return;
uint32_t idx = get_file_transfer_index(filenum);
/* first check if we need to resume a broken transfer */
if (chat_resume_broken_ft(self, m, friendnum, filenum))
return;
if (idx >= MAX_FILES) {
struct FileTransfer *ft = new_file_transfer(self, friendnum, filenum, FILE_TRANSFER_RECV, TOX_FILE_KIND_DATA);
if (!ft) {
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Too many concurrent file transfers.");
return;
}
char sizestr[32];
bytes_convert_str(sizestr, sizeof(sizestr), file_size);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)",
filename, sizestr);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
char file_path[MAX_STR_SIZE];
size_t path_len = name_length;
@ -479,8 +541,9 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t file
snprintf(file_path, sizeof(file_path), "%s", filename);
}
if (path_len >= sizeof(Friends.list[num].file_receiver[idx].file_path)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File name too long.");
if (path_len >= sizeof(file_path) || path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) {
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File path too long.");
return;
}
@ -505,16 +568,18 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t file
file_path[path_len + d_len] = '\0';
if (count > 999) {
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: invalid file path.");
return;
}
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", idx);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", ft->index);
Friends.list[num].file_receiver[idx].pending = true;
Friends.list[num].file_receiver[idx].file_size = file_size;
strcpy(Friends.list[num].file_receiver[idx].file_path, file_path);
ft->file_size = file_size;
snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL);
if (self->active_box != -1)
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
@ -872,7 +937,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (diff != -1) {
if (x + diff > x2 - 1) {
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
@ -929,7 +994,10 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
ChatContext *ctx = self->chatwin;
pthread_mutex_lock(&Winthread.lock);
line_info_print(self);
pthread_mutex_unlock(&Winthread.lock);
wclear(ctx->linewin);
curs_set(1);
@ -1023,7 +1091,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
int y, x;
getyx(self->window, y, x);
(void) x;
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x);
wrefresh(self->window);
@ -1090,11 +1158,13 @@ static void chat_onInit(ToxWindow *self, Tox *m)
char myid[TOX_ADDRESS_SIZE];
tox_self_get_address(m, (uint8_t *) myid);
log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
int log_ret = log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
load_chat_history(self, ctx->log);
if (!Friends.list[self->num].logging_on)
log_disable(ctx->log);
else if (log_ret == -1)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);

View File

@ -52,31 +52,30 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
return;
}
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */
if (!Friends.list[self->num].file_receiver[idx].active) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
struct FileTransfer *ft = NULL;
const char *file_path = Friends.list[self->num].file_receiver[idx].file_path;
char file_name[MAX_STR_SIZE];
get_file_name(file_name, sizeof(file_name), file_path);
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", file_name);
close_file_transfer(self, m, get_file_receiver_filenum(idx), self->num, TOX_FILE_CONTROL_CANCEL, msg, silent);
return;
} else if (strcasecmp(inoutstr, "out") == 0) { /* cancel an outgoing file transfer */
if (!Friends.list[self->num].file_sender[idx].active) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", Friends.list[self->num].file_sender[idx].file_name);
close_file_transfer(self, m, idx, self->num, TOX_FILE_CONTROL_CANCEL, msg, silent);
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'.");
return;
}
if (!ft) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
if (ft->state == FILE_TRANSFER_INACTIVE) {
line_info_add(self, NULL, 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])
@ -124,7 +123,7 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
#ifdef AUDIO
else
groupnum = toxav_join_av_groupchat(m, self->num, (uint8_t *) groupkey, length,
write_device_callback_group, NULL);
NULL, NULL);
#endif
if (groupnum == -1) {
@ -154,36 +153,39 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return;
}
uint32_t filenum = get_file_receiver_filenum(idx);
struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
if (!Friends.list[self->num].file_receiver[idx].pending) {
if (!ft) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return;
}
const char *file_path = Friends.list[self->num].file_receiver[idx].file_path;
if (ft->state != FILE_TRANSFER_PENDING) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return;
}
if ((ft->file = fopen(ft->file_path, "a")) == NULL) {
const char *msg = "File transfer failed: Invalid file 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, filenum, TOX_FILE_CONTROL_RESUME, &err);
tox_file_control(m, self->num, ft->filenum, TOX_FILE_CONTROL_RESUME, &err);
if (err != TOX_ERR_FILE_CONTROL_OK)
goto on_recv_error;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, file_path);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, ft->file_path);
/* prep progress bar line */
char progline[MAX_STR_SIZE];
prep_prog_line(progline);
init_progress_bar(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
Friends.list[self->num].file_receiver[idx].line_id = self->chatwin->hst->line_end->id + 2;
Friends.list[self->num].file_receiver[idx].pending = false;
if ((Friends.list[self->num].file_receiver[idx].file = fopen(file_path, "a")) == NULL) {
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid file path.");
} else {
Friends.list[self->num].file_receiver[idx].active = true;
}
ft->line_id = self->chatwin->hst->line_end->id + 2;
ft->state = FILE_TRANSFER_STARTED;
return;
@ -252,33 +254,30 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
}
char file_name[TOX_MAX_FILENAME_LENGTH];
get_file_name(file_name, sizeof(file_name), path);
size_t namelen = strlen(file_name);
size_t namelen = get_file_name(file_name, sizeof(file_name), path);
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);
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
(uint8_t *) file_name, namelen, &err);
if (err != TOX_ERR_FILE_SEND_OK)
goto on_send_error;
uint32_t idx = get_file_transfer_index(filenum);
struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);
if (idx >= MAX_FILES) {
errmsg = "File transfer failed: Too many concurrent file transfers";
if (!ft) {
err = TOX_ERR_FILE_SEND_TOO_MANY;
goto on_send_error;
}
memcpy(Friends.list[self->num].file_sender[idx].file_name, file_name, namelen + 1);
Friends.list[self->num].file_sender[idx].active = true;
Friends.list[self->num].file_sender[idx].started = false;
Friends.list[self->num].file_sender[idx].file = file_to_send;
Friends.list[self->num].file_sender[idx].timestamp = get_unix_time();
Friends.list[self->num].file_sender[idx].file_size = filesize;
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, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", idx, file_name, sizestr);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", filenum, file_name, sizestr);
return;
@ -301,7 +300,7 @@ on_send_error:
break;
default:
errmsg = "File transfer failed";
errmsg = "File transfer failed.";
break;
}

View File

@ -140,7 +140,10 @@ DeviceError init_devices()
DeviceError terminate_devices()
{
/* Cleanup if needed */
lock;
thread_running = false;
unlock;
usleep(20000);
if (pthread_mutex_destroy(&mutex) != 0)
@ -406,8 +409,15 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
int32_t sample = 0;
while (thread_running)
while (true)
{
lock;
if (!thread_running) {
unlock;
break;
}
unlock;
if (thread_paused) usleep(10000); /* Wait for unpause. */
else
{

View File

@ -234,12 +234,16 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
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)
static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *dombuf, size_t dombuf_sz)
{
char tmpaddr[MAX_STR_SIZE];
char *tmpname, *tmpdom;
if (strlen(addr) >= MAX_STR_SIZE)
return -1;
strcpy(tmpaddr, addr);
char tmpaddr[MAX_STR_SIZE];
char *tmpname = NULL;
char *tmpdom = NULL;
snprintf(tmpaddr, sizeof(tmpaddr), "%s", addr);
tmpname = strtok(tmpaddr, "@");
tmpdom = strtok(NULL, "");
@ -247,8 +251,8 @@ static int parse_addr(const char *addr, char *namebuf, char *dombuf)
return -1;
str_to_lower(tmpdom);
strcpy(namebuf, tmpname);
strcpy(dombuf, tmpdom);
snprintf(namebuf, namebuf_sz, "%s", tmpname);
snprintf(dombuf, dombuf_sz, "%s", tmpdom);
return strlen(namebuf);
}
@ -295,7 +299,7 @@ void *dns3_lookup_thread(void *data)
char inputdomain[MAX_STR_SIZE];
char name[MAX_STR_SIZE];
int namelen = parse_addr(t_data.addr, name, inputdomain);
int namelen = parse_addr(t_data.addr, name, sizeof(name), inputdomain, sizeof(inputdomain));
if (namelen == -1) {
dns_error(self, "Must be a Tox ID or an address in the form username@domain");

View File

@ -1,297 +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 FriendsList Friends;
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
/* 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;
uint32_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, uint32_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)
{
uint8_t 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, uint8_t i, uint32_t friendnum, uint32_t filenum,
const char *filename)
{
FILE *fp = file_senders[i].file;
while (true) {
TOX_ERR_FILE_SEND_CHUNK err;
if (!tox_file_send_chunk(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece,
file_senders[i].piecelen, &err) {
fprintf(stderr, "tox_file_send_chunk failed with error %d\n", err);
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;
uint32_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)
&& (!file_senders[i].paused || (file_senders[i].paused && file_senders[i].noconnection))) {
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);
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].paused | 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,76 +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
typedef struct {
FILE *file;
ToxWindow *toxwin;
uint32_t friendnum;
bool active;
bool noconnection; /* set when the connection has been interrupted */
bool paused; /* set when transfer has been explicitly paused */
bool finished; /* set after entire file has been sent but no TOX_FILECONTROL_FINISHED receieved */
bool started; /* set after TOX_FILECONTROL_ACCEPT received */
int filenum;
char nextpiece[FILE_PIECE_SIZE];
size_t piecelen;
char filename[MAX_STR_SIZE];
uint64_t timestamp; /* marks the last time data was successfully transfered */
uint64_t last_progress; /* marks the last time the progress bar was refreshed */
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 */

View File

@ -35,11 +35,52 @@
extern FriendsList Friends;
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
#define NUM_PROG_MARKS 50
/* Checks for timed out file transfers and closes them. */
#define CHECK_FILE_TIMEOUT_INTERAVAL 5
void check_file_transfer_timeouts(Tox *m)
{
char msg[MAX_STR_SIZE];
static uint64_t last_check = 0;
if (!timed_out(last_check, CHECK_FILE_TIMEOUT_INTERAVAL))
return;
last_check = get_unix_time();
size_t i, j;
for (i = 0; i < Friends.max_idx; ++i) {
if (!Friends.list[i].active)
continue;
for (j = 0; j < MAX_FILES; ++j) {
struct FileTransfer *ft_send = &Friends.list[i].file_sender[j];
if (ft_send->state > FILE_TRANSFER_PAUSED) {
if (timed_out(ft_send->last_keep_alive, TIMEOUT_FILESENDER)) {
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", ft_send->file_name);
close_file_transfer(ft_send->window, m, ft_send, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
}
}
struct FileTransfer *ft_recv = &Friends.list[i].file_receiver[j];
if (ft_recv->state > FILE_TRANSFER_PAUSED) {
if (timed_out(ft_recv->last_keep_alive, TIMEOUT_FILESENDER)) {
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", ft_recv->file_name);
close_file_transfer(ft_recv->window, m, ft_recv, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
}
}
}
}
}
/* creates initial progress line that will be updated during file transfer.
Assumes progline is of size MAX_STR_SIZE */
void prep_prog_line(char *progline)
void init_progress_bar(char *progline)
{
strcpy(progline, "0.0 B/s [");
int i;
@ -54,6 +95,9 @@ void prep_prog_line(char *progline)
if friendnum is -1 we're sending the file, otherwise we're receiving. */
void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id)
{
if (bps < 0 || pct_done < 0 || pct_done > 100)
return;
char msg[MAX_STR_SIZE];
bytes_convert_str(msg, sizeof(msg), bps);
strcat(msg, "/s [");
@ -77,106 +121,179 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
line_info_set(self, line_id, msg);
}
/* Filenumbers >= this number are receiving, otherwise sending.
* Warning: This behaviour is not defined by the Tox API and is subject to change at any time.
*/
#define FILE_NUMBER_MAGIC_NUM (1 << 16)
/* Returns filenum's file transfer array index */
uint32_t get_file_transfer_index(uint32_t filenum)
static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer *ft)
{
return filenum >= FILE_NUMBER_MAGIC_NUM ? (filenum >> 16) - 1 : filenum;
if (ft->state == FILE_TRANSFER_INACTIVE)
return;
/* Timeout must be set to 1 second to show correct bytes per second */
if (!timed_out(ft->last_line_progress, 1))
return;
double remain = ft->file_size - ft->position;
double pct_done = remain > 0 ? (1 - (remain / ft->file_size)) * 100 : 100;
print_progress_bar(self, ft->bps, pct_done, ft->line_id);
ft->bps = 0;
ft->last_line_progress = get_unix_time();
}
/* Returns the filenumber of a file receiver's index */
uint32_t get_file_receiver_filenum(uint32_t idx)
{
return (idx + 1) << 16;
}
/* Return true if filenum is associated with a file receiver, false if file sender */
bool filenum_is_sending(uint32_t filenum)
{
return filenum < FILE_NUMBER_MAGIC_NUM;
}
/* refreshes active file receiver status bars for friendnum */
/* refreshes active file transfer status bars. */
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum)
{
uint64_t curtime = get_unix_time();
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
if (Friends.list[friendnum].file_receiver[i].active) {
if (timed_out(Friends.list[friendnum].file_receiver[i].last_progress, curtime, 1)) {
uint64_t size = Friends.list[friendnum].file_receiver[i].file_size;
double remain = size - Friends.list[friendnum].file_receiver[i].position;
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
print_progress_bar(self, Friends.list[friendnum].file_receiver[i].bps, pct_done,
Friends.list[friendnum].file_receiver[i].line_id);
Friends.list[friendnum].file_receiver[i].bps = 0;
Friends.list[friendnum].file_receiver[i].last_progress = curtime;
refresh_progress_helper(self, m, &Friends.list[friendnum].file_receiver[i]);
refresh_progress_helper(self, m, &Friends.list[friendnum].file_sender[i]);
}
}
if (Friends.list[friendnum].file_sender[i].active) {
if (timed_out(Friends.list[friendnum].file_sender[i].last_progress, curtime, 1)) {
uint64_t size = Friends.list[friendnum].file_sender[i].file_size;
double remain = size - Friends.list[friendnum].file_sender[i].position;
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
* Returns NULL if filenum is invalid.
*/
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum)
{
size_t i;
print_progress_bar(self, Friends.list[friendnum].file_sender[i].bps, pct_done,
Friends.list[friendnum].file_sender[i].line_id);
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft_send = &Friends.list[friendnum].file_sender[i];
Friends.list[friendnum].file_sender[i].bps = 0;
Friends.list[friendnum].file_sender[i].last_progress = curtime;
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum)
return ft_send;
struct FileTransfer *ft_recv = &Friends.list[friendnum].file_receiver[i];
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum)
return ft_recv;
}
return NULL;
}
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
* Returns NULL on failure.
*/
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
FILE_TRANSFER_DIRECTION direction)
{
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND)
return NULL;
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
&Friends.list[friendnum].file_sender[i] :
&Friends.list[friendnum].file_receiver[i];
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index)
return ft;
}
return NULL;
}
/* Returns a pointer to an unused file sender.
* Returns NULL if all file senders are in use.
*/
static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type)
{
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
if (ft->state == FILE_TRANSFER_INACTIVE) {
memset(ft, 0, sizeof(struct FileTransfer));
ft->window = window;
ft->index = i;
ft->friendnum = friendnum;
ft->filenum = filenum;
ft->file_type = type;
ft->last_keep_alive = get_unix_time();
ft->state = FILE_TRANSFER_PENDING;
ft->direction = FILE_TRANSFER_SEND;
return ft;
}
}
/* Closes file transfer with filenum.
return NULL;
}
/* Returns a pointer to an unused file receiver.
* Returns NULL if all file receivers are in use.
*/
static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type)
{
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i];
if (ft->state == FILE_TRANSFER_INACTIVE) {
memset(ft, 0, sizeof(struct FileTransfer));
ft->window = window;
ft->index = i;
ft->friendnum = friendnum;
ft->filenum = filenum;
ft->file_type = type;
ft->last_keep_alive = get_unix_time();
ft->state = FILE_TRANSFER_PENDING;
ft->direction = FILE_TRANSFER_RECV;
return ft;
}
}
return NULL;
}
/* Initializes an unused file transfer and returns its pointer.
* Returns NULL on failure.
*/
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
FILE_TRANSFER_DIRECTION direction, uint8_t type)
{
if (direction == FILE_TRANSFER_RECV)
return new_file_receiver(window, friendnum, filenum, type);
if (direction == FILE_TRANSFER_SEND)
return new_file_sender(window, friendnum, filenum, type);
return NULL;
}
/* Closes file transfer ft.
*
* 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.
*/
void close_file_transfer(ToxWindow *self, Tox *m, uint32_t filenum, uint32_t friendnum, int CTRL,
const char *message, Notification sound_type)
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
Notification sound_type)
{
uint32_t idx = get_file_transfer_index(filenum);
bool sending = filenum_is_sending(filenum);
if (sending && Friends.list[friendnum].file_sender[idx].active) {
FILE *fp = Friends.list[friendnum].file_sender[idx].file;
if (fp)
fclose(fp);
memset(&Friends.list[friendnum].file_sender[idx], 0, sizeof(struct FileSender));
}
else if (!sending && Friends.list[friendnum].file_receiver[idx].active) {
FILE *fp = Friends.list[friendnum].file_receiver[idx].file;
if (fp)
fclose(fp);
memset(&Friends.list[friendnum].file_receiver[idx], 0, sizeof(struct FileReceiver));
}
else
if (!ft)
return;
if (ft->state == FILE_TRANSFER_INACTIVE)
return;
if (ft->file)
fclose(ft->file);
if (CTRL >= 0)
tox_file_control(m, friendnum, filenum, CTRL, NULL);
tox_file_control(m, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) CTRL, NULL);
if (message && self) {
if (self->active_box != -1)
if (self->active_box != -1 && sound_type != silent)
box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message);
else
box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
}
memset(ft, 0, sizeof(struct FileTransfer));
}
/* Kills all active file transfers for friendnum */
@ -185,10 +302,15 @@ void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum)
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
fprintf(stderr, "%lu\n", i);
if (Friends.list[friendnum].file_sender[i].active)
close_file_transfer(NULL, m, i, friendnum, -1, NULL, silent);
if (Friends.list[friendnum].file_receiver[i].active)
close_file_transfer(NULL, m, get_file_receiver_filenum(i), friendnum, -1, NULL, silent);
close_file_transfer(NULL, m, &Friends.list[friendnum].file_sender[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
close_file_transfer(NULL, m, &Friends.list[friendnum].file_receiver[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
}
}
void kill_all_file_transfers(Tox *m)
{
size_t i;
for (i = 0; i < Friends.max_idx; ++i)
kill_all_file_transfers_friend(m, Friends.list[i].num);
}

View File

@ -33,64 +33,83 @@
#define MiB 1048576 /* 1024^2 */
#define GiB 1073741824 /* 1024^3 */
#define FILE_PIECE_SIZE 2048
#define MAX_FILES 32
#define TIMEOUT_FILESENDER 120
struct FileSender {
typedef enum FILE_TRANSFER_STATE {
FILE_TRANSFER_INACTIVE,
FILE_TRANSFER_PAUSED,
FILE_TRANSFER_PENDING,
FILE_TRANSFER_STARTED,
} FILE_TRANSFER_STATE;
typedef enum FILE_TRANSFER_DIRECTION {
FILE_TRANSFER_SEND,
FILE_TRANSFER_RECV
} FILE_TRANSFER_DIRECTION;
struct FileTransfer {
ToxWindow *window;
FILE *file;
char file_name[TOX_MAX_FILENAME_LENGTH];
bool active;
bool noconnection; /* set when the connection has been interrupted */
bool paused; /* set when transfer has been explicitly paused */
bool started; /* set after TOX_FILECONTROL_ACCEPT received */
uint64_t timestamp; /* marks the last time data was successfully transfered */
FILE_TRANSFER_STATE state;
FILE_TRANSFER_DIRECTION direction;
uint8_t file_type;
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
char file_path[PATH_MAX + 1]; /* Not used by senders */
double bps;
uint32_t filenum;
uint32_t friendnum;
size_t index;
uint64_t file_size;
uint64_t last_progress; /* marks the last time the progress bar was refreshed */
uint64_t position;
uint64_t last_line_progress; /* The last time we updated the progress bar */
uint64_t last_keep_alive; /* The last time we sent or received data */
uint32_t line_id;
uint8_t file_id[TOX_FILE_ID_LENGTH];
};
struct FileReceiver {
FILE *file;
char file_path[PATH_MAX + 1];
bool pending;
bool active;
double bps;
uint64_t file_size;
uint64_t last_progress;
uint64_t position;
uint32_t line_id;
};
/* Checks for timed out file transfers and closes them. */
void check_file_transfer_timeouts(Tox *m);
/* creates initial progress line that will be updated during file transfer.
progline must be at lesat MAX_STR_SIZE bytes */
void prep_prog_line(char *progline);
void init_progress_bar(char *progline);
/* prints a progress bar for file transfers */
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
/* refreshes active file receiver status bars for friendnum */
/* refreshes active file transfer status bars. */
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum);
/* Returns filenum's file transfer array index */
uint32_t get_file_transfer_index(uint32_t filenum);
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
* Returns NULL if filenum is invalid.
*/
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum);
/* Returns the filenumber of a file receiver's index */
uint32_t get_file_receiver_filenum(uint32_t idx);
/* Return true if filenum is associated with a file receiver, false if file sender */
bool filenum_is_sending(uint32_t filenum);
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
* Returns NULL on failure.
*/
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
FILE_TRANSFER_DIRECTION direction);
/* Closes file transfer with filenum.
/* Initializes an unused file transfer and returns its pointer.
* Returns NULL on failure.
*/
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
FILE_TRANSFER_DIRECTION direction, uint8_t type);
/* Closes file transfer ft.
*
* 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.
*/
void close_file_transfer(ToxWindow *self, Tox *m, uint32_t filenum, uint32_t friendnum, int CTRL,
const char *message, Notification sound_type);
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
Notification sound_type);
/* Kills all active file transfers for friendnum */
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
void kill_all_file_transfers(Tox *m);
#endif /* #define FILE_TRANSFERS_H */

View File

@ -38,6 +38,7 @@
#include "notify.h"
#include "help.h"
#include "log.h"
#include "avatars.h"
#ifdef AUDIO
#include "audio_call.h"
@ -138,8 +139,10 @@ static int save_blocklist(char *path)
int count = 0;
for (i = 0; i < Blocked.max_idx; ++i) {
if (count > Blocked.num_blocked)
goto on_error;
if (count > Blocked.num_blocked) {
free(data);
return -1;
}
if (Blocked.list[i].active) {
BlockedFriend tmp;
@ -160,19 +163,20 @@ static int save_blocklist(char *path)
FILE *fp = fopen(path, "wb");
if (fp == NULL)
goto on_error;
if (fp == NULL) {
free(data);
return -1;
}
if (fwrite(data, len, 1, fp) != 1)
goto on_error;
if (fwrite(data, len, 1, fp) != 1) {
fclose(fp);
free(data);
return -1;
}
fclose(fp);
free(data);
return 0;
on_error:
free(data);
return -1;
}
static void sort_blocklist_index(void);
@ -220,9 +224,10 @@ int load_blocklist(char *path)
int i;
for (i = 0; i < num; ++i) {
BlockedFriend tmp;
memset(&tmp, 0, sizeof(BlockedFriend));
memset(&Blocked.list[i], 0, sizeof(BlockedFriend));
BlockedFriend tmp;
memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend));
Blocked.list[i].active = true;
Blocked.list[i].num = i;
@ -330,11 +335,15 @@ static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num,
if (num >= Friends.max_idx)
return;
if (connection_status == TOX_CONNECTION_NONE)
if (connection_status == TOX_CONNECTION_NONE) {
--Friends.num_online;
else
} else if (Friends.list[num].connection_status == TOX_CONNECTION_NONE) {
++Friends.num_online;
if (avatar_send(m, num) == -1)
fprintf(stderr, "avatar_send failed for friend %d\n", num);
}
Friends.list[num].connection_status = connection_status;
update_friend_last_online(num, get_unix_time());
store_data(m, DATA_FILE);
@ -403,13 +412,19 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
Friends.list[i].status = TOX_USER_STATUS_NONE;
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
TOX_ERR_FRIEND_GET_PUBLIC_KEY err;
tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, &err);
TOX_ERR_FRIEND_GET_PUBLIC_KEY pkerr;
tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, &pkerr);
if (err != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK)
fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", err);
if (pkerr != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK)
fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", pkerr);
// update_friend_last_online(i, 0);
TOX_ERR_FRIEND_GET_LAST_ONLINE loerr;
uint64_t t = tox_friend_get_last_online(m, num, &loerr);
if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK)
t = 0;
update_friend_last_online(i, t);
char tempname[TOX_MAX_NAME_LENGTH] = {0};
get_nick_truncate(m, tempname, num);
@ -460,7 +475,7 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
}
}
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind,
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum,
uint64_t file_size, const char *filename, size_t name_length)
{
if (num >= Friends.max_idx)
@ -609,10 +624,12 @@ static void draw_del_popup(void)
wprintw(PendingDelete.popup, "Delete contact ");
wattron(PendingDelete.popup, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
if (blocklist_view == 0)
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
else
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
pthread_mutex_unlock(&Winthread.lock);
wattroff(PendingDelete.popup, A_BOLD);
wprintw(PendingDelete.popup, "? y/n");
@ -873,12 +890,13 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
return;
}
// uint64_t cur_time = get_unix_time();
// struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
uint64_t cur_time = time(NULL);
struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
wattron(self->window, A_BOLD);
wprintw(self->window, " Online: ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends);
if ((y2 - FLIST_OFST) <= 0)
@ -887,18 +905,30 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
uint32_t selected_num = 0;
/* Determine which portion of friendlist to draw based on current position */
pthread_mutex_lock(&Winthread.lock);
int page = Friends.num_selected / (y2 - FLIST_OFST);
pthread_mutex_unlock(&Winthread.lock);
int start = (y2 - FLIST_OFST) * page;
int end = y2 - FLIST_OFST + start;
pthread_mutex_lock(&Winthread.lock);
size_t num_friends = Friends.num_friends;
pthread_mutex_unlock(&Winthread.lock);
int i;
for (i = start; i < Friends.num_friends && i < end; ++i) {
for (i = start; i < num_friends && i < end; ++i) {
pthread_mutex_lock(&Winthread.lock);
uint32_t f = Friends.index[i];
bool is_active = Friends.list[f].active;
int num_selected = Friends.num_selected;
pthread_mutex_unlock(&Winthread.lock);
bool f_selected = false;
if (Friends.list[f].active) {
if (i == Friends.num_selected) {
if (is_active) {
if (i == num_selected) {
wattron(self->window, A_BOLD);
wprintw(self->window, " > ");
wattroff(self->window, A_BOLD);
@ -908,8 +938,12 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wprintw(self->window, " ");
}
if (Friends.list[f].connection_status != TOX_CONNECTION_NONE) {
pthread_mutex_lock(&Winthread.lock);
TOX_CONNECTION connection_status = Friends.list[f].connection_status;
TOX_USER_STATUS status = Friends.list[f].status;
pthread_mutex_unlock(&Winthread.lock);
if (connection_status != TOX_CONNECTION_NONE) {
int colour = MAGENTA;
switch (status) {
@ -932,7 +966,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wattron(self->window, COLOR_PAIR(BLUE));
wattron(self->window, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
wprintw(self->window, "%s", Friends.list[f].name);
pthread_mutex_unlock(&Winthread.lock);
wattroff(self->window, A_BOLD);
if (f_selected)
@ -947,14 +983,21 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
size_t s_len = tox_friend_get_status_message_size(m, Friends.list[f].num, NULL);
pthread_mutex_unlock(&Winthread.lock);
statusmsg[s_len] = '\0';
filter_str(statusmsg, s_len);
pthread_mutex_lock(&Winthread.lock);
snprintf(Friends.list[f].statusmsg, sizeof(Friends.list[f].statusmsg), "%s", statusmsg);
Friends.list[f].statusmsg_len = strlen(Friends.list[f].statusmsg);
pthread_mutex_unlock(&Winthread.lock);
}
/* Truncate note if it doesn't fit on one line */
size_t maxlen = x2 - getcurx(self->window) - 2;
pthread_mutex_lock(&Winthread.lock);
if (Friends.list[f].statusmsg_len > maxlen) {
Friends.list[f].statusmsg[maxlen - 3] = '\0';
strcat(Friends.list[f].statusmsg, "...");
@ -962,9 +1005,11 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
Friends.list[f].statusmsg_len = maxlen;
}
if (Friends.list[f].statusmsg[0])
if (Friends.list[f].statusmsg_len > 0)
wprintw(self->window, " %s", Friends.list[f].statusmsg);
pthread_mutex_unlock(&Winthread.lock);
wprintw(self->window, "\n");
} else {
wprintw(self->window, "%s ", OFFLINE_CHAR);
@ -973,47 +1018,52 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wattron(self->window, COLOR_PAIR(BLUE));
wattron(self->window, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
wprintw(self->window, "%s", Friends.list[f].name);
pthread_mutex_unlock(&Winthread.lock);
wattroff(self->window, A_BOLD);
if (f_selected)
wattroff(self->window, COLOR_PAIR(BLUE));
wprintw(self->window, "\n");
/* Last online is currently broken in core */
pthread_mutex_lock(&Winthread.lock);
uint64_t last_seen = Friends.list[f].last_online.last_on;
pthread_mutex_unlock(&Winthread.lock);
// uint64_t last_seen = Friends.list[f].last_online.last_on;
//
// if (last_seen != 0) {
// int day_dist = (
// cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
// + ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
// );
// const char *hourmin = Friends.list[f].last_online.hour_min_str;
if (last_seen != 0) {
pthread_mutex_lock(&Winthread.lock);
// switch (day_dist) {
// case 0:
// wprintw(self->window, " Last seen: Today %s\n", hourmin);
// break;
int day_dist = (
cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
+ ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
);
const char *hourmin = Friends.list[f].last_online.hour_min_str;
// case 1:
// wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
// break;
pthread_mutex_unlock(&Winthread.lock);
// default:
// wprintw(self->window, " Last seen: %d days ago\n", day_dist);
// break;
// }
// } else {
// wprintw(self->window, " Last seen: Never\n");
// }
switch (day_dist) {
case 0:
wprintw(self->window, " Last seen: Today %s\n", hourmin);
break;
case 1:
wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
break;
default:
wprintw(self->window, " Last seen: %d days ago\n", day_dist);
break;
}
} else {
wprintw(self->window, " Last seen: Never\n");
}
}
}
}
self->x = x2;
if (Friends.num_friends) {
if (num_friends) {
wmove(self->window, y2 - 1, 1);
wattron(self->window, A_BOLD);

View File

@ -59,8 +59,8 @@ typedef struct {
struct LastOnline last_online;
struct GroupChatInvite group_invite;
struct FileReceiver file_receiver[MAX_FILES];
struct FileSender file_sender[MAX_FILES];
struct FileTransfer file_receiver[MAX_FILES];
struct FileTransfer file_sender[MAX_FILES];
} ToxicFriend;
typedef struct {

View File

@ -35,6 +35,7 @@
#include "prompt.h"
#include "help.h"
#include "term_mplex.h"
#include "avatars.h"
extern char *DATA_FILE;
extern ToxWindow *prompt;
@ -198,72 +199,39 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
// if (argc < 2) {
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: No file path supplied.");
// return;
// }
if (argc < 2 || strlen(argv[1]) < 3) {
avatar_unset(m);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar is not set.");
return;
}
// /* turns the avatar off */
// if (strlen(argv[1]) < 3) {
// tox_unset_avatar(m);
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No avatar set.");
// return;
// }
if (argv[1][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes.");
return;
}
// if (argv[1][0] != '\"') {
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "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 len = strlen(path) - 1;
// /* remove opening and closing quotes */
// char path[MAX_STR_SIZE];
// snprintf(path, sizeof(path), "%s", &argv[1][1]);
// int len = strlen(path) - 1;
// path[len] = '\0';
if (len <= 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid path.");
return;
}
// off_t sz = file_size(path);
path[len] = '\0';
char filename[MAX_STR_SIZE];
get_file_name(filename, sizeof(filename), path);
// if (sz <= 8) {
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Invalid file.");
// return;
// }
if (avatar_set(m, path, len) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
"Failed to set avatar. Avatars must be in PNG format and may not exceed %d bytes.",
MAX_AVATAR_FILE_SIZE);
return;
}
// FILE *fp = fopen(path, "rb");
// if (fp == NULL) {
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Could not open file.");
// return;
// }
// 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);
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File type not supported.");
// return;
// }
// char *avatar = malloc(sz);
// if (avatar == NULL)
// exit_toxic_err("Failed in cmd_avatar", FATALERR_MEMORY);
// if (fread(avatar, sz, 1, fp) != 1) {
// fclose(fp);
// free(avatar);
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Read fail.");
// return;
// }
// if (tox_set_avatar(m, TOX_AVATAR_FORMAT_PNG, (const uint8_t *) avatar, (uint32_t) sz) == -1)
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar");
// char filename[MAX_STR_SIZE];
// get_file_name(filename, sizeof(filename), path);
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename);
// fclose(fp);
// free(avatar);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename);
}
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -281,18 +249,22 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
const char *ip = argv[1];
const char *port = argv[2];
const char *key = argv[3];
const char *ascii_key = argv[3];
if (atoi(port) == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid port.");
return;
}
char *binary_string = hex_string_to_bin(key);
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
return;
}
TOX_ERR_BOOTSTRAP err;
tox_bootstrap(m, ip, atoi(port), (uint8_t *) binary_string, &err);
free(binary_string);
tox_bootstrap(m, ip, atoi(port), (uint8_t *) key_binary, &err);
tox_add_tcp_relay(m, ip, atoi(port), (uint8_t *) key_binary, &err);
switch (err) {
case TOX_ERR_BOOTSTRAP_BAD_HOST:
@ -372,7 +344,7 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
groupnum = tox_add_groupchat(m);
#ifdef AUDIO
else
groupnum = toxav_add_av_groupchat(m, write_device_callback_group, NULL);
groupnum = toxav_add_av_groupchat(m, NULL, NULL);
#endif
if (groupnum == -1) {
@ -410,16 +382,18 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
char myid[TOX_ADDRESS_SIZE];
tox_self_get_address(m, (uint8_t *) myid);
int log_ret = -1;
if (self->is_chat) {
Friends.list[self->num].logging_on = true;
log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT);
log_ret = log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT);
} else if (self->is_prompt) {
log_enable(self->name, myid, NULL, log, LOG_PROMPT);
log_ret = log_enable(self->name, myid, NULL, log, LOG_PROMPT);
} else if (self->is_groupchat) {
log_enable(self->name, myid, NULL, log, LOG_GROUP);
log_ret = log_enable(self->name, myid, NULL, log, LOG_GROUP);
}
msg = "Logging enabled";
msg = log_ret == 0 ? "Logging enabled." : "Warning: Log failed to initialize.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
return;
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
@ -428,7 +402,7 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
log_disable(log);
msg = "Logging disabled";
msg = "Logging disabled.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
return;
}

View File

@ -323,7 +323,7 @@ static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, int groupnum,
get_time_str(timefrmt, sizeof(timefrmt));
/* don't announce title when we join the room */
if (!timed_out(groupchats[self->num].start_time, get_unix_time(), GROUP_EVENT_WAIT))
if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT))
return;
char nick[TOX_MAX_NAME_LENGTH];
@ -402,7 +402,7 @@ void *group_add_wait(void *data)
pthread_mutex_lock(&Winthread.lock);
get_group_nick_truncate(m, peername, thrd->peernum, thrd->groupnum);
if (strcmp(peername, DEFAULT_TOX_NAME) || timed_out(thrd->timestamp, get_unix_time(), GROUP_EVENT_WAIT)) {
if (strcmp(peername, DEFAULT_TOX_NAME) || timed_out(thrd->timestamp, GROUP_EVENT_WAIT)) {
pthread_mutex_unlock(&Winthread.lock);
break;
}
@ -478,7 +478,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
switch (change) {
case TOX_CHAT_CHANGE_PEER_ADD:
if (!timed_out(groupchats[groupnum].start_time, get_unix_time(), GROUP_EVENT_WAIT))
if (!timed_out(groupchats[groupnum].start_time, GROUP_EVENT_WAIT))
break;
struct group_add_thrd *thrd = malloc(sizeof(struct group_add_thrd));
@ -518,7 +518,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
break;
case TOX_CHAT_CHANGE_PEER_NAME:
if (!timed_out(groupchats[self->num].start_time, get_unix_time(), GROUP_EVENT_WAIT))
if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT))
return;
/* ignore initial name change (TODO: this is a bad way to do this) */
@ -593,7 +593,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (diff != -1) {
if (x + diff > x2 - 1) {
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
@ -650,7 +650,10 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
ChatContext *ctx = self->chatwin;
pthread_mutex_lock(&Winthread.lock);
line_info_print(self);
pthread_mutex_unlock(&Winthread.lock);
wclear(ctx->linewin);
curs_set(1);
@ -695,7 +698,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
int y, x;
getyx(self->window, y, x);
(void) x;
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x);
wrefresh(self->window);
@ -726,7 +729,9 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
if (user_settings->autolog == AUTOLOG_ON) {
char myid[TOX_ADDRESS_SIZE];
tox_self_get_address(m, (uint8_t *) myid);
log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP);
if (log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP) == -1)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
}
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
@ -790,66 +795,66 @@ static int group_audio_close_out_device(int groupnum)
return 0;
}
static int group_audio_write(int peernum, int groupnum, const int16_t *pcm, unsigned int samples, uint8_t channels,
unsigned int sample_rate)
{
if (!pcm)
return -1;
// static int group_audio_write(int peernum, int groupnum, const int16_t *pcm, unsigned int samples, uint8_t channels,
// unsigned int sample_rate)
// {
// if (!pcm)
// return -1;
if (channels == 0 || channels > 2)
return -2;
// if (channels == 0 || channels > 2)
// return -2;
ALuint bufid;
ALint processed = 0, queued = 0;
// ALuint bufid;
// ALint processed = 0, queued = 0;
alGetSourcei(groupchats[groupnum].audio.source, AL_BUFFERS_PROCESSED, &processed);
alGetSourcei(groupchats[groupnum].audio.source, AL_BUFFERS_QUEUED, &queued);
fprintf(stderr, "source: %d, queued: %d, processed: %d\n", groupchats[groupnum].audio.source, queued, processed);
// alGetSourcei(groupchats[groupnum].audio.source, AL_BUFFERS_PROCESSED, &processed);
// alGetSourcei(groupchats[groupnum].audio.source, AL_BUFFERS_QUEUED, &queued);
// fprintf(stderr, "source: %d, queued: %d, processed: %d\n", groupchats[groupnum].audio.source, queued, processed);
if (processed) {
ALuint bufids[processed];
alSourceUnqueueBuffers(groupchats[groupnum].audio.source, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
} else if (queued < 16) {
alGenBuffers(1, &bufid);
} else {
return -3;
}
// if (processed) {
// ALuint bufids[processed];
// alSourceUnqueueBuffers(groupchats[groupnum].audio.source, processed, bufids);
// alDeleteBuffers(processed - 1, bufids + 1);
// bufid = bufids[0];
// } else if (queued < 16) {
// alGenBuffers(1, &bufid);
// } else {
// return -3;
// }
int length = samples * channels * sizeof(int16_t);
// int length = samples * channels * sizeof(int16_t);
alBufferData(bufid, (channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, pcm, length, sample_rate);
alSourceQueueBuffers(groupchats[groupnum].audio.source, 1, &bufid);
// alBufferData(bufid, (channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, pcm, length, sample_rate);
// alSourceQueueBuffers(groupchats[groupnum].audio.source, 1, &bufid);
ALint state;
alGetSourcei(groupchats[groupnum].audio.source, AL_SOURCE_STATE, &state);
// ALint state;
// alGetSourcei(groupchats[groupnum].audio.source, AL_SOURCE_STATE, &state);
if (state != AL_PLAYING)
alSourcePlay(groupchats[groupnum].audio.source);
// if (state != AL_PLAYING)
// alSourcePlay(groupchats[groupnum].audio.source);
return 0;
}
// return 0;
// }
static void groupchat_onWriteDevice(ToxWindow *self, Tox *m, int groupnum, int peernum, const int16_t *pcm,
unsigned int samples, uint8_t channels, unsigned int sample_rate)
{
return;
if (groupnum != self->num)
return;
// if (groupnum != self->num)
// return;
if (peernum < 0)
return;
// if (peernum < 0)
// return;
if (groupchats[groupnum].audio.dvhandle == NULL)
fprintf(stderr, "dvhandle is null)\n");
// if (groupchats[groupnum].audio.dvhandle == NULL)
// fprintf(stderr, "dvhandle is null)\n");
if (groupchats[groupnum].audio.dvctx == NULL)
fprintf(stderr, "ctx is null\n");
// if (groupchats[groupnum].audio.dvctx == NULL)
// fprintf(stderr, "ctx is null\n");
int ret = group_audio_write(peernum, groupnum, pcm, samples, channels, sample_rate);
fprintf(stderr, "write: %d\n", ret);
// int ret = group_audio_write(peernum, groupnum, pcm, samples, channels, sample_rate);
// fprintf(stderr, "write: %d\n", ret);
}
#endif /* AUDIO */

View File

@ -144,7 +144,7 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, " /add <addr> <msg> : Add contact with optional message\n");
wprintw(win, " /accept <id> : Accept friend request\n");
wprintw(win, " /avatar <path> : Set a personal avatar\n");
wprintw(win, " /avatar <path> : Set an avatar (leave path empty to unset)\n");
wprintw(win, " /decline <id> : Decline friend request\n");
wprintw(win, " /requests : List pending friend requests\n");
wprintw(win, " /connect <ip> <port> <key> : Manually connect to a DHT node\n");
@ -245,13 +245,6 @@ static void help_draw_group(ToxWindow *self)
wprintw(win, " /title <msg> : Set group title (show current title if no msg)\n\n");
wattron(win, A_BOLD);
wprintw(win, " Audio commands:\n");
wattroff(win, A_BOLD);
wprintw(win, " /mute <type> : Mute active device where type: in | out\n");
wprintw(win, " /sense <n> : VAD sensitivity threshold\n\n");
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
@ -306,12 +299,10 @@ void help_onKey(ToxWindow *self, wint_t key)
self->help->type = HELP_GLOBAL;
break;
#ifdef AUDIO /* remove if/when we add non-audio group commands */
case 'r':
help_init_window(self, 10, 80);
help_init_window(self, 6, 80);
self->help->type = HELP_GROUP;
break;
#endif
case 'f':
help_init_window(self, 10, 80);

View File

@ -125,7 +125,7 @@ static void input_yank(ToxWindow *self, int x, int mx_x)
if (x + yank_cols >= mx_x) {
int rmdr = MAX(0, (x + yank_cols) - mx_x);
int s_len = wcswidth(&ctx->line[ctx->start], rmdr);
int s_len = MAX(0, wcswidth(&ctx->line[ctx->start], rmdr));
ctx->start += s_len + 1;
}
}
@ -137,7 +137,7 @@ static void input_mv_end(ToxWindow *self, int y, int mx_x)
ctx->pos = ctx->len;
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
ctx->start = MAX(0, 1 + (mx_x * (wlen / mx_x) - mx_x) + (wlen % mx_x));
}
@ -196,7 +196,7 @@ static void input_history(ToxWindow *self, wint_t key, int mx_x)
ChatContext *ctx = self->chatwin;
fetch_hist_item(ctx, key);
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
ctx->start = wlen < mx_x ? 0 : wlen - mx_x + 1;
}

View File

@ -133,6 +133,9 @@ static struct line_info *line_info_ret_queue(struct history *hst)
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
uint8_t bold, uint8_t colour, const char *msg, ...)
{
if (!self)
return;
struct history *hst = self->chatwin->hst;
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
@ -155,11 +158,13 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
/* for type-specific formatting in print function */
switch (type) {
case IN_ACTION:
/* fallthrough */
case OUT_ACTION:
len += strlen(user_settings->line_normal) + 2;
break;
case IN_MSG:
/* fallthrough */
case OUT_MSG:
len += strlen(user_settings->line_normal) + 3;
break;
@ -299,7 +304,9 @@ void line_info_print(ToxWindow *self)
switch (type) {
case OUT_MSG:
/* fallthrough */
case OUT_MSG_READ:
/* fallthrough */
case IN_MSG:
wattron(win, COLOR_PAIR(BLUE));
wprintw(win, "%s ", line->timestr);
@ -318,13 +325,17 @@ void line_info_print(ToxWindow *self)
if (line->msg[0] == '>')
wattron(win, COLOR_PAIR(GREEN));
else if (line->msg[0] == '<')
wattron(win, COLOR_PAIR(RED));
wprintw(win, "%s", line->msg);
if (line->msg[0] == '>')
wattroff(win, COLOR_PAIR(GREEN));
else if (line->msg[0] == '<')
wattroff(win, COLOR_PAIR(RED));
if (type == OUT_MSG && timed_out(line->timestamp, get_unix_time(), NOREAD_FLAG_TIMEOUT)) {
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
wattron(win, COLOR_PAIR(RED));
wprintw(win, " x", line->msg);
wattroff(win, COLOR_PAIR(RED));
@ -339,7 +350,9 @@ void line_info_print(ToxWindow *self)
break;
case OUT_ACTION_READ:
/* fallthrough */
case OUT_ACTION:
/* fallthrough */
case IN_ACTION:
wattron(win, COLOR_PAIR(BLUE));
wprintw(win, "%s ", line->timestr);
@ -349,7 +362,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s %s %s", user_settings->line_normal, line->name1, line->msg);
wattroff(win, COLOR_PAIR(YELLOW));
if (type == OUT_ACTION && timed_out(line->timestamp, get_unix_time(), NOREAD_FLAG_TIMEOUT)) {
if (type == OUT_ACTION && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
wattron(win, COLOR_PAIR(RED));
wprintw(win, " x", line->msg);
wattroff(win, COLOR_PAIR(RED));

View File

@ -139,11 +139,9 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
strftime(s, MAX_STR_SIZE, t, get_time());
fprintf(log->file, "%s %s %s\n", s, name_frmt, msg);
uint64_t curtime = get_unix_time();
if (timed_out(log->lastwrite, curtime, LOG_FLUSH_LIMIT)) {
if (timed_out(log->lastwrite, LOG_FLUSH_LIMIT)) {
fflush(log->file);
log->lastwrite = curtime;
log->lastwrite = get_unix_time();
}
}
@ -155,15 +153,19 @@ void log_disable(struct chatlog *log)
memset(log, 0, sizeof(struct chatlog));
}
void log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
{
log->log_on = true;
if (log->file != NULL)
return;
return 0;
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1)
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1) {
log_disable(log);
return -1;
}
return 0;
}
/* Loads previous history from chat log */
@ -177,7 +179,7 @@ void load_chat_history(ToxWindow *self, struct chatlog *log)
if (sz <= 0)
return;
char *hstbuf = malloc(sz);
char *hstbuf = malloc(sz + 1);
if (hstbuf == NULL)
exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY);
@ -194,6 +196,8 @@ void load_chat_history(ToxWindow *self, struct chatlog *log)
return;
}
hstbuf[sz] = '\0';
/* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */
int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size);
int start, count = 0;

View File

@ -39,8 +39,12 @@ enum {
/* formats/writes line to log file */
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event);
/* enables logging for specified log and creates/fetches file if necessary */
void log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype);
/* enables logging for specified log and creates/fetches file if necessary.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype);
/* disables logging for specified log and closes file */
void log_disable(struct chatlog *log);

View File

@ -140,9 +140,7 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
if (!msg)
return;
uint64_t curtime = get_unix_time();
if (msg->receipt != 0 && !timed_out(msg->last_send_try, curtime, CQUEUE_TRY_SEND_INTERVAL))
if (msg->receipt != 0 && !timed_out(msg->last_send_try, CQUEUE_TRY_SEND_INTERVAL))
return;
uint32_t receipt = 0;
@ -150,7 +148,7 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
msg->last_send_try = curtime;
msg->last_send_try = get_unix_time();
msg->receipt = receipt;
return;
}

View File

@ -54,6 +54,7 @@ void hst_to_net(uint8_t *num, uint16_t numbytes)
return;
}
/* Note: The time functions are not thread safe */
void update_unix_time(void)
{
current_unix_time = (uint64_t) time(NULL);
@ -65,9 +66,9 @@ uint64_t get_unix_time(void)
}
/* Returns 1 if connection has timed out, 0 otherwise */
int timed_out(uint64_t timestamp, uint64_t curtime, uint64_t timeout)
int timed_out(uint64_t timestamp, uint64_t timeout)
{
return timestamp + timeout <= curtime;
return timestamp + timeout <= get_unix_time();
}
/* Get the current local time */
@ -109,20 +110,24 @@ void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs)
snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds);
}
char *hex_string_to_bin(const char *hex_string)
/*
* Converts a hexidecimal string of length hex_len to binary format and puts the result in output.
* output_size must be exactly half of hex_len.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size_t output_size)
{
size_t len = strlen(hex_string);
char *val = malloc(len);
if (output_size == 0 || hex_len != output_size * 2)
return -1;
if (val == NULL)
exit_toxic_err("failed in hex_string_to_bin", FATALERR_MEMORY);
for (size_t i = 0; i < output_size; ++i) {
sscanf(hex_string, "%2hhx", &output[i]);
hex_string += 2;
}
size_t i;
for (i = 0; i < len; ++i, hex_string += 2)
sscanf(hex_string, "%2hhx", &val[i]);
return val;
return 0;
}
int hex_string_to_bytes(char *buf, int size, const char *keystr)
@ -147,6 +152,9 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr)
/* Returns 1 if the string is empty, 0 otherwise */
int string_is_empty(const char *string)
{
if (!string)
return true;
return string[0] == '\0';
}
@ -217,22 +225,24 @@ void filter_str(char *str, size_t len)
size_t i;
for (i = 0; i < len; ++i) {
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v')
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0')
str[i] = ' ';
}
}
/* gets base file name from path or original file name if no path is supplied */
void get_file_name(char *namebuf, int bufsize, const char *pathname)
/* gets base file name from path or original file name if no path is supplied.
* Returns the file name length
*/
size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname)
{
int idx = strlen(pathname) - 1;
int len = strlen(pathname) - 1;
char *path = strdup(pathname);
if (path == NULL)
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
while (idx >= 0 && pathname[idx] == '/')
path[idx--] = '\0';
while (len >= 0 && pathname[len] == '/')
path[len--] = '\0';
char *finalname = strdup(path);
@ -249,6 +259,8 @@ void get_file_name(char *namebuf, int bufsize, const char *pathname)
snprintf(namebuf, bufsize, "%s", finalname);
free(finalname);
free(path);
return strlen(namebuf);
}
/* converts str to all lowercase */
@ -363,7 +375,7 @@ bool file_exists(const char *path)
return stat(path, &s) == 0;
}
/* returns file size or 0 on error */
/* returns file size. If file doesn't exist returns 0. */
off_t file_size(const char *path)
{
struct stat st;

View File

@ -41,22 +41,28 @@
void hst_to_net(uint8_t *num, uint16_t numbytes);
/* convert a hex string to binary */
char *hex_string_to_bin(const char *hex_string);
/*
* Converts a hexidecimal string of length hex_len to binary format and puts the result in output.
* output_size must be exactly half of hex_len.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size_t output_size);
/* convert a hex string to bytes. returns 0 on success, -1 on failure */
int hex_string_to_bytes(char *buf, int size, const char *keystr);
/* get the current unix time */
/* get the current unix time (not thread safe) */
uint64_t get_unix_time(void);
/* Puts the current time in buf in the format of [HH:mm:ss] */
/* Puts the current time in buf in the format of [HH:mm:ss] (not thread safe) */
void get_time_str(char *buf, int bufsize);
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs);
/* get the current local time */
/* get the current local time (not thread safe) */
struct tm *get_time(void);
/* updates current unix time (should be run once per do_toxic loop) */
@ -75,7 +81,7 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n);
int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
/* Returns 1 if connection has timed out, 0 otherwise */
int timed_out(uint64_t timestamp, uint64_t timeout, uint64_t curtime);
int timed_out(uint64_t timestamp, uint64_t timeout);
/* Colours the window tab according to type. Beeps if is_beep is true */
void alert_window(ToxWindow *self, int type, bool is_beep);
@ -92,10 +98,10 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
int valid_nick(const char *nick);
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
void filter_str(char *str, size_t len);;
void filter_str(char *str, size_t len);
/* gets base file name from path or original file name if no path is supplied */
void get_file_name(char *namebuf, int bufsize, const char *pathname);
size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname);
/* converts str to all lowercase */
void str_to_lower(char *str);
@ -125,7 +131,7 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes);
/* checks if a file exists. Returns true or false */
bool file_exists(const char *path);
/* returns file size or 0 on error */
/* returns file size. If file doesn't exist returns 0. */
off_t file_size(const char *path);
/* compares the first size bytes of fp and signature.

View File

@ -90,7 +90,7 @@ struct _ActiveNotifications {
#ifdef BOX_NOTIFY
NotifyNotification* box;
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
char title[24];
char title[64];
size_t size;
time_t n_timeout;
#endif
@ -117,9 +117,12 @@ static void tab_notify(ToxWindow *self, uint64_t flags)
static bool notifications_are_disabled(uint64_t flags)
{
bool res = flags & NT_RESTOL && Control.cooldown > get_unix_time();
if (user_settings->alerts != ALERTS_ENABLED)
return true;
bool res = (flags & NT_RESTOL) && (Control.cooldown > get_unix_time());
#ifdef X11
return res || (flags & NT_NOFOCUS && is_focused());
return res || ((flags & NT_NOFOCUS) && is_focused());
#else
return res;
#endif
@ -153,33 +156,36 @@ bool is_playing(int source)
static bool device_opened = false;
time_t last_opened_update = 0;
bool m_open_device()
/* Opens primary device. Returns true on succe*/
void m_open_device()
{
last_opened_update = get_unix_time();
if (device_opened) return true;
if (device_opened) return;
/* Blah error check */
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
return (device_opened = true);
device_opened = true;
}
bool m_close_device()
void m_close_device()
{
if (!device_opened) return true;
if (!device_opened) return;
close_device(output, Control.device_idx);
return !(device_opened = false);
device_opened = false;
}
/* Terminate all sounds but wait for them to finish first */
void graceful_clear()
{
int i;
control_lock();
while (1) {
int i;
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].active) {
#ifdef BOX_NOTIFY
@ -211,18 +217,24 @@ void graceful_clear()
usleep(1000);
}
control_unlock();
}
void* do_playing(void* _p)
{
(void)_p;
int i;
bool has_looping = false;
while(Control.poll_active) {
while(true) {
control_lock();
if (!Control.poll_active) {
control_unlock();
break;
}
bool has_looping = false;
int i;
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
@ -245,7 +257,7 @@ void* do_playing(void* _p)
}
}
#ifdef BOX_NOTIFY
else if (actives[i].box && get_unix_time() >= actives[i].n_timeout)
else if (actives[i].box && time(NULL) >= actives[i].n_timeout)
{
GError* ignore;
notify_notification_close(actives[i].box, &ignore);
@ -266,7 +278,7 @@ void* do_playing(void* _p)
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
if (device_opened && !has_looping &&
(get_unix_time() - last_opened_update) > DEVICE_COOLDOWN) {
(time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
m_close_device();
}
has_looping = false;
@ -299,11 +311,19 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
void* do_playing(void* _p)
{
(void)_p;
int i;
while(Control.poll_active) {
while(true) {
control_lock();
if (!Control.poll_active) {
control_unlock();
break;
}
int i;
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].box && get_unix_time() >= actives[i].n_timeout)
if (actives[i].box && time(NULL) >= actives[i].n_timeout)
{
GError* ignore;
notify_notification_close(actives[i].box, &ignore);
@ -361,16 +381,17 @@ int init_notify(int login_cooldown, int notification_timeout)
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
return -1;
Control.poll_active = 1;
pthread_t thread;
if (pthread_create(&thread, NULL, do_playing, NULL) != 0 || pthread_detach(thread) != 0 ) {
pthread_mutex_destroy(Control.poll_mutex);
Control.poll_active = 0;
return -1;
}
Control.poll_active = 1;
#endif
Control.cooldown = get_unix_time() + login_cooldown;
Control.cooldown = time(NULL) + login_cooldown;
#ifdef BOX_NOTIFY
@ -383,8 +404,15 @@ int init_notify(int login_cooldown, int notification_timeout)
void terminate_notify()
{
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
if ( !Control.poll_active ) return;
control_lock();
if ( !Control.poll_active ) {
control_unlock();
return;
}
Control.poll_active = 0;
control_unlock();
graceful_clear();
#endif
@ -503,7 +531,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
int id = -1;
control_lock();
if (self && (!self->stb || self->stb->status != TOX_USER_STATUS_BUSY) && user_settings->alerts == ALERTS_ENABLED)
if (self && (!self->stb || self->stb->status != TOX_USER_STATUS_BUSY))
id = m_play_sound(notif, flags);
else if (flags & NT_ALWAYS)
id = m_play_sound(notif, flags);
@ -598,9 +626,12 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
actives[id].id_indicator = id_indicator;
if (id_indicator) *id_indicator = id;
}
#endif
#else
if (id == -1)
return -1;
#endif /* SOUND_NOTIFY */
strncpy(actives[id].title, title, 24);
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
va_list __ARGS__; va_start (__ARGS__, format);
@ -623,7 +654,7 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
return id;
#else
return sound_notify(self, notif, flags, id_indicator);
#endif
#endif /* BOX_NOTIFY */
}
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...)
@ -699,7 +730,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
*id_indicator = id;
}
strncpy(actives[id].title, title, 24);
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
va_list __ARGS__; va_start (__ARGS__, format);

View File

@ -31,6 +31,7 @@
#include "toxic.h"
#include "windows.h"
#include "prompt.h"
#include "friendlist.h"
#include "execute.h"
#include "misc_tools.h"
#include "toxic_strings.h"
@ -46,6 +47,7 @@ extern ToxWindow *prompt;
extern struct user_settings *user_settings;
extern struct Winthread Winthread;
extern FriendsList Friends;
FriendRequests FrndRequests;
#ifdef AUDIO
@ -210,7 +212,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (diff != -1) {
if (x + diff > x2 - 1) {
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
@ -246,7 +248,10 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
ChatContext *ctx = self->chatwin;
pthread_mutex_lock(&Winthread.lock);
line_info_print(self);
pthread_mutex_unlock(&Winthread.lock);
wclear(ctx->linewin);
curs_set(1);
@ -255,14 +260,23 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
StatusBar *statusbar = self->stb;
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
wmove(statusbar->topline, 0, 0);
if (statusbar->connection != TOX_CONNECTION_NONE) {
pthread_mutex_lock(&Winthread.lock);
TOX_CONNECTION connection = statusbar->connection;
pthread_mutex_unlock(&Winthread.lock);
if (connection != TOX_CONNECTION_NONE) {
int colour = MAGENTA;
const char *status_text = "ERROR";
switch (statusbar->status) {
pthread_mutex_lock(&Winthread.lock);
TOX_USER_STATUS status = statusbar->status;
pthread_mutex_unlock(&Winthread.lock);
switch (status) {
case TOX_USER_STATUS_NONE:
status_text = "Online";
colour = GREEN;
@ -282,12 +296,16 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
wattron(statusbar->topline, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
wprintw(statusbar->topline, " %s", statusbar->nick);
pthread_mutex_unlock(&Winthread.lock);
wattroff(statusbar->topline, A_BOLD);
} else {
wprintw(statusbar->topline, " [Offline]");
wattron(statusbar->topline, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
wprintw(statusbar->topline, " %s", statusbar->nick);
pthread_mutex_unlock(&Winthread.lock);
wattroff(statusbar->topline, A_BOLD);
}
@ -296,11 +314,12 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
pthread_mutex_lock(&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m);
tox_self_get_status_message (m, (uint8_t*) statusmsg);
pthread_mutex_unlock(&Winthread.lock);
statusmsg[slen] = '\0';
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
pthread_mutex_unlock(&Winthread.lock);
}
self->x = x2;
@ -308,6 +327,8 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
/* Truncate note if it doesn't fit in statusbar */
uint16_t maxlen = x2 - getcurx(statusbar->topline) - 3;
pthread_mutex_lock(&Winthread.lock);
if (statusbar->statusmsg_len > maxlen) {
statusbar->statusmsg[maxlen - 3] = '\0';
strcat(statusbar->statusmsg, "...");
@ -317,13 +338,15 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
if (statusbar->statusmsg[0])
wprintw(statusbar->topline, " : %s", statusbar->statusmsg);
pthread_mutex_unlock(&Winthread.lock);
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
int y, x;
getyx(self->window, y, x);
(void) x;
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x);
wrefresh(self->window);
@ -334,9 +357,6 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum , TOX_CONNECTION connection_status)
{
if (friendnum < 0)
return;
ChatContext *ctx = self->chatwin;
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */
@ -349,7 +369,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
get_time_str(timefrmt, sizeof(timefrmt));
const char *msg;
if (connection_status != TOX_CONNECTION_NONE) {
if (connection_status != TOX_CONNECTION_NONE && Friends.list[friendnum].connection_status == TOX_CONNECTION_NONE) {
msg = "has come online";
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
write_to_log(msg, nick, ctx->log, true);
@ -360,7 +380,8 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
else
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
"Toxic", "%s has come online", nick );
} else {
}
else if (connection_status == TOX_CONNECTION_NONE) {
msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true);
@ -472,7 +493,9 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
if (user_settings->autolog == AUTOLOG_ON) {
char myid[TOX_ADDRESS_SIZE];
tox_self_get_address(m, (uint8_t *) myid);
log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT);
if (log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT) == -1)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
}
scrollok(ctx->history, 0);

View File

@ -41,6 +41,7 @@ typedef struct {
} FriendRequests;
ToxWindow new_prompt(void);
void prep_prompt_win(void);
void prompt_init_statusbar(ToxWindow *self, Tox *m);
void prompt_update_nick(ToxWindow *prompt, const char *nick);

View File

@ -167,6 +167,10 @@ static int detect_gnu_screen ()
free (dyn_buffer);
dyn_buffer = NULL;
if (strlen(socket_path) + strlen(PATH_SEP_S) + strlen(socket_name) >= sizeof(mplex_data))
goto nomplex;
strcpy (mplex_data, socket_path);
strcat (mplex_data, PATH_SEP_S);
strcat (mplex_data, socket_name);
@ -181,6 +185,8 @@ nomplex:
pclose (session_info_stream);
if (dyn_buffer)
free (dyn_buffer);
if (socket_path)
free(socket_path);
return 0;
}
@ -196,7 +202,7 @@ static int detect_tmux ()
return 0;
/* store the session number string for later use */
strcpy (mplex_data, pos + 1);
snprintf (mplex_data, sizeof(mplex_data), "%s", pos + 1);
mplex = MPLEX_TMUX;
return 1;
}
@ -339,7 +345,9 @@ static void mplex_timer_handler (Tox *m)
prev_status = current_status;
new_status = TOX_USER_STATUS_AWAY;
pthread_mutex_lock (&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m);
tox_self_get_status_message (m, (uint8_t*) prev_note);
prev_note[slen] = '\0';
pthread_mutex_unlock (&Winthread.lock);
new_note = user_settings->mplex_away_note;
}

View File

@ -77,6 +77,9 @@ char *DATA_FILE = NULL;
char *BLOCK_FILE = NULL;
ToxWindow *prompt = NULL;
#define DATANAME "data"
#define BLOCKNAME "data-blocklist"
#define AUTOSAVE_FREQ 60
#define MIN_PASSWORD_LEN 6
#define MAX_PASSWORD_LEN 64
@ -119,10 +122,29 @@ static void init_signal_catchers(void)
signal(SIGSEGV, catch_SIGSEGV);
}
void free_global_data(void)
{
if (DATA_FILE) {
free(DATA_FILE);
DATA_FILE = NULL;
}
if (BLOCK_FILE) {
free(BLOCK_FILE);
BLOCK_FILE = NULL;
}
if (user_settings) {
free(user_settings);
user_settings = NULL;
}
}
void exit_toxic_success(Tox *m)
{
store_data(m, DATA_FILE);
memset(&user_password, 0, sizeof(struct user_password));
kill_all_file_transfers(m);
kill_all_windows(m);
terminate_notify();
@ -130,10 +152,7 @@ void exit_toxic_success(Tox *m)
terminate_audio();
#endif /* AUDIO */
free(DATA_FILE);
free(BLOCK_FILE);
free(user_settings);
free_global_data();
tox_kill(m);
endwin();
@ -149,6 +168,7 @@ void exit_toxic_success(Tox *m)
void exit_toxic_err(const char *errmsg, int errcode)
{
free_global_data();
freopen("/dev/tty", "w", stderr);
endwin();
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
@ -250,7 +270,7 @@ static void print_init_messages(ToxWindow *toxwin)
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
}
#define MIN_NODE_LINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
#define MIN_NODE_LINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.chat = 8) */
#define MAX_NODE_LINE 256 /* Approx max number of chars in a sever line (name + port + key) */
#define MAXNODES 50
#define NODELEN (MAX_NODE_LINE - TOX_PUBLIC_KEY_SIZE - 7)
@ -275,22 +295,34 @@ static int load_nodelist(const char *filename)
char line[MAX_NODE_LINE];
while (fgets(line, sizeof(line), fp) && toxNodes.lines < MAXNODES) {
if (strlen(line) > MIN_NODE_LINE) {
size_t line_len = strlen(line);
if (line_len >= MIN_NODE_LINE && line_len <= MAX_NODE_LINE) {
const char *name = strtok(line, " ");
const char *port = strtok(NULL, " ");
const char *key_ascii = strtok(NULL, " ");
/* invalid line */
if (name == NULL || port == NULL || key_ascii == NULL)
continue;
size_t key_len = strlen(key_ascii);
size_t name_len = strlen(name);
if (key_len < TOX_PUBLIC_KEY_SIZE * 2 || name_len >= NODELEN)
continue;
snprintf(toxNodes.nodes[toxNodes.lines], sizeof(toxNodes.nodes[toxNodes.lines]), "%s", name);
toxNodes.nodes[toxNodes.lines][NODELEN - 1] = 0;
toxNodes.ports[toxNodes.lines] = atoi(port);
char *key_binary = hex_string_to_bin(key_ascii);
memcpy(toxNodes.keys[toxNodes.lines], key_binary, TOX_PUBLIC_KEY_SIZE);
free(key_binary);
/* remove possible trailing newline from key string */
char real_ascii_key[TOX_PUBLIC_KEY_SIZE * 2 + 1];
memcpy(real_ascii_key, key_ascii, TOX_PUBLIC_KEY_SIZE * 2);
key_len = TOX_PUBLIC_KEY_SIZE * 2;
real_ascii_key[key_len] = '\0';
if (hex_string_to_bin(real_ascii_key, key_len, toxNodes.keys[toxNodes.lines], TOX_PUBLIC_KEY_SIZE) == -1)
continue;
toxNodes.lines++;
}
@ -304,14 +336,34 @@ static int load_nodelist(const char *filename)
return 0;
}
/* Bootstraps and adds as TCP relay.
* Returns 0 if both actions are successful.
* Returns -1 otherwise.
*/
int init_connection_helper(Tox *m, int line)
{
return tox_bootstrap(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line], NULL);
TOX_ERR_BOOTSTRAP err;
tox_bootstrap(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line], &err);
if (err != TOX_ERR_BOOTSTRAP_OK) {
fprintf(stderr, "Failed to bootstrap %s:%d\n", toxNodes.nodes[line], toxNodes.ports[line]);
return -1;
}
tox_add_tcp_relay(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line], &err);
if (err != TOX_ERR_BOOTSTRAP_OK) {
fprintf(stderr, "Failed to add TCP relay %s:%d\n", toxNodes.nodes[line], toxNodes.ports[line]);
return -1;
}
return 0;
}
/* Connects to a random DHT node listed in the DHTnodes file
*
* return codes:
* 0: success
* 1: failed to open node file
* 2: no line of sufficient length in node file
* 3: failed to resolve name to IP
@ -323,8 +375,10 @@ static bool srvlist_loaded = false;
int init_connection(Tox *m)
{
if (toxNodes.lines > 0) /* already loaded nodelist */
return init_connection_helper(m, rand() % toxNodes.lines) ? 0 : 3;
if (toxNodes.lines > 0) { /* already loaded nodelist */
init_connection_helper(m, rand() % toxNodes.lines);
return 0;
}
/* only once:
* - load the nodelist
@ -347,7 +401,7 @@ int init_connection(Tox *m)
int n = MIN(NUM_INIT_NODES, toxNodes.lines);
for (i = 0; i < n; ++i) {
if (init_connection_helper(m, rand() % toxNodes.lines))
if (init_connection_helper(m, rand() % toxNodes.lines) == 0)
res = 0;
}
@ -460,7 +514,7 @@ static void first_time_encrypt(const char *msg)
valid_password = true;
}
queue_init_message("Data file '%s' will be encrypted", DATA_FILE);
queue_init_message("Data file '%s' is encrypted", DATA_FILE);
memset(passconfirm, 0, sizeof(passconfirm));
user_password.data_is_encrypted = true;
}
@ -468,44 +522,51 @@ static void first_time_encrypt(const char *msg)
system("clear");
}
/*
* Store Messenger to given location
* Return 0 if stored successfully or ignoring data file. Return -1 on error
/* Store Tox data to given location
*
* Return 0 if stored successfully or ignoring data file.
* Return -1 on error
*/
int store_data(Tox *m, const char *path)
{
if (path == NULL)
return -1;
size_t len = user_password.data_is_encrypted ? tox_encrypted_size(m) : tox_get_savedata_size(m);
char *buf = malloc(len);
if (buf == NULL)
exit_toxic_err("failed in store_data", FATALERR_MEMORY);
if (user_password.data_is_encrypted && !arg_opts.unencrypt_data) {
if (tox_encrypted_save(m, (uint8_t *) buf, (uint8_t *) user_password.pass, user_password.len) != 0) {
free(buf);
return -1;
}
} else {
tox_get_savedata(m, (uint8_t *) buf);
}
FILE *fp = fopen(path, "wb");
if (fp == NULL) {
free(buf);
if (fp == NULL)
return -1;
}
if (fwrite(buf, len, 1, fp) != 1) {
free(buf);
size_t data_len = tox_get_savedata_size(m);
char data[data_len];
tox_get_savedata(m, (uint8_t *) data);
if (user_password.data_is_encrypted && !arg_opts.unencrypt_data) {
size_t enc_len = data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
char enc_data[enc_len];
TOX_ERR_ENCRYPTION err;
tox_pass_encrypt((uint8_t *) data, data_len, (uint8_t *) user_password.pass, user_password.len,
(uint8_t *) enc_data, &err);
if (err != TOX_ERR_ENCRYPTION_OK) {
fprintf(stderr, "tox_pass_encrypt() failed with error %d\n", err);
fclose(fp);
return -1;
}
free(buf);
if (fwrite(enc_data, enc_len, 1, fp) != 1) {
fclose(fp);
return -1;
}
} else { /* data will not be encrypted */
if (fwrite(data, data_len, 1, fp) != 1) {
fclose(fp);
return -1;
}
}
fclose(fp);
return 0;
}
@ -534,13 +595,19 @@ static void init_tox_callbacks(Tox *m)
static void init_tox_options(struct Tox_Options *tox_opts)
{
tox_options_default(tox_opts);
tox_opts->ipv6_enabled = !arg_opts.use_ipv4;
tox_opts->udp_enabled = !arg_opts.force_tcp;
tox_opts->proxy_type = arg_opts.proxy_type;
tox_opts->tcp_port = arg_opts.tcp_port;
if (!tox_opts->ipv6_enabled)
queue_init_message("Forcing IPv4 connection");
if (tox_opts->tcp_port)
queue_init_message("TCP relaying enabled on port %d", tox_opts->tcp_port);
if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) {
tox_opts->proxy_port = arg_opts.proxy_port;
tox_opts->proxy_host = arg_opts.proxy_address;
@ -564,13 +631,13 @@ static void init_tox_options(struct Tox_Options *tox_opts)
/* Returns a new Tox object on success.
* If object fails to initialize the toxic process will terminate.
*/
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts)
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW *new_err)
{
Tox *m = NULL;
FILE *fp = fopen(data_path, "rb");
if (fp != NULL) {
if (fp != NULL) { /* Data file exists */
off_t len = file_size(data_path);
if (len == 0) {
@ -578,24 +645,20 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts)
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
}
char *buf = malloc(len);
char data[len];
if (buf == NULL) {
fclose(fp);
exit_toxic_err("failed in load_toxic", FATALERR_MEMORY);
}
if (fread(buf, len, 1, fp) != 1) {
free(buf);
if (fread(data, sizeof(data), 1, fp) != 1) {
fclose(fp);
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
}
bool is_encrypted = tox_is_data_encrypted((uint8_t *) buf);
bool is_encrypted = tox_is_data_encrypted((uint8_t *) data);
/* attempt to encrypt an already encrypted data file */
if (arg_opts.encrypt_data && is_encrypted)
if (arg_opts.encrypt_data && is_encrypted) {
fclose(fp);
exit_toxic_err("failed in load_toxic", FATALERR_ENCRYPT);
}
if (arg_opts.unencrypt_data && is_encrypted)
queue_init_message("Data file '%s' has been unencrypted", data_path);
@ -610,12 +673,17 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts)
system("clear"); // TODO: is this portable?
printf("Enter password (q to quit) ");
size_t plain_len = len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
char plain[plain_len];
while (true) {
pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
user_password.len = pwlen;
if (strcasecmp(user_password.pass, "q") == 0)
if (strcasecmp(user_password.pass, "q") == 0) {
fclose(fp);
exit(0);
}
if (pwlen < MIN_PASSWORD_LEN) {
system("clear");
@ -624,39 +692,56 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts)
continue;
}
TOX_ERR_ENCRYPTED_NEW enc_err;
m = tox_encrypted_new(tox_opts, (uint8_t *) buf, len, (uint8_t *) user_password.pass, pwlen, &enc_err);
TOX_ERR_DECRYPTION pwerr;
tox_pass_decrypt((uint8_t *) data, len, (uint8_t *) user_password.pass, pwlen,
(uint8_t *) plain, &pwerr);
if (pwerr == TOX_ERR_DECRYPTION_OK) {
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
tox_opts->savedata_data = (uint8_t *) plain;
tox_opts->savedata_length = plain_len;
m = tox_new(tox_opts, new_err);
if (m == NULL) {
fclose(fp);
return NULL;
}
if (enc_err == TOX_ERR_ENCRYPTED_NEW_OK) {
break;
} else if (enc_err == TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED) {
} else if (pwerr == TOX_ERR_DECRYPTION_FAILED) {
system("clear");
sleep(1);
printf("Invalid password. Try again. ");
} else {
exit_toxic_err("tox_encrypted_new() failed", enc_err);
}
}
} else {
TOX_ERR_NEW err;
m = tox_new(tox_opts, (uint8_t *) buf, len, &err);
if (err != TOX_ERR_NEW_OK)
exit_toxic_err("tox_new() failed", err);
}
free(buf);
fclose(fp);
} else {
/* if file exists then open() failing is fatal */
exit_toxic_err("tox_pass_decrypt() failed", pwerr);
}
}
} else { /* data is not encrypted */
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
tox_opts->savedata_data = (uint8_t *) data;
tox_opts->savedata_length = len;
m = tox_new(tox_opts, new_err);
if (m == NULL) {
fclose(fp);
return NULL;
}
}
fclose(fp);
} else { /* Data file does not/should not exist */
if (file_exists(data_path))
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
TOX_ERR_NEW err;
m = tox_new(tox_opts, NULL, 0, &err);
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_NONE;
if (err != TOX_ERR_NEW_OK)
exit_toxic_err("tox_new() failed", err);
m = tox_new(tox_opts, new_err);
if (m == NULL)
return NULL;
if (store_data(m, data_path) == -1)
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
@ -670,10 +755,20 @@ static Tox *load_toxic(char *data_path)
struct Tox_Options tox_opts;
init_tox_options(&tox_opts);
Tox *m = load_tox(data_path, &tox_opts);
TOX_ERR_NEW new_err;
Tox *m = load_tox(data_path, &tox_opts, &new_err);
if (m == NULL)
exit_toxic_err("load_tox() failed", FATALERR_TOX_INIT);
if (new_err == TOX_ERR_NEW_PORT_ALLOC && tox_opts.ipv6_enabled) {
queue_init_message("Falling back to ipv4");
tox_opts.ipv6_enabled = false;
m = load_tox(data_path, &tox_opts, &new_err);
}
if (!m)
exit_toxic_err("tox_new returned fatal error", new_err);
if (new_err != TOX_ERR_NEW_OK)
queue_init_message("tox_new returned non-fatal error %d", new_err);
init_tox_callbacks(m);
load_friendlist(m);
@ -685,13 +780,42 @@ static Tox *load_toxic(char *data_path)
return m;
}
#define TRY_BOOTSTRAP_INTERVAL 5
static uint64_t last_bootstrap_time = 0;
static void do_bootstrap(Tox *m)
{
static int conn_err = 0;
if (!timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL))
return;
if (tox_self_get_connection_status(m) != TOX_CONNECTION_NONE)
return;
if (conn_err != 0)
return;
last_bootstrap_time = get_unix_time();
conn_err = init_connection(m);
if (conn_err != 0)
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Auto-connect failed with error code %d", conn_err);
}
static void do_toxic(Tox *m, ToxWindow *prompt)
{
pthread_mutex_lock(&Winthread.lock);
update_unix_time();
if (arg_opts.no_connect == 0)
tox_iterate(m); /* main toxcore loop */
if (arg_opts.no_connect) {
pthread_mutex_unlock(&Winthread.lock);
return;
}
tox_iterate(m);
do_bootstrap(m);
check_file_transfer_timeouts(m);
pthread_mutex_unlock(&Winthread.lock);
}
@ -700,6 +824,7 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
void *thread_winref(void *data)
{
Tox *m = (Tox *) data;
uint8_t draw_count = 0;
init_signal_catchers();
@ -775,7 +900,8 @@ static void print_usage(void)
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, " -r, --dnslist Use specified DNSservers file\n");
fprintf(stderr, " -t, --force-tcp Force TCP connection (use this 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, " -u, --unencrypt-data Unencrypt an encrypted data file\n");
}
@ -803,13 +929,14 @@ static void parse_args(int argc, char *argv[])
{"noconnect", no_argument, 0, 'o'},
{"dnslist", required_argument, 0, 'r'},
{"force-tcp", no_argument, 0, 't'},
{"tcp-server", required_argument, 0, 'T'},
{"SOCKS5-proxy", required_argument, 0, 'p'},
{"HTTP-proxy", required_argument, 0, 'P'},
{"unencrypt-data", no_argument, 0, 'u'},
{NULL, no_argument, NULL, 0},
};
const char *opts_str = "4bdehotuxc:f:n:r:p:P:";
const char *opts_str = "4bdehotuxc:f:n:r:p:P:T:";
int opt, indexptr;
while ((opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr)) != -1) {
@ -842,10 +969,22 @@ static void parse_args(int argc, char *argv[])
case 'f':
arg_opts.use_custom_data = 1;
DATA_FILE = strdup(optarg);
if (DATA_FILE)
free(DATA_FILE);
if (BLOCK_FILE)
free(BLOCK_FILE);
DATA_FILE = malloc(strlen(optarg) + 1);
strcpy(DATA_FILE, optarg);
if (DATA_FILE == NULL)
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
if (BLOCK_FILE == NULL)
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
strcpy(BLOCK_FILE, optarg);
@ -900,6 +1039,10 @@ static void parse_args(int argc, char *argv[])
arg_opts.force_tcp = 1;
break;
case 'T':
arg_opts.tcp_port = (uint16_t) atoi(optarg);
break;
case 'u':
arg_opts.unencrypt_data = 1;
break;
@ -912,8 +1055,6 @@ static void parse_args(int argc, char *argv[])
}
}
#define DATANAME "data"
#define BLOCKNAME "data-blocklist"
static int init_default_data_files(void)
{
if (arg_opts.use_custom_data)
@ -953,7 +1094,7 @@ static int init_default_data_files(void)
/* Adjusts usleep value so that tox_do runs close to the recommended number of times per second */
static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, uint64_t cur_time, useconds_t msleepval)
{
useconds_t new_sleep = msleepval;
useconds_t new_sleep = MAX(msleepval, 3);
++(*loopcount);
if (*looptimer == cur_time)
@ -967,14 +1108,16 @@ static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, ui
return new_sleep;
}
// this doesn't do anything (yet)
#ifdef X11
// FIXME
void DnD_callback(const char* asdv, DropType dt)
{
if (dt != DT_plain)
return;
// if (dt != DT_plain)
// return;
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, asdv);
// pthread_mutex_lock(&Winthread.lock);
// line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, asdv);
pthread_mutex_unlock(&Winthread.lock);
}
#endif /* X11 */
@ -998,6 +1141,9 @@ int main(int argc, char *argv[])
int config_err = init_default_data_files();
bool datafile_exists = file_exists(DATA_FILE);
if (datafile_exists)
last_bootstrap_time = get_unix_time();
if (!datafile_exists && !arg_opts.unencrypt_data)
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
else if (arg_opts.encrypt_data)
@ -1040,6 +1186,7 @@ int main(int argc, char *argv[])
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
#ifdef AUDIO
av = init_audio(prompt, m);
@ -1073,7 +1220,10 @@ int main(int argc, char *argv[])
if (init_mplex_away_timer(m) == -1)
queue_init_message("Failed to init mplex auto-away.");
pthread_mutex_lock(&Winthread.lock);
print_init_messages(prompt);
pthread_mutex_unlock(&Winthread.lock);
cleanup_init_messages();
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
@ -1087,11 +1237,10 @@ int main(int argc, char *argv[])
uint64_t loopcount = 0;
while (true) {
update_unix_time();
do_toxic(m, prompt);
uint64_t cur_time = get_unix_time();
if (timed_out(last_save, cur_time, AUTOSAVE_FREQ)) {
if (timed_out(last_save, AUTOSAVE_FREQ)) {
pthread_mutex_lock(&Winthread.lock);
if (store_data(m, DATA_FILE) != 0)
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");

View File

@ -121,9 +121,4 @@ void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t k
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
#ifdef AUDIO
void write_device_callback_group(Tox *m, int groupnum, int peernum, const int16_t *pcm, unsigned int samples,
uint8_t channels, unsigned int sample_rate, void *arg);
#endif /* AUDIO */
#endif /* #define TOXIC_H */

View File

@ -33,8 +33,10 @@
#include "chat.h"
#include "line_info.h"
#include "misc_tools.h"
#include "avatars.h"
#include "settings.h"
#include "file_transfers.h"
extern char *DATA_FILE;
extern struct Winthread Winthread;
static ToxWindow windows[MAX_WINDOWS_NUM];
@ -215,6 +217,16 @@ void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position,
size_t length, void *userdata)
{
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft)
return;
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
on_avatar_chunk_request(m, ft, position, length);
return;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
@ -226,6 +238,11 @@ void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, u
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position,
const uint8_t *data, size_t length, void *user_data)
{
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft)
return;
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
@ -237,6 +254,16 @@ void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint
void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control,
void *userdata)
{
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft)
return;
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
on_avatar_file_control(m, ft, control);
return;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
@ -248,11 +275,17 @@ void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FIL
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
const uint8_t *filename, size_t filename_length, void *userdata)
{
/* We don't care about receiving avatars */
if (kind != TOX_FILE_KIND_DATA) {
tox_file_control(m, friendnumber, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
return;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileRecv != NULL)
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, kind, file_size, (char *) filename,
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, file_size, (char *) filename,
filename_length);
}
}
@ -266,20 +299,6 @@ void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *user
windows[i].onReadReceipt(&windows[i], m, friendnumber, receipt);
}
}
#ifdef AUDIO
void write_device_callback_group(Tox *m, int groupnum, int peernum, const int16_t *pcm, unsigned int samples,
uint8_t channels, unsigned int sample_rate, void *arg)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onWriteDevice != NULL)
windows[i].onWriteDevice(&windows[i], m, groupnum, peernum, pcm, samples, channels, samples);
}
}
#endif /* AUDIO */
/* CALLBACKS END */
int add_window(Tox *m, ToxWindow w)
@ -435,10 +454,16 @@ void on_window_resize(void)
static void draw_window_tab(ToxWindow *toxwin)
{
pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
pthread_mutex_unlock(&Winthread.lock);
clrtoeol();
printw(" [%s]", toxwin->name);
pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
pthread_mutex_unlock(&Winthread.lock);
}
static void draw_bar(void)
@ -486,7 +511,10 @@ static void draw_bar(void)
void draw_active_window(Tox *m)
{
ToxWindow *a = active_window;
pthread_mutex_lock(&Winthread.lock);
a->alert = WINDOW_ALERT_NONE;
pthread_mutex_unlock(&Winthread.lock);
wint_t ch = 0;
@ -536,8 +564,11 @@ void refresh_inactive_windows(void)
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *a = &windows[i];
if (a->active && a != active_window && !a->is_friendlist)
if (a->active && a != active_window && !a->is_friendlist) {
pthread_mutex_lock(&Winthread.lock);
line_info_print(a);
pthread_mutex_unlock(&Winthread.lock);
}
}
}
@ -546,7 +577,7 @@ ToxWindow *get_window_ptr(int i)
{
ToxWindow *toxwin = NULL;
if (i >= 0 && i <= MAX_WINDOWS_NUM && windows[i].active)
if (i >= 0 && i < MAX_WINDOWS_NUM && windows[i].active)
toxwin = &windows[i];
return toxwin;
@ -573,7 +604,7 @@ void kill_all_windows(Tox *m)
if (windows[i].is_chat)
kill_chat_window(&windows[i], m);
else if (windows[i].is_groupchat)
close_groupchat(&windows[i], m, i);
close_groupchat(&windows[i], m, windows[i].num);
}
kill_prompt_window(prompt);

View File

@ -97,6 +97,8 @@ struct arg_opts {
char proxy_address[256];
uint8_t proxy_type;
uint16_t proxy_port;
uint16_t tcp_port;
};
typedef struct ToxWindow ToxWindow;
@ -127,7 +129,7 @@ struct ToxWindow {
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL);
void(*onFileRecv)(ToxWindow *, Tox *, uint32_t, uint32_t, uint32_t, uint64_t, const char *, size_t);
void(*onFileRecv)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool);
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);

View File

@ -333,7 +333,9 @@ int init_xtra(drop_callback d)
(unsigned char*)&XdndVersion, 1);
pthread_t id;
pthread_create(&id, NULL, event_loop, NULL);
if (pthread_create(&id, NULL, event_loop, NULL) != 0)
return -1;
pthread_detach(id);
return 0;