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

Compare commits

..

65 Commits

Author SHA1 Message Date
2ce42ab057 bump version to 0.5.0 2014-09-01 18:56:20 -04:00
934459dea8 show connection change message in chat windows 2014-08-31 14:17:33 -04:00
52bc874675 Merge pull request #234 from Ansa89/trivial-fix
Cosmetic fixes
2014-08-31 11:26:48 +02:00
511907fbc5 better way to check if files exist 2014-08-27 22:51:46 -04:00
155e194174 fix segfault on unknown long option 2014-08-27 14:30:06 -04:00
b1c7e21ca9 fix possible segfaults 2014-08-27 13:54:02 -04:00
7edcf6cb45 add setting to set path for chatlogs 2014-08-26 23:56:37 -04:00
9581940cfa Cosmetic fixes 2014-08-26 10:39:43 +02:00
f2aa57c4fa additional messages for startup options 2014-08-26 02:28:05 -04:00
8bf4405fd0 fix error code 2014-08-25 19:55:00 -04:00
21ef1788ca print init messages to prompt window intead of stderr 2014-08-25 19:26:41 -04:00
68f1dffba7 add command to decline friend requests 2014-08-25 14:08:01 -04:00
092df2c0e4 Merge pull request #231 from Ansa89/trivial-fix
Reworked manpage build system
2014-08-25 14:12:12 +02:00
691f94c75c README.md: second try 2014-08-25 12:59:34 +02:00
d6d4476e85 README.md: better look 2014-08-25 12:56:14 +02:00
924e8e0860 Reworked manpage build system 2014-08-25 12:54:44 +02:00
53193e933f Merge pull request #230 from louipc/manpage
Manpage
2014-08-25 00:49:31 -04:00
328587ad9c doc: Make asciidoc extra optional.
Completely separate man page generation from the main build to satisfy
travis-ci behaviour.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-24 17:00:25 -04:00
1a8fdb1b99 Make asciidoc 'optional'
Run `make doc` in the build directory after editing the asciidoc to
regenerate the manpages. Changes to asciidoc source and generated man
pages will need to be commited together.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-24 16:34:16 -04:00
690f0221b5 Add generated man pages.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-24 00:16:55 -04:00
e117bd3985 Add Asciidoc to README and travis
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-21 05:00:15 -04:00
15cc87bffd Remove old man pages.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-21 04:40:10 -04:00
97d4c97c52 Generate man pages from asciidoc
Working directly with g/roff is a pain.
Also changed the formatting of toxic.conf.5 a bit.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-21 04:39:24 -04:00
c8b22d7e8a Merge pull request #229 from Ansa89/trivial-fix
toxic.conf.example: better formatting
2014-08-20 13:12:41 -04:00
f48ec4f49b array bounds fix 2014-08-20 13:10:21 -04:00
d4ce697bd9 toxic.conf.example: better formatting 2014-08-20 12:40:32 +02:00
bd20513493 a few fixes 2014-08-19 23:41:43 -04:00
fd3f4eb724 Merge branch 'master' of https://github.com/Tox/toxic 2014-08-19 20:55:38 -04:00
75e8486061 add command to list pending friend requests, a few related fixes 2014-08-19 20:52:17 -04:00
bd216709fc Merge pull request #226 from Ansa89/freebsd-man
Fix Tox/toxic#222 and reorganize cfg dir
2014-08-19 13:04:52 -04:00
a3a8f7608a Fix Tox/toxic#222 and reorganize cfg dir 2014-08-19 18:22:57 +02:00
affc88d0a8 error checking for file senders, fixes 2014-08-17 15:32:38 -04:00
eca4882ce2 transfer progress bar fix 2014-08-17 13:50:22 -04:00
58b0a04019 separate file transfer updates from callbacks 2014-08-17 00:11:49 -04:00
b870679f2c allow resuming of broken file transfers (needs testing) 2014-08-16 17:20:53 -04:00
ae83725cb6 Merge pull request #223 from louipc/master
Add debug flag and update man page.
2014-08-16 02:59:55 -04:00
595e42b587 Clarify function of -b switch.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-16 02:35:21 -04:00
f5401df2c7 doc/toxic: Add missing flags and sort alphabetically.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-15 19:26:06 -04:00
3e79a5ca8b Add -b flag for debugging
For now this just prints messages to stderr, so the user should manually
redirect stderr to avoid breaking the ui. This can be later expanded
upon to provide debugging messages in the command window.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-15 19:06:16 -04:00
327081945e update DHTnodes 2014-08-15 18:17:03 -04:00
68ec484a58 don't allow DNS lookups when using a proxy + forced TCP & fix arg parsing 2014-08-15 15:13:35 -04:00
1d6ccf56a8 name conflict with core function might cause linking error 2014-08-15 12:22:39 -04:00
67f637a1e1 redirect stderr before audio init to prevent error spam 2014-08-14 21:31:28 -04:00
5e175d5319 Merge pull request #220 from louipc/master
new tox_bootstrap_from_address() behaviour and a minor ui change
2014-08-14 20:47:17 -04:00
778db0fece core change: ports no longer in network byte order 2014-08-14 20:38:33 -04:00
72010dd2e1 allow connections through proxies 2014-08-14 20:31:52 -04:00
39556b36f3 port is no longer passed in network byte order to tox_bootstrap_from_address()
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-14 20:10:14 -04:00
dc9ffa6e56 ipv6enabled parameter was removed in toxcore.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-14 19:51:52 -04:00
1e92bb3c2b help: lowercase keybinding hints for clarity.
Seeing the uppercase character I expected it to be the actual key.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-14 19:22:59 -04:00
edbdf2966a toxcore API update, add option to force TCP connection 2014-08-14 18:45:41 -04:00
3f6fd734d3 Merge pull request #218 from louipc/louipc
toxic.conf.5: Remove default config from man page
2014-08-14 12:05:33 -04:00
919a06d282 toxic.conf.5: Remove default config from man page
The reference to the config example in the FILES section should be sufficient.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-14 01:13:27 -04:00
35cc815cdb add option to specify DNSservers path 2014-08-12 22:32:36 -04:00
a318bdb034 add option to not connect to the DHT network 2014-08-12 18:59:27 -04:00
d6aaa95b25 ignore invalid file data callbacks 2014-08-12 15:27:42 -04:00
5718ad52db a few fixes 2014-08-12 03:01:18 -04:00
0f4cffbacc a few dns fixes 2014-08-11 01:59:01 -04:00
d9a861331f Use DNS server list instead of hard coding domains/keys 2014-08-10 21:40:19 -04:00
2f12a8d429 prevent statusmessage from wrapping on prompt screen 2014-08-10 00:37:26 -04:00
e75cf4f3ad fix bug where tab alert colours weren't being properly prioritized 2014-08-08 13:39:05 -04:00
bb85f31bb2 convert bytes for file transfer message, general fixes 2014-08-07 19:31:36 -04:00
396d08f0d2 refactor friend/blocklist, dynamically allocate memory 2014-08-07 13:24:29 -04:00
6ab184e7ce file transfer improvements and bug fixes 2014-08-05 17:38:33 -04:00
fd65fbfd0c temporarily disabling clang in travis script due to weird errors unrelated to toxic 2014-08-05 00:27:55 -04:00
637ea0ed55 attempt to fix travis with clang 2014-08-05 00:16:01 -04:00
46 changed files with 1979 additions and 1071 deletions

View File

@ -1,7 +1,7 @@
language: c
compiler:
- gcc
- clang
# - clang # Fix me
before_script:
# Installing yasm (needed for compiling vpx) and openal

View File

