Merge remote-tracking branch 'ProjectTox/master'

This commit is contained in:
Astonex 2013-07-31 23:02:09 +01:00
commit f05aa30870
47 changed files with 1148 additions and 268 deletions

8
.gitignore vendored
View File

@ -12,3 +12,11 @@ install_manifest.txt
testing/data testing/data
*~ *~
# Object files
*.o
# Executables
*.exe
*.out
*.app

View File

@ -11,12 +11,17 @@ before_script:
- ./autogen.sh - ./autogen.sh
- ./configure && make check -j3 - ./configure && make check -j3
- sudo make install - sudo make install
- sudo ldconfig
- cd .. - cd ..
# installing libconfig, needed for DHT_bootstrap_daemon # installing libconfig, needed for DHT_bootstrap_daemon
- sudo sed -i 's/precise/quantal/' /etc/apt/sources.list # needed for libconfig-dev - wget http://www.hyperrealm.com/libconfig/libconfig-1.4.9.tar.gz
- sudo apt-get update -qq - tar -xvzf libconfig-1.4.9.tar.gz
- yes | sudo apt-get install libconfig-dev - cd libconfig-1.4.9
- ./configure && make -j3
- sudo make install
- cd ..
# creating librarys' links and updating cache
- sudo ldconfig
script: script:
- mkdir build && cd build - mkdir build && cd build

24
CMakeLists.txt Normal file → Executable file
View File

@ -1,11 +1,31 @@
cmake_minimum_required(VERSION 2.6.0) cmake_minimum_required(VERSION 2.6.0)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
if(NOT WIN32)
option(USE_NACL "Use NaCl library instead of libsodium")
endif()
if(USE_NACL)
find_package(NaCl REQUIRED)
include_directories(${NACL_INCLUDE_DIR})
add_definitions(-DVANILLA_NACL)
set(LINK_CRYPTO_LIBRARY ${NACL_LIBRARIES})
endif()
#MinGW prints more warnings for -Wall than gcc does, thus causing build to fail #MinGW prints more warnings for -Wall than gcc does, thus causing build to fail
if(NOT WIN32) if(NOT WIN32)
if(("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") OR ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")) if(("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") OR ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang"))
message(STATUS "==== ${CMAKE_C_COMPILER_ID} detected - Adding compiler flags ====") message(STATUS "==== ${CMAKE_C_COMPILER_ID} detected - Adding compiler flags ====")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
endif() endif()
find_package(SODIUM REQUIRED)
endif()
if(NOT USE_NACL)
set(LINK_CRYPTO_LIBRARY ${SODIUM_LIBRARY})
endif() endif()
macro(linkCoreLibraries exe_name) macro(linkCoreLibraries exe_name)
@ -16,8 +36,10 @@ macro(linkCoreLibraries exe_name)
${CMAKE_SOURCE_DIR}/sodium/lib/libsodium.a ${CMAKE_SOURCE_DIR}/sodium/lib/libsodium.a
ws2_32) ws2_32)
else() else()
include_directories(${SODIUM_INCLUDE_DIR})
target_link_libraries(${exe_name} core target_link_libraries(${exe_name} core
sodium) ${LINK_CRYPTO_LIBRARY})
endif() endif()
endmacro() endmacro()

View File