@ -1,7 +1,7 @@
# 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 Screenshot](https://i.imgur.com/ryaEmQZ.png "Home Screen").
![Toxic Screenshot](https://i.imgur.com/ryaEmQZ.png "Home Screen")
## Installation
@ -22,6 +22,11 @@ Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly
##### Desktop notifications
* [libnotify](https://developer.gnome.org/libnotify) (for Debian based systems, 'libnotify-dev')
##### Documentation
* [Asciidoc](http://asciidoc.org/index.html) (only required for regenerating manpages)
* Run `make doc` after editing the asciidoc files to regenerate the manpages.
* **NOTE FOR DEVELOPERS**: asciidoc files and generated manpages will need to be commited together.
### Compiling
1. `cd build/`
2. `make PREFIX="/where/to/install"`

View File

@ -1,13 +1,7 @@
TOXIC_VERSION = 0.4.7
REV = $(shell git rev-list HEAD --count)
VERSION = $(TOXIC_VERSION)_r$(REV)
BASE_DIR = $(shell cd .. && pwd -P)
CFG_DIR = $(BASE_DIR)/cfg
CFG_DIR = ../cfg
SRC_DIR = ../src
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
DATADIR = $(PREFIX)/share/toxic
MANDIR = $(PREFIX)/share/man
-include $(CFG_DIR)/global_vars.mk
LIBS = libtoxcore ncursesw libconfig
@ -49,10 +43,10 @@ ifneq ($(filter arm%, $(UNAME_M)),)
endif
# Include all needed checks
-include $(CFG_DIR)/check_features.mk
-include $(CFG_DIR)/checks/check_features.mk
# Targets
all: toxic
all: toxic doc
toxic: $(OBJ)
@echo " LD $@"
@ -68,7 +62,6 @@ clean:
-include $(OBJ:.o=.d)
-include $(CFG_DIR)/install.mk
-include $(CFG_DIR)/help.mk
-include $(CFG_DIR)/targets/*.mk
.PHONY: clean all

View File

@ -8,14 +8,14 @@ else
endif
# Check if we can build audio support
CHECK_AUDIO_LIBS = $(shell pkg-config $(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 $$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

@ -1,5 +1,7 @@
CHECKS_DIR = $(CFG_DIR)/checks
# Check if we can use X11
CHECK_X11_LIBS = $(shell pkg-config x11 || echo -n "error")
CHECK_X11_LIBS = $(shell pkg-config --exists x11 || echo -n "error")
ifneq ($(CHECK_X11_LIBS), error)
LIBS += x11
CFLAGS += -D_X11
@ -8,29 +10,29 @@ endif
# Check if we want build audio support
AUDIO = $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(AUDIO), disabled)
-include $(CFG_DIR)/av.mk
-include $(CHECKS_DIR)/av.mk
endif
# Check if we want build sound notifications support
SND_NOTIFY = $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(SND_NOTIFY), disabled)
-include $(CFG_DIR)/sound_notifications.mk
-include $(CHECKS_DIR)/sound_notifications.mk
endif
# Check if we want build desktop notifications support
DESK_NOTIFY = $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(DESK_NOTIFY), disabled)
-include $(CFG_DIR)/desktop_notifications.mk
-include $(CHECKS_DIR)/desktop_notifications.mk
endif
# Check if we can build Toxic
CHECK_LIBS = $(shell pkg-config $(LIBS) || echo -n "error")
CHECK_LIBS = $(shell pkg-config --exists $(LIBS) || echo -n "error")
ifneq ($(CHECK_LIBS), error)
CFLAGS += $(shell pkg-config --cflags $(LIBS))
LDFLAGS += $(shell pkg-config --libs $(LIBS))
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_LIBS = $(shell for lib in $(LIBS) ; do if ! pkg-config $$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,13 +3,13 @@ DESK_NOTIFY_LIBS = libnotify
DESK_NOTIFY_CFLAGS = -D_BOX_NOTIFY
# Check if we can build desktop notifications support
CHECK_DESK_NOTIFY_LIBS = $(shell pkg-config $(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 $$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,14 +8,14 @@ else
endif
# Check if we can build sound notifications support
CHECK_SND_NOTIFY_LIBS = $(shell pkg-config $(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 $$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))

23
cfg/global_vars.mk Normal file
View File

@ -0,0 +1,23 @@
# Version
TOXIC_VERSION = 0.5.0
REV = $(shell git rev-list HEAD --count)
VERSION = $(TOXIC_VERSION)_r$(REV)
# Project directories
DOC_DIR = $(BASE_DIR)/doc
SRC_DIR = $(BASE_DIR)/src
SND_DIR = $(BASE_DIR)/sounds
MISC_DIR = $(BASE_DIR)/misc
# Project files
MANFILES = toxic.1 toxic.conf.5
DATAFILES = DHTnodes DNSservers toxic.conf.example
SNDFILES = ContactLogsIn.wav ContactLogsOut.wav Error.wav IncomingCall.wav
SNDFILES += LogIn.wav LogOut.wav NewMessage.wav OutgoingCall.wav
SNDFILES += TransferComplete.wav TransferPending.wav
# Install directories
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
DATADIR = $(PREFIX)/share/toxic
MANDIR = $(PREFIX)/share/man

View File

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

View File

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

10
cfg/targets/doc.mk Normal file
View File

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

View File

@ -1,8 +1,9 @@
# Help target
help:
@echo "-- Targets --"
@echo " all: Build toxic [DEFAULT]"
@echo " all: Build toxic and documentation [DEFAULT]"
@echo " toxic: Build toxic"
@echo " doc: Build documentation"
@echo " install: Build toxic and install it in PREFIX (default PREFIX is \"$(abspath $(PREFIX))\")"
@echo " clean: Remove built files"
@echo " help: This help"

View File

@ -1,19 +1,13 @@
MISC_DIR = ../misc
DOC_DIR = ../doc
SND_DIR = ../sounds
DATAFILES = DHTnodes toxic.conf.example
MANFILES = toxic.1 toxic.conf.5
SNDFILES = ContactLogsIn.wav ContactLogsOut.wav Error.wav IncomingCall.wav
SNDFILES += LogIn.wav LogOut.wav NewMessage.wav OutgoingCall.wav
SNDFILES += TransferComplete.wav TransferPending.wav
install: toxic
# Install target
install: toxic doc
mkdir -p $(abspath $(DESTDIR)/$(BINDIR))
mkdir -p $(abspath $(DESTDIR)/$(DATADIR))
mkdir -p $(abspath $(DESTDIR)/$(DATADIR))/sounds
mkdir -p $(abspath $(DESTDIR)/$(MANDIR))
@echo "Installing toxic executable"
@install -m 0755 toxic $(abspath $(DESTDIR)/$(BINDIR))
@echo "Installing data files"
@for f in $(DATAFILES) ; do \
install -m 0644 $(MISC_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)) ;\
@ -23,6 +17,7 @@ install: toxic
@for f in $(SNDFILES) ; do \
install -m 0644 $(SND_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR))/sounds ;\
done
@echo "Installing man pages"
@for f in $(MANFILES) ; do \
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\

View File

@ -1,63 +1,143 @@
.TH TOXIC 1 "June 2014" "Toxic v__VERSION__" "User Manual"
.SH NAME
Toxic \- CLI client for Tox
.SH SYNOPSYS
.B toxic [\-f
.I data\-file
.B ] [\-x] [\-4] [\-c
.I config\-file
.B ] [\-n
.I nodes\-file
.B ] [\-h]
.SH DESCRIPTION
Toxic is an ncurses-based instant messaging client for Tox which formerly
resided in the Tox core repository, and is now available as a standalone
application.
.SH OPTIONS
.IP "\-f, \-\-file data\-file"
Use specified
.I data\-file
instead of
.IR ~/.config/tox/data
.IP "\-x, \-\-nodata"
Ignore data file
.IP "\-4, \-\-ipv4"
'\" t
.\" Title: toxic
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2014-08-21
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC" "1" "2014\-08\-21" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
toxic \- CLI client for Tox
.SH "SYNOPSIS"
.sp
\fBtoxic\fR [\-f \fIdata\-file\fR] [\-x] [\-4] [\-c \fIconfig\-file\fR] [\-n \fInodes\-file\fR] [\-h]
.SH "DESCRIPTION"
.sp
toxic is an ncurses\-based instant messaging client for Tox which formerly resided in the Tox core repository, and is now available as a standalone application\&.
.SH "OPTIONS"
.PP
\-4, \-\-ipv4
.RS 4
Force IPv4 connection
.IP "\-d, \-\-default_locale
Use default locale
.IP "\-c, \-\-config config\-file"
.RE
.PP
\-b, \-\-debug
.RS 4
Enable stderr for debugging\&. Redirect output to avoid breaking the curses interface and better capture messages\&.
.RE
.PP
\-c, \-\-config config\-file
.RS 4
Use specified
.I config\-file
\fIconfig\-file\fR
instead of
.IR ~/.config/tox/toxic.conf
.IP "\-n, \-\-nodes nodes\-file"
\fI~/\&.config/tox/toxic\&.conf\fR
.RE
.PP
\-d, \-\-default_locale
.RS 4
Use default locale
.RE
.PP
\-f, \-\-file data\-file
.RS 4
Use specified
.I nodes\-file
for DHT bootstrap nodes, instead of
.IR __DATADIR__/DHTnodes
.IP "\-h, \-\-help"
\fIdata\-file\fR
instead of
\fI~/\&.config/tox/data\fR
.RE
.PP
\-h, \-\-help
.RS 4
Show help message
.SH FILES
.IP __DATADIR__/DHTnodes
Default list of DHT bootstrap nodes.
.IP ~/.config/tox/data
Savestate which contains your personal info (nickname, Tox ID,...) and
your contacts list.
.IP ~/.config/tox/toxic.conf
Configuration file. See
.BR toxic.conf (5)
for more details.
.IP __DATADIR__/toxic.conf.example
Configuration example.
.SH BUGS
Unicode characters with a width larger than 1 column may cause
strange behaviour. Expect more bugs and bad
behaviour: this software is in a pre\-alpha stage.
.SH AUTHORS
JFreegman <JFreegman@gmail.com>
.SH SEE ALSO
.BR toxic.conf (5)
.SH LINKS
Project page on github: https://github.com/Tox/toxic
.br
IRC channel on Freenode: chat.freenode.net#tox
.RE
.PP
\-n, \-\-nodes nodes\-file
.RS 4
Use specified
\fInodes\-file\fR
for DHT bootstrap nodes, instead of
\fI__DATADIR__/DHTnodes\fR
.RE
.PP
\-o, \-\-noconnect
.RS 4
Do not connect to the DHT network
.RE
.PP
\-p, \-\-proxy
.RS 4
Use proxy: Requires [IP] [port]
.RE
.PP
\-r, \-\-dnslist
.RS 4
Use specified DNSservers file
.RE
.PP
\-t, \-\-force\-tcp
.RS 4
Force TCP connection (use this with proxies)
.RE
.PP
\-x, \-\-nodata
.RS 4
Ignore data file
.RE
.SH "FILES"
.PP
__DATADIR__/DHTnodes
.RS 4
Default list of DHT bootstrap nodes\&.
.RE
.PP
~/\&.config/tox/data
.RS 4
Savestate which contains your personal info (nickname, Tox ID, contacts, etc)
.RE
.PP
~/\&.config/tox/toxic\&.conf
.RS 4
Configuration file\&. See
\fBtoxic\&.conf\fR(5) for more details\&.
.RE
.PP
__DATADIR__/toxic\&.conf\&.example
.RS 4
Configuration example\&.
.RE
.SH "BUGS"
.sp
Unicode characters with a width larger than 1 column may cause strange behaviour\&. Expect more bugs and bad behaviour: this software is in a pre\-alpha stage\&.
.SH "AUTHORS"
.sp
JFreegman <JFreegman@gmail\&.com>
.SH "SEE ALSO"
.sp
\fBtoxic\&.conf\fR(5)
.SH "LINKS"
.sp
Project page: https://github\&.com/Tox/toxic
.sp
IRC channel: chat\&.freenode\&.net#tox

91
doc/toxic.1.asc Normal file
View File

@ -0,0 +1,91 @@
toxic(1)
========
NAME
----
toxic - CLI client for Tox
SYNOPSIS
--------
*toxic* [-f 'data-file'] [-x] [-4] [-c 'config-file'] [-n 'nodes-file'] [-h]
DESCRIPTION
-----------
toxic is an ncurses-based instant messaging client for Tox which formerly
resided in the Tox core repository, and is now available as a standalone
application.
OPTIONS
-------
-4, --ipv4::
Force IPv4 connection
-b, --debug::
Enable stderr for debugging. Redirect output to
avoid breaking the curses interface and better capture messages.
-c, --config config-file::
Use specified 'config-file' instead of '~/.config/tox/toxic.conf'
-d, --default_locale::
Use default locale
-f, --file data-file::
Use specified 'data-file' instead of '~/.config/tox/data'
-h, --help::
Show help message
-n, --nodes nodes-file::
Use specified 'nodes-file' for DHT bootstrap nodes, instead of
'{datadir}/DHTnodes'
-o, --noconnect::
Do not connect to the DHT network
-p, --proxy::
Use proxy: Requires [IP] [port]
-r, --dnslist::
Use specified DNSservers file
-t, --force-tcp::
Force TCP connection (use this with proxies)
-x, --nodata::
Ignore data file
FILES
-----
{datadir}/DHTnodes::
Default list of DHT bootstrap nodes.
~/.config/tox/data::
Savestate which contains your personal info (nickname, Tox ID, contacts,
etc)
~/.config/tox/toxic.conf::
Configuration file. See *toxic.conf*(5) for more details.
{datadir}/toxic.conf.example::
Configuration example.
BUGS
----
Unicode characters with a width larger than 1 column may cause strange
behaviour. Expect more bugs and bad behaviour: this software is in a
pre-alpha stage.
AUTHORS
-------
JFreegman <JFreegman@gmail.com>
SEE ALSO
--------
*toxic.conf*(5)
LINKS
-----
Project page: <https://github.com/Tox/toxic>
IRC channel: chat.freenode.net#tox

View File

@ -1,413 +1,271 @@
.TH TOXIC.CONF 5 "June 2014" "Toxic v__VERSION__" "User Manual"
.SH NAME
toxic.conf \- Configuration file for toxic(1)
.SH DESCRIPTION
The
.I toxic.conf
file is the main configuration file for
.BR toxic (1)
client.
.SH SYNTAX
.I <SECTION>
.B = {
.PP
.IB <KEY1> = <VALUE1> ;
.br
.IB <KEY2> = <VALUE2> ;
.br
...
.PP
.B };
.PP
Uses syntax accepted by libconfig.
.br
Lines starting with "//" are comments and will be ignored.
.PP
Sections:
.PP
.B ui
.RS
Configurations related to user interface elements.
.PP
Keys:
.br
.B timestamps
.RS
Enable or disable timestamps.
.br
Values: 'true' to enable, 'false' to disable
.RE
.PP
.B alerts
.RS
Enable or disable terminal alerts on events.
.br
Values: 'true' to enable, 'false' to disable
.RE
.PP
.B native_colors
.RS
Select between native terminal colors and toxic color theme.
.br
Values: 'true' for terminal colours, 'false' for toxic colours
.RE
.PP
.B autolog
.RS
Enable or disable autologging.
.br
Values: 'true' to enable, 'false' to disable
.RE
.PP
.B time_format
.RS
Select between 24 and 12 hour time.
.br
Values: 24, 12
.RE
.PP
.B show_typing_other
.RS
Show you when others are typing in a 1-on-1 chat
.br
Values: 'true' to enable, 'false' to disable
.RE
.PP
.B show_typing_self
.RS
Show others when you're typing in a 1-on-1 chat
.br
Values: 'true' to enable, 'false' to disable
.RE
.PP
.B history_size
.RS
Maximum lines for chat window history.
.br
Values: <INTEGER> (for example: 700)
.RE
.RE
.PP
.B audio
.RS
Configurations related to audio devices.
.PP
Keys:
.br
.B input_device
.RS
Audio input device.
.br
Values: <INTEGER> (number correspond to "/lsdev in")
.RE
.PP
.B output_device
.RS
Audio output device.
.br
Values: <INTEGER> (number correspond to "/lsdev out")
.RE
.PP
.B VAD_treshold
.RS
Voice Activity Detection treshold.
.br
Values: <FLOAT> (recommended values are around 40.0)
.RE
.RE
.PP
.B tox
.RS
Configurations related to file transfer.
.PP
Keys:
.br
.B download_path
.RS
Default path for downloads.
.br
Values: <STRING> (absolute path where to store downloaded files)
.RE
.RE
.PP
.B sounds
.RS
Configurations related to notification sounds.
.br
(Special value "silent" can be used to disable a specific notification)
.PP
Keys:
.br
.B error
.RS
Sound to play when an error occurs.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B self_log_in
.RS
Sound to play when you log in.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B self_log_out
.RS
Sound to play when you log out.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B user_log_in
.RS
Sound to play when a contact become online.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B user_log_out
.RS
Sound to play when a contact become offline.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B call_incoming
.RS
Sound to play when you receive an incoming call.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B call_outgoing
.RS
Sound to play when you start a call.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B generic_message
.RS
Sound to play when an event occurs.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B transfer_pending
.RS
Sound to play when you receive a file transfer request.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B transfer_completed
.RS
Sound to play when a file transfer is completed.
.br
Values: <STRING> (sound file absolute path)
.RE
.RE
.PP
.B keys
.RS
Configurations related to user interface interaction.
.br
(Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive))
.PP
Keys:
.br
.B next_tab
.RS
Key combination to switch next tab.
.br
Values: <STRING> (key combination)
.RE
.PP
.B prev_tab
.RS
Key combination to switch previous tab.
.br
Values: <STRING> (key combination)
.RE
.PP
.B scroll_line_up
.RS
Key combination to scroll one line up.
.br
Values: <STRING> (key combination)
.RE
.PP
.B scroll_line_down
.RS
Key combination to scroll one line down.
.br
Values: <STRING> (key combination)
.RE
.PP
.B half_page_up
.RS
Key combination to scroll half page up.
.br
Values: <STRING> (key combination)
.RE
.PP
.B half_page_down
.RS
Key combination to scroll half page down.
.br
Values: <STRING> (key combination)
.RE
.PP
.B page_bottom
.RS
Key combination to scroll to page bottom.
.br
Values: <STRING> (key combination)
.RE
.PP
.B peer_list_up
.RS
Key combination to scroll contacts list up.
.br
Values: <STRING> (key combination)
.RE
.PP
.B peer_list_down
.RS
Key combination to scroll contacts list down.
.br
Values: <STRING> (key combination)
.RE
.RE
.SH EXAMPLES
Default settings from __DATADIR__/toxic.conf.exmaple:
.PP
// SAMPLE TOXIC CONFIGURATION
.br
// USES LIBCONFIG-ACCEPTED SYNTAX
.br
'\" t
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2014-08-21
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC\&.CONF" "5" "2014\-08\-21" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
toxic.conf \- Configuration file for toxic
.SH "SYNOPSIS"
.sp
~/\&.config/tox/toxic\&.conf
.SH "DESCRIPTION"
.sp
The \fItoxic\&.conf\fR file is the main configuration file for \fBtoxic\fR(1) client\&. It uses syntax accepted by \fBlibconfig\fR\&. Lines starting with "//" are comments and will be ignored\&.
.SH "EXAMPLE"
.sp
.if n \{\
.RS 4
.\}
.nf
// Configuration for interface
ui = {
.RS
// true to enable timestamps, false to disable
.br
timestamps=true;
.br
// true to enable terminal alerts on messages, false to disable
.br
alerts=true;
.br
// true to use native terminal colours, false to use toxic default colour theme
.br
native_colors=false;
.br
// true to enable autologging, false to disable
.br
autolog=false;
.br
// 24 or 12 hour time
.br
time_format=24;
.br
// true to show you when others are typing a message in 1-on-1 chats
.br
show_typing_other=true;
.br
// true to show others when you're typing a message in 1-on-1 chats
.br
show_typing_self=true;
.br
// maximum lines for chat window history
.br
history_size=700;
.RE
timestamps = true;
alerts = false;
};
.PP
// Configuration for audio
audio = {
.RS
// preferred audio input device; numbers correspond to /lsdev in
.br
input_device=2;
.br
// preferred audio output device; numbers correspond to /lsdev out
.br
output_device=0;
.br
// default VAD treshold; float (recommended values are around 40)
.br
VAD_treshold=40.0;
.RE
input_device = 1;
};
.fi
.if n \{\
.RE
.\}
.SH "OPTIONS"
.PP
tox = {
.RS
// where to store received files
.br
//download_path="/home/USERNAME/Downloads/";
.RE
};
\fBui\fR
.RS 4
Configuration related to interface elements\&.
.PP
// To disable a sound set the path to "silent"
.br
sounds = {
.RS
error="__DATADIR__/sounds/Error.wav";
.br
self_log_in="__DATADIR__/sounds/LogIn.wav";
.br
self_log_out="__DATADIR__/sounds/LogOut.wav";
.br
user_log_in="__DATADIR__/sounds/ContactLogsIn.wav";
.br
user_log_out="__DATADIR__/sounds/ContactLogsOut.wav";
.br
call_incoming="__DATADIR__/sounds/IncomingCall.wav";
.br
call_outgoing="__DATADIR__/sounds/OutgoingCall.wav";
.br
generic_message="__DATADIR__/sounds/NewMessage.wav";
.br
transfer_pending="__DATADIR__/sounds/TransferPending.wav";
.br
transfer_completed="__DATADIR__/sounds/TransferComplete.wav";
\fBtimestamps\fR
.RS 4
Enable or disable timestamps\&. true or false
.RE
};
.PP
// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
.br
// Note: All printable keys register as input
.br
keys = {
.RS
next_tab="Ctrl+P";
.br
prev_tab="Ctrl+O";
.br
scroll_line_up="PAGEUP";
.br
scroll_line_down="PAGEDOWN";
.br
half_page_up="Ctrl+F";
.br
half_page_down="Ctrl+V";
.br
page_bottom="Ctrl+H";
.br
peer_list_up="Ctrl+[";
.br
peer_list_down="Ctrl+]";
\fBalerts\fR
.RS 4
Enable or disable terminal alerts on events\&. true or false
.RE
};
.SH FILES
.IP ~/.config/tox/toxic.conf
Main configuration file.
.IP __DATADIR__/toxic.conf.example
Configuration example.
.SH AUTHORS
JFreegman <JFreegman@gmail.com>
.SH SEE ALSO
.BR toxic (1)
.SH LINKS
Project page on github: https://github.com/Tox/toxic
.br
IRC channel on Freenode: chat.freenode.net#tox
.PP
\fBnative_colors\fR
.RS 4
Select between native terminal colors and toxic color theme\&. true or false
.RE
.PP
\fBautolog\fR
.RS 4
Enable or disable autologging\&. true or false
.RE
.PP
\fBtime_format\fR
.RS 4
Select between 24 and 12 hour time\&. Specify 24 or 12
.RE
.PP
\fBshow_typing_other\fR
.RS 4
Show when others are typing in a 1\-on\-1 chat\&. true or false
.RE
.PP
\fBshow_typing_self\fR
.RS 4
Show others when you\(cqre typing in a 1\-on\-1 chat\&. true or false
.RE
.PP
\fBhistory_size\fR
.RS 4
Maximum lines for chat window history\&. Integer value\&. (for example: 700)
.RE
.RE
.PP
\fBaudio\fR
.RS 4
Configuration related to audio devices\&.
.PP
\fBinput_device\fR
.RS 4
Audio input device\&. Integer value\&. Number corresponds to
/lsdev in
.RE
.PP
\fBoutput_device\fR
.RS 4
Audio output device\&. Integer value\&. Number corresponds to
/lsdev out
.RE
.PP
\fBVAD_treshold\fR
.RS 4
Voice Activity Detection treshold\&. Float value\&. Recommended values are around 40\&.0
.RE
.RE
.PP
\fBtox\fR
.RS 4
Configuration related to paths\&.
.PP
\fBdownload_path\fR
.RS 4
Default path for downloads\&. String value\&. Absolute path for downloaded files\&.
.RE
.PP
\fBchatlogs_path\fR
.RS 4
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
.RE
.RE
.PP
\fBsounds\fR
.RS 4
Configuration related to notification sounds\&. Special value "silent" can be used to disable a specific notification\&.
Each value is a string which corresponds to the absolute path of a wav sound file\&.
.PP
\fBerror\fR
.RS 4
Sound to play when an error occurs\&.
.RE
.PP
\fBself_log_in\fR
.RS 4
Sound to play when you log in\&.
.RE
.PP
\fBself_log_out\fR
.RS 4
Sound to play when you log out\&.
.RE
.PP
\fBuser_log_in\fR
.RS 4
Sound to play when a contact become online\&.
.RE
.PP
\fBuser_log_out\fR
.RS 4
Sound to play when a contact become offline\&.
.RE
.PP
\fBcall_incoming\fR
.RS 4
Sound to play when you receive an incoming call\&.
.RE
.PP
\fBcall_outgoing\fR
.RS 4
Sound to play when you start a call\&.
.RE
.PP
\fBgeneric_message\fR
.RS 4
Sound to play when an event occurs\&.
.RE
.PP
\fBtransfer_pending\fR
.RS 4
Sound to play when you receive a file transfer request\&.
.RE
.PP
\fBtransfer_completed\fR
.RS 4
Sound to play when a file transfer is completed\&.
.RE
.RE
.PP
\fBkeys\fR
.RS 4
Configuration related to user interface interaction\&. Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN\&.
Each value is a string which corresponds to a key combination\&.
.PP
\fBnext_tab\fR
.RS 4
Key combination to switch next tab\&.
.RE
.PP
\fBprev_tab\fR
.RS 4
Key combination to switch previous tab\&.
.RE
.PP
\fBscroll_line_up\fR
.RS 4
Key combination to scroll one line up\&.
.RE
.PP
\fBscroll_line_down\fR
.RS 4
Key combination to scroll one line down\&.
.RE
.PP
\fBhalf_page_up\fR
.RS 4
Key combination to scroll half page up\&.
.RE
.PP
\fBhalf_page_down\fR
.RS 4
Key combination to scroll half page down\&.
.RE
.PP
\fBpage_bottom\fR
.RS 4
Key combination to scroll to page bottom\&.
.RE
.PP
\fBpeer_list_up\fR
.RS 4
Key combination to scroll contacts list up\&.
.RE
.PP
\fBpeer_list_down\fR
.RS 4
Key combination to scroll contacts list down\&.
.RE
.RE
.SH "FILES"
.PP
~/\&.config/tox/toxic\&.conf
.RS 4
Main configuration file\&.
.RE
.PP
__DATADIR__/toxic\&.conf\&.example
.RS 4
Configuration example\&.
.RE
.SH "SEE ALSO"
.sp
\fBtoxic\fR(1)
.SH "RESOURCES"
.sp
Project page: https://github\&.com/Tox/toxic
.sp
IRC channel: chat\&.freenode\&.net#tox
.SH "AUTHORS"
.sp
JFreegman <JFreegman@gmail\&.com>

182
doc/toxic.conf.5.asc Normal file
View File

@ -0,0 +1,182 @@
toxic.conf(5)
=============
NAME
----
toxic.conf - Configuration file for toxic
SYNOPSIS
--------
~/.config/tox/toxic.conf
DESCRIPTION
-----------
The 'toxic.conf' file is the main configuration file for *toxic*(1) client.
It uses syntax accepted by *libconfig*.
Lines starting with "//" are comments and will be ignored.
EXAMPLE
-------
----
// Configuration for interface
ui = {
timestamps = true;
alerts = false;
};
// Configuration for audio
audio = {
input_device = 1;
};
----
OPTIONS
-------
*ui*::
Configuration related to interface elements.
*timestamps*;;
Enable or disable timestamps. true or false
*alerts*;;
Enable or disable terminal alerts on events. true or false
*native_colors*;;
Select between native terminal colors and toxic color theme. true or false
*autolog*;;
Enable or disable autologging. true or false
*time_format*;;
Select between 24 and 12 hour time. Specify 24 or 12
*show_typing_other*;;
Show when others are typing in a 1-on-1 chat. true or false
*show_typing_self*;;
Show others when you're typing in a 1-on-1 chat. true or false
*history_size*;;
Maximum lines for chat window history. Integer value. (for example: 700)
*audio*::
Configuration related to audio devices.
*input_device*;;
Audio input device. Integer value. Number corresponds to `/lsdev in`
*output_device*;;
Audio output device. Integer value. Number corresponds to `/lsdev out`
*VAD_treshold*;;
Voice Activity Detection treshold. Float value. Recommended values are
around 40.0
*tox*::
Configuration related to paths.
*download_path*;;
Default path for downloads. String value. Absolute path for downloaded
files.
*chatlogs_path*;;
Default path for chatlogs. String value. Absolute path for chatlog files.
*sounds*::
Configuration related to notification sounds.
Special value "silent" can be used to disable a specific notification. +
Each value is a string which corresponds to the absolute path of a wav
sound file.
*error*;;
Sound to play when an error occurs.
*self_log_in*;;
Sound to play when you log in.
*self_log_out*;;
Sound to play when you log out.
*user_log_in*;;
Sound to play when a contact become online.
*user_log_out*;;
Sound to play when a contact become offline.
*call_incoming*;;
Sound to play when you receive an incoming call.
*call_outgoing*;;
Sound to play when you start a call.
*generic_message*;;
Sound to play when an event occurs.
*transfer_pending*;;
Sound to play when you receive a file transfer request.
*transfer_completed*;;
Sound to play when a file transfer is completed.
*keys*::
Configuration related to user interface interaction.
Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN. +
Each value is a string which corresponds to a key combination.
*next_tab*;;
Key combination to switch next tab.
*prev_tab*;;
Key combination to switch previous tab.
*scroll_line_up*;;
Key combination to scroll one line up.
*scroll_line_down*;;
Key combination to scroll one line down.
*half_page_up*;;
Key combination to scroll half page up.
*half_page_down*;;
Key combination to scroll half page down.
*page_bottom*;;
Key combination to scroll to page bottom.
*peer_list_up*;;
Key combination to scroll contacts list up.
*peer_list_down*;;
Key combination to scroll contacts list down.
FILES
-----
~/.config/tox/toxic.conf::
Main configuration file.
{datadir}/toxic.conf.example::
Configuration example.
SEE ALSO
--------
*toxic*(1)
RESOURCES
---------
Project page: <https://github.com/Tox/toxic>
IRC channel: chat.freenode.net#tox
AUTHORS
-------
JFreegman <JFreegman@gmail.com>

View File

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

2
misc/DNSservers Normal file
View File

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

View File

@ -39,8 +39,11 @@ audio = {
};
tox = {
// where to store received files
//download_path="/home/USERNAME/Downloads/";
// Path for downloaded files
// download_path="/home/USERNAME/Downloads/";
// Path for chatlogs
// chatlogs_path="/home/USERNAME/toxic_chatlogs/";
};
// To disable a sound set the path to "silent"
@ -60,14 +63,14 @@ sounds = {
// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
// Note: All printable keys register as input
keys = {
next_tab="Ctrl+P";
prev_tab="Ctrl+O";
scroll_line_up="PAGEUP";
scroll_line_down="PAGEDOWN";
half_page_up="Ctrl+F";
half_page_down="Ctrl+V";
page_bottom="Ctrl+H";
peer_list_up="Ctrl+[";
peer_list_down="Ctrl+]";
next_tab="Ctrl+P";
prev_tab="Ctrl+O";
scroll_line_up="PAGEUP";
scroll_line_down="PAGEDOWN";
half_page_up="Ctrl+F";
half_page_down="Ctrl+V";
page_bottom="Ctrl+H";
peer_list_up="Ctrl+[";
peer_list_down="Ctrl+]";
};

View File

@ -244,7 +244,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line)
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
return -1;
if (!strncmp(b_path, "~/", 2))
if (b_path[0] == '~')
complt_home_dir(self, b_path, sizeof(b_path));
int si = char_rfind(b_path, '/', strlen(b_path));

View File

@ -52,7 +52,7 @@
extern char *DATA_FILE;
extern FileSender file_senders[MAX_FILES];
extern ToxicFriend friends[MAX_FRIENDS_NUM];
extern _Friends Friends;
extern struct _Winthread Winthread;
extern struct user_settings *user_settings_;
@ -124,11 +124,14 @@ static void chat_set_window_name(ToxWindow *self, char *nick, int len)
snprintf(self->name, sizeof(self->name), "%s", nick);
}
void kill_chat_window(ToxWindow *self)
static void close_all_file_receivers(Tox *m, int friendnum);
void kill_chat_window(ToxWindow *self, Tox *m)
{
ChatContext *ctx = self->chatwin;
StatusBar *statusbar = self->stb;
close_all_file_receivers(m, self->num);
log_disable(ctx->log);
line_info_cleanup(ctx->hst);
@ -173,24 +176,45 @@ static void chat_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *msg
}
static void chat_resume_file_transfers(Tox *m, int fnum);
static void chat_stop_file_senders(int fnum);
static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
{
if (self->num != num)
return;
StatusBar *statusbar = self->stb;
ChatContext *ctx = self->chatwin;
const char *msg;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
if (status == 1) { /* Friend goes online */
statusbar->is_online = true;
friends[num].is_typing = user_settings_->show_typing_other == SHOW_TYPING_ON
Friends.list[num].is_typing = user_settings_->show_typing_other == SHOW_TYPING_ON
? tox_get_is_typing(m, num) : 0;
chat_resume_file_transfers(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 { /* Friend goes offline */
statusbar->is_online = false;
friends[num].is_typing = 0;
Friends.list[num].is_typing = 0;
if (self->chatwin->self_is_typing)
set_self_typingstatus(self, m, 0);
chat_stop_file_senders(num);
msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true);
}
}
@ -199,7 +223,7 @@ static void chat_onTypingChange(ToxWindow *self, Tox *m, int32_t num, uint8_t is
if (self->num != num)
return;
friends[num].is_typing = is_typing;
Friends.list[num].is_typing = is_typing;
}
static void chat_onAction(ToxWindow *self, Tox *m, int32_t num, const char *action, uint16_t len)
@ -219,9 +243,9 @@ static void chat_onAction(ToxWindow *self, Tox *m, int32_t num, const char *acti
write_to_log(action, nick, ctx->log, true);
if (self->active_box != -1)
box_notify2(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
else
box_notify(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action );
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action );
}
static void chat_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *nick, uint16_t len)
@ -277,9 +301,11 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
/* holds the lone filename */
char filename_nopath[MAX_STR_SIZE];
get_file_name(filename_nopath, sizeof(filename_nopath), pathname);
char sizestr[32];
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
int len = strlen(filename_nopath);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%llu bytes).",
filename_nopath, (long long unsigned int) filesize);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)",
filename_nopath, sizestr);
if (filenum >= MAX_FILES) {
errmsg = "Too many pending file requests; discarding.";
@ -293,7 +319,7 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
len += strlen(user_settings_->download_path);
}
if (len >= sizeof(friends[num].file_receiver.filenames[filenum])) {
if (len >= sizeof(Friends.list[num].file_receiver[filenum].filename)) {
errmsg = "File name too long; discarding.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
@ -333,18 +359,49 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", filenum);
friends[num].file_receiver.pending[filenum] = true;
friends[num].file_receiver.size[filenum] = filesize;
strcpy(friends[num].file_receiver.filenames[filenum], filename);
Friends.list[num].file_receiver[filenum].pending = true;
Friends.list[num].file_receiver[filenum].size = filesize;
Friends.list[num].file_receiver[filenum].filenum = filenum;
strcpy(Friends.list[num].file_receiver[filenum].filename, filename);
if (self->active_box != -1)
box_notify2(self, transfer_pending, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box,
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
"Incoming file: %s", filename );
else
box_notify(self, transfer_pending, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, self->name,
box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, &self->active_box, self->name,
"Incoming file: %s", filename );
}
/* Stops active file senders for this friend. Call when a friend goes offline */
static void chat_stop_file_senders(int fnum)
{
int i;
for (i = 0; i < MAX_FILES; ++i) {
if (file_senders[i].active && file_senders[i].friendnum == fnum)
file_senders[i].noconnection = true;
}
}
/* Tries to resume broken file transfers. Call when a friend comes online */
static void chat_resume_file_transfers(Tox *m, int fnum)
{
if (Friends.list[fnum].active_file_receivers == 0)
return;
int 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));
int 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));
}
}
}
/* set CTRL to -1 if we don't want to send a control signal.
set msg to NULL if we don't want to display a message */
void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL)
@ -352,13 +409,22 @@ void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL)
if (CTRL > 0)
tox_file_send_control(m, friendnum, 1, filenum, CTRL, 0, 0);
friends[friendnum].file_receiver.active[filenum] = false;
friends[friendnum].file_receiver.pending[filenum] = false;
FILE *file = friends[friendnum].file_receiver.files[filenum];
FILE *file = Friends.list[friendnum].file_receiver[filenum].file;
if (file != NULL) {
if (file != NULL)
fclose(file);
friends[friendnum].file_receiver.files[filenum] = NULL;
memset(&Friends.list[friendnum].file_receiver[filenum], 0, sizeof(struct FileReceiver));
--Friends.list[friendnum].active_file_receivers;
}
static void close_all_file_receivers(Tox *m, int friendnum)
{
int i;
for (i = 0; i < MAX_FILES; ++i) {
if (Friends.list[friendnum].file_receiver[i].active)
chat_close_file_receiver(m, i, friendnum, TOX_FILECONTROL_KILL);
}
}
@ -370,17 +436,27 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
const char *filename;
char msg[MAX_STR_SIZE] = {0};
int i = 0; /* file_sender index */
int send_idx = 0; /* file sender index */
if (receive_send == 0) {
filename = friends[num].file_receiver.filenames[filenum];
if (!Friends.list[num].file_receiver[filenum].active)
return;
filename = Friends.list[num].file_receiver[filenum].filename;
} else {
int i;
for (i = 0; i < MAX_FILES; ++i) {
send_idx = i;
if (file_senders[i].active && file_senders[i].filenum == filenum)
break;
}
filename = file_senders[i].filename;
if (!file_senders[send_idx].active)
return;
filename = file_senders[send_idx].filename;
}
switch (control_type) {
@ -392,7 +468,7 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
char progline[MAX_STR_SIZE];
prep_prog_line(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
file_senders[i].line_id = self->chatwin->hst->line_end->id + 2;
file_senders[send_idx].line_id = self->chatwin->hst->line_end->id + 2;
sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
}
@ -411,29 +487,47 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
if (receive_send == 0)
chat_close_file_receiver(m, filenum, num, -1);
else
close_file_sender(self, m, i, NULL, -1, filenum, num);
close_file_sender(self, m, send_idx, NULL, -1, filenum, num);
break;
case TOX_FILECONTROL_FINISHED:
if (receive_send == 0) {
print_progress_bar(self, filenum, num, 100.0);
snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename);
chat_close_file_receiver(m, filenum, num, TOX_FILECONTROL_FINISHED);
} else {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", filename);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_FINISHED, filenum, num);
return;
close_file_sender(self, m, send_idx, NULL, TOX_FILECONTROL_FINISHED, filenum, num);
}
if (self->active_box != -1)
box_notify2(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2,
self->active_box, "%s", msg);
box_notify2(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg);
else
box_notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box,
self->name, "%s", msg);
break;
case TOX_FILECONTROL_RESUME_BROKEN:
if (receive_send == 0)
break;
FILE *fp = file_senders[send_idx].file;
if (fp == NULL)
break;
uint8_t tmp[sizeof(uint64_t)];
memcpy(tmp, &data, sizeof(uint64_t));
net_to_host(tmp, sizeof(uint64_t));
uint64_t datapos;
memcpy(&datapos, tmp, sizeof(uint64_t));
fseek(fp, datapos, SEEK_SET);
tox_file_send_control(m, num, 0, filenum, TOX_FILECONTROL_ACCEPT, 0, 0);
file_senders[send_idx].noconnection = false;
break;
}
if (msg[0])
@ -446,7 +540,7 @@ static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenu
if (self->num != num)
return;
FILE *fp = friends[num].file_receiver.files[filenum];
FILE *fp = Friends.list[num].file_receiver[filenum].file;
if (fp) {
if (fwrite(data, length, 1, fp) != 1) {
@ -455,18 +549,8 @@ static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenu
}
}
friends[num].file_receiver.bps[filenum] += length;
double remain = (double) tox_file_data_remaining(m, num, filenum, 1);
uint64_t curtime = get_unix_time();
/* refresh line with percentage complete and transfer speed (must be called once per second) */
if (!remain || timed_out(friends[num].file_receiver.last_progress[filenum], curtime, 1)) {
friends[num].file_receiver.last_progress[filenum] = curtime;
uint64_t size = friends[num].file_receiver.size[filenum];
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
print_progress_bar(self, filenum, num, pct_done);
friends[num].file_receiver.bps[filenum] = 0;
}
Friends.list[num].file_receiver[filenum].bps += length;
Friends.list[num].file_receiver[filenum].bytes_recv += length;
}
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, const char *group_pub_key)
@ -480,9 +564,9 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, co
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to a group chat.", name);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat.");
memcpy(friends[friendnumber].groupchat_key, group_pub_key,
sizeof(friends[friendnumber].groupchat_key));
friends[friendnumber].groupchat_pending = true;
memcpy(Friends.list[friendnumber].groupchat_key, group_pub_key,
sizeof(Friends.list[friendnumber].groupchat_key));
Friends.list[friendnumber].groupchat_pending = true;
sound_notify(self, generic_message, NT_WNDALERT_2, NULL);
@ -819,7 +903,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
kill_chat_window(self);
kill_chat_window(self, m);
return;
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
send_action(self, ctx, m, line + strlen("/me "));
@ -899,14 +983,14 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
wprintw(statusbar->topline, " %s", ONLINE_CHAR);
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
if (friends[self->num].is_typing)
if (Friends.list[self->num].is_typing)
wattron(statusbar->topline, COLOR_PAIR(YELLOW));
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " %s ", statusbar->nick);
wattroff(statusbar->topline, A_BOLD);
if (friends[self->num].is_typing)
if (Friends.list[self->num].is_typing)
wattroff(statusbar->topline, COLOR_PAIR(YELLOW));
} else {
wprintw(statusbar->topline, " %s", OFFLINE_CHAR);
@ -930,10 +1014,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
self->x = x2;
/* Truncate note if it doesn't fit in statusbar */
uint16_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 7;
uint16_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 6;
if (statusbar->statusmsg_len > maxlen) {
statusbar->statusmsg[maxlen] = '\0';
statusbar->statusmsg[maxlen - 3] = '\0';
strcat(statusbar->statusmsg, "...");
statusbar->statusmsg_len = maxlen;
}
@ -947,7 +1032,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
int i;
for (i = 0; i < KEY_IDENT_DIGITS; ++i)
wprintw(statusbar->topline, "%02X", friends[self->num].pub_key[i] & 0xff);
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
wprintw(statusbar->topline, "}\n");
@ -1011,8 +1096,8 @@ static void chat_onInit(ToxWindow *self, Tox *m)
line_info_init(ctx->hst);
if (friends[self->num].logging_on)
log_enable(nick, friends[self->num].pub_key, ctx->log);
if (Friends.list[self->num].logging_on)
log_enable(nick, Friends.list[self->num].pub_key, ctx->log);
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);

View File

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

View File

@ -34,8 +34,7 @@
#include "file_senders.h"
extern ToxWindow *prompt;
extern ToxicFriend friends[MAX_FRIENDS_NUM];
extern _Friends Friends;
extern FileSender file_senders[MAX_FILES];
extern uint8_t max_file_senders_index;
@ -57,12 +56,12 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
}
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */
if (!friends[self->num].file_receiver.active[filenum]) {
if (!Friends.list[self->num].file_receiver[filenum].active) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
const char *filepath = friends[self->num].file_receiver.filenames[filenum];
const char *filepath = Friends.list[self->num].file_receiver[filenum].filename;
char name[MAX_STR_SIZE];
get_file_name(name, sizeof(name), filepath);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer for '%s' canceled.", name);
@ -124,9 +123,9 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
return;
}
const char *groupkey = friends[self->num].groupchat_key;
const char *groupkey = Friends.list[self->num].groupchat_key;
if (!friends[self->num].groupchat_pending) {
if (!Friends.list[self->num].groupchat_pending) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite.");
return;
}
@ -159,12 +158,12 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return;
}
if (!friends[self->num].file_receiver.pending[filenum]) {
if (!Friends.list[self->num].file_receiver[filenum].pending) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return;
}
const char *filename = friends[self->num].file_receiver.filenames[filenum];
const char *filename = Friends.list[self->num].file_receiver[filenum].filename;
if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", filenum, filename);
@ -173,18 +172,20 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
char progline[MAX_STR_SIZE];
prep_prog_line(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
friends[self->num].file_receiver.line_id[filenum] = self->chatwin->hst->line_end->id + 2;
Friends.list[self->num].file_receiver[filenum].line_id = self->chatwin->hst->line_end->id + 2;
if ((friends[self->num].file_receiver.files[filenum] = fopen(filename, "a")) == NULL) {
if ((Friends.list[self->num].file_receiver[filenum].file = fopen(filename, "a")) == NULL) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Error writing to file.");
tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
} else {
Friends.list[self->num].file_receiver[filenum].active = true;
++Friends.list[self->num].active_file_receivers;
}
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed.");
}
friends[self->num].file_receiver.pending[filenum] = false;
friends[self->num].file_receiver.active[filenum] = true;
Friends.list[self->num].file_receiver[filenum].pending = false;
}
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -241,7 +242,6 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
for (i = 0; i < MAX_FILES; ++i) {
if (!file_senders[i].active) {
file_senders[i].queue_pos = num_active_file_senders;
memcpy(file_senders[i].filename, filename, namelen + 1);
file_senders[i].active = true;
file_senders[i].toxwin = self;
@ -253,13 +253,17 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
tox_file_data_size(m, self->num), file_to_send);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s'", filenum, filename);
char sizestr[32];
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
"Sending file [%d]: '%s' (%s)", filenum, filename, sizestr);
++num_active_file_senders;
if (i == max_file_senders_index)
++max_file_senders_index;
reset_file_sender_queue();
return;
}
}