@ -5,8 +5,9 @@
Build dependencies: Build dependencies:
```bash ```bash
apt-get install build-essential libtool autotools-dev automake libconfig-dev ncurses-dev apt-get install build-essential libtool autotools-dev automake libconfig-dev ncurses-dev cmake checkinstall
``` ```
Note that `libconfig-dev` should be >= 1.4.
You should get and install [libsodium](https://github.com/jedisct1/libsodium): You should get and install [libsodium](https://github.com/jedisct1/libsodium):
```bash ```bash
@ -15,7 +16,7 @@ cd libsodium
git checkout tags/0.4.2 git checkout tags/0.4.2
./autogen.sh ./autogen.sh
./configure && make check ./configure && make check
sudo make install sudo checkinstall --install --pkgname libsodium --pkgversion 0.4.2 --nodoc
sudo ldconfig sudo ldconfig
``` ```
@ -41,7 +42,17 @@ make
###OSX: ###OSX:
Much the same as above, remember to install the latest XCode and the developer tools (Preferences -> Downloads -> Command Line Tools). ####Homebrew:
```
brew install libtool automake autoconf libconfig libsodium
cmake .
make
sudo make install
```
####Non-homebrew:
Much the same as Linux, remember to install the latest XCode and the developer tools (Preferences -> Downloads -> Command Line Tools).
Users running Mountain Lion and the latest version of XCode (4.6.3) will also need to install libtool, automake and autoconf. Users running Mountain Lion and the latest version of XCode (4.6.3) will also need to install libtool, automake and autoconf.
They are easy enough to install, grab them from http://www.gnu.org/software/libtool/, http://www.gnu.org/software/autoconf/ and http://www.gnu.org/software/automake/, then follow these steps for each: They are easy enough to install, grab them from http://www.gnu.org/software/libtool/, http://www.gnu.org/software/autoconf/ and http://www.gnu.org/software/automake/, then follow these steps for each:
@ -68,7 +79,7 @@ You have to [modify your PATH environment variable](http://www.computerhope.com/
Then you should either clone this repo by using git, or just download a [zip of current Master branch](https://github.com/irungentoo/ProjectTox-Core/archive/master.zip) and extract it somewhere. Then you should either clone this repo by using git, or just download a [zip of current Master branch](https://github.com/irungentoo/ProjectTox-Core/archive/master.zip) and extract it somewhere.
After that you should get precompiled packages of libsodium from [here](https://download.libsodium.org/libsodium/releases/) and extract the archive into this repo's root. That is, `sodium` folder should be along with `core`, `testing` and other folders. After that you should get precompiled package of libsodium from [here](https://download.libsodium.org/libsodium/releases/libsodium-win32-0.4.2.tar.gz) and extract the archive into this repo's root. That is, `sodium` folder should be along with `core`, `testing` and other folders.
Navigate in `cmd` to this repo and run: Navigate in `cmd` to this repo and run:
```cmd ```cmd

View File

@ -1,54 +1,51 @@
![Project Tox](https://rbt.asia/boards/g/img/0352/79/1373823047559.png "Project Tox") ![Project Tox](https://rbt.asia/boards/g/img/0352/79/1373823047559.png "Project Tox")
Project Tox, _also known as Tox_, is a FOSS instant messaging application aimed to replace Skype.<br /> Project Tox, _also known as Tox_, is a FOSS (Free and Open Source Software) instant messaging application aimed to replace Skype.<br />
With the rise of governmental monitoring programs, Tox aims to be an easy to use application that allows people to connect with friends and loved ones without the worry of privacy.<br /> <br /> With the rise of governmental monitoring programs, Tox aims to be an easy to use, all-in-one communication platform (including audio, and videochats in the future) that ensures their users full privacy and secure message delivery.<br /> <br />
**IRC**: #tox on freenode, alternatively, you can use the [webchat](http://webchat.freenode.net/?channels=#tox).<br />
**IRC**: #tox on Freenode, alternatively, you can use the [webchat](http://webchat.freenode.net/?channels=#tox).<br />
**Website**: [http://tox.im](http://tox.im) **Website**: [http://tox.im](http://tox.im)
**Website translations**: [see stal888's repository](https://github.com/stal888/ProjectTox-Website)<br/> **Website translations**: [see stal888's repository](https://github.com/stal888/ProjectTox-Website)<br/>
**Qt GUI**: [see nurupo's repository](https://github.com/nurupo/ProjectTox-Qt-GUI) **Qt GUI**: [see nurupo's repository](https://github.com/nurupo/ProjectTox-Qt-GUI)
**How to build Tox on Linux**: [YouTube video](http://www.youtube.com/watch?v=M4WXE4VKmyg)<br />
**How to use Tox on Windows**: [YouTube video](http://www.youtube.com/watch?v=qg_j_sDb6WQ)
### Objectives:
Keep everything really simple.
## The Complex Stuff: ## The Complex Stuff:
+ Tox must use UDP simply because you can't hole punch with TCP. It's possible, but it doesn't work all the time. + Tox must use UDP simply because [hole punching](http://en.wikipedia.org/wiki/UDP_hole_punching) with TCP is not as reliable.
+ Every peer is represented as a byte string (the public key of the peer [client id]) + Every peer is represented as a [byte string](https://en.wikipedia.org/wiki/String_(computer_science)) (the public key of the peer [client ID]).
+ We're using torrent-style DHT so that peers can find the IP of the other peers when they have their ID. + We're using torrent-style DHT so that peers can find the IP of the other peers when they have their ID.
+ Once the client has the IP of that peer, they start initiating a secure connection with each other. (See [Crypto](https://github.com/irungentoo/ProjectTox-Core/wiki/Crypto) + Once the client has the IP of that peer, they start initiating a secure connection with each other. (See [Crypto](https://github.com/irungentoo/ProjectTox-Core/wiki/Crypto))
+ When both peers are securely connect with the encryption, they can securely exchange messages, initiate a video chat, send files, etc.<br /> + When both peers are securely connected, they can exchange messages, initiate a video chat, send files, etc, all using encrypted communications.
+ Current build status: [![Build Status](https://travis-ci.org/irungentoo/ProjectTox-Core.png?branch=master)](https://travis-ci.org/irungentoo/ProjectTox-Core) + Current build status: [![Build Status](https://travis-ci.org/irungentoo/ProjectTox-Core.png?branch=master)](https://travis-ci.org/irungentoo/ProjectTox-Core)
## Roadmap: ## Roadmap:
- [x] Get our DHT working perfectly.(Done, needs large scale testing though.) - [x] Get our DHT working perfectly. (Done, needs large scale testing though)
- [x] Reliable connection (See Lossless_UDP protocol) to other peers according to client id. (Done, see DHT_sendfiletest.c for an example) - [x] Reliable connection (See Lossless UDP protocol) to other peers according to client ID. (Done, see DHT_sendfiletest.c for an example)
- [x] Encryption. (Done) - [x] Encryption. (Done)
- [ ] Get a simple text only im client working perfectly. (This is where we are) - [ ] Get a simple text only IM client working perfectly. (This is where we are)
- [ ] Streaming media - [ ] Streaming media
- [ ] ??? - [ ] ???
For further information, check our [To-do list](https://github.com/irungentoo/ProjectTox-Core/wiki/TODO) For further information, check our [To-do list](https://github.com/irungentoo/ProjectTox-Core/wiki/TODO)
### Why are you doing this? There are already a bunch of free skype alternatives.
The goal of this project is to create a configuration-free P2P skype
replacement. Configuration-free means that the user will simply have to open the program and
without any account configuration will be capable of adding people to his
friends list and start conversing with them. There are many so called skype replacements and all of them are either hard to
configure for the normal user or suffer from being way too centralized.
### Important-stuff: ### Documentation:
Use the same UDP socket for everything
Keep everything really simple.
### Details and Documents:
[DHT Protocol](https://github.com/irungentoo/ProjectTox-Core/wiki/DHT)<br /> [DHT Protocol](https://github.com/irungentoo/ProjectTox-Core/wiki/DHT)<br />
[Lossless UDP Protocol](https://github.com/irungentoo/ProjectTox-Core/wiki/Lossless-UDP)<br /> [Lossless UDP Protocol](https://github.com/irungentoo/ProjectTox-Core/wiki/Lossless-UDP)<br />
[Crypto](https://github.com/irungentoo/ProjectTox-Core/wiki/Crypto)<br /> [Crypto](https://github.com/irungentoo/ProjectTox-Core/wiki/Crypto)<br />
[Ideas](https://github.com/irungentoo/ProjectTox-Core/wiki/Ideas) [Ideas](https://github.com/irungentoo/ProjectTox-Core/wiki/Ideas)
### Why are you doing this? There are already a bunch of free skype alternatives.
The goal of this project is to create a configuration-free p2p skype
replacement. Configuration-free means that the user will simply have to open the program and
without any account configuration will be capable of adding people to his
friends list and start conversing with them. There are many so called skype replacements and all of them are either hard to
configure for the normal user or suffer from being much too centralized.

15
cmake/FindLIBCONFIG.cmake Normal file
View File

@ -0,0 +1,15 @@
# Find LIBCONFIG
#
# LIBCONFIG_INCLUDE_DIR
# LIBCONFIG_LIBRARY
# LIBCONFIG_FOUND
#
FIND_PATH(LIBCONFIG_INCLUDE_DIR NAMES libconfig.h)
FIND_LIBRARY(LIBCONFIG_LIBRARY NAMES config)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBCONFIG DEFAULT_MSG LIBCONFIG_LIBRARY LIBCONFIG_INCLUDE_DIR)
MARK_AS_ADVANCED(LIBCONFIG_INCLUDE_DIR LIBCONFIG_LIBRARY)

17
cmake/FindNaCl.cmake Normal file
View File

@ -0,0 +1,17 @@
find_path(NACL_INCLUDE_DIR crypto_box.h
$ENV{NACL_INCLUDE_DIR} /usr/include/nacl/
DOC "Directory which contain NaCl headers")
find_path(NACL_LIBRARY_DIR libnacl.a
$ENV{NACL_LIBRARY_DIR} /usr/lib/nacl
DOC "Directory which contain libnacl.a, cpucycles.o, and randombytes.o")
if(NACL_LIBRARY_DIR)
set(NACL_LIBRARIES
"${NACL_LIBRARY_DIR}/cpucycles.o"
"${NACL_LIBRARY_DIR}/libnacl.a"
"${NACL_LIBRARY_DIR}/randombytes.o")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(NaCl DEFAULT_MSG NACL_INCLUDE_DIR NACL_LIBRARY_DIR NACL_LIBRARIES)

15
cmake/FindSODIUM.cmake Normal file
View File

@ -0,0 +1,15 @@
# Find SODIUM
#
# SODIUM_INCLUDE_DIR
# SODIUM_LIBRARY
# SODIUM_FOUND
#
FIND_PATH(SODIUM_INCLUDE_DIR NAMES sodium.h)
FIND_LIBRARY(SODIUM_LIBRARY NAMES sodium)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SODIUM DEFAULT_MSG SODIUM_LIBRARY SODIUM_INCLUDE_DIR)
MARK_AS_ADVANCED(SODIUM_INCLUDE_DIR SODIUM_LIBRARY)

View File

@ -3,6 +3,8 @@ project(core C)
if(WIN32) if(WIN32)
include_directories(${CMAKE_HOME_DIRECTORY}/sodium/include/) include_directories(${CMAKE_HOME_DIRECTORY}/sodium/include/)
else(WIN32)
include_directories(${SODIUM_INCLUDE_DIR})
endif() endif()
set(core_sources set(core_sources

View File

@ -308,12 +308,16 @@ IP_Port connection_ip(int connection_id)
/* returns the number of packets in the queue waiting to be successfully sent. */ /* returns the number of packets in the queue waiting to be successfully sent. */
uint32_t sendqueue(int connection_id) uint32_t sendqueue(int connection_id)
{ {
if (connection_id < 0 || connection_id >= MAX_CONNECTIONS)
return 0;
return connections[connection_id].sendbuff_packetnum - connections[connection_id].successful_sent; return connections[connection_id].sendbuff_packetnum - connections[connection_id].successful_sent;
} }
/* returns the number of packets in the queue waiting to be successfully read with read_packet(...) */ /* returns the number of packets in the queue waiting to be successfully read with read_packet(...) */
uint32_t recvqueue(int connection_id) uint32_t recvqueue(int connection_id)
{ {
if (connection_id < 0 || connection_id >= MAX_CONNECTIONS)
return 0;
return connections[connection_id].recv_packetnum - connections[connection_id].successful_read; return connections[connection_id].recv_packetnum - connections[connection_id].successful_read;
} }
@ -321,6 +325,8 @@ uint32_t recvqueue(int connection_id)
return -1 if no packet in queue */ return -1 if no packet in queue */
char id_packet(int connection_id) char id_packet(int connection_id)
{ {
if (connection_id < 0 || connection_id >= MAX_CONNECTIONS)
return -1;
if (recvqueue(connection_id) != 0 && connections[connection_id].status != 0) if (recvqueue(connection_id) != 0 && connections[connection_id].status != 0)
return connections[connection_id].recvbuffer[connections[connection_id].successful_read % MAX_QUEUE_NUM].data[0]; return connections[connection_id].recvbuffer[connections[connection_id].successful_read % MAX_QUEUE_NUM].data[0];
return -1; return -1;

View File

@ -99,18 +99,21 @@ int getclient_id(int friend_id, uint8_t *client_id)
client_id is the client id of the friend client_id is the client id of the friend
data is the data and length is the length data is the data and length is the length
returns the friend number if success returns the friend number if success
return -1 if failure. */ return -1 if key length is wrong.
return -2 if user's own key
return -3 if already a friend
return -4 for other*/
int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length) int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length)
{ {
if (length == 0 || length >= if (length == 0 || length >=
(MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES)) (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES))
return -1; return -1;
if (memcmp(client_id, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) if (memcmp(client_id, self_public_key, crypto_box_PUBLICKEYBYTES) == 0)
return -1; return -2;
if (getfriend_id(client_id) != -1) if (getfriend_id(client_id) != -1)
return -1; return -3;
uint32_t i; uint32_t i;
for (i = 0; i <= numfriends; ++i) { for (i = 0; i <= numfriends; ++i) { /*TODO: dynamic memory allocation, this will segfault if there are more than MAX_NUM_FRIENDS*/
if(friendlist[i].status == 0) { if(friendlist[i].status == 0) {
DHT_addfriend(client_id); DHT_addfriend(client_id);
friendlist[i].status = 1; friendlist[i].status = 1;
@ -126,7 +129,7 @@ int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length)
return i; return i;
} }
} }
return -1; return -4;
} }
int m_addfriend_norequest(uint8_t * client_id) int m_addfriend_norequest(uint8_t * client_id)
@ -134,7 +137,7 @@ int m_addfriend_norequest(uint8_t * client_id)
if (getfriend_id(client_id) != -1) if (getfriend_id(client_id) != -1)
return -1; return -1;
uint32_t i; uint32_t i;
for (i = 0; i <= numfriends; ++i) { for (i = 0; i <= numfriends; ++i) {/*TODO: dynamic memory allocation, this will segfault if there are more than MAX_NUM_FRIENDS*/
if(friendlist[i].status == 0) { if(friendlist[i].status == 0) {
DHT_addfriend(client_id); DHT_addfriend(client_id);
friendlist[i].status = 2; friendlist[i].status = 2;
@ -165,7 +168,7 @@ int m_delfriend(int friendnumber)
uint32_t i; uint32_t i;
for (i = numfriends; i != 0; --i) { for (i = numfriends; i != 0; --i) {
if (friendlist[i].status != 0) if (friendlist[i-1].status != 0)
break; break;
} }
numfriends = i; numfriends = i;
@ -180,7 +183,7 @@ int m_delfriend(int friendnumber)
return 0 if there is no friend with that number */ return 0 if there is no friend with that number */
int m_friendstatus(int friendnumber) int m_friendstatus(int friendnumber)
{ {
if (friendnumber < 0 || friendnumber >= MAX_NUM_FRIENDS) if (friendnumber < 0 || friendnumber >= numfriends)
return 0; return 0;
return friendlist[friendnumber].status; return friendlist[friendnumber].status;
} }
@ -190,7 +193,7 @@ int m_friendstatus(int friendnumber)
return 0 if it was not */ return 0 if it was not */
int m_sendmessage(int friendnumber, uint8_t *message, uint32_t length) int m_sendmessage(int friendnumber, uint8_t *message, uint32_t length)
{ {
if (friendnumber < 0 || friendnumber >= MAX_NUM_FRIENDS) if (friendnumber < 0 || friendnumber >= numfriends)
return 0; return 0;
if (length >= MAX_DATA_SIZE || friendlist[friendnumber].status != 4) if (length >= MAX_DATA_SIZE || friendlist[friendnumber].status != 4)
/* this does not mean the maximum message length is MAX_DATA_SIZE - 1, it is actually 17 bytes less. */ /* this does not mean the maximum message length is MAX_DATA_SIZE - 1, it is actually 17 bytes less. */
@ -242,6 +245,16 @@ int setname(uint8_t * name, uint16_t length)
return 0; return 0;
} }
/* get our nickname
put it in name
name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
return the length of the name */
uint16_t getself_name(uint8_t *name)
{
memcpy(name, self_name, self_name_length);
return self_name_length;
}
/* get name of friendnumber /* get name of friendnumber
put it in name put it in name
name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.

View File

@ -50,7 +50,10 @@ extern "C" {
client_id is the client id of the friend client_id is the client id of the friend
data is the data and length is the length data is the data and length is the length
returns the friend number if success returns the friend number if success
return -1 if failure. */ return -1 if key length is wrong.
return -2 if user's own key
return -3 if already a friend
return -4 for other*/
int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length); int m_addfriend(uint8_t *client_id, uint8_t *data, uint16_t length);
@ -92,6 +95,11 @@ int m_sendmessage(int friendnumber, uint8_t *message, uint32_t length);
return -1 if failure */ return -1 if failure */
int setname(uint8_t *name, uint16_t length); int setname(uint8_t *name, uint16_t length);
/* get our nickname
put it in name
return the length of the name*/
uint16_t getself_name(uint8_t *name);
/* get name of friendnumber /* get name of friendnumber
put it in name put it in name
name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.

View File

@ -169,7 +169,7 @@ void shutdown_networking()
address should represent IPv4, IPv6 or a hostname address should represent IPv4, IPv6 or a hostname
on success returns a data in network byte order that can be used to set IP.i or IP_Port.ip.i on success returns a data in network byte order that can be used to set IP.i or IP_Port.ip.i
on failure returns -1 */ on failure returns -1 */
int resolve_addr(char *address) int resolve_addr(const char *address)
{ {
struct addrinfo hints; struct addrinfo hints;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
@ -178,7 +178,7 @@ int resolve_addr(char *address)
struct addrinfo *server = NULL; struct addrinfo *server = NULL;
int success = getaddrinfo(address, "7", &hints, &server); int success = getaddrinfo(address, "echo", &hints, &server);
if(success != 0) if(success != 0)
return -1; return -1;

View File

@ -56,11 +56,7 @@
/* we use libsodium by default */ /* we use libsodium by default */
#include <sodium.h> #include <sodium.h>
#else #else
#include <crypto_box.h>
/* TODO: Including stuff like this is bad. This needs fixing.
We keep support for the original NaCl for now. */
#include "../nacl/build/Linux/include/amd64/crypto_box.h"
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
@ -125,7 +121,7 @@ void shutdown_networking();
address should represent IPv4, IPv6 or a hostname address should represent IPv4, IPv6 or a hostname
on success returns a data in network byte order that can be used to set IP.i or IP_Port.ip.i on success returns a data in network byte order that can be used to set IP.i or IP_Port.ip.i
on failure returns -1 */ on failure returns -1 */
int resolve_addr(char *address); int resolve_addr(const char *address);
#ifdef __cplusplus #ifdef __cplusplus
} }

25
docs/commands.md Normal file
View File

@ -0,0 +1,25 @@
# Tox User Commands
Here's a list of commands that nTox accepts,
which can all be used by starting your line with
a */*. Currently there can be no spaces before this.
* */f* [ID]
+ Add a friend with ID [ID].
* */d*
+ Call doMessenger() which does...something?
* */m* \[FRIEND\_NUM\] \[MESSAGE\]
+ Message \[FRIEND\_NUM\] \[MESSAGE\].
* */n* \[NAME\]
+ Change your username to \[NAME\].
* */l*
+ Print your list of friends. (like you have any)
* */s* \[STATUS\]
+ Set your status to \[STATUS\].
* */a* \[ID\]
+ Accept friend request from \[ID\].
* */i*
+ Print useful info about your client.
* */h*
+ Print some help.
* */q/*
+ Quit Tox. (why ;_;)

38
docs/using_tox.md Normal file
View File

@ -0,0 +1,38 @@
# Using Tox
1. Build Tox
2. Fix errors
3. Consult IRC for help
4. Go on debugging journy for devs
5. Build Tox for real
6. ???
For all the work we've put into Tox so far,
there isn't yet a decent guide for how you _use_
Tox. Here's a user-friendly attempt at it.
1. Connect to the network!
+ You need to connect to a bootstrapping server, to give you a public key.
+ Where can I find a public server? Right here, as of now:
(the help message from running nTox with no args will help)
+ 198.46.136.167 33445 728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854
+ 192.81.133.111 33445 8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858
+ 66.175.223.88 33445 AC4112C975240CAD260BB2FCD134266521FAAF0A5D159C5FD3201196191E4F5D
+ 192.184.81.118 33445 5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143
2. Find a friend!
+ Now that you're on the network, you need a friend. To get one of those,
you need to to send or receive a request. What's a request, you ask?
It's like a friend request, but we use really scary and cryptic numbers
instead of names. When nTox starts, it shows your _your_ long, scary number,
called your *public key*. Give that to people, and they can add you as
as "friend". Or, you can add someone else, with the */f* command, if you like.
3. Chat it up!
+ Now use the */m* command to send a message to someone. Wow, you're chatting!
4. But something broke!
+ Yeah, pre-alpha-alpha software tends to do that. We're working on it.
+ Please report all crashes to either the github page, or #tox-dev on freenode.
5. Nothing broke, but what does */f* mean?
+ nTox parses text as a command if the first character is a forward-slash ('/').
You can check all commands in commands.md.
6. Use and support Tox!
+ Code for us, debug for us, document for us, translate for us, even just talk about us!
+ The more interest we get, the more work gets done, the better Tox is.

View File

@ -3,8 +3,17 @@ project(DHT_bootstrap_daemon C)
set(exe_name DHT_bootstrap_daemon) set(exe_name DHT_bootstrap_daemon)
find_package(LIBCONFIG REQUIRED)
include_directories(${LIBCONFIG_INCLUDE_DIR})
add_executable(${exe_name} add_executable(${exe_name}
DHT_bootstrap_daemon.c) DHT_bootstrap_daemon.c)
target_link_libraries(${exe_name} config) target_link_libraries(${exe_name}
${LIBCONFIG_LIBRARY})
linkCoreLibraries(${exe_name}) linkCoreLibraries(${exe_name})
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
find_package(LibConfig REQUIRED)

View File

@ -123,11 +123,12 @@ void manage_keys(char *keys_file)
{ {
const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
uint8_t keys[KEYS_SIZE]; uint8_t keys[KEYS_SIZE];
struct stat existence;
FILE *keysf;
/* TODO: stat the file before trying to open it. We aren't cave people! */ /* Check if file exits, proceed to open and load keys */
FILE *keysf = fopen(keys_file, "r"); if(stat(keys_file,&existence) >= 0) {
if (keysf != NULL) { keysf = fopen(keys_file, "r");
/* if file was opened successfully -- load keys */
size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keysf); size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keysf);
if (read_size != KEYS_SIZE) { if (read_size != KEYS_SIZE) {
printf("Error while reading the key file\nExiting.\n"); printf("Error while reading the key file\nExiting.\n");

View File

@ -0,0 +1,73 @@
#Ref: https://github.com/schnorr/pajeng/blob/master/cmake/FindLibConfig.cmake
#
# This module defines
# LIBCONFIG_INCLUDE_DIR, where to find cppunit include files, etc.
# LIBCONFIG_LIBRARIES, the libraries to link against to use CppUnit.
# LIBCONFIG_STATIC_LIBRARIY_PATH
# LIBCONFIG_FOUND, If false, do not try to use CppUnit.
# also defined, but not for general use are
# LIBCONFIG_LIBRARY, where to find the CUnit library.
#MESSAGE("Searching for libconfig library")
FIND_PATH(LIBCONFIG_INCLUDE_DIR libconfig.h
/usr/local/include
/usr/include
)
FIND_PATH(LIBCONFIGPP_INCLUDE_DIR libconfig.h++
/usr/local/include
/usr/include
)
FIND_LIBRARY(LIBCONFIG_LIBRARY config
/usr/local/lib
/usr/lib
)
FIND_LIBRARY(LIBCONFIGPP_LIBRARY config++
/usr/local/lib
/usr/lib
)
FIND_LIBRARY(LIBCONFIG_STATIC_LIBRARY "libconfig${CMAKE_STATIC_LIBRARY_SUFFIX}"
/usr/local/lib
/usr/lib
)
FIND_LIBRARY(LIBCONFIGPP_STATIC_LIBRARY "libconfig++${CMAKE_STATIC_LIBRARY_SUFFIX}"
/usr/local/lib
/usr/lib
)
IF(LIBCONFIG_INCLUDE_DIR)
IF(LIBCONFIG_LIBRARY)
SET(LIBCONFIG_FOUND TRUE)
SET(LIBCONFIG_LIBRARIES ${LIBCONFIG_LIBRARY})
SET(LIBCONFIG_STATIC_LIBRARY_PATH ${LIBCONFIG_STATIC_LIBRARY})
ENDIF(LIBCONFIG_LIBRARY)
ENDIF(LIBCONFIG_INCLUDE_DIR)
IF(LIBCONFIGPP_INCLUDE_DIR)
IF(LIBCONFIGPP_LIBRARY)
SET(LIBCONFIGPP_FOUND TRUE)
SET(LIBCONFIGPP_LIBRARIES ${LIBCONFIGPP_LIBRARY})
SET(LIBCONFIGPP_STATIC_LIBRARY_PATH ${LIBCONFIGPP_STATIC_LIBRARY})
ENDIF(LIBCONFIGPP_LIBRARY)
ENDIF(LIBCONFIGPP_INCLUDE_DIR)
IF (LIBCONFIG_FOUND)
IF (NOT LibConfig_FIND_QUIETLY)
MESSAGE(STATUS "Found LibConfig++: ${LIBCONFIGPP_LIBRARIES}" )
MESSAGE(STATUS "Found LibConfig: ${LIBCONFIG_LIBRARIES}")
MESSAGE(STATUS "static LibConfig path: ${LIBCONFIG_STATIC_LIBRARY_PATH}")
ENDIF (NOT LibConfig_FIND_QUIETLY)
ELSE (LIBCONFIG_FOUND)
IF (LibConfig_FIND_REQUIRED)
MESSAGE(SEND_ERROR "Could NOT find LibConfig")
ENDIF (LibConfig_FIND_REQUIRED)
ENDIF (LIBCONFIG_FOUND)
MARK_AS_ADVANCED(LIBCONFIG_INCLUDE_DIR LIBCONFIG_LIBRARIES)

View File

@ -6,11 +6,15 @@ port = 33445;
// The key file // The key file
// make sure that the user who runs the server // make sure that the user who runs the server
// does have permissions to read it/write to it // does have permissions to read it/write to it
// Remember to replace the provided example with
// the directory the DHT server will run in.
keys_file = "/home/tom/.bootstrap_server.keys" keys_file = "/home/tom/.bootstrap_server.keys"
// The PID file written to by bootstrap_server, // The PID file written to by bootstrap_server,
// make sure that the user who runs the server // make sure that the user who runs the server
// does have permissions to write to it // does have permissions to write to it
// Remember to replace the provided example with
// the directory the DHT server will run in.
pid_file = "/home/tom/.bootstrap_server.pid"; pid_file = "/home/tom/.bootstrap_server.pid";
// The info of the node bootstap_server will // The info of the node bootstap_server will

View File

@ -4,6 +4,7 @@ project(DHT_bootstrap C)
set(exe_name DHT_bootstrap) set(exe_name DHT_bootstrap)
add_executable(${exe_name} add_executable(${exe_name}
DHT_bootstrap.c ../testing/misc_tools.c) DHT_bootstrap.c
../testing/misc_tools.c)
linkCoreLibraries(${exe_name}) linkCoreLibraries(${exe_name})

40
start_guide.de.md Normal file
View File

@ -0,0 +1,40 @@
# Tox nutzen
1. Tox erstellen
2. Fehler korrigieren
3. Im IRC nach Hilfe fragen
4. Auf Debug-Reise für Entwickler
5. Tox wirklich erstellen
6. ???
Trotz der ganzen Arbeit, die wir bisher in Tox
gesteckt haben, gibt es noch keine richtige
Anleitung, wie man Tox _benutzt_.
Dies ist ein anwenderfreundlicher Versuch.
1. Verbinde dich zum Netzwerk!
+ Du musst dich zu einem Bootstrap-Server verbinden, um einen öffentlichen Schlüssel zu erhalten.
+ Wo finde ich einen öffentlichen Server? Zur Zeit hier:
(die Hilfe-Nachricht von nTox ohne Kommandos hilft auch)
+ 198.46.136.167 33445 728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854
+ 192.81.133.111 33445 8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858
+ 66.175.223.88 33445 AC4112C975240CAD260BB2FCD134266521FAAF0A5D159C5FD3201196191E4F5D
+ 192.184.81.118 33445 5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143
2. Finde einen Freund!
+ Jetzt, da du im Netzwerk bist, brauchst du einen Freund. Um einen zu bekommen,
musst du eine Anfrage senden oder erhalten. Was eine Anfrage ist?
Es ist wie eine Freundschaftsanfrage, jedoch benutzen wir unglaublich schaurige
und kryptische Nummern anstatt Namen. When nTox startet, erscheint _deine_ lange,
schaurige Nummer, auch *öffentlicher Schlüssel* genannt. Diesen kannst du an
andere Personen weitergeben und sie können dich als "Freund" hinzufügen. Oder du
fügst andere Personen mit dem */f*-Befehl hinzu, wenn du möchtest.
3. Chatte drauf los!
+ Benutze nun den */m*-Befehl, um eine Nachricht an jemanden zu senden. Wow, du chattest!
4. Mach etwas kaputt!
+ Jep, pre-alpha-alpha-Software stürzt manchmal ab. Wir arbeiten daran.
+ Bitte melde alle Abstürze entweder an die GitHub-Seite oder #tox-dev im freenode-IRC.
5. Nichts ist kaputt, aber was bedeutet */f*?
+ nTox liest einen Text als Befehl, wenn das erste Zeichen ein Schrägstrich ist ('/').
Du kannst alle Befehle in commands.md nachlesen.
6. Benutze und unterstütze Tox!
+ Programmiere, debugge, dokumentiere, übersetze für uns, oder sprich einfach über uns!
+ Je mehr Interesse wir erhalten, desto mehr Arbeit wird getan und desto besser wird Tox.

38
start_guide.md Normal file
View File

@ -0,0 +1,38 @@
# Using Tox
1. Build Tox
2. Fix errors
3. Consult IRC for help
4. Go on debugging journy for devs
5. Build Tox for real
6. ???
For all the work we've put into Tox so far,
there isn't yet a decent guide for how you _use_
Tox. Here's a user-friendly attempt at it.
1. Connect to the network!
+ You need to connect to a bootstrapping server, to give you a public key.
+ Where can I find a public server? Right here, as of now:
(the help message from running nTox with no args will help)
+ 198.46.136.167 33445 728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854
+ 192.81.133.111 33445 8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858
+ 66.175.223.88 33445 AC4112C975240CAD260BB2FCD134266521FAAF0A5D159C5FD3201196191E4F5D
+ 192.184.81.118 33445 5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143
2. Find a friend!
+ Now that you're on the network, you need a friend. To get one of those,
you need to to send or receive a request. What's a request, you ask?
It's like a friend request, but we use really scary and cryptic numbers
instead of names. When nTox starts, it shows your _your_ long, scary number,
called your *public key*. Give that to people, and they can add you as
as "friend". Or, you can add someone else, with the */f* command, if you like.
3. Chat it up!
+ Now use the */m* command to send a message to someone. Wow, you're chatting!
4. But something broke!
+ Yeah, pre-alpha-alpha software tends to do that. We're working on it.
+ Please report all crashes to either the github page, or #tox-dev on freenode.
5. Nothing broke, but what does */f* mean?
+ nTox parses text as a command if the first character is a forward-slash ('/').
You can check all commands in commands.md.
6. Use and support Tox!
+ Code for us, debug for us, document for us, translate for us, even just talk about us!
+ The more interest we get, the more work gets done, the better Tox is.

View File

@ -11,8 +11,8 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Messenger_test.cmake)
if(WIN32) if(WIN32)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/nTox_win32.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/nTox_win32.cmake)
endif() endif()
if(NOT WIN32) if(NOT WIN32)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/nTox.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/nTox.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/toxic.cmake) add_subdirectory(toxic)
endif() endif()

View File

@ -87,7 +87,7 @@ void print_friendlist()
for(i = 0; i < 4; i++) { for(i = 0; i < 4; i++) {
printf("ClientID: "); printf("ClientID: ");
for(j = 0; j < 32; j++) { for(j = 0; j < 32; j++) {
if(0 <= friends_list[k].client_list[i].client_id[j] && friends_list[k].client_list[i].client_id[j] < 16) if(friends_list[k].client_list[i].client_id[j] < 16)
printf("0"); printf("0");
printf("%hhX", friends_list[k].client_list[i].client_id[j]); printf("%hhX", friends_list[k].client_list[i].client_id[j]);
} }
@ -134,7 +134,9 @@ int main(int argc, char *argv[])
char temp_id[128]; char temp_id[128];
printf("\nEnter the client_id of the friend you wish to add (32 bytes HEX format):\n"); printf("\nEnter the client_id of the friend you wish to add (32 bytes HEX format):\n");
scanf("%s", temp_id); if(scanf("%s", temp_id) != 1)
exit(0);
DHT_addfriend(hex_string_to_bin(temp_id)); DHT_addfriend(hex_string_to_bin(temp_id));
/* initialize networking */ /* initialize networking */

View File

@ -4,6 +4,7 @@ project(DHT_cryptosendfiletest C)
set(exe_name DHT_cryptosendfiletest) set(exe_name DHT_cryptosendfiletest)
add_executable(${exe_name} add_executable(${exe_name}
DHT_cryptosendfiletest.c misc_tools.c) DHT_cryptosendfiletest.c
misc_tools.c)
linkCoreLibraries(${exe_name}) linkCoreLibraries(${exe_name})

View File

@ -4,6 +4,7 @@ project(DHT_test C)
set(exe_name DHT_test) set(exe_name DHT_test)
add_executable(${exe_name} add_executable(${exe_name}
DHT_test.c misc_tools.c) DHT_test.c
misc_tools.c)
linkCoreLibraries(${exe_name}) linkCoreLibraries(${exe_name})

View File

@ -6,6 +6,7 @@ set(exe_name nTox)
add_executable(${exe_name} add_executable(${exe_name}
nTox.c misc_tools.c) nTox.c misc_tools.c)
target_link_libraries(${exe_name} ncurses) target_link_libraries(${exe_name}
ncurses)
linkCoreLibraries(${exe_name}) linkCoreLibraries(${exe_name})

View File

@ -20,12 +20,12 @@
* along with Tox. If not, see <http://www.gnu.org/licenses/>. * along with Tox. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
#include "nTox.h" #include "nTox.h"
#include "misc_tools.h" #include "misc_tools.h"
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#ifdef WIN32 #ifdef WIN32
#define c_sleep(x) Sleep(1*x) #define c_sleep(x) Sleep(1*x)
#else #else
@ -35,10 +35,14 @@
char lines[HISTORY][STRING_LENGTH]; char lines[HISTORY][STRING_LENGTH];
char line[STRING_LENGTH]; char line[STRING_LENGTH];
char *help = "[i] commands: /f ID (to add friend), /m friendnumber message (to send message), /s status (to change status)\n"
"[i] /l list (list friends), /h for help, /i for info, /n nick (to change nickname), /q (to quit)";
int x, y; int x, y;
uint8_t pending_requests[256][CLIENT_ID_SIZE]; uint8_t pending_requests[256][CLIENT_ID_SIZE];
uint8_t num_requests; uint8_t num_requests = 0;
void new_lines(char *line) void new_lines(char *line)
{ {
@ -50,13 +54,53 @@ void new_lines(char *line)
do_refresh(); do_refresh();
} }
void print_friendlist()
{
char name[MAX_NAME_LENGTH];
new_lines("[i] Friend List:");
uint32_t i;
for (i = 0; i <= num_requests; i++) {
char fstring[128];
getname(i, (uint8_t*)name);
if (strlen(name) <= 0) {
sprintf(fstring, "[i] Friend: NULL\n\tid: %i", i);
} else {
sprintf(fstring, "[i] Friend: %s\n\tid: %i", (uint8_t*)name, i);
}
new_lines(fstring);
}
}
char *format_message(char *message, int friendnum)
{
char name[MAX_NAME_LENGTH];
if (friendnum != -1) {
getname(friendnum, (uint8_t*)name);
} else {
getself_name((uint8_t*)name);
}
char *msg = malloc(100+strlen(message)+strlen(name)+1);
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
char* time = asctime(timeinfo);
size_t len = strlen(time);
time[len-1] = '\0';
sprintf(msg, "[%d] %s <%s> %s", friendnum, time, name, message); // timestamp
return msg;
}
void line_eval(char lines[HISTORY][STRING_LENGTH], char *line) void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
{ {
if (line[0] == '/') { if (line[0] == '/') {
char command[STRING_LENGTH + 2] = "> "; char inpt_command = line[1];
strcat(command, line); char prompt[STRING_LENGTH + 2] = "> ";
new_lines(command); strcat(prompt, line);
if (line[1] == 'f') { // add friend command: /f ID new_lines(prompt);
if (inpt_command == 'f') { // add friend command: /f ID
int i; int i;
char temp_id[128]; char temp_id[128];
for (i = 0; i < 128; i++) for (i = 0; i < 128; i++)
@ -67,20 +111,20 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
new_lines(numstring); new_lines(numstring);
do_refresh(); do_refresh();
} }
else if (line[1] == 'd') { else if (inpt_command == 'd') {
doMessenger(); doMessenger();
} }
else if (line[1] == 'm') { //message command: /m friendnumber messsage else if (inpt_command == 'm') { //message command: /m friendnumber messsage
int i;
size_t len = strlen(line); size_t len = strlen(line);
char numstring[len-3]; char numstring[len-3];
char message[len-3]; char message[len-3];
int i;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (line[i+3] != ' ') { if (line[i+3] != ' ') {
numstring[i] = line[i+3]; numstring[i] = line[i+3];
} else { } else {
int j; int j;
for (j=i+1; j<len; j++) for (j = (i+1); j < len; j++)
message[j-i-1] = line[j+3]; message[j-i-1] = line[j+3];
break; break;
} }
@ -88,9 +132,11 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
int num = atoi(numstring); int num = atoi(numstring);
if (m_sendmessage(num, (uint8_t*) message, sizeof(message)) != 1) { if (m_sendmessage(num, (uint8_t*) message, sizeof(message)) != 1) {
new_lines("[i] could not send message"); new_lines("[i] could not send message");
} else {
new_lines(format_message(message, -1));
} }
} }
else if (line[1] == 'n') { else if (inpt_command == 'n') {
uint8_t name[MAX_NAME_LENGTH]; uint8_t name[MAX_NAME_LENGTH];
int i = 0; int i = 0;
size_t len = strlen(line); size_t len = strlen(line);
@ -104,7 +150,10 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
sprintf(numstring, "[i] changed nick to %s", (char*)name); sprintf(numstring, "[i] changed nick to %s", (char*)name);
new_lines(numstring); new_lines(numstring);
} }
else if (line[1] == 's') { else if (inpt_command == 'l') {
print_friendlist();
}
else if (inpt_command == 's') {
uint8_t status[MAX_USERSTATUS_LENGTH]; uint8_t status[MAX_USERSTATUS_LENGTH];
int i = 0; int i = 0;
size_t len = strlen(line); size_t len = strlen(line);
@ -118,31 +167,65 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
sprintf(numstring, "[i] changed status to %s", (char*)status); sprintf(numstring, "[i] changed status to %s", (char*)status);
new_lines(numstring); new_lines(numstring);
} }
else if (line[1] == 'a') { else if (inpt_command == 'a') {
uint8_t numf = atoi(line + 3); uint8_t numf = atoi(line + 3);
char numchar[100]; char numchar[100];
int num = m_addfriend_norequest(pending_requests[numf]);
if (num != -1) {
sprintf(numchar, "[i] friend request %u accepted", numf); sprintf(numchar, "[i] friend request %u accepted", numf);
new_lines(numchar); new_lines(numchar);
int num = m_addfriend_norequest(pending_requests[numf]);
sprintf(numchar, "[i] added friendnumber %d", num); sprintf(numchar, "[i] added friendnumber %d", num);
new_lines(numchar); new_lines(numchar);
do_refresh(); } else {
sprintf(numchar, "[i] failed to add friend");
new_lines(numchar);
} }
else if (line[1] == 'q') { //exit do_refresh();
}
else if (inpt_command == 'h') { //help
new_lines("[i] commands: /f ID (to add friend), /m friendnumber message (to send message), /s status (to change status)");
new_lines("[i] /l list (list friends), /h for help, /i for info, /n nick (to change nickname), /q (to quit)");
}
else if (inpt_command == 'i') { //info
char idstring0[200];
char idstring1[PUB_KEY_BYTES][5];
char idstring2[PUB_KEY_BYTES][5];
int i;
for (i = 0; i < PUB_KEY_BYTES; i++)
{
if (self_public_key[i] < (PUB_KEY_BYTES/2))
strcpy(idstring1[i],"0");
else
strcpy(idstring1[i], "");
sprintf(idstring2[i], "%hhX", self_public_key[i]);
}
//
strcpy(idstring0,"[i] ID: ");
int j;
for (j = 0; j < PUB_KEY_BYTES; j++) {
strcat(idstring0,idstring1[j]);
strcat(idstring0,idstring2[j]);
}
new_lines(idstring0);
}
else if (inpt_command == 'q') { //exit
endwin(); endwin();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} else {
new_lines("[i] invalid command");
} }
} else { } else {
new_lines("[i] invalid command");
//new_lines(line); //new_lines(line);
} }
} }
void wrap(char output[STRING_LENGTH], char input[STRING_LENGTH], int line_width) void wrap(char output[STRING_LENGTH], char input[STRING_LENGTH], int line_width)
{ {
int i = 0;
strcpy(output,input); strcpy(output,input);
size_t len = strlen(output); size_t len = strlen(output);
int i = 0;
for (i = line_width; i < len; i = i + line_width) { for (i = line_width; i < len; i = i + line_width) {
while (output[i] != ' ' && i != 0) { while (output[i] != ' ' && i != 0) {
i--; i--;
@ -156,8 +239,8 @@ void wrap(char output[STRING_LENGTH], char input[STRING_LENGTH], int line_width)
int count_lines(char *string) int count_lines(char *string)
{ {
size_t len = strlen(string); size_t len = strlen(string);
int i;
int count = 1; int count = 1;
int i;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (string[i] == '\n') if (string[i] == '\n')
count++; count++;
@ -177,14 +260,14 @@ char *appender(char *str, const char c)
void do_refresh() void do_refresh()
{ {
int i;
int count=0; int count=0;
int l;
char wrap_output[STRING_LENGTH]; char wrap_output[STRING_LENGTH];
int L;
int i;
for (i = 0; i < HISTORY; i++) { for (i = 0; i < HISTORY; i++) {
wrap(wrap_output, lines[i], x); wrap(wrap_output, lines[i], x);
l = count_lines(wrap_output); L = count_lines(wrap_output);
count = count + l; count = count + L;
if (count < y) { if (count < y) {
move(y-1-count, 0); move(y-1-count, 0);
printw(wrap_output); printw(wrap_output);
@ -224,10 +307,11 @@ void print_message(int friendnumber, uint8_t * string, uint16_t length)
size_t len = strlen(temp); size_t len = strlen(temp);
temp[len-1] = '\0'; temp[len-1] = '\0';
sprintf(msg, "[%d] %s <%s> %s", friendnumber, temp, name, string); // timestamp sprintf(msg, "[%d] %s <%s> %s", friendnumber, temp, name, string); // timestamp
new_lines(msg); new_lines(format_message((char*)string, friendnumber));
} }
void print_nickchange(int friendnumber, uint8_t *string, uint16_t length) { void print_nickchange(int friendnumber, uint8_t *string, uint16_t length)
{
char name[MAX_NAME_LENGTH]; char name[MAX_NAME_LENGTH];
getname(friendnumber, (uint8_t*)name); getname(friendnumber, (uint8_t*)name);
char msg[100+length]; char msg[100+length];
@ -235,7 +319,8 @@ void print_nickchange(int friendnumber, uint8_t *string, uint16_t length) {
new_lines(msg); new_lines(msg);
} }
void print_statuschange(int friendnumber, uint8_t *string, uint16_t length) { void print_statuschange(int friendnumber, uint8_t *string, uint16_t length)
{
char name[MAX_NAME_LENGTH]; char name[MAX_NAME_LENGTH];
getname(friendnumber, (uint8_t*)name); getname(friendnumber, (uint8_t*)name);
char msg[100+length+strlen(name)+1]; char msg[100+length+strlen(name)+1];
@ -243,9 +328,11 @@ void print_statuschange(int friendnumber, uint8_t *string, uint16_t length) {
new_lines(msg); new_lines(msg);
} }
void load_key(){ void load_key()
{
FILE *data_file = NULL; FILE *data_file = NULL;
if ((data_file = fopen("data","r"))) { data_file = fopen("data","r");
if (data_file) {
//load keys //load keys
fseek(data_file, 0, SEEK_END); fseek(data_file, 0, SEEK_END);
int size = ftell(data_file); int size = ftell(data_file);
@ -292,28 +379,29 @@ int main(int argc, char *argv[])
m_callback_namechange(print_nickchange); m_callback_namechange(print_nickchange);
m_callback_userstatus(print_statuschange); m_callback_userstatus(print_statuschange);
char idstring0[200]; char idstring0[200];
char idstring1[32][5]; char idstring1[PUB_KEY_BYTES][5];
char idstring2[32][5]; char idstring2[PUB_KEY_BYTES][5];
uint32_t i; int i;
for(i = 0; i < 32; i++) for(i = 0; i < PUB_KEY_BYTES; i++)
{ {
if(self_public_key[i] < 16) if (self_public_key[i] < (PUB_KEY_BYTES / 2))
strcpy(idstring1[i],"0"); strcpy(idstring1[i],"0");
else else
strcpy(idstring1[i], ""); strcpy(idstring1[i], "");
sprintf(idstring2[i], "%hhX",self_public_key[i]); sprintf(idstring2[i], "%hhX",self_public_key[i]);
} }
strcpy(idstring0,"[i] your ID: "); strcpy(idstring0,"[i] your ID: ");
for (i=0; i<32; i++) { int j;
strcat(idstring0,idstring1[i]); for (j = 0; j < PUB_KEY_BYTES; j++) {
strcat(idstring0,idstring2[i]); strcat(idstring0,idstring1[j]);
strcat(idstring0,idstring2[j]);
} }
initscr(); initscr();
noecho(); noecho();
raw(); raw();
getmaxyx(stdscr, y, x); getmaxyx(stdscr, y, x);
new_lines(idstring0); new_lines(idstring0);
new_lines("[i] commands: /f ID (to add friend), /m friendnumber message (to send message), /s status (to change status), /n nick (to change nickname), /q (to quit)"); new_lines(help);
strcpy(line, ""); strcpy(line, "");
IP_Port bootstrap_ip_port; IP_Port bootstrap_ip_port;
bootstrap_ip_port.port = htons(atoi(argv[2])); bootstrap_ip_port.port = htons(atoi(argv[2]));
@ -336,7 +424,6 @@ int main(int argc, char *argv[])
do_refresh(); do_refresh();
c = getch(); c = getch();
if (c == ERR || c == 27) if (c == ERR || c == 27)
continue; continue;

View File

@ -39,6 +39,7 @@
#include "../core/network.h" #include "../core/network.h"
#define STRING_LENGTH 256 #define STRING_LENGTH 256
#define HISTORY 50 #define HISTORY 50
#define PUB_KEY_BYTES 32
void new_lines(char *line); void new_lines(char *line);
void line_eval(char lines[HISTORY][STRING_LENGTH], char *line); void line_eval(char lines[HISTORY][STRING_LENGTH], char *line);

View File

@ -27,7 +27,7 @@
#include <process.h> #include <process.h>
uint8_t pending_requests[256][CLIENT_ID_SIZE]; uint8_t pending_requests[256][CLIENT_ID_SIZE];
uint8_t num_requests; uint8_t num_requests = 0;
char line[STRING_LENGTH]; char line[STRING_LENGTH];
char users_id[200]; char users_id[200];
@ -89,13 +89,12 @@ void print_statuschange(int friendnumber, uint8_t *string, uint16_t length)
void load_key() void load_key()
{ {
FILE *data_file = NULL; FILE *data_file = NULL;
data_file = fopen("data","r");
if ((data_file = fopen("data", "r"))) { if (data_file) {
fseek(data_file, 0, SEEK_END); fseek(data_file, 0, SEEK_END);
int size = ftell(data_file); int size = ftell(data_file);
fseek(data_file, 0, SEEK_SET); fseek(data_file, 0, SEEK_SET);
uint8_t data[size]; uint8_t data[size];
if (fread(data, sizeof(uint8_t), size, data_file) != size) { if (fread(data, sizeof(uint8_t), size, data_file) != size) {
printf("\n[i] Could not read the data file. Exiting."); printf("\n[i] Could not read the data file. Exiting.");
exit(1); exit(1);
@ -113,15 +112,15 @@ void load_key()
exit(1); exit(1);
} }
} }
fclose(data_file); fclose(data_file);
} }
void line_eval(char* line) void line_eval(char* line)
{ {
if(line[0] == '/') { if(line[0] == '/') {
char inpt_command = line[1];
/* Add friend */ /* Add friend */
if(line[1] == 'f') { if(inpt_command == 'f') {
int i; int i;
char temp_id[128]; char temp_id[128];
for (i = 0; i < 128; i++) for (i = 0; i < 128; i++)
@ -132,16 +131,15 @@ void line_eval(char* line)
printf(numstring); printf(numstring);
} }
else if (line[1] == 'r') { else if (inpt_command == 'r') {
do_header(); do_header();
printf("\n\n"); printf("\n\n");
} }
else if (line[1] == 'l') { else if (inpt_command == 'l') {
printf("\n[i] Friend List | Total: %d\n\n", getnumfriends()); printf("\n[i] Friend List | Total: %d\n\n", getnumfriends());
int i; int i;
for (i = 0; i < getnumfriends(); i++) { for (i = 0; i < getnumfriends(); i++) {
char name[MAX_NAME_LENGTH]; char name[MAX_NAME_LENGTH];
getname(i, (uint8_t*)name); getname(i, (uint8_t*)name);
@ -152,7 +150,7 @@ void line_eval(char* line)
} }
} }
else if (line[1] == 'd') { else if (inpt_command == 'd') {
size_t len = strlen(line); size_t len = strlen(line);
char numstring[len-3]; char numstring[len-3];
int i; int i;
@ -166,17 +164,17 @@ void line_eval(char* line)
printf("\n\n"); printf("\n\n");
} }
/* Send message to friend */ /* Send message to friend */
else if (line[1] == 'm') { else if (inpt_command == 'm') {
int i;
size_t len = strlen(line); size_t len = strlen(line);
char numstring[len-3]; char numstring[len-3];
char message[len-3]; char message[len-3];
int i;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (line[i+3] != ' ') { if (line[i+3] != ' ') {
numstring[i] = line[i+3]; numstring[i] = line[i+3];
} else { } else {
int j; int j;
for (j=i+1; j<len; j++) for (j = (i+1); j < len; j++)
message[j-i-1] = line[j+3]; message[j-i-1] = line[j+3];
break; break;
} }
@ -190,7 +188,7 @@ void line_eval(char* line)
} }
} }
else if (line[1] == 'n') { else if (inpt_command == 'n') {
uint8_t name[MAX_NAME_LENGTH]; uint8_t name[MAX_NAME_LENGTH];
int i = 0; int i = 0;
size_t len = strlen(line); size_t len = strlen(line);
@ -205,7 +203,7 @@ void line_eval(char* line)
printf(numstring); printf(numstring);
} }
else if (line[1] == 's') { else if (inpt_command == 's') {
uint8_t status[MAX_USERSTATUS_LENGTH]; uint8_t status[MAX_USERSTATUS_LENGTH];
int i = 0; int i = 0;
size_t len = strlen(line); size_t len = strlen(line);
@ -220,7 +218,7 @@ void line_eval(char* line)
printf(numstring); printf(numstring);
} }
else if (line[1] == 'a') { else if (inpt_command == 'a') {
uint8_t numf = atoi(line + 3); uint8_t numf = atoi(line + 3);
char numchar[100]; char numchar[100];
sprintf(numchar, "\n[i] friend request %u accepted\n\n", numf); sprintf(numchar, "\n[i] friend request %u accepted\n\n", numf);
@ -230,12 +228,10 @@ void line_eval(char* line)
printf(numchar); printf(numchar);
} }
/* EXIT */ /* EXIT */
else if (line[1] == 'q') { else if (inpt_command == 'q') {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
} } else {
else {
//nothing atm //nothing atm
} }
} }
@ -255,12 +251,10 @@ int main(int argc, char *argv[])
printf("[!] Usage: %s [IP] [port] [public_key] <nokey>\n", argv[0]); printf("[!] Usage: %s [IP] [port] [public_key] <nokey>\n", argv[0]);
exit(0); exit(0);
} }
if (initMessenger() == -1) { if (initMessenger() == -1) {
printf("initMessenger failed"); printf("initMessenger failed");
exit(0); exit(0);
} }
if (argc > 4) { if (argc > 4) {
if(strncmp(argv[4], "nokey", 6) < 0) { if(strncmp(argv[4], "nokey", 6) < 0) {
} }
@ -272,26 +266,25 @@ int main(int argc, char *argv[])
m_callback_friendmessage(print_message); m_callback_friendmessage(print_message);
m_callback_namechange(print_nickchange); m_callback_namechange(print_nickchange);
m_callback_userstatus(print_statuschange); m_callback_userstatus(print_statuschange);
char idstring1[PUB_KEY_BYTES][5];
char idstring1[32][5]; char idstring2[PUB_KEY_BYTES][5];
char idstring2[32][5]; int i;
uint32_t i; for(i = 0; i < PUB_KEY_BYTES; i++)
for(i = 0; i < 32; i++)
{ {
if(self_public_key[i] < 16) if(self_public_key[i] < (PUB_KEY_BYTES/2))
strcpy(idstring1[i],"0"); strcpy(idstring1[i],"0");
else else
strcpy(idstring1[i], ""); strcpy(idstring1[i], "");
sprintf(idstring2[i], "%hhX",self_public_key[i]); sprintf(idstring2[i], "%hhX",self_public_key[i]);
} }
strcpy(users_id,"[i] your ID: "); strcpy(users_id,"[i] your ID: ");
for (i=0; i<32; i++) { int j;
strcat(users_id,idstring1[i]); for (j = 0; j < PUB_KEY_BYTES; j++) {
strcat(users_id,idstring2[i]); strcat(users_id,idstring1[j]);
strcat(users_id,idstring2[j]);
} }
do_header(); do_header();
IP_Port bootstrap_ip_port; IP_Port bootstrap_ip_port;
bootstrap_ip_port.port = htons(atoi(argv[2])); bootstrap_ip_port.port = htons(atoi(argv[2]));
int resolved_address = resolve_addr(argv[1]); int resolved_address = resolve_addr(argv[1]);
@ -301,12 +294,9 @@ int main(int argc, char *argv[])
exit(1); exit(1);
DHT_bootstrap(bootstrap_ip_port, hex_string_to_bin(argv[3])); DHT_bootstrap(bootstrap_ip_port, hex_string_to_bin(argv[3]));
int c; int c;
int on = 0; int on = 0;
_beginthread(get_input, 0, NULL); _beginthread(get_input, 0, NULL);
while(1) { while(1) {
if (on == 1 && DHT_isconnected() == -1) { if (on == 1 && DHT_isconnected() == -1) {
printf("\n---------------------------------"); printf("\n---------------------------------");
@ -314,16 +304,13 @@ int main(int argc, char *argv[])
printf("\n---------------------------------\n\n"); printf("\n---------------------------------\n\n");
on = 0; on = 0;
} }
if (on == 0 && DHT_isconnected()) { if (on == 0 && DHT_isconnected()) {
printf("\n[i] Connected to DHT"); printf("\n[i] Connected to DHT");
printf("\n---------------------------------\n\n"); printf("\n---------------------------------\n\n");
on = 1; on = 1;
} }
doMessenger(); doMessenger();
Sleep(1); Sleep(1);
} }
return 0; return 0;
} }

View File

@ -27,6 +27,7 @@
#include "../core/network.h" #include "../core/network.h"
#define STRING_LENGTH 256 #define STRING_LENGTH 256
#define PUB_KEY_BYTES 32
void do_header(); void do_header();
void print_message(int friendnumber, uint8_t * string, uint16_t length); void print_message(int friendnumber, uint8_t * string, uint16_t length);

View File

@ -4,8 +4,12 @@ project(toxic C)
set(exe_name toxic) set(exe_name toxic)
add_executable(${exe_name} add_executable(${exe_name}
toxic/main.c toxic/prompt.c) main.c
prompt.c
friendlist.c
chat.c)
target_link_libraries(${exe_name} curses) target_link_libraries(${exe_name}
curses)
linkCoreLibraries(${exe_name}) linkCoreLibraries(${exe_name})

155
testing/toxic/chat.c Normal file
View File

@ -0,0 +1,155 @@
/*
* Toxic -- Tox Curses Client
*/
#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include "../../core/Messenger.h"
#include "../../core/network.h"
#include "windows.h"
typedef struct {
int friendnum;
char line[256];
size_t pos;
WINDOW* history;
WINDOW* linewin;
} ChatContext;
extern void fix_name(uint8_t* name);
static void chat_onMessage(ToxWindow* self, int num, uint8_t* msg, uint16_t len) {
ChatContext* ctx = (ChatContext*) self->x;
uint8_t nick[MAX_NAME_LENGTH] = {0};
if(ctx->friendnum != num)
return;
getname(num, (uint8_t*) &nick);
msg[len-1] = '\0';
nick[MAX_NAME_LENGTH-1] = '\0';
fix_name(msg);
fix_name(nick);
wattron(ctx->history, COLOR_PAIR(4));
wprintw(ctx->history, "%s: ", nick);
wattroff(ctx->history, COLOR_PAIR(4));
wprintw(ctx->history, "%s\n", msg);
self->blink = true;
}
static void chat_onNickChange(ToxWindow* self, int num, uint8_t* nick, uint16_t len) {
ChatContext* ctx = (ChatContext*) self->x;
if(ctx->friendnum != num)
return;
nick[len-1] = '\0';
fix_name(nick);
wattron(ctx->history, COLOR_PAIR(3));
wprintw(ctx->history, " * Your partner changed nick to '%s'\n", nick);
wattroff(ctx->history, COLOR_PAIR(3));
}
static void chat_onStatusChange(ToxWindow* self, int num, uint8_t* status, uint16_t len) {
}
static void chat_onKey(ToxWindow* self, int key) {
ChatContext* ctx = (ChatContext*) self->x;
if(isprint(key)) {
if(ctx->pos != sizeof(ctx->line)-1) {
ctx->line[ctx->pos++] = key;
ctx->line[ctx->pos] = '\0';
}
}
else if(key == '\n') {
wattron(ctx->history, COLOR_PAIR(1));
wprintw(ctx->history, "you: ", ctx->line);
wattroff(ctx->history, COLOR_PAIR(1));
wprintw(ctx->history, "%s\n", ctx->line);
if(m_sendmessage(ctx->friendnum, (uint8_t*) ctx->line, strlen(ctx->line)+1) < 0) {
wattron(ctx->history, COLOR_PAIR(3));
wprintw(ctx->history, " * Failed to send message.\n");
wattroff(ctx->history, COLOR_PAIR(3));
}
ctx->line[0] = '\0';
ctx->pos = 0;
}
else if(key == 0x107 || key == 0x8 || key == 0x7f) {
if(ctx->pos != 0) {
ctx->line[--ctx->pos] = '\0';
}
}
}
static void chat_onDraw(ToxWindow* self) {
int x, y;
ChatContext* ctx = (ChatContext*) self->x;
getmaxyx(self->window, y, x);
(void) x;
if(y < 3)
return;
wclear(ctx->linewin);
mvwhline(ctx->linewin, 0, 0, '_', COLS);
mvwprintw(ctx->linewin, 1, 0, "%s\n", ctx->line);
wrefresh(self->window);
}
static void chat_onInit(ToxWindow* self) {
int x, y;
ChatContext* ctx = (ChatContext*) self->x;
getmaxyx(self->window, y, x);
ctx->history = subwin(self->window, y - 4, x, 0, 0);
scrollok(ctx->history, 1);
ctx->linewin = subwin(self->window, 2, x, y - 3, 0);
}
ToxWindow new_chat(int friendnum) {
ToxWindow ret;
memset(&ret, 0, sizeof(ret));
ret.onKey = &chat_onKey;
ret.onDraw = &chat_onDraw;
ret.onInit = &chat_onInit;
ret.onMessage = &chat_onMessage;
ret.onNickChange = &chat_onNickChange;
ret.onStatusChange = &chat_onStatusChange;
snprintf(ret.title, sizeof(ret.title), "[chat %d]", friendnum);
ChatContext* x = calloc(1, sizeof(ChatContext));
x->friendnum = friendnum;
ret.x = (void*) x;
return ret;
}

166
testing/toxic/friendlist.c Normal file
View File

@ -0,0 +1,166 @@
/*
* Toxic -- Tox Curses Client
*/
#include <curses.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include "../../core/Messenger.h"
#include "../../core/network.h"
#include "windows.h"
extern int add_window(ToxWindow w);
extern int focus_window(int num);
extern ToxWindow new_chat(int friendnum);
#define MAX_FRIENDS_NUM 100
typedef struct {
uint8_t name[MAX_NAME_LENGTH];
uint8_t status[MAX_USERSTATUS_LENGTH];
int num;
int chatwin;
} friend_t;
static friend_t friends[MAX_FRIENDS_NUM];
static int num_friends = 0;
static int num_selected = 0;
void fix_name(uint8_t* name) {
// Remove all non alphanumeric characters.
uint8_t* p = name;
uint8_t* q = name;
while(*p != 0) {
if(isprint(*p)) {
*q++ = *p;
}
p++;
}
*q = 0;
}
void friendlist_onMessage(ToxWindow* self, int num, uint8_t* str, uint16_t len) {
if(num >= num_friends)
return;
if(friends[num].chatwin == -1) {
friends[num].chatwin = add_window(new_chat(num));
}
}
void friendlist_onNickChange(ToxWindow* self, int num, uint8_t* str, uint16_t len) {
if(len >= MAX_NAME_LENGTH || num >= num_friends)
return;
memcpy((char*) &friends[num].name, (char*) str, len);
friends[num].name[len] = 0;
fix_name(friends[num].name);
}
void friendlist_onStatusChange(ToxWindow* self, int num, uint8_t* str, uint16_t len) {
if(len >= MAX_USERSTATUS_LENGTH || num >= num_friends)
return;
memcpy((char*) &friends[num].status, (char*) str, len);
friends[num].status[len] = 0;
fix_name(friends[num].status);
}
int friendlist_onFriendAdded(int num) {
if(num_friends == MAX_FRIENDS_NUM)
return -1;
friends[num_friends].num = num;
getname(num, friends[num_friends].name);
strcpy((char*) friends[num_friends].name, "unknown");
strcpy((char*) friends[num_friends].status, "unknown");
friends[num_friends].chatwin = -1;
num_friends++;
return 0;
}
static void friendlist_onKey(ToxWindow* self, int key) {
if(key == KEY_UP) {
if(num_selected != 0)
num_selected--;
}
else if(key == KEY_DOWN) {
if(num_friends != 0)
num_selected = (num_selected+1) % num_friends;
}
else if(key == '\n') {
if(friends[num_selected].chatwin != -1)
return;
friends[num_selected].chatwin = add_window(new_chat(num_selected));
focus_window(friends[num_selected].chatwin);
}
}
static void friendlist_onDraw(ToxWindow* self) {
size_t i;
wclear(self->window);
if(num_friends == 0) {
wprintw(self->window, "Empty. Add some friends! :-)\n");
}
else {
wattron(self->window, COLOR_PAIR(2) | A_BOLD);
wprintw(self->window, "Open chat with.. (up/down keys, enter)\n");
wattroff(self->window, COLOR_PAIR(2) | A_BOLD);
}
wprintw(self->window, "\n");
for(i=0; i<num_friends; i++) {
if(i == num_selected) wattron(self->window, COLOR_PAIR(3));
wprintw(self->window, " [#%d] ", friends[i].num);
if(i == num_selected) wattroff(self->window, COLOR_PAIR(3));
attron(A_BOLD);
wprintw(self->window, "%s ", friends[i].name);
attroff(A_BOLD);
wprintw(self->window, "(%s)\n", friends[i].status);
}
wrefresh(self->window);
}
static void friendlist_onInit(ToxWindow* self) {
}
ToxWindow new_friendlist() {
ToxWindow ret;
memset(&ret, 0, sizeof(ret));
ret.onKey = &friendlist_onKey;
ret.onDraw = &friendlist_onDraw;
ret.onInit = &friendlist_onInit;
ret.onMessage = &friendlist_onMessage;
ret.onNickChange = &friendlist_onNickChange;
ret.onStatusChange = &friendlist_onStatusChange;
strcpy(ret.title, "[friends]");
return ret;
}

View File

@ -14,6 +14,10 @@
#include "windows.h" #include "windows.h"
extern ToxWindow new_prompt(); extern ToxWindow new_prompt();
extern ToxWindow new_friendlist();
extern int friendlist_onFriendAdded(int num);
extern int add_req(uint8_t* public_key); // XXX extern int add_req(uint8_t* public_key); // XXX
#define TOXWINDOWS_MAX_NUM 32 #define TOXWINDOWS_MAX_NUM 32
@ -25,21 +29,59 @@ static ToxWindow* prompt;
// CALLBACKS START // CALLBACKS START
void on_request(uint8_t* public_key, uint8_t* data, uint16_t length) { void on_request(uint8_t* public_key, uint8_t* data, uint16_t length) {
size_t i;
int n = add_req(public_key); int n = add_req(public_key);
wprintw(prompt->window, "\nFriend request.\nUse \"accept %d\" to accept it.\n", n); wprintw(prompt->window, "\nFriend request from:\n");
for(i=0; i<32; i++) {
wprintw(prompt->window, "%02x", public_key[i] & 0xff);
}
wprintw(prompt->window, "\n");
wprintw(prompt->window, "Use \"accept %d\" to accept it.\n", n);
for(i=0; i<w_num; i++) {
if(windows[i].onFriendRequest != NULL)
windows[i].onFriendRequest(&windows[i], public_key, data, length);
}
} }
void on_message(int friendnumber, uint8_t* string, uint16_t length) { void on_message(int friendnumber, uint8_t* string, uint16_t length) {
size_t i;
wprintw(prompt->window, "\n(message) %d: %s!\n", friendnumber, string); wprintw(prompt->window, "\n(message) %d: %s!\n", friendnumber, string);
for(i=0; i<w_num; i++) {
if(windows[i].onMessage != NULL)
windows[i].onMessage(&windows[i], friendnumber, string, length);
}
} }
void on_nickchange(int friendnumber, uint8_t* string, uint16_t length) { void on_nickchange(int friendnumber, uint8_t* string, uint16_t length) {
wprintw(prompt->window, "\n(nick) %d: %s!\n", friendnumber, string); size_t i;
wprintw(prompt->window, "\n(nickchange) %d: %s!\n", friendnumber, string);
for(i=0; i<w_num; i++) {
if(windows[i].onNickChange != NULL)
windows[i].onNickChange(&windows[i], friendnumber, string, length);
}
} }
void on_statuschange(int friendnumber, uint8_t* string, uint16_t length) { void on_statuschange(int friendnumber, uint8_t* string, uint16_t length) {
wprintw(prompt->window, "\n(status) %d: %s!\n", friendnumber, string); size_t i;
wprintw(prompt->window, "\n(statuschange) %d: %s!\n", friendnumber, string);
for(i=0; i<w_num; i++) {
if(windows[i].onStatusChange != NULL)
windows[i].onStatusChange(&windows[i], friendnumber, string, length);
}
}
void on_friendadded(int friendnumber) {
friendlist_onFriendAdded(friendnumber);
} }
// CALLBACKS END // CALLBACKS END
@ -73,7 +115,7 @@ static void init_tox() {
m_callback_userstatus(on_statuschange); m_callback_userstatus(on_statuschange);
} }
static int add_window(ToxWindow w) { int add_window(ToxWindow w) {
if(w_num == TOXWINDOWS_MAX_NUM) if(w_num == TOXWINDOWS_MAX_NUM)
return -1; return -1;
@ -88,14 +130,22 @@ static int add_window(ToxWindow w) {
windows[w_num++] = w; windows[w_num++] = w;
w.onInit(&w); w.onInit(&w);
return w_num; return w_num - 1;
}
int focus_window(int num) {
if(num >= w_num || num < 0)
return -1;
w_active = num;
return 0;
} }
static void init_windows() { static void init_windows() {
w_num = 0; w_num = 0;
w_active = 0; w_active = 0;
if(add_window(new_prompt()) == -1) { if(add_window(new_prompt()) == -1 || add_window(new_friendlist()) == -1) {
fprintf(stderr, "add_window() failed.\n"); fprintf(stderr, "add_window() failed.\n");
endwin(); endwin();
@ -134,14 +184,18 @@ static void load_data() {
if(buf == NULL) { if(buf == NULL) {
fprintf(stderr, "malloc() failed.\n"); fprintf(stderr, "malloc() failed.\n");
fclose(fd); fclose(fd);
endwin();
exit(1); exit(1);
} }
if(fread(buf, len, 1, fd) != 1){ if(fread(buf, len, 1, fd) != 1){
fprintf(stderr, "fread() failed.\n"); fprintf(stderr, "fread() failed.\n");
free(buf); free(buf);
fclose(fd); fclose(fd);
endwin();
exit(1); exit(1);
} }
@ -153,6 +207,7 @@ static void load_data() {
if(buf == NULL) { if(buf == NULL) {
fprintf(stderr, "malloc() failed.\n"); fprintf(stderr, "malloc() failed.\n");
endwin();
exit(1); exit(1);
} }
@ -161,14 +216,18 @@ static void load_data() {
fd = fopen("data", "w"); fd = fopen("data", "w");
if(fd == NULL) { if(fd == NULL) {
fprintf(stderr, "fopen() failed.\n"); fprintf(stderr, "fopen() failed.\n");
free(buf); free(buf);
endwin();
exit(1); exit(1);
} }
if(fwrite(buf, len, 1, fd) != 1){ if(fwrite(buf, len, 1, fd) != 1){
fprintf(stderr, "fwrite() failed.\n"); fprintf(stderr, "fwrite() failed.\n");
free(buf); free(buf);
fclose(fd); fclose(fd);
endwin();
exit(1); exit(1);
} }
} }
@ -178,6 +237,7 @@ static void load_data() {
} }
static void draw_bar() { static void draw_bar() {
static int odd = 0;
size_t i; size_t i;
attron(COLOR_PAIR(4)); attron(COLOR_PAIR(4));
@ -186,13 +246,27 @@ static void draw_bar() {
move(LINES - 1, 0); move(LINES - 1, 0);
attron(COLOR_PAIR(4) | A_BOLD);
printw(" TOXIC 1.0 |");
attroff(COLOR_PAIR(4) | A_BOLD);
for(i=0; i<w_num; i++) { for(i=0; i<w_num; i++) {
if(i == w_active) { if(i == w_active) {
attron(A_BOLD); attron(A_BOLD);
} }
odd = (odd+1) % 2;
if(windows[i].blink && odd) {
attron(COLOR_PAIR(3));
}
printw(" %s", windows[i].title); printw(" %s", windows[i].title);
if(windows[i].blink && odd) {
attron(COLOR_PAIR(3));
}
if(i == w_active) { if(i == w_active) {
attroff(A_BOLD); attroff(A_BOLD);
} }
@ -201,6 +275,11 @@ static void draw_bar() {
refresh(); refresh();
} }
void prepare_window(WINDOW* w) {
mvwin(w, 0, 0);
wresize(w, LINES-2, COLS);
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
int ch; int ch;
ToxWindow* a; ToxWindow* a;
@ -211,14 +290,22 @@ int main(int argc, char* argv[]) {
init_windows(); init_windows();
while(true) { while(true) {
// Update tox.
do_tox(); do_tox();
// Draw.
a = &windows[w_active]; a = &windows[w_active];
prepare_window(a->window);
a->blink = false;
a->onDraw(a); a->onDraw(a);
draw_bar(); draw_bar();
// Handle input.
ch = getch(); ch = getch();
if(ch != ERR) { if(ch == '\t') {
w_active = (w_active + 1) % w_num;
}
else if(ch != ERR) {
a->onKey(a, ch); a->onKey(a, ch);
} }

View File

@ -15,6 +15,8 @@
uint8_t pending_requests[256][CLIENT_ID_SIZE]; // XXX uint8_t pending_requests[256][CLIENT_ID_SIZE]; // XXX
uint8_t num_requests=0; // XXX uint8_t num_requests=0; // XXX
extern void on_friendadded(int friendnumber);
// XXX: // XXX:
int add_req(uint8_t* public_key) { int add_req(uint8_t* public_key) {
memcpy(pending_requests[num_requests], public_key, CLIENT_ID_SIZE); memcpy(pending_requests[num_requests], public_key, CLIENT_ID_SIZE);
@ -40,8 +42,7 @@ static int prompt_buf_pos=0;
static void execute(ToxWindow* self, char* cmd) { static void execute(ToxWindow* self, char* cmd) {
// quit/exit: Exit program. if(!strcmp(cmd, "quit") || !strcmp(cmd, "exit") || !strcmp(cmd, "q")) {
if(!strcmp(cmd, "quit") || !strcmp(cmd, "exit")) {
endwin(); endwin();
exit(0); exit(0);
} }
@ -53,33 +54,32 @@ static void execute(ToxWindow* self, char* cmd) {
ip = strchr(cmd, ' '); ip = strchr(cmd, ' ');
if(ip == NULL) { if(ip == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return; return;
} }
ip++; ip++;
port = strchr(ip, ' '); port = strchr(ip, ' ');
if(port == NULL) { if(port == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return; return;
} }
port[0] = 0; port[0] = 0;
port++; port++;
key = strchr(port, ' '); key = strchr(port, ' ');
if(key == NULL) { if(key == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return; return;
} }
key[0] = 0; key[0] = 0;
key++; key++;
if(atoi(port) == 0) { if(atoi(port) == 0) {
wprintw(self->window, "Invalid syntax.\n");
return; return;
} }
wprintw(self->window, "ip=%s, port=%s, key=%s\n", ip, port, key);
dht.port = htons(atoi(port)); dht.port = htons(atoi(port));
int resolved_address = resolve_addr(ip); int resolved_address = resolve_addr(ip);
@ -91,38 +91,62 @@ static void execute(ToxWindow* self, char* cmd) {
DHT_bootstrap(dht, hex_string_to_bin(key)); DHT_bootstrap(dht, hex_string_to_bin(key));
} }
else if(!strncmp(cmd, "add ", strlen("add "))) { else if(!strncmp(cmd, "add ", strlen("add "))) {
uint8_t id_bin[32];
size_t i;
char xx[3];
uint32_t x;
char* id; char* id;
char* msg; char* msg;
int num; int num;
id = strchr(cmd, ' '); id = strchr(cmd, ' ');
if(id == NULL) { if(id == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return; return;
} }
id++; id++;
msg = strchr(id, ' '); msg = strchr(id, ' ');
if(msg == NULL) { if(msg != NULL) {
msg[0] = 0;
msg++;
}
else msg = "";
if(strlen(id) != 2*32) {
wprintw(self->window, "Invalid ID length.\n");
return; return;
} }
msg[0] = 0; for(i=0; i<32; i++) {
msg++; xx[0] = id[2*i];
xx[1] = id[2*i+1];
xx[2] = '\0';
if(sscanf(xx, "%02x", &x) != 1) {
wprintw(self->window, "Invalid ID.\n");
return;
}
id_bin[i] = x;
}
num = m_addfriend(id_bin, (uint8_t*) msg, strlen(msg)+1);
num = m_addfriend((uint8_t*) id, (uint8_t*) msg, strlen(msg)+1);
wprintw(self->window, "Friend added as %d.\n", num); wprintw(self->window, "Friend added as %d.\n", num);
on_friendadded(num);
} }
else if(!strncmp(cmd, "status ", strlen("status "))) { else if(!strncmp(cmd, "status ", strlen("status "))) {
char* msg; char* msg;
msg = strchr(cmd, ' '); msg = strchr(cmd, ' ');
if(msg == NULL) { if(msg == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return; return;
} }
msg++; msg++;
m_set_userstatus((uint8_t*) msg, strlen(msg)+1); m_set_userstatus((uint8_t*) msg, strlen(msg)+1);
wprintw(self->window, "Status set to: %s.\n", msg); wprintw(self->window, "Status set to: %s.\n", msg);
} }
@ -133,33 +157,22 @@ static void execute(ToxWindow* self, char* cmd) {
if(nick == NULL) { if(nick == NULL) {
return; return;
} }
nick++; nick++;
setname((uint8_t*) nick, strlen(nick)+1); setname((uint8_t*) nick, strlen(nick)+1);
wprintw(self->window, "Nickname set to: %s.\n", nick); wprintw(self->window, "Nickname set to: %s.\n", nick);
} }
else if(!strcmp(cmd, "myid")) { else if(!strcmp(cmd, "myid")) {
// XXX: Clean this up char id[32*2 + 1] = {0};
char idstring0[200]; size_t i;
char idstring1[32][5];
char idstring2[32][5];
uint32_t i;
for(i=0; i<32; i++) { for(i=0; i<32; i++) {
if(self_public_key[i] < 16) char xx[3];
strcpy(idstring1[i], "0"); snprintf(xx, sizeof(xx), "%02x", self_public_key[i] & 0xff);
else strcat(id, xx);
strcpy(idstring1[i], "");
sprintf(idstring2[i], "%hhX", self_public_key[i]);
} }
for (i=0; i<32; i++) { wprintw(self->window, "%s\n", id);
strcat(idstring0, idstring1[i]);
strcat(idstring0, idstring2[i]);
}
wprintw(self->window, "%s\n", idstring0);
} }
else if(!strncmp(cmd, "accept ", strlen("accept "))) { else if(!strncmp(cmd, "accept ", strlen("accept "))) {
char* id; char* id;
@ -167,17 +180,26 @@ static void execute(ToxWindow* self, char* cmd) {
id = strchr(cmd, ' '); id = strchr(cmd, ' ');
if(id == NULL) { if(id == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return; return;
} }
id++; id++;
num = atoi(id); num = atoi(id);
if(num >= num_requests) { if(num >= num_requests) {
wprintw(self->window, "Invalid syntax.\n");
return; return;
} }
num = m_addfriend_norequest(pending_requests[num]); num = m_addfriend_norequest(pending_requests[num]);
if(num == -1) {
wprintw(self->window, "Failed to add friend.\n");
}
else {
wprintw(self->window, "Friend accepted as: %d.\n", num); wprintw(self->window, "Friend accepted as: %d.\n", num);
on_friendadded(num);
}
} }
else if(!strncmp(cmd, "msg ", strlen("msg "))) { else if(!strncmp(cmd, "msg ", strlen("msg "))) {
char* id; char* id;
@ -186,26 +208,29 @@ static void execute(ToxWindow* self, char* cmd) {
id = strchr(cmd, ' '); id = strchr(cmd, ' ');
if(id == NULL) { if(id == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return; return;
} }
id++; id++;
msg = strchr(id, ' '); msg = strchr(id, ' ');
if(msg == NULL) { if(msg == NULL) {
wprintw(self->window, "Invalid syntax.\n");
return; return;
} }
msg[0] = 0; msg[0] = 0;
msg++; msg++;
if(m_sendmessage(atoi(id), (uint8_t*) msg, strlen(msg)+1) != 1) { if(m_sendmessage(atoi(id), (uint8_t*) msg, strlen(msg)+1) < 0) {
wprintw(self->window, "Error occurred while sending message.\n"); wprintw(self->window, "Error occurred while sending message.\n");
} }
else { else {
wprintw(self->window, "Message successfully sent.\n"); wprintw(self->window, "Message successfully sent.\n");
} }
} }
else {
wprintw(self->window, "Invalid syntax.\n");
}
} }
static void prompt_onKey(ToxWindow* self, int key) { static void prompt_onKey(ToxWindow* self, int key) {
@ -231,7 +256,7 @@ static void prompt_onKey(ToxWindow* self, int key) {
} }
// BACKSPACE key: Remove one character from line. // BACKSPACE key: Remove one character from line.
else if(key == 0x107) { else if(key == 0x107 || key == 0x8 || key == 0x7f) {
if(prompt_buf_pos != 0) { if(prompt_buf_pos != 0) {
prompt_buf[--prompt_buf_pos] = 0; prompt_buf[--prompt_buf_pos] = 0;
@ -242,9 +267,6 @@ static void prompt_onKey(ToxWindow* self, int key) {
static void prompt_onDraw(ToxWindow* self) { static void prompt_onDraw(ToxWindow* self) {
int x, y; int x, y;
mvwin(self->window,0,0);
wresize(self->window, LINES-2, COLS);
getyx(self->window, y, x); getyx(self->window, y, x);
(void) x; (void) x;
@ -260,7 +282,7 @@ static void prompt_onDraw(ToxWindow* self) {
static void print_usage(ToxWindow* self) { static void print_usage(ToxWindow* self) {
wattron(self->window, COLOR_PAIR(2) | A_BOLD); wattron(self->window, COLOR_PAIR(2) | A_BOLD);
wprintw(self->window, "Usage:\n"); wprintw(self->window, "Commands:\n");
wattroff(self->window, A_BOLD); wattroff(self->window, A_BOLD);
wprintw(self->window, " connect <ip> <port> <key> : Connect to DHT server\n"); wprintw(self->window, " connect <ip> <port> <key> : Connect to DHT server\n");
@ -270,6 +292,12 @@ static void print_usage(ToxWindow* self) {
wprintw(self->window, " accept <number> : Accept friend request\n"); wprintw(self->window, " accept <number> : Accept friend request\n");
wprintw(self->window, " myid : Print your ID\n"); wprintw(self->window, " myid : Print your ID\n");
wprintw(self->window, " quit/exit : Exit program\n"); wprintw(self->window, " quit/exit : Exit program\n");
wattron(self->window, A_BOLD);
wprintw(self->window, "TIP: Use the TAB key to navigate through the tabs.\n\n");
wattroff(self->window, A_BOLD);
wattroff(self->window, COLOR_PAIR(2)); wattroff(self->window, COLOR_PAIR(2));
} }
@ -283,6 +311,8 @@ static void prompt_onInit(ToxWindow* self) {
ToxWindow new_prompt() { ToxWindow new_prompt() {
ToxWindow ret; ToxWindow ret;
memset(&ret, 0, sizeof(ret));
ret.onKey = &prompt_onKey; ret.onKey = &prompt_onKey;
ret.onDraw = &prompt_onDraw; ret.onDraw = &prompt_onDraw;
ret.onInit = &prompt_onInit; ret.onInit = &prompt_onInit;

View File

@ -1,10 +1,23 @@
/*
* Toxic -- Tox Curses Client
*/
#include <stdbool.h>
typedef struct ToxWindow_ ToxWindow; typedef struct ToxWindow_ ToxWindow;
struct ToxWindow_ { struct ToxWindow_ {
void(*onKey)(ToxWindow*, int); void(*onKey)(ToxWindow*, int);
void(*onDraw)(ToxWindow*); void(*onDraw)(ToxWindow*);
void(*onInit)(ToxWindow*); void(*onInit)(ToxWindow*);
void(*onFriendRequest)(ToxWindow*, uint8_t*, uint8_t*, uint16_t);
void(*onMessage)(ToxWindow*, int, uint8_t*, uint16_t);
void(*onNickChange)(ToxWindow*, int, uint8_t*, uint16_t);
void(*onStatusChange)(ToxWindow*, int, uint8_t*, uint16_t);
char title[256]; char title[256];
void* x;
bool blink;
WINDOW* window; WINDOW* window;
}; };