156
src/dns.c
View File

@ -40,19 +40,23 @@
#include "dns.h"
#include "global_commands.h"
#include "misc_tools.h"
#include "configdir.h"
#define MAX_DNS_REQST_SIZE 256
#define NUM_DNS3_SERVERS 2 /* must correspond to number of items in dns3_servers array */
#define DNS3_KEY_SIZE 32
#define MAX_DNS_REQST_SIZE 255
#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
#define DNS3_KEY_SZ 32
extern struct _Winthread Winthread;
extern struct _dns3_servers dns3_servers;
extern struct arg_opts arg_opts;
/* TODO: process keys from key file instead of hard-coding like a noob */
static struct dns3_server {
#define NUM_DNS3_BACKUP_SERVERS 2
/* Hardcoded backup in case domain list is not loaded */
static struct dns3_server_backup {
const char *name;
char key[DNS3_KEY_SZ];
} dns3_servers[] = {
char key[DNS3_KEY_SIZE];
} dns3_servers_backup[] = {
{
"utox.org",
{
@ -84,6 +88,61 @@ static struct _dns_thread {
} dns_thread;
#define MAX_DNS_SERVERS 50
#define MAX_DOMAIN_SIZE 32
#define MAX_DNS_LINE MAX_DOMAIN_SIZE + (DNS3_KEY_SIZE * 2) + 3
struct _dns3_servers {
bool loaded;
int lines;
char names[MAX_DNS_SERVERS][MAX_DOMAIN_SIZE];
char keys[MAX_DNS_SERVERS][DNS3_KEY_SIZE];
} dns3_servers;
static int load_dns_domainlist(const char *path)
{
FILE *fp = fopen(path, "r");
if (fp == NULL)
return -1;
char line[MAX_DNS_LINE];
while (fgets(line, sizeof(line), fp) && dns3_servers.lines < MAX_DNS_SERVERS) {
int linelen = strlen(line);
if (linelen < DNS3_KEY_SIZE * 2 + 5)
continue;
if (line[linelen - 1] == '\n')
line[--linelen] = '\0';
const char *name = strtok(line, " ");
const char *keystr = strtok(NULL, " ");
if (name == NULL || keystr == NULL)
continue;
if (strlen(keystr) != DNS3_KEY_SIZE * 2)
continue;
snprintf(dns3_servers.names[dns3_servers.lines], sizeof(dns3_servers.names[dns3_servers.lines]), "%s", name);
int res = hex_string_to_bytes(dns3_servers.keys[dns3_servers.lines], DNS3_KEY_SIZE, keystr);
if (res == -1)
continue;
++dns3_servers.lines;
}
fclose(fp);
if (dns3_servers.lines < 1)
return -2;
return 0;
}
static int dns_error(ToxWindow *self, const char *errmsg)
{
pthread_mutex_lock(&Winthread.lock);
@ -161,6 +220,9 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
if (!size || txt_len >= size || !txt_len)
return dns_error(self, "No record found.");
if (txt_len > MAX_DNS_REQST_SIZE)
return dns_error(self, "Invalid DNS response.");
ans_pt++;
ans_pt[txt_len] = '\0';
memcpy(buf, ans_pt, txt_len + 1);
@ -191,35 +253,61 @@ static int parse_addr(const char *addr, char *namebuf, char *dombuf)
return strlen(namebuf);
}
/* matches input domain name with domains in list and obtains key. Return 0 on success, -1 on failure */
static int get_domain_match(char *pubkey, char *domain, const char *inputdomain)
{
/* check server list first */
int i;
bool match = false;
for (i = 0; i < dns3_servers.lines; ++i) {
if (strcmp(dns3_servers.names[i], inputdomain) == 0) {
memcpy(pubkey, dns3_servers.keys[i], DNS3_KEY_SIZE);
snprintf(domain, MAX_DOMAIN_SIZE, "%s", dns3_servers.names[i]);
match = true;
break;
}
}
/* fall back to hard-coded domains on server list failure */
if (!match) {
for (i = 0; i < NUM_DNS3_BACKUP_SERVERS; ++i) {
if (strcmp(dns3_servers_backup[i].name, inputdomain) == 0) {
memcpy(pubkey, dns3_servers_backup[i].key, DNS3_KEY_SIZE);
snprintf(domain, MAX_DOMAIN_SIZE, "%s", dns3_servers_backup[i].name);
match = true;
break;
}
}
if (!match)
return -1;
}
return 0;
}
/* Does DNS lookup for addr and puts resulting tox id in id_bin. */
void *dns3_lookup_thread(void *data)
{
ToxWindow *self = t_data.self;
char domain[MAX_STR_SIZE];
char inputdomain[MAX_STR_SIZE];
char name[MAX_STR_SIZE];
int namelen = parse_addr(t_data.addr, name, domain);
int namelen = parse_addr(t_data.addr, name, inputdomain);
if (namelen == -1) {
dns_error(self, "Must be a Tox ID or an address in the form username@domain");
kill_dns_thread(NULL);
}
/* get domain name/pub key */
const char *DNS_pubkey = NULL;
const char *domname = NULL;
int i;
char DNS_pubkey[DNS3_KEY_SIZE];
char domain[MAX_DOMAIN_SIZE];
for (i = 0; i < NUM_DNS3_SERVERS; ++i) {
if (strcmp(dns3_servers[i].name, domain) == 0) {
DNS_pubkey = dns3_servers[i].key;
domname = dns3_servers[i].name;
break;
}
}
int match = get_domain_match(DNS_pubkey, domain, inputdomain);
if (domname == NULL) {
if (match == -1) {
dns_error(self, "Domain not found.");
kill_dns_thread(NULL);
}
@ -231,7 +319,7 @@ void *dns3_lookup_thread(void *data)
kill_dns_thread(NULL);
}
char string[MAX_DNS_REQST_SIZE];
char string[MAX_DNS_REQST_SIZE + 1];
uint32_t request_id;
int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id,
@ -245,10 +333,10 @@ void *dns3_lookup_thread(void *data)
string[str_len] = '\0';
u_char answer[PACKETSZ];
char d_string[MAX_DNS_REQST_SIZE];
char d_string[MAX_DOMAIN_SIZE + MAX_DNS_REQST_SIZE + 10];
/* format string and create dns query */
snprintf(d_string, sizeof(d_string), "_%s._tox.%s", string, domname);
snprintf(d_string, sizeof(d_string), "_%s._tox.%s", string, domain);
int ans_len = res_query(d_string, C_IN, T_TXT, answer, sizeof(answer));
if (ans_len <= 0) {
@ -256,13 +344,13 @@ void *dns3_lookup_thread(void *data)
kill_dns_thread(dns_obj);
}
char ans_id[MAX_DNS_REQST_SIZE];
char ans_id[MAX_DNS_REQST_SIZE + 1];
/* extract TXT from DNS response */
if (parse_dns_response(self, answer, ans_len, ans_id) == -1)
kill_dns_thread(dns_obj);
char encrypted_id[MAX_DNS_REQST_SIZE];
char encrypted_id[MAX_DNS_REQST_SIZE + 1];
int prfx_len = strlen(TOX_DNS3_TXT_PREFIX);
/* extract the encrypted ID from TXT response */
@ -290,12 +378,28 @@ void *dns3_lookup_thread(void *data)
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg)
{
if (arg_opts.use_proxy && arg_opts.force_tcp) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "DNS lookups are disabled.");
return;
}
if (t_data.busy) {
const char *err = "Please wait for previous user lookup to finish.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, err);
return;
}
if (!dns3_servers.loaded) {
const char *path = arg_opts.dns_path[0] ? arg_opts.dns_path : PACKAGE_DATADIR "/DNSservers";
dns3_servers.loaded = true;
int ret = load_dns_domainlist(path);
if (ret < 0) {
const char *errmsg = "DNS server list failed to load with error code %d. Falling back to hard-coded list.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg, ret);
}
}
snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin);
snprintf(t_data.addr, sizeof(t_data.addr), "%s", addr);
snprintf(t_data.msg, sizeof(t_data.msg), "%s", msg);

View File

@ -43,6 +43,7 @@ static struct cmd_func global_commands[] = {
{ "/add", cmd_add },
{ "/clear", cmd_clear },
{ "/connect", cmd_connect },
{ "/decline", cmd_decline },
{ "/exit", cmd_quit },
{ "/groupchat", cmd_groupchat },
{ "/help", cmd_prompt_help },
@ -52,6 +53,7 @@ static struct cmd_func global_commands[] = {
{ "/note", cmd_note },
{ "/q", cmd_quit },
{ "/quit", cmd_quit },
{ "/requests", cmd_requests },
{ "/status", cmd_status },
#ifdef _AUDIO
@ -168,9 +170,5 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
if (do_command(w, self, m, num_args, GLOBAL_NUM_COMMANDS, global_commands, args) == 0)
return;
#ifdef _SOUND_NOTIFY
sound_notify(self, error, 0, NULL);
#else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
#endif
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
}

View File

@ -29,10 +29,10 @@
#define MAX_NUM_ARGS 4 /* Includes command */
#ifdef _AUDIO
#define GLOBAL_NUM_COMMANDS 16
#define GLOBAL_NUM_COMMANDS 18
#define CHAT_NUM_COMMANDS 12
#else
#define GLOBAL_NUM_COMMANDS 14
#define GLOBAL_NUM_COMMANDS 16
#define CHAT_NUM_COMMANDS 5
#endif /* _AUDIO */

View File

@ -36,11 +36,7 @@
FileSender file_senders[MAX_FILES];
uint8_t max_file_senders_index;
uint8_t num_active_file_senders;
extern ToxicFriend friends[MAX_FRIENDS_NUM];
#define KiB 1024
#define MiB 1048576 /* 1024 ^ 2 */
#define GiB 1073741824 /* 1024 ^ 3 */
extern _Friends Friends;
/* creates initial progress line that will be updated during file transfer.
Assumes progline is of size MAX_STR_SIZE */
@ -66,35 +62,20 @@ void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_done
bps = file_senders[idx].bps;
line_id = file_senders[idx].line_id;
} else {
bps = friends[friendnum].file_receiver.bps[idx];
line_id = friends[friendnum].file_receiver.line_id[idx];
}
const char *unit;
if (bps < KiB) {
unit = "B/s";
} else if (bps < MiB) {
unit = "KiB/s";
bps /= (double) KiB;
} else if (bps < GiB) {
unit = "MiB/s";
bps /= (double) MiB;
} else {
unit = "GiB/s";
bps /= (double) GiB;
bps = Friends.list[friendnum].file_receiver[idx].bps;
line_id = Friends.list[friendnum].file_receiver[idx].line_id;
}
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "%.1f %s [", bps, unit);
bytes_convert_str(msg, sizeof(msg), bps);
strcat(msg, "/s [");
int n = pct_done / (100 / NUM_PROG_MARKS);
int i;
int i, j;
for (i = 0; i < n; ++i)
strcat(msg, "#");
int j;
for (j = i; j < NUM_PROG_MARKS; ++j)
strcat(msg, "-");
@ -108,6 +89,64 @@ void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_done
line_info_set(self, line_id, msg);
}
/* refreshes active file receiver status bars */
static void refresh_recv_prog(Tox *m)
{
int i;
uint64_t curtime = get_unix_time();
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *toxwin = get_window_ptr(i);
if (toxwin == NULL || !toxwin->is_chat)
continue;
int fnum = toxwin->num;
int j;
for (j = 0; j < MAX_FILES; ++j) {
if (!Friends.list[fnum].file_receiver[j].active)
continue;
int filenum = Friends.list[fnum].file_receiver[j].filenum;
double remain = (double) tox_file_data_remaining(m, fnum, filenum, 1);
/* must be called once per second */
if (timed_out(Friends.list[fnum].file_receiver[filenum].last_progress, curtime, 1)) {
Friends.list[fnum].file_receiver[filenum].last_progress = curtime;
uint64_t size = Friends.list[fnum].file_receiver[filenum].size;
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
print_progress_bar(toxwin, filenum, fnum, pct_done);
Friends.list[fnum].file_receiver[filenum].bps = 0;
}
}
}
}
/* refreshes active file sender status bars */
static void refresh_sender_prog(Tox *m)
{
int i;
uint64_t curtime = get_unix_time();
for (i = 0; i < max_file_senders_index; ++i) {
if (!file_senders[i].active || file_senders[i].finished)
continue;
int filenum = file_senders[i].filenum;
int32_t friendnum = file_senders[i].friendnum;
double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0);
/* must be called once per second */
if (timed_out(file_senders[i].last_progress, curtime, 1)) {
file_senders[i].last_progress = curtime;
double pct_done = remain > 0 ? (1 - (remain / file_senders[i].size)) * 100 : 100;
print_progress_bar(file_senders[i].toxwin, i, -1, pct_done);
file_senders[i].bps = 0;
}
}
}
static void set_max_file_senders_index(void)
{
int j;
@ -120,6 +159,18 @@ static void set_max_file_senders_index(void)
max_file_senders_index = j;
}
/* called whenever a file sender is opened or closed */
void reset_file_sender_queue(void)
{
int i;
int pos = 0;
for (i = 0; i < max_file_senders_index; ++i) {
if (file_senders[i].active)
file_senders[i].queue_pos = pos++;
}
}
/* set CTRL to -1 if we don't want to send a control signal.
set msg to NULL if we don't want to display a message */
void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum)
@ -133,6 +184,7 @@ void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL
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;
}
@ -161,27 +213,30 @@ static void send_file_data(ToxWindow *self, Tox *m, int i, int32_t friendnum, in
file_senders[i].piecelen) == -1)
return;
uint64_t curtime = get_unix_time();
file_senders[i].timestamp = curtime;
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);
double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0);
/* 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);
}
/* refresh line with percentage complete and transfer speed (must be called once per second) */
if ( (self->chatwin != NULL && timed_out(file_senders[i].last_progress, curtime, 1))
|| (!remain && !file_senders[i].finished) ) {
file_senders[i].last_progress = curtime;
double pct_done = remain > 0 ? (1 - (remain / file_senders[i].size)) * 100 : 100;
print_progress_bar(self, i, -1, pct_done);
file_senders[i].bps = 0;
}
/* file sender is closed in chat_onFileControl callback after receiving reply */
if (file_senders[i].piecelen == 0 && !file_senders[i].finished) {
tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0);
file_senders[i].finished = true;
return;
}
}
}
@ -218,15 +273,18 @@ void do_file_senders(Tox *m)
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, "File transfer for '%s' timed out.", filename );
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, "File transfer for '%s' timed out.", filename );
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg);
continue;
}
if (!file_senders[i].noconnection && !file_senders[i].finished)
send_file_data(self, m, i, friendnum, filenum, filename);
file_senders[i].queue_pos = num_active_file_senders - 1;
send_file_data(self, m, i, friendnum, filenum, filename);
}
refresh_sender_prog(m);
refresh_recv_prog(m);
}

View File

@ -26,8 +26,12 @@
#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 255
#define MAX_FILES 32
#define TIMEOUT_FILESENDER 120
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
@ -36,6 +40,7 @@ typedef struct {
ToxWindow *toxwin;
int32_t friendnum;
bool active;
bool noconnection;
bool finished;
int filenum;
char nextpiece[FILE_PIECE_SIZE];
@ -61,6 +66,9 @@ void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_rema
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);

View File

@ -51,20 +51,17 @@ extern struct user_settings *user_settings_;
extern struct arg_opts arg_opts;
static uint8_t blocklist_view = 0; /* 0 if we're in friendlist view, 1 if we're in blocklist view */
static int num_selected = 0;
static int max_friends_index = 0; /* 1 + the index of the last friend in friends array */
static int num_friends = 0;
ToxicFriend friends[MAX_FRIENDS_NUM];
static int friendlist_index[MAX_FRIENDS_NUM] = {0};
_Friends Friends;
static struct _Blocked_Contacts {
static struct _Blocked {
int num_selected;
int max_index;
int max_idx;
int num_blocked;
BlockedFriend list[MAX_FRIENDS_NUM];
int index[MAX_FRIENDS_NUM];
} Blocked_Contacts;
int *index;
BlockedFriend *list;
} Blocked;
static struct _pendingDel {
int num;
@ -72,6 +69,52 @@ static struct _pendingDel {
WINDOW *popup;
} pendingdelete;
static void realloc_friends(int n)
{
if (n <= 0) {
free(Friends.list);
free(Friends.index);
Friends.list = NULL;
Friends.index = NULL;
return;
}
ToxicFriend *f = realloc(Friends.list, n * sizeof(ToxicFriend));
int *f_idx = realloc(Friends.index, n * sizeof(int));
if (f == NULL || f_idx == NULL)
exit_toxic_err("failed in realloc_friends", FATALERR_MEMORY);
Friends.list = f;
Friends.index = f_idx;
}
static void realloc_blocklist(int n)
{
if (n <= 0) {
free(Blocked.list);
free(Blocked.index);
Blocked.list = NULL;
Blocked.index = NULL;
return;
}
BlockedFriend *b = realloc(Blocked.list, n * sizeof(BlockedFriend));
int *b_idx = realloc(Blocked.index, n * sizeof(int));
if (b == NULL || b_idx == NULL)
exit_toxic_err("failed in realloc_blocklist", FATALERR_MEMORY);
Blocked.list = b;
Blocked.index = b_idx;
}
void kill_friendlist(void)
{
realloc_blocklist(0);
realloc_friends(0);
}
static int save_blocklist(char *path)
{
if (arg_opts.ignore_data_file)
@ -80,7 +123,7 @@ static int save_blocklist(char *path)
if (path == NULL)
return -1;
int len = sizeof(BlockedFriend) * Blocked_Contacts.num_blocked;
int len = sizeof(BlockedFriend) * Blocked.num_blocked;
char *data = malloc(len);
if (data == NULL)
@ -89,20 +132,20 @@ static int save_blocklist(char *path)
int i;
int count = 0;
for (i = 0; i < Blocked_Contacts.max_index; ++i) {
if (count > Blocked_Contacts.num_blocked)
for (i = 0; i < Blocked.max_idx; ++i) {
if (count > Blocked.num_blocked)
return -1;
if (Blocked_Contacts.list[i].active) {
if (Blocked.list[i].active) {
BlockedFriend tmp;
memset(&tmp, 0, sizeof(BlockedFriend));
tmp.namelength = htons(Blocked_Contacts.list[i].namelength);
memcpy(tmp.name, Blocked_Contacts.list[i].name, Blocked_Contacts.list[i].namelength + 1);
memcpy(tmp.pub_key, Blocked_Contacts.list[i].pub_key, TOX_CLIENT_ID_SIZE);
tmp.namelength = htons(Blocked.list[i].namelength);
memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1);
memcpy(tmp.pub_key, Blocked.list[i].pub_key, TOX_CLIENT_ID_SIZE);
uint8_t lastonline[sizeof(uint64_t)];
memcpy(lastonline, &Blocked_Contacts.list[i].last_on, sizeof(uint64_t));
host_to_net(lastonline, sizeof(uint64_t));
memcpy(lastonline, &Blocked.list[i].last_on, sizeof(uint64_t));
hst_to_net(lastonline, sizeof(uint64_t));
memcpy(&tmp.last_on, lastonline, sizeof(uint64_t));
memcpy(data + count * sizeof(BlockedFriend), &tmp, sizeof(BlockedFriend));
@ -163,27 +206,30 @@ int load_blocklist(char *path)
}
int num = len / sizeof(BlockedFriend);
Blocked.max_idx = num;
realloc_blocklist(num);
int i;
for (i = 0; i < num; ++i) {
memset(&Blocked.list[i], 0, sizeof(BlockedFriend));
BlockedFriend tmp;
memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend));
Blocked_Contacts.list[i].active = true;
Blocked_Contacts.list[i].num = i;
Blocked_Contacts.list[i].namelength = ntohs(tmp.namelength);
memcpy(Blocked_Contacts.list[i].name, tmp.name, Blocked_Contacts.list[i].namelength + 1);
memcpy(Blocked_Contacts.list[i].pub_key, tmp.pub_key, TOX_CLIENT_ID_SIZE);
Blocked.list[i].active = true;
Blocked.list[i].num = i;
Blocked.list[i].namelength = ntohs(tmp.namelength);
memcpy(Blocked.list[i].name, tmp.name, Blocked.list[i].namelength + 1);
memcpy(Blocked.list[i].pub_key, tmp.pub_key, TOX_CLIENT_ID_SIZE);
uint8_t lastonline[sizeof(uint64_t)];
memcpy(lastonline, &tmp.last_on, sizeof(uint64_t));
net_to_host(lastonline, sizeof(uint64_t));
memcpy(&Blocked_Contacts.list[i].last_on, lastonline, sizeof(uint64_t));
memcpy(&Blocked.list[i].last_on, lastonline, sizeof(uint64_t));
++Blocked_Contacts.num_blocked;
++Blocked.num_blocked;
}
Blocked_Contacts.max_index = i + 1;
free(data);
fclose(fp);
sort_blocklist_index();
@ -194,32 +240,32 @@ int load_blocklist(char *path)
#define S_WEIGHT 100000
static int index_name_cmp(const void *n1, const void *n2)
{
int res = qsort_strcasecmp_hlpr(friends[*(int *) n1].name, friends[*(int *) n2].name);
int res = qsort_strcasecmp_hlpr(Friends.list[*(int *) n1].name, Friends.list[*(int *) n2].name);
/* Use weight to make qsort always put online friends before offline */
res = friends[*(int *) n1].online ? (res - S_WEIGHT) : (res + S_WEIGHT);
res = friends[*(int *) n2].online ? (res + S_WEIGHT) : (res - S_WEIGHT);
res = Friends.list[*(int *) n1].online ? (res - S_WEIGHT) : (res + S_WEIGHT);
res = Friends.list[*(int *) n2].online ? (res + S_WEIGHT) : (res - S_WEIGHT);
return res;
}
/* sorts friendlist_index first by connection status then alphabetically */
/* sorts Friends.index first by connection status then alphabetically */
void sort_friendlist_index(void)
{
int i;
int n = 0;
for (i = 0; i < max_friends_index; ++i) {
if (friends[i].active)
friendlist_index[n++] = friends[i].num;
for (i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].active)
Friends.index[n++] = Friends.list[i].num;
}
qsort(friendlist_index, num_friends, sizeof(int), index_name_cmp);
qsort(Friends.index, Friends.num_friends, sizeof(int), index_name_cmp);
}
static int index_name_cmp_block(const void *n1, const void *n2)
{
return qsort_strcasecmp_hlpr(Blocked_Contacts.list[*(int *) n1].name, Blocked_Contacts.list[*(int *) n2].name);
return qsort_strcasecmp_hlpr(Blocked.list[*(int *) n1].name, Blocked.list[*(int *) n2].name);
}
static void sort_blocklist_index(void)
@ -227,33 +273,33 @@ static void sort_blocklist_index(void)
int i;
int n = 0;
for (i = 0; i < Blocked_Contacts.max_index; ++i) {
if (Blocked_Contacts.list[i].active)
Blocked_Contacts.index[n++] = Blocked_Contacts.list[i].num;
for (i = 0; i < Blocked.max_idx; ++i) {
if (Blocked.list[i].active)
Blocked.index[n++] = Blocked.list[i].num;
}
qsort(Blocked_Contacts.index, Blocked_Contacts.num_blocked, sizeof(int), index_name_cmp_block);
qsort(Blocked.index, Blocked.num_blocked, sizeof(int), index_name_cmp_block);
}
static void update_friend_last_online(int32_t num, uint64_t timestamp)
{
friends[num].last_online.last_on = timestamp;
friends[num].last_online.tm = *localtime((const time_t*)&timestamp);
Friends.list[num].last_online.last_on = timestamp;
Friends.list[num].last_online.tm = *localtime((const time_t*)&timestamp);
/* if the format changes make sure TIME_STR_SIZE is the correct size */
const char *t = user_settings_->time == TIME_12 ? "%I:%M %p" : "%H:%M";
strftime(friends[num].last_online.hour_min_str, TIME_STR_SIZE, t,
&friends[num].last_online.tm);
strftime(Friends.list[num].last_online.hour_min_str, TIME_STR_SIZE, t,
&Friends.list[num].last_online.tm);
}
static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *str, uint16_t len)
{
if (num >= max_friends_index)
if (num >= Friends.max_idx)
return;
if (friends[num].chatwin == -1) {
if (Friends.list[num].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
} else {
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
@ -272,10 +318,10 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, const cha
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
{
if (num >= max_friends_index)
if (num >= Friends.max_idx)
return;
friends[num].online = status;
Friends.list[num].online = status;
update_friend_last_online(num, get_unix_time());
store_data(m, DATA_FILE);
sort_friendlist_index();
@ -283,106 +329,110 @@ static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int32_t num,
static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *nick, uint16_t len)
{
if (len > TOX_MAX_NAME_LENGTH || num >= max_friends_index)
if (len > TOX_MAX_NAME_LENGTH || num >= Friends.max_idx)
return;
char tempname[TOX_MAX_NAME_LENGTH];
strcpy(tempname, nick);
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
tempname[len] = '\0';
snprintf(friends[num].name, sizeof(friends[num].name), "%s", tempname);
friends[num].namelength = len;
snprintf(Friends.list[num].name, sizeof(Friends.list[num].name), "%s", tempname);
Friends.list[num].namelength = len;
sort_friendlist_index();
}
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
{
if (num >= max_friends_index)
if (num >= Friends.max_idx)
return;
friends[num].status = status;
Friends.list[num].status = status;
}
static void friendlist_onStatusMessageChange(ToxWindow *self, int32_t num, const char *status, uint16_t len)
{
if (len > TOX_MAX_STATUSMESSAGE_LENGTH || num >= max_friends_index)
if (len > TOX_MAX_STATUSMESSAGE_LENGTH || num >= Friends.max_idx)
return;
snprintf(friends[num].statusmsg, sizeof(friends[num].statusmsg), "%s", status);
friends[num].statusmsg_len = strlen(friends[num].statusmsg);
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", status);
Friends.list[num].statusmsg_len = strlen(Friends.list[num].statusmsg);
}
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
{
if (max_friends_index < 0 || max_friends_index >= MAX_FRIENDS_NUM)
if (Friends.max_idx < 0)
return;
Friends.num_friends = tox_count_friendlist(m);
realloc_friends(Friends.max_idx + 1);
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
int i;
for (i = 0; i <= max_friends_index; ++i) {
if (!friends[i].active) {
friends[i].num = num;
friends[i].active = true;
friends[i].chatwin = -1;
friends[i].online = false;
friends[i].status = TOX_USERSTATUS_NONE;
friends[i].logging_on = (bool) user_settings_->autolog == AUTOLOG_ON;
tox_get_client_id(m, num, (uint8_t *) friends[i].pub_key);
update_friend_last_online(i, tox_get_last_online(m, i));
for (i = 0; i <= Friends.max_idx; ++i) {
if (Friends.list[i].active)
continue;
char tempname[TOX_MAX_NAME_LENGTH] = {0};
int len = get_nick_truncate(m, tempname, num);
Friends.list[i].num = num;
Friends.list[i].active = true;
Friends.list[i].chatwin = -1;
Friends.list[i].online = false;
Friends.list[i].status = TOX_USERSTATUS_NONE;
Friends.list[i].logging_on = (bool) user_settings_->autolog == AUTOLOG_ON;
tox_get_client_id(m, num, (uint8_t *) Friends.list[i].pub_key);
update_friend_last_online(i, tox_get_last_online(m, i));
if (len == -1 || tempname[0] == '\0') {
strcpy(friends[i].name, UNKNOWN_NAME);
friends[i].namelength = strlen(UNKNOWN_NAME);
} else { /* Enforce toxic's maximum name length */
friends[i].namelength = len;
snprintf(friends[i].name, sizeof(friends[i].name), "%s", tempname);
}
char tempname[TOX_MAX_NAME_LENGTH] = {0};
int len = get_nick_truncate(m, tempname, num);
num_friends = tox_count_friendlist(m);
if (i == max_friends_index)
++max_friends_index;
if (sort)
sort_friendlist_index();
return;
if (len == -1 || tempname[0] == '\0') {
strcpy(Friends.list[i].name, UNKNOWN_NAME);
Friends.list[i].namelength = strlen(UNKNOWN_NAME);
} else { /* Enforce toxic's maximum name length */
Friends.list[i].namelength = len;
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
}
if (i == Friends.max_idx)
++Friends.max_idx;
if (sort)
sort_friendlist_index();
return;
}
}
/* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */
static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum)
{
if (max_friends_index >= MAX_FRIENDS_NUM)
return;
Friends.num_friends = tox_count_friendlist(m);
realloc_friends(Friends.max_idx + 1);
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
int i;
for (i = 0; i <= max_friends_index; ++i) {
if (friends[i].active)
for (i = 0; i <= Friends.max_idx; ++i) {
if (Friends.list[i].active)
continue;
friends[i].num = fnum;
friends[i].active = true;
friends[i].chatwin = -1;
friends[i].status = TOX_USERSTATUS_NONE;
friends[i].logging_on = (bool) user_settings_->autolog == AUTOLOG_ON;
friends[i].namelength = Blocked_Contacts.list[bnum].namelength;
update_friend_last_online(i, Blocked_Contacts.list[bnum].last_on);
memcpy(friends[i].name, Blocked_Contacts.list[bnum].name, friends[i].namelength + 1);
memcpy(friends[i].pub_key, Blocked_Contacts.list[bnum].pub_key, TOX_CLIENT_ID_SIZE);
Friends.list[i].num = fnum;
Friends.list[i].active = true;
Friends.list[i].chatwin = -1;
Friends.list[i].status = TOX_USERSTATUS_NONE;
Friends.list[i].logging_on = (bool) user_settings_->autolog == AUTOLOG_ON;
Friends.list[i].namelength = Blocked.list[bnum].namelength;
update_friend_last_online(i, Blocked.list[bnum].last_on);
memcpy(Friends.list[i].name, Blocked.list[bnum].name, Friends.list[i].namelength + 1);
memcpy(Friends.list[i].pub_key, Blocked.list[bnum].pub_key, TOX_CLIENT_ID_SIZE);
num_friends = tox_count_friendlist(m);
if (i == max_friends_index)
++max_friends_index;
if (i == Friends.max_idx)
++Friends.max_idx;
sort_blocklist_index();
sort_friendlist_index();
return;
}
}
@ -390,12 +440,12 @@ static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum)
static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum,
uint64_t filesize, const char *filename, uint16_t filename_len)
{
if (num >= max_friends_index)
if (num >= Friends.max_idx)
return;
if (friends[num].chatwin == -1) {
if (Friends.list[num].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
} else {
tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
@ -412,20 +462,12 @@ static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, u
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const char *group_pub_key)
{
if (num >= max_friends_index)
if (num >= Friends.max_idx)
return;
if (friends[num].chatwin == -1) {
if (Friends.list[num].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
if (self->active_box != -1)
box_notify2(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
"You are invited to join group" );
else
box_notify(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS, &self->active_box, self->name,
"You are invited to join group" );
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
} else {
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
@ -452,31 +494,32 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
static void delete_friend(Tox *m, int32_t f_num)
{
if (friends[f_num].chatwin >= 0) {
ToxWindow *toxwin = get_window_ptr(friends[f_num].chatwin);
if (Friends.list[f_num].chatwin >= 0) {
ToxWindow *toxwin = get_window_ptr(Friends.list[f_num].chatwin);
if (toxwin != NULL) {
kill_chat_window(toxwin);
kill_chat_window(toxwin, m);
set_active_window(1); /* keep friendlist focused */
}
}
tox_del_friend(m, f_num);
memset(&friends[f_num], 0, sizeof(ToxicFriend));
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
int i;
for (i = max_friends_index; i > 0; --i) {
if (friends[i - 1].active)
for (i = Friends.max_idx; i > 0; --i) {
if (Friends.list[i - 1].active)
break;
}
max_friends_index = i;
num_friends = tox_count_friendlist(m);
Friends.max_idx = i;
Friends.num_friends = tox_count_friendlist(m);
realloc_friends(i);
/* make sure num_selected stays within num_friends range */
if (num_friends && num_selected == num_friends)
--num_selected;
/* make sure num_selected stays within Friends.num_friends range */
if (Friends.num_friends && Friends.num_selected == Friends.num_friends)
--Friends.num_selected;
store_data(m, DATA_FILE);
}
@ -524,9 +567,9 @@ static void draw_del_popup(void)
wattron(pendingdelete.popup, A_BOLD);
if (blocklist_view == 0)
wprintw(pendingdelete.popup, "%s", friends[pendingdelete.num].name);
wprintw(pendingdelete.popup, "%s", Friends.list[pendingdelete.num].name);
else
wprintw(pendingdelete.popup, "%s", Blocked_Contacts.list[pendingdelete.num].name);
wprintw(pendingdelete.popup, "%s", Blocked.list[pendingdelete.num].name);
wattroff(pendingdelete.popup, A_BOLD);
wprintw(pendingdelete.popup, "? y/n");
@ -537,46 +580,50 @@ static void draw_del_popup(void)
/* deletes contact from blocked list */
static void delete_blocked_friend(int32_t bnum)
{
memset(&Blocked_Contacts.list[bnum], 0, sizeof(BlockedFriend));
memset(&Blocked.list[bnum], 0, sizeof(BlockedFriend));
int i;
for (i = Blocked_Contacts.max_index; i > 0; --i) {
if (Blocked_Contacts.list[i - 1].active)
for (i = Blocked.max_idx; i > 0; --i) {
if (Blocked.list[i - 1].active)
break;
}
--Blocked_Contacts.num_blocked;
Blocked_Contacts.max_index = i;
--Blocked.num_blocked;
Blocked.max_idx = i;
realloc_blocklist(i);
save_blocklist(BLOCK_FILE);
if (Blocked_Contacts.num_blocked && Blocked_Contacts.num_selected == Blocked_Contacts.num_blocked)
--Blocked_Contacts.num_selected;
if (Blocked.num_blocked && Blocked.num_selected == Blocked.num_blocked)
--Blocked.num_selected;
}
/* deletes contact from friendlist and puts in blocklist */
void block_friend(Tox *m, int32_t fnum)
{
if (Blocked_Contacts.max_index >= MAX_FRIENDS_NUM || num_friends <= 0)
if (Friends.num_friends <= 0)
return;
realloc_blocklist(Blocked.max_idx + 1);
memset(&Blocked.list[Blocked.max_idx], 0, sizeof(BlockedFriend));
int i;
for (i = 0; i <= Blocked_Contacts.max_index; ++i) {
if (Blocked_Contacts.list[i].active)
for (i = 0; i <= Blocked.max_idx; ++i) {
if (Blocked.list[i].active)
continue;
Blocked_Contacts.list[i].active = true;
Blocked_Contacts.list[i].num = i;
Blocked_Contacts.list[i].namelength = friends[fnum].namelength;
Blocked_Contacts.list[i].last_on = friends[fnum].last_online.last_on;
memcpy(Blocked_Contacts.list[i].pub_key, friends[fnum].pub_key, TOX_CLIENT_ID_SIZE);
memcpy(Blocked_Contacts.list[i].name, friends[fnum].name, friends[fnum].namelength + 1);
Blocked.list[i].active = true;
Blocked.list[i].num = i;
Blocked.list[i].namelength = Friends.list[fnum].namelength;
Blocked.list[i].last_on = Friends.list[fnum].last_online.last_on;
memcpy(Blocked.list[i].pub_key, Friends.list[fnum].pub_key, TOX_CLIENT_ID_SIZE);
memcpy(Blocked.list[i].name, Friends.list[fnum].name, Friends.list[fnum].namelength + 1);
++Blocked_Contacts.num_blocked;
++Blocked.num_blocked;
if (i == Blocked_Contacts.max_index)
++Blocked_Contacts.max_index;
if (i == Blocked.max_idx)
++Blocked.max_idx;
delete_friend(m, fnum);
save_blocklist(BLOCK_FILE);
@ -590,10 +637,10 @@ void block_friend(Tox *m, int32_t fnum)
/* removes friend from blocklist, puts back in friendlist */
static void unblock_friend(Tox *m, int32_t bnum)
{
if (Blocked_Contacts.num_blocked <= 0)
if (Blocked.num_blocked <= 0)
return;
int32_t friendnum = tox_add_friend_norequest(m, (uint8_t *) Blocked_Contacts.list[bnum].pub_key);
int32_t friendnum = tox_add_friend_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key);
if (friendnum == -1) {
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend");
@ -619,14 +666,18 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
return;
}
if (!blocklist_view && !num_friends && (key != KEY_RIGHT && key != KEY_LEFT))
if (!blocklist_view && !Friends.num_friends && (key != KEY_RIGHT && key != KEY_LEFT))
return;
if (blocklist_view && !Blocked_Contacts.num_blocked && (key != KEY_RIGHT && key != KEY_LEFT))
if (blocklist_view && !Blocked.num_blocked && (key != KEY_RIGHT && key != KEY_LEFT))
return;
int f = blocklist_view == 1 ? Blocked_Contacts.index[Blocked_Contacts.num_selected]
: friendlist_index[num_selected];
int f = 0;
if (blocklist_view == 1 && Blocked.num_blocked)
f = Blocked.index[Blocked.num_selected];
else if (Friends.num_friends)
f = Friends.index[Friends.num_selected];
/* lock screen and force decision on deletion popup */
if (pendingdelete.active) {
@ -645,11 +696,11 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
break;
/* Jump to chat window if already open */
if (friends[f].chatwin != -1) {
set_active_window(friends[f].chatwin);
if (Friends.list[f].chatwin != -1) {
set_active_window(Friends.list[f].chatwin);
} else if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[f].chatwin = add_window(m, new_chat(m, friends[f].num));
set_active_window(friends[f].chatwin);
Friends.list[f].chatwin = add_window(m, new_chat(m, Friends.list[f].num));
set_active_window(Friends.list[f].chatwin);
} else {
const char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
@ -676,9 +727,9 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
default:
if (blocklist_view == 0)
select_friend(self, key, &num_selected, num_friends);
select_friend(self, key, &Friends.num_selected, Friends.num_friends);
else
select_friend(self, key, &Blocked_Contacts.num_selected, Blocked_Contacts.num_blocked);
select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked);
break;
}
}
@ -690,7 +741,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
wattron(self->window, A_BOLD);
wprintw(self->window, " Blocked: ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "%d\n\n", Blocked_Contacts.num_blocked);
wprintw(self->window, "%d\n\n", Blocked.num_blocked);
if ((y2 - FLIST_OFST) <= 0)
return;
@ -698,17 +749,17 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
int selected_num = 0;
/* Determine which portion of friendlist to draw based on current position */
int page = Blocked_Contacts.num_selected / (y2 - FLIST_OFST);
int page = Blocked.num_selected / (y2 - FLIST_OFST);
int start = (y2 - FLIST_OFST) * page;
int end = y2 - FLIST_OFST + start;
int i;
for (i = start; i < Blocked_Contacts.num_blocked && i < end; ++i) {
int f = Blocked_Contacts.index[i];
for (i = start; i < Blocked.num_blocked && i < end; ++i) {
int f = Blocked.index[i];
bool f_selected = false;
if (i == Blocked_Contacts.num_selected) {
if (i == Blocked.num_selected) {
wattron(self->window, A_BOLD);
wprintw(self->window, " > ");
wattroff(self->window, A_BOLD);
@ -726,7 +777,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
wattron(self->window, COLOR_PAIR(BLUE));
wattron(self->window, A_BOLD);
wprintw(self->window, " %s\n", Blocked_Contacts.list[f].name);
wprintw(self->window, " %s\n", Blocked.list[f].name);
wattroff(self->window, A_BOLD);
if (f_selected)
@ -736,17 +787,17 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
wprintw(self->window, "\n");
self->x = x2;
if (Blocked_Contacts.num_blocked) {
if (Blocked.num_blocked) {
wmove(self->window, y2 - 1, 1);
wattron(self->window, A_BOLD);
wprintw(self->window, "ID: ");
wprintw(self->window, "Key: ");
wattroff(self->window, A_BOLD);
int i;
for (i = 0; i < TOX_CLIENT_ID_SIZE; ++i)
wprintw(self->window, "%02X", Blocked_Contacts.list[selected_num].pub_key[i] & 0xff);
wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff);
}
wrefresh(self->window);
@ -768,7 +819,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wattron(self->window, COLOR_PAIR(CYAN));
wprintw(self->window, " Press the");
wattron(self->window, A_BOLD);
wprintw(self->window, " H ");
wprintw(self->window, " h ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "key for help\n\n");
wattroff(self->window, COLOR_PAIR(CYAN));
@ -788,7 +839,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wattron(self->window, A_BOLD);
wprintw(self->window, " Online: ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "%d/%d \n\n", nf, num_friends);
wprintw(self->window, "%d/%d \n\n", nf, Friends.num_friends);
if ((y2 - FLIST_OFST) <= 0)
return;
@ -796,18 +847,18 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
int selected_num = 0;
/* Determine which portion of friendlist to draw based on current position */
int page = num_selected / (y2 - FLIST_OFST);
int page = Friends.num_selected / (y2 - FLIST_OFST);
int start = (y2 - FLIST_OFST) * page;
int end = y2 - FLIST_OFST + start;
int i;
for (i = start; i < num_friends && i < end; ++i) {
int f = friendlist_index[i];
for (i = start; i < Friends.num_friends && i < end; ++i) {
int f = Friends.index[i];
bool f_selected = false;
if (friends[f].active) {
if (i == num_selected) {
if (Friends.list[f].active) {
if (i == Friends.num_selected) {
wattron(self->window, A_BOLD);
wprintw(self->window, " > ");
wattroff(self->window, A_BOLD);
@ -817,8 +868,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wprintw(self->window, " ");
}
if (friends[f].online) {
uint8_t status = friends[f].status;
if (Friends.list[f].online) {
uint8_t status = Friends.list[f].status;
int colour = WHITE;
switch (status) {
@ -847,36 +898,36 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wattron(self->window, COLOR_PAIR(BLUE));
wattron(self->window, A_BOLD);
wprintw(self->window, "%s", friends[f].name);
wprintw(self->window, "%s", Friends.list[f].name);
wattroff(self->window, A_BOLD);
if (f_selected)
wattroff(self->window, COLOR_PAIR(BLUE));
/* Reset friends[f].statusmsg on window resize */
/* Reset Friends.list[f].statusmsg on window resize */
if (fix_statuses) {
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
pthread_mutex_lock(&Winthread.lock);
tox_get_status_message(m, friends[f].num, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
tox_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
pthread_mutex_unlock(&Winthread.lock);
snprintf(friends[f].statusmsg, sizeof(friends[f].statusmsg), "%s", statusmsg);
friends[f].statusmsg_len = strlen(friends[f].statusmsg);
snprintf(Friends.list[f].statusmsg, sizeof(Friends.list[f].statusmsg), "%s", statusmsg);
Friends.list[f].statusmsg_len = strlen(Friends.list[f].statusmsg);
}
/* Truncate note if it doesn't fit on one line */
uint16_t maxlen = x2 - getcurx(self->window) - 2;
if (friends[f].statusmsg_len > maxlen) {
friends[f].statusmsg[maxlen - 3] = '\0';
strcat(friends[f].statusmsg, "...");
friends[f].statusmsg[maxlen] = '\0';
friends[f].statusmsg_len = maxlen;
if (Friends.list[f].statusmsg_len > maxlen) {
Friends.list[f].statusmsg[maxlen - 3] = '\0';
strcat(Friends.list[f].statusmsg, "...");
Friends.list[f].statusmsg[maxlen] = '\0';
Friends.list[f].statusmsg_len = maxlen;
}
if (friends[f].statusmsg[0])
wprintw(self->window, " %s", friends[f].statusmsg);
if (Friends.list[f].statusmsg[0])
wprintw(self->window, " %s", Friends.list[f].statusmsg);
wprintw(self->window, "\n");
} else {
@ -886,17 +937,17 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wattron(self->window, COLOR_PAIR(BLUE));
wattron(self->window, A_BOLD);
wprintw(self->window, "%s", friends[f].name);
wprintw(self->window, "%s", Friends.list[f].name);
wattroff(self->window, A_BOLD);
if (f_selected)
wattroff(self->window, COLOR_PAIR(BLUE));
uint64_t last_seen = friends[f].last_online.last_on;
uint64_t last_seen = Friends.list[f].last_online.last_on;
if (last_seen != 0) {
int day_dist = (cur_loc_tm.tm_yday - friends[f].last_online.tm.tm_yday) % 365;
const char *hourmin = friends[f].last_online.hour_min_str;
int day_dist = (cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday) % 365;
const char *hourmin = Friends.list[f].last_online.hour_min_str;
switch (day_dist) {
case 0:
@ -920,17 +971,17 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
self->x = x2;
if (num_friends) {
if (Friends.num_friends) {
wmove(self->window, y2 - 1, 1);
wattron(self->window, A_BOLD);
wprintw(self->window, "ID: ");
wprintw(self->window, "Key: ");
wattroff(self->window, A_BOLD);
int i;
for (i = 0; i < TOX_CLIENT_ID_SIZE; ++i)
wprintw(self->window, "%02X", friends[selected_num].pub_key[i] & 0xff);
wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
}
wrefresh(self->window);
@ -942,7 +993,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
void disable_chatwin(int32_t f_num)
{
friends[f_num].chatwin = -1;
Friends.list[f_num].chatwin = -1;
}
#ifdef _AUDIO
@ -951,19 +1002,19 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
int id = toxav_get_peer_id(av, call_index, 0);
/*id++;*/
if ( id != ErrorInternal && id >= max_friends_index)
if ( id != ErrorInternal && id >= Friends.max_idx)
return;
Tox *m = toxav_get_tox(av);
if (friends[id].chatwin == -1) {
if (Friends.list[id].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
if (toxav_get_call_state(av, call_index) == av_CallStarting) { /* Only open windows when call is incoming */
friends[id].chatwin = add_window(m, new_chat(m, friends[id].num));
Friends.list[id].chatwin = add_window(m, new_chat(m, Friends.list[id].num));
}
} else {
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, friends[id].num);
get_nick_truncate(m, nick, Friends.list[id].num);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio action from: %s!", nick);
const char *errmsg = "* Warning: Too many windows are open.";

View File

@ -30,15 +30,16 @@
#include "file_senders.h"
struct FileReceiver {
char filenames[MAX_FILES][MAX_STR_SIZE];
FILE *files[MAX_FILES];
bool pending[MAX_FILES];
bool active[MAX_FILES];
uint64_t size[MAX_FILES];
double bps[MAX_FILES];
uint64_t last_progress[MAX_FILES];
uint32_t line_id[MAX_FILES];
int filenums[MAX_FILES];
char filename[MAX_STR_SIZE];
int filenum;
FILE *file;
bool pending;
bool active;
uint64_t size;
uint64_t bytes_recv;
double bps;
uint64_t last_progress; /* unix-time when we last updated progress */
uint32_t line_id;
};
struct LastOnline {
@ -60,10 +61,11 @@ typedef struct {
bool active;
bool online;
uint8_t is_typing;
bool logging_on; /* saves preference for friend irrespective of chat windows */
bool logging_on; /* saves preference for friend irrespective of global settings */
uint8_t status;
struct LastOnline last_online;
struct FileReceiver file_receiver;
struct FileReceiver file_receiver[MAX_FILES];
uint8_t active_file_receivers;
} ToxicFriend;
typedef struct {
@ -75,11 +77,19 @@ typedef struct {
uint64_t last_on;
} BlockedFriend;
typedef struct {
int num_selected;
int max_idx; /* 1 + the index of the last friend in list */
int num_friends;
int *index;
ToxicFriend *list;
} _Friends;
ToxWindow new_friendlist(void);
void disable_chatwin(int32_t f_num);
int get_friendnum(uint8_t *name);
int load_blocklist(char *data);
void kill_friendlist(void);
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort);
/* sorts friendlist_index first by connection status then alphabetically */

View File

@ -37,11 +37,8 @@
extern char *DATA_FILE;
extern ToxWindow *prompt;
extern ToxicFriend friends[MAX_FRIENDS_NUM];
extern char pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
extern uint8_t num_frnd_requests;
extern _Friends Friends;
extern _FriendRequests FriendRequests;
/* command functions */
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -53,18 +50,18 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
int req = atoi(argv[1]);
if ((req == 0 && strcmp(argv[1], "0")) || req >= MAX_FRIENDS_NUM) {
if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req > MAX_FRIEND_REQUESTS) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
return;
}
if (!strlen(pending_frnd_requests[req])) {
if (!FriendRequests.request[req].active) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
return;
}
const char *msg;
int32_t friendnum = tox_add_friend_norequest(m, (uint8_t *) pending_frnd_requests[req]);
int32_t friendnum = tox_add_friend_norequest(m, FriendRequests.request[req].key);
if (friendnum == -1)
msg = "Failed to add friend.";
@ -73,16 +70,17 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
on_friendadded(m, friendnum, true);
}
memset(&pending_frnd_requests[req], 0, TOX_CLIENT_ID_SIZE);
memset(&FriendRequests.request[req], 0, sizeof(struct _friend_request));
int i;
for (i = num_frnd_requests; i > 0; --i) {
if (!strlen(pending_frnd_requests[i - 1]))
for (i = FriendRequests.max_idx; i > 0; --i) {
if (FriendRequests.request[i - 1].active)
break;
}
num_frnd_requests = i;
FriendRequests.max_idx = i;
--FriendRequests.num_requests;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
}
@ -211,10 +209,42 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
}
char *binary_string = hex_string_to_bin(key);
tox_bootstrap_from_address(m, ip, TOX_ENABLE_IPV6_DEFAULT, htons(atoi(port)), (uint8_t *) binary_string);
tox_bootstrap_from_address(m, ip, atoi(port), (uint8_t *) binary_string);
free(binary_string);
}
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
return;
}
int req = atoi(argv[1]);
if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req > MAX_FRIEND_REQUESTS) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
return;
}
if (!FriendRequests.request[req].active) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
return;
}
memset(&FriendRequests.request[req], 0, sizeof(struct _friend_request));
int i;
for (i = FriendRequests.max_idx; i > 0; --i) {
if (FriendRequests.request[i - 1].active)
break;
}
FriendRequests.max_idx = i;
--FriendRequests.num_requests;
}
void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
@ -258,8 +288,8 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
if (self->is_chat) {
friends[self->num].logging_on = true;
log_enable(self->name, friends[self->num].pub_key, log);
Friends.list[self->num].logging_on = true;
log_enable(self->name, Friends.list[self->num].pub_key, log);
} else if (self->is_prompt) {
char myid[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(m, (uint8_t *) myid);
@ -273,7 +303,7 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
return;
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
if (self->is_chat)
friends[self->num].logging_on = false;
Friends.list[self->num].logging_on = false;
log_disable(log);
@ -354,8 +384,7 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
int len = strlen(msg) - 1;
msg[len] = '\0';
tox_set_status_message(m, (uint8_t *) msg, (uint16_t) len);
prompt_update_statusmessage(prompt, msg);
prompt_update_statusmessage(prompt, m, msg);
}
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -368,6 +397,36 @@ void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
exit_toxic_success(m);
}
void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (FriendRequests.num_requests == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
return;
}
int i, j;
int count = 0;
for (i = 0; i < FriendRequests.max_idx; ++i) {
if (!FriendRequests.request[i].active)
continue;
char id[TOX_CLIENT_ID_SIZE * 2 + 1] = {0};
for (j = 0; j < TOX_CLIENT_ID_SIZE; ++j) {
char d[3];
snprintf(d, sizeof(d), "%02X", FriendRequests.request[i].key[j] & 0xff);
strcat(id, d);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d : %s", i, id);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", FriendRequests.request[i].msg);
if (++count < FriendRequests.num_requests)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
}
}
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
bool have_note = false;
@ -414,7 +473,6 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
int len = strlen(msg) - 1;
msg[len] = '\0';
tox_set_status_message(m, (uint8_t *) msg, (uint16_t) len);
prompt_update_statusmessage(prompt, msg);
prompt_update_statusmessage(prompt, m, msg);
}
}

View File

@ -30,6 +30,7 @@ void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@ -37,6 +38,7 @@ void cmd_nick(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]
void cmd_note(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_prompt_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_requests(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg);

View File

@ -77,26 +77,26 @@ static void help_draw_menu(ToxWindow *self)
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " G");
wprintw(win, " g");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "lobal commands\n");
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " C");
wprintw(win, " c");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "hat commands\n");
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " F");
wprintw(win, " f");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "riendlist controls\n");
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " K");
wprintw(win, " k");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "ey bindings\n");
wprintw(win, " E");
wprintw(win, " e");
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "x");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
@ -115,11 +115,11 @@ static void help_draw_bottom_menu(WINDOW *win)
wmove(win, y2 - 2, 1);
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " M");
wprintw(win, " m");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "ain menu |");
wprintw(win, " E");
wprintw(win, " e");
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "x");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
@ -138,6 +138,8 @@ 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, " /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");
wprintw(win, " /status <type> <msg> : Set status with optional note\n");
wprintw(win, " /note <msg> : Set a personal note\n");
@ -264,9 +266,9 @@ void help_onKey(ToxWindow *self, wint_t key)
case 'g':
#ifdef _AUDIO
help_init_window(self, 21, 80);
help_init_window(self, 23, 80);
#else
help_init_window(self, 17, 80);
help_init_window(self, 19, 80);
#endif
self->help->type = HELP_GLOBAL;
break;

View File

@ -42,15 +42,17 @@ void init_logging_session(char *name, const char *key, struct chatlog *log)
if (!valid_nick(name))
name = UNKNOWN_NAME;
const char *set_path = user_settings_->chatlogs_path;
char *user_config_dir = get_user_config_dir();
int path_len = strlen(user_config_dir) + strlen(LOGDIR) + strlen(name);
int path_len = strlen(set_path) + strlen(name) ? *set_path
: strlen(user_config_dir) + strlen(LOGDIR) + strlen(name);
/* use first 4 digits of key as log ident. If no key use a timestamp */
char ident[32];
if (key != NULL) {
path_len += (KEY_IDENT_DIGITS * 2 + 5);
sprintf(&ident[0], "%02X", key[0] & 0xff);
sprintf(&ident[2], "%02X", key[1] & 0xff);
ident[KEY_IDENT_DIGITS * 2 + 1] = '\0';
@ -66,7 +68,11 @@ void init_logging_session(char *name, const char *key, struct chatlog *log)
}
char log_path[MAX_STR_SIZE];
snprintf(log_path, MAX_STR_SIZE, "%s%s%s-%s.log", user_config_dir, LOGDIR, name, ident);
if (*set_path)
snprintf(log_path, sizeof(log_path), "%s%s-%s.log", set_path, name, ident);
else
snprintf(log_path, sizeof(log_path), "%s%s%s-%s.log", user_config_dir, LOGDIR, name, ident);
free(user_config_dir);

View File

@ -26,18 +26,20 @@
#include <time.h>
#include <limits.h>
#include <dirent.h>
#include <sys/stat.h>
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "settings.h"
#include "file_senders.h"
extern ToxWindow *prompt;
extern struct user_settings *user_settings_;
static uint64_t current_unix_time;
void host_to_net(uint8_t *num, uint16_t numbytes)
void hst_to_net(uint8_t *num, uint16_t numbytes)
{
#ifndef WORDS_BIGENDIAN
uint32_t i;
@ -123,6 +125,25 @@ char *hex_string_to_bin(const char *hex_string)
return val;
}
int hex_string_to_bytes(char *buf, int size, const char *keystr)
{
if (size % 2 != 0)
return -1;
int i, res;
const char *pos = keystr;
for (i = 0; i < size; ++i) {
res = sscanf(pos, "%2hhx", &buf[i]);
pos += 2;
if (res == EOF || res < 1)
return -1;
}
return 0;
}
/* Returns 1 if the string is empty, 0 otherwise */
int string_is_empty(const char *string)
{
@ -261,3 +282,32 @@ int char_rfind(const char *s, char ch, int len)
return i;
}
/* Converts bytes to appropriate unit and puts in buf as a string */
void bytes_convert_str(char *buf, int size, uint64_t bytes)
{
double conv = bytes;
const char *unit;
if (conv < KiB) {
unit = "Bytes";
} else if (conv < MiB) {
unit = "KiB";
conv /= (double) KiB;
} else if (conv < GiB) {
unit = "MiB";
conv /= (double) MiB;
} else {
unit = "GiB";
conv /= (double) GiB;
}
snprintf(buf, size, "%.1f %s", conv, unit);
}
/* checks if a file exists. Returns true or false */
bool file_exists(const char *fp)
{
struct stat s;
return stat(fp, &s) == 0;
}

View File

@ -34,18 +34,21 @@
#endif
#ifndef net_to_host
#define net_to_host(x, y) host_to_net(x, y)
#define net_to_host(x, y) hst_to_net(x, y)
#endif
void host_to_net(uint8_t *num, uint16_t numbytes);
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);
/* 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 */
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] */
void get_time_str(char *buf, int bufsize);
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
@ -103,4 +106,10 @@ int char_find(int idx, const char *s, char ch);
returns 0 if char not found */
int char_rfind(const char *s, char ch, int len);
/* Converts bytes to appropriate unit and puts in buf as a string */
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 *fp);
#endif /* #define _misc_tools_h */

View File

@ -443,10 +443,10 @@ void m_notify_action(NotifyNotification *box, char *action, void* data)
int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator)
{
/* Consider colored notify as primary */
if (self && self->alert == WINDOW_ALERT_NONE) {
if (self) {
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
else if (flags & NT_WNDALERT_1) self->alert = WINDOW_ALERT_1;
else if (flags & NT_WNDALERT_2) self->alert = WINDOW_ALERT_2;
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) self->alert = WINDOW_ALERT_2;
}
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
@ -487,10 +487,10 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
{
/* Consider colored notify as primary */
if (self && self->alert == WINDOW_ALERT_NONE) {
if (self) {
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
else if (flags & NT_WNDALERT_1) self->alert = WINDOW_ALERT_1;
else if (flags & NT_WNDALERT_2) self->alert = WINDOW_ALERT_2;
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) self->alert = WINDOW_ALERT_2;
}
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
@ -636,10 +636,10 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...)
{
/* Always do colored notify */
if (self && self->alert == WINDOW_ALERT_NONE) {
if (self) {
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
else if (flags & NT_WNDALERT_1) self->alert = WINDOW_ALERT_1;
else if (flags & NT_WNDALERT_2) self->alert = WINDOW_ALERT_2;
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) self->alert = WINDOW_ALERT_2;
}
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
@ -692,10 +692,10 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...)
{
/* Always do colored notify */
if (self && self->alert == WINDOW_ALERT_NONE) {
if (self) {
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
else if (flags & NT_WNDALERT_1) self->alert = WINDOW_ALERT_1;
else if (flags & NT_WNDALERT_2) self->alert = WINDOW_ALERT_2;
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) self->alert = WINDOW_ALERT_2;
}
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||

View File

@ -42,12 +42,11 @@
#include "notify.h"
#include "autocomplete.h"
char pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
uint16_t num_frnd_requests = 0;
extern ToxWindow *prompt;
struct _Winthread Winthread;
extern struct user_settings *user_settings_;
extern struct _Winthread Winthread;
_FriendRequests FriendRequests;
/* Array of global command names used for tab completion. */
const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
@ -56,6 +55,7 @@ const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/clear" },
{ "/close" }, /* rm /close when groupchats gets its own list */
{ "/connect" },
{ "/decline" },
{ "/exit" },
{ "/groupchat" },
{ "/help" },
@ -64,6 +64,7 @@ const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/nick" },
{ "/note" },
{ "/quit" },
{ "/requests" },
{ "/status" },
#ifdef _AUDIO
@ -103,12 +104,14 @@ void prompt_update_nick(ToxWindow *prompt, const char *nick)
statusbar->nick_len = strlen(statusbar->nick);
}
/* Updates own statusmessage in prompt statusbar */
void prompt_update_statusmessage(ToxWindow *prompt, const char *statusmsg)
/* Updates own statusmessage */
void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg)
{
StatusBar *statusbar = prompt->stb;
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
int len = strlen(statusbar->statusmsg);
statusbar->statusmsg_len = len;
tox_set_status_message(m, (uint8_t *) statusmsg, (uint64_t) len);
}
/* Updates own status in prompt statusbar */
@ -126,20 +129,24 @@ void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected)
}
/* Adds friend request to pending friend requests.
Returns request number on success, -1 if queue is full or other error. */
static int add_friend_request(const char *public_key)
Returns request number on success, -1 if queue is full. */
static int add_friend_request(const char *public_key, const char *data)
{
if (num_frnd_requests >= MAX_FRIENDS_NUM)
if (FriendRequests.max_idx >= MAX_FRIEND_REQUESTS)
return -1;
int i;
for (i = 0; i <= num_frnd_requests; ++i) {
if (!strlen(pending_frnd_requests[i])) {
memcpy(pending_frnd_requests[i], public_key, TOX_CLIENT_ID_SIZE);
for (i = 0; i <= FriendRequests.max_idx; ++i) {
if (!FriendRequests.request[i].active) {
FriendRequests.request[i].active = true;
memcpy(FriendRequests.request[i].key, public_key, TOX_CLIENT_ID_SIZE);
snprintf(FriendRequests.request[i].msg, sizeof(FriendRequests.request[i].msg), "%s", data);
if (i == num_frnd_requests)
++num_frnd_requests;
if (i == FriendRequests.max_idx)
++FriendRequests.max_idx;
++FriendRequests.num_requests;
return i;
}
@ -269,6 +276,29 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
wattroff(statusbar->topline, A_BOLD);
}
/* Reset statusbar->statusmsg on window resize */
if (x2 != self->x) {
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {0};
pthread_mutex_lock(&Winthread.lock);
tox_get_self_status_message(m, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
pthread_mutex_unlock(&Winthread.lock);
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
}
self->x = x2;
/* Truncate note if it doesn't fit in statusbar */
uint16_t maxlen = x2 - getcurx(statusbar->topline) - 3;
if (statusbar->statusmsg_len > maxlen) {
statusbar->statusmsg[maxlen - 3] = '\0';
strcat(statusbar->statusmsg, "...");
statusbar->statusmsg_len = maxlen;
}
if (statusbar->statusmsg[0])
wprintw(statusbar->topline, " - %s", statusbar->statusmsg);
@ -340,16 +370,15 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 0, 0, "Friend request with the message '%s'", data);
write_to_log("Friend request with the message '%s'", "", ctx->log, true);
int n = add_friend_request(key);
int n = add_friend_request(key, data);
if (n == -1) {
const char *errmsg = "Friend request queue is full. Discarding request.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
write_to_log(errmsg, "", ctx->log, true);
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/accept %d\" to accept it.", n);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/accept %d\" or \"/decline %d\"", n, n);
sound_notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND, NULL);
}
@ -379,13 +408,13 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
strcpy(ver, TOXICVER);
const char *toxic_ver = strtok(ver, "_");
if ( (!statusmsg[0] || !strncmp("Toxing on Toxic", statusmsg, 15)) && toxic_ver != NULL) {
snprintf(statusmsg, MAX_STR_SIZE, "Toxing on Toxic v.%s", toxic_ver);
if ( (s_len <= 0 || !strncmp("Toxing on Toxic", statusmsg, strlen("Toxing on Toxic"))) && toxic_ver != NULL) {
snprintf(statusmsg, sizeof(statusmsg), "Toxing on Toxic v.%s", toxic_ver);
s_len = strlen(statusmsg);
statusmsg[s_len] = '\0';
}
prompt_update_statusmessage(prompt, statusmsg);
prompt_update_statusmessage(prompt, m, statusmsg);
prompt_update_status(prompt, status);
prompt_update_nick(prompt, nick);

View File

@ -27,16 +27,30 @@
#include "windows.h"
#ifdef _AUDIO
#define AC_NUM_GLOB_COMMANDS 16
#define AC_NUM_GLOB_COMMANDS 18
#else
#define AC_NUM_GLOB_COMMANDS 14
#define AC_NUM_GLOB_COMMANDS 16
#endif /* _AUDIO */
#define MAX_FRIEND_REQUESTS 32
struct _friend_request {
bool active;
char msg[MAX_STR_SIZE];
uint8_t key[TOX_CLIENT_ID_SIZE];
};
typedef struct {
int max_idx;
int num_requests;
struct _friend_request request[MAX_FRIEND_REQUESTS];
} _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);
void prompt_update_statusmessage(ToxWindow *prompt, const char *statusmsg);
void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg);
void prompt_update_status(ToxWindow *prompt, uint8_t status);
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
void kill_prompt_window(ToxWindow *self);

View File

@ -29,6 +29,7 @@
#include "windows.h"
#include "configdir.h"
#include "notify.h"
#include "misc_tools.h"
#ifdef _AUDIO
#include "device.h"
@ -41,7 +42,9 @@
#define PACKAGE_DATADIR "."
#endif
const struct _ui_strings {
#define NO_SOUND "silent"
static struct _ui_strings {
const char* self;
const char* timestamps;
const char* alerts;
@ -75,7 +78,7 @@ static void ui_defaults(struct user_settings* settings)
settings->show_typing_other = SHOW_TYPING_ON;
}
const struct _keys_strings {
static const struct _keys_strings {
const char* self;
const char* next_tab;
const char* prev_tab;
@ -113,21 +116,24 @@ static void key_defaults(struct user_settings* settings)
settings->key_peer_list_down = T_KEY_C_RB;
}
const struct _tox_strings {
static const struct _tox_strings {
const char* self;
const char* download_path;
const char* chatlogs_path;
} tox_strings = {
"tox",
"download_path",
"chatlogs_path",
};
static void tox_defaults(struct user_settings* settings)
{
strcpy(settings->download_path, ""); /* explicitly set default to pwd */
strcpy(settings->download_path, "");
strcpy(settings->chatlogs_path, "");
}
#ifdef _AUDIO
const struct _audio_strings {
static const struct _audio_strings {
const char* self;
const char* input_device;
const char* output_device;
@ -148,7 +154,7 @@ static void audio_defaults(struct user_settings* settings)
#endif
#ifdef _SOUND_NOTIFY
const struct _sound_strings {
static const struct _sound_strings {
const char* self;
const char* error;
const char* self_log_in;
@ -196,12 +202,13 @@ int settings_load(struct user_settings *s, const char *patharg)
{
config_t cfg[1];
config_setting_t *setting;
const char *str;
const char *str = NULL;
/* Load default settings */
ui_defaults(s);
tox_defaults(s);
key_defaults(s);
#ifdef _AUDIO
audio_defaults(s);
#endif
@ -217,13 +224,14 @@ int settings_load(struct user_settings *s, const char *patharg)
free(user_config_dir);
/* make sure path exists or is created on first time running */
FILE *fp = fopen(path, "r");
if (fp == NULL) {
if ((fp = fopen(path, "w")) == NULL)
return -1;
}
if (!file_exists(path)) {
FILE *fp = fopen(path, "w");
fclose(fp);
if (fp == NULL)
return -1;
fclose(fp);
}
} else {
snprintf(path, sizeof(path), "%s", patharg);
}
@ -246,24 +254,42 @@ int settings_load(struct user_settings *s, const char *patharg)
s->time = s->time == TIME_24 || s->time == TIME_12 ? s->time : TIME_24; /* Check defaults */
}
/* paths */
if ((setting = config_lookup(cfg, tox_strings.self)) != NULL) {
if ( config_setting_lookup_string(setting, tox_strings.download_path, &str) ) {
strcpy(s->download_path, str);
snprintf(s->download_path, sizeof(s->download_path), "%s", str);
int len = strlen(s->download_path);
/* make sure path ends with a '/' */
if (len >= sizeof(s->download_path) - 2)
s->download_path[0] = '\0';
else if (s->download_path[len - 1] != '/')
strcat(&s->download_path[len - 1], "/");
}
if ( config_setting_lookup_string(setting, tox_strings.chatlogs_path, &str) ) {
snprintf(s->chatlogs_path, sizeof(s->chatlogs_path), "%s", str);
int len = strlen(s->chatlogs_path);
if (len >= sizeof(s->chatlogs_path) - 2)
s->chatlogs_path[0] = '\0';
else if (s->chatlogs_path[len - 1] != '/')
strcat(&s->chatlogs_path[len - 1], "/");
}
}
/* keys */
if((setting = config_lookup(cfg, key_strings.self)) != NULL) {
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
const char* tmp = NULL;
if(config_setting_lookup_string(setting, key_strings.next_tab, &tmp)) s->key_next_tab = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.prev_tab, &tmp)) s->key_prev_tab = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp)) s->key_scroll_line_up = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp)) s->key_scroll_line_down= key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.half_page_up, &tmp)) s->key_half_page_up = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.half_page_down, &tmp)) s->key_half_page_down = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.page_bottom, &tmp)) s->key_page_bottom = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp)) s->key_peer_list_up = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp)) s->key_peer_list_down = key_parse(&tmp);
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp)) s->key_next_tab = key_parse(&tmp);
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp)) s->key_prev_tab = key_parse(&tmp);
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp)) s->key_scroll_line_up = key_parse(&tmp);
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp)) s->key_scroll_line_down= key_parse(&tmp);
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp)) s->key_half_page_up = key_parse(&tmp);
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp)) s->key_half_page_down = key_parse(&tmp);
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp)) s->key_page_bottom = key_parse(&tmp);
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp)) s->key_peer_list_up = key_parse(&tmp);
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp)) s->key_peer_list_down = key_parse(&tmp);
}
#ifdef _AUDIO
@ -282,61 +308,61 @@ int settings_load(struct user_settings *s, const char *patharg)
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
if ( (config_setting_lookup_string(setting, sound_strings.error, &str) != CONFIG_TRUE) ||
!set_sound(error, str) ) {
if (strcasecmp(str, NO_SOUND) != 0)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(error, PACKAGE_DATADIR "/sounds/Error.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
!set_sound(user_log_in, str) ) {
if (strcasecmp(str, NO_SOUND) != 0)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ContactLogsIn.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.self_log_in, &str) ||
!set_sound(self_log_in, str) ) {
if (strcasecmp(str, NO_SOUND) != 0)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(self_log_in, PACKAGE_DATADIR "/sounds/LogIn.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
!set_sound(user_log_out, str) ) {
if (strcasecmp(str, NO_SOUND) != 0)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ContactLogsOut.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.self_log_out, &str) ||
!set_sound(self_log_out, str) ) {
if (strcasecmp(str, NO_SOUND) != 0)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(self_log_out, PACKAGE_DATADIR "/sounds/LogOut.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
!set_sound(call_incoming, str) ) {
if (strcasecmp(str, NO_SOUND) != 0)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/IncomingCall.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
!set_sound(call_outgoing, str) ) {
if (strcasecmp(str, NO_SOUND) != 0)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/OutgoingCall.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
!set_sound(generic_message, str) ) {
if (strcasecmp(str, NO_SOUND) != 0)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(generic_message, PACKAGE_DATADIR "/sounds/NewMessage.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
!set_sound(transfer_pending, str) ) {
if (strcasecmp(str, NO_SOUND) != 0)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/TransferPending.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
!set_sound(transfer_completed, str) ) {
if (strcasecmp(str, NO_SOUND) != 0)
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/TransferComplete.wav");
}
}

View File

@ -23,7 +23,7 @@
#ifndef _settings_h
#define _settings_h
#define NO_SOUND "silent"
#include <limits.h>
/* holds user setting values */
struct user_settings {
@ -36,7 +36,8 @@ struct user_settings {
int show_typing_self; /* boolean */
int show_typing_other; /* boolean */
char download_path[MAX_STR_SIZE];
char download_path[PATH_MAX];
char chatlogs_path[PATH_MAX];
int key_next_tab; /* character code */
int key_prev_tab; /* character code */

View File

@ -37,6 +37,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <limits.h>
#include <tox/tox.h>
@ -105,7 +106,7 @@ void exit_toxic_success(Tox *m)
{
store_data(m, DATA_FILE);
close_all_file_senders(m);
kill_all_windows();
kill_all_windows(m);
free(DATA_FILE);
free(BLOCK_FILE);
@ -175,23 +176,93 @@ static void init_term(void)
refresh();
}
static Tox *init_tox(int ipv4)
{
/* Init core */
int ipv6 = !ipv4;
Tox *m = tox_new(ipv6);
static struct _init_messages {
char **msgs;
int num;
} init_messages;
/*
* TOX_ENABLE_IPV6_DEFAULT is always 1.
* Checking it is redundant, this *should* be doing ipv4 fallback
*/
if (ipv6 && m == NULL) {
fprintf(stderr, "IPv6 didn't initialize, trying IPv4\n");
m = tox_new(0);
/* One-time queue for messages created during init. Do not use after program init. */
static void queue_init_message(const char *msg)
{
int i = init_messages.num;
++init_messages.num;
char **new_msgs = realloc(init_messages.msgs, sizeof(char *) * init_messages.num);
if (new_msgs == NULL)
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
new_msgs[i] = malloc(MAX_STR_SIZE);
if (new_msgs[i] == NULL)
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
snprintf(new_msgs[i], MAX_STR_SIZE, "%s", msg);
init_messages.msgs = new_msgs;
}
/* called after messages have been printed to console and are no longer needed */
static void cleanup_init_messages(void)
{
if (init_messages.num <= 0)
return;
int i;
for (i = 0; i < init_messages.num; ++i)
free(init_messages.msgs[i]);
free(init_messages.msgs);
}
static void print_init_messages(ToxWindow *toxwin)
{
int i;
for (i = 0; i < init_messages.num; ++i)
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
}
static Tox *init_tox(void)
{
Tox_Options tox_opts;
tox_opts.ipv6enabled = !arg_opts.use_ipv4;
tox_opts.udp_disabled = arg_opts.force_tcp;
tox_opts.proxy_enabled = arg_opts.use_proxy;
if (tox_opts.proxy_enabled) {
tox_opts.proxy_port = arg_opts.proxy_port;
snprintf(tox_opts.proxy_address, sizeof(tox_opts.proxy_address), "%s", arg_opts.proxy_address);
char tmp[48];
snprintf(tmp, sizeof(tmp), "Using proxy %s : %d",
arg_opts.proxy_address, arg_opts.proxy_port);
queue_init_message(tmp);
}
if (ipv4)
fprintf(stderr, "Forcing IPv4 connection\n");
if (tox_opts.udp_disabled) {
queue_init_message("UDP disabled");
} else if (tox_opts.proxy_enabled) {
const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address.";
queue_init_message(msg);
msg = "Use the -t option to disable UDP.";
queue_init_message(msg);
}
/* Init core */
Tox *m = tox_new(&tox_opts);
if (tox_opts.ipv6enabled && m == NULL) {
queue_init_message("IPv6 failed to initialize");
tox_opts.ipv6enabled = 0;
m = tox_new(&tox_opts);
}
if (!tox_opts.ipv6enabled)
queue_init_message("Forcing IPv4 connection");
if (tox_opts.proxy_enabled && m == NULL)
exit_toxic_err("Proxy error", FATALERR_PROXY);
if (m == NULL)
return NULL;
@ -226,10 +297,10 @@ static Tox *init_tox(int ipv4)
return m;
}
#define MINLINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
#define MAXLINE 256 /* Approx max number of chars in a sever line (name + port + key) */
#define MIN_NODE_LINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
#define MAX_NODE_LINE 256 /* Approx max number of chars in a sever line (name + port + key) */
#define MAXNODES 50
#define NODELEN (MAXLINE - TOX_CLIENT_ID_SIZE - 7)
#define NODELEN (MAX_NODE_LINE - TOX_CLIENT_ID_SIZE - 7)
static struct _toxNodes {
int lines;
@ -238,7 +309,7 @@ static struct _toxNodes {
char keys[MAXNODES][TOX_CLIENT_ID_SIZE];
} toxNodes;
static int nodelist_load(const char *filename)
static int load_nodelist(const char *filename)
{
if (!filename)
return 1;
@ -248,10 +319,10 @@ static int nodelist_load(const char *filename)
if (fp == NULL)
return 1;
char line[MAXLINE];
char line[MAX_NODE_LINE];
while (fgets(line, sizeof(line), fp) && toxNodes.lines < MAXNODES) {
if (strlen(line) > MINLINE) {
if (strlen(line) > MIN_NODE_LINE) {
const char *name = strtok(line, " ");
const char *port = strtok(NULL, " ");
const char *key_ascii = strtok(NULL, " ");
@ -262,7 +333,7 @@ static int nodelist_load(const char *filename)
snprintf(toxNodes.nodes[toxNodes.lines], sizeof(toxNodes.nodes[toxNodes.lines]), "%s", name);
toxNodes.nodes[toxNodes.lines][NODELEN - 1] = 0;
toxNodes.ports[toxNodes.lines] = htons(atoi(port));
toxNodes.ports[toxNodes.lines] = atoi(port);
char *key_binary = hex_string_to_bin(key_ascii);
memcpy(toxNodes.keys[toxNodes.lines], key_binary, TOX_CLIENT_ID_SIZE);
@ -272,19 +343,17 @@ static int nodelist_load(const char *filename)
}
}
if (toxNodes.lines < 1) {
fclose(fp);
return 2;
}
fclose(fp);
if (toxNodes.lines < 1)
return 1;
return 0;
}
int init_connection_helper(Tox *m, int line)
{
return tox_bootstrap_from_address(m, toxNodes.nodes[line], TOX_ENABLE_IPV6_DEFAULT,
toxNodes.ports[line], (uint8_t *) toxNodes.keys[line]);
return tox_bootstrap_from_address(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line]);
}
/* Connects to a random DHT node listed in the DHTnodes file
@ -313,11 +382,11 @@ int init_connection(Tox *m)
int res;
if (!arg_opts.nodes_path[0])
res = nodelist_load(PACKAGE_DATADIR "/DHTnodes");
res = load_nodelist(PACKAGE_DATADIR "/DHTnodes");
else
res = nodelist_load(arg_opts.nodes_path);
res = load_nodelist(arg_opts.nodes_path);
if (toxNodes.lines < 1)
if (res != 0)
return res;
res = 3;
@ -340,6 +409,9 @@ int init_connection(Tox *m)
static void do_connection(Tox *m, ToxWindow *prompt)
{
if (arg_opts.no_connect == 1)
return;
char msg[MAX_STR_SIZE] = {0};
static int conn_err = 0;
@ -354,7 +426,7 @@ static void do_connection(Tox *m, ToxWindow *prompt)
if (!was_connected && is_connected) {
was_connected = true;
prompt_update_connectionstatus(prompt, was_connected);
snprintf(msg, sizeof(msg), "DHT connected.");
snprintf(msg, sizeof(msg), "DHT connected");
} else if (was_connected && !is_connected) {
was_connected = false;
prompt_update_connectionstatus(prompt, was_connected);
@ -468,7 +540,10 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
pthread_mutex_lock(&Winthread.lock);
do_connection(m, prompt);
do_file_senders(m);
tox_do(m); /* main tox-core loop */
if (arg_opts.no_connect == 0)
tox_do(m); /* main tox-core loop */
pthread_mutex_unlock(&Winthread.lock);
}
@ -501,21 +576,30 @@ void *thread_winref(void *data)
static void print_usage(void)
{
fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n");
fprintf(stderr, " -f, --file Use specified data file\n");
fprintf(stderr, " -x, --nodata Ignore data file\n");
fprintf(stderr, " -4, --ipv4 Force IPv4 connection\n");
fprintf(stderr, " -d, --default_locale Use default locale\n");
fprintf(stderr, " -b --debug Enable stderr for debugging\n");
fprintf(stderr, " -c, --config Use specified config file\n");
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
fprintf(stderr, " -d, --default-locale Use default POSIX locale\n");
fprintf(stderr, " -f, --file Use specified data file\n");
fprintf(stderr, " -h, --help Show this message and exit\n");
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
fprintf(stderr, " -o, --noconnect Do not connect to the DHT network\n");
fprintf(stderr, " -p, --proxy Use 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, " -x, --nodata Ignore data file\n");
}
static void set_default_opts(void)
{
arg_opts.use_ipv4 = 0;
arg_opts.ignore_data_file = 0;
arg_opts.debug = 0;
arg_opts.default_locale = 0;
arg_opts.use_custom_data = 0;
arg_opts.no_connect = 0;
arg_opts.force_tcp = 0;
arg_opts.use_proxy = 0;
}
static void parse_args(int argc, char *argv[])
@ -526,17 +610,45 @@ static void parse_args(int argc, char *argv[])
{"file", required_argument, 0, 'f'},
{"nodata", no_argument, 0, 'x'},
{"ipv4", no_argument, 0, '4'},
{"default_locale", no_argument, 0, 'd'},
{"debug", no_argument, 0, 'b'},
{"default-locale", no_argument, 0, 'd'},
{"config", required_argument, 0, 'c'},
{"nodes", required_argument, 0, 'n'},
{"help", no_argument, 0, 'h'},
{"noconnect", no_argument, 0, 'o'},
{"dnslist", required_argument, 0, 'r'},
{"force-tcp", no_argument, 0, 't'},
{"proxy", required_argument, 0, 'p'},
{NULL, no_argument, NULL, 0},
};
const char *opts_str = "4xdf:c:n:h";
const char *opts_str = "4bdhotxc:f:n:r:p:";
int opt, indexptr;
while ((opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr)) != -1) {
switch (opt) {
case '4':
arg_opts.use_ipv4 = 1;
break;
case 'b':
arg_opts.debug = 1;
queue_init_message("stderr enabled");
break;
case 'c':
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
if (!file_exists(arg_opts.config_path))
queue_init_message("Config file not found");
break;
case 'd':
arg_opts.default_locale = 1;
queue_init_message("Using default POSIX locale");
break;
case 'f':
arg_opts.use_custom_data = 1;
DATA_FILE = strdup(optarg);
@ -547,26 +659,50 @@ static void parse_args(int argc, char *argv[])
strcpy(BLOCK_FILE, optarg);
strcat(BLOCK_FILE, "-blocklist");
break;
case 'x':
arg_opts.ignore_data_file = 1;
break;
case '4':
arg_opts.use_ipv4 = 1;
break;
case 'c':
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
char tmp[PATH_MAX];
snprintf(tmp, sizeof(tmp), "Using '%s' data file", DATA_FILE);
queue_init_message(tmp);
break;
case 'n':
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg);
if (!file_exists(arg_opts.nodes_path))
queue_init_message("DHTnodes file not found");
break;
case 'd':
arg_opts.default_locale = 1;
case 'o':
arg_opts.no_connect = 1;
queue_init_message("DHT disabled");
break;
case 'p':
arg_opts.use_proxy = 1;
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
if (++optind > argc || argv[optind-1][0] == '-')
exit_toxic_err("Proxy error", FATALERR_PROXY);
arg_opts.proxy_port = (uint16_t) atoi(argv[optind-1]);
break;
case 'r':
snprintf(arg_opts.dns_path, sizeof(arg_opts.dns_path), "%s", optarg);
if (!file_exists(arg_opts.dns_path))
queue_init_message("DNSservers file not found");
break;
case 't':
arg_opts.force_tcp = 1;
break;
case 'x':
arg_opts.ignore_data_file = 1;
queue_init_message("Ignoring data file");
break;
case 'h':
@ -652,9 +788,13 @@ int main(int argc, char *argv[])
char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
int settings_err = settings_load(user_settings_, p);
Tox *m = init_tox(arg_opts.use_ipv4);
Tox *m = init_tox();
init_term();
/* enable stderr for debugging */
if (!arg_opts.debug)
freopen("/dev/null", "w", stderr);
if (m == NULL)
exit_toxic_err("failed in main", FATALERR_NETWORKINIT);
@ -678,9 +818,10 @@ int main(int argc, char *argv[])
set_primary_device(input, user_settings_->audio_in_dev);
set_primary_device(output, user_settings_->audio_out_dev);
#elif _SOUND_NOTIFY
if ( init_devices() == de_InternalError )
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
queue_init_message("Failed to init audio devices");
#endif /* _AUDIO */
@ -694,17 +835,14 @@ int main(int argc, char *argv[])
if (config_err) {
msg = "Unable to determine configuration directory. Defaulting to 'data' for data file...";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
queue_init_message(msg);
}
if (settings_err == -1) {
msg = "Failed to load user settings";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
}
if (settings_err == -1)
queue_init_message("Failed to load user settings");
/* Redirect stderr to /dev/null
NOTE: Might not be best solution. Comment out for debugging. */
freopen("/dev/null", "w", stderr);
print_init_messages(prompt);
cleanup_init_messages();
uint64_t last_save = (uint64_t) time(NULL);
uint64_t looptimer = last_save;

View File

@ -42,7 +42,6 @@
#define UNKNOWN_NAME "Anonymous"
#define MAX_FRIENDS_NUM 999
#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH
#define MAX_CMDNAME_SIZE 64
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
@ -79,6 +78,7 @@ typedef enum _FATAL_ERRS {
FATALERR_NETWORKINIT = -8, /* Tox network failed to init */
FATALERR_INFLOOP = -9, /* infinite loop detected */
FATALERR_WININIT = -10, /* window init failed */
FATALERR_PROXY = -11, /* Tox network failed to init using a proxy */
} FATAL_ERRS;
/* Fixes text color problem on some terminals.

View File

@ -100,9 +100,6 @@ void on_action(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t len
void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
{
if (friendnumber < 0 || friendnumber > MAX_FRIENDS_NUM)
return;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
@ -371,13 +368,12 @@ void on_window_resize(void)
}
}
static void draw_window_tab(ToxWindow toxwin)
static void draw_window_tab(ToxWindow *toxwin)
{
if (toxwin.alert) attron(COLOR_PAIR(toxwin.alert));
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
clrtoeol();
printw(" [%s]", toxwin.name);
if (toxwin.alert) attroff(COLOR_PAIR(toxwin.alert));
printw(" [%s]", toxwin->name);
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
}
static void draw_bar(void)
@ -407,7 +403,7 @@ static void draw_bar(void)
attron(A_BOLD);
draw_window_tab(windows[i]);
draw_window_tab(&windows[i]);
if (windows + i == active_window)
@ -485,7 +481,7 @@ ToxWindow *get_window_ptr(int i)
{
ToxWindow *toxwin = NULL;
if (windows[i].active)
if (i >= 0 && i <= MAX_WINDOWS_NUM && windows[i].active)
toxwin = &windows[i];
return toxwin;
@ -497,16 +493,17 @@ int get_num_active_windows(void)
}
/* destroys all chat and groupchat windows (should only be called on shutdown) */
void kill_all_windows(void)
void kill_all_windows(Tox *m)
{
kill_prompt_window(prompt);
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].is_chat)
kill_chat_window(&windows[i]);
kill_chat_window(&windows[i], m);
else if (windows[i].is_groupchat)
kill_groupchat_window(&windows[i]);
}
kill_prompt_window(prompt);
kill_friendlist();
}

View File

@ -52,7 +52,7 @@ enum {
BLACK,
} C_COLOURS;
/* tab alert types: lower types take priority */
/* tab alert types: lower types take priority (this relies on the order of C_COLOURS) */
typedef enum {
WINDOW_ALERT_NONE = 0,
WINDOW_ALERT_0 = GREEN,
@ -74,10 +74,19 @@ struct _Winthread {
struct arg_opts {
int ignore_data_file;
int use_ipv4;
int force_tcp;
int debug;
int default_locale;
int use_custom_data;
int no_connect;
char dns_path[MAX_STR_SIZE];
char config_path[MAX_STR_SIZE];
char nodes_path[MAX_STR_SIZE];
int use_proxy;
char proxy_address[256];
uint16_t proxy_port;
};
typedef struct ToxWindow ToxWindow;
@ -223,7 +232,7 @@ int add_window(Tox *m, ToxWindow w);
void del_window(ToxWindow *w);
void set_active_window(int ch);
int get_num_active_windows(void);
void kill_all_windows(void); /* should only be called on shutdown */
void kill_all_windows(Tox *m); /* should only be called on shutdown */
void on_window_resize(void);
ToxWindow *get_window_ptr(int i);