Add custom user statuses to core, updated nTox to support nicknames and user statuses.

This commit is contained in:
Sebastian Stal 2013-07-18 10:56:50 -07:00
parent 7611ca810f
commit b190dc6fbe
4 changed files with 209 additions and 30 deletions

View File

@ -1,7 +1,7 @@
/* Messenger.c
*
*
* An implementation of a simple text chat only messenger on the tox network core.
*
*
Copyright (C) 2013 Tox project All Rights Reserved.
@ -23,8 +23,7 @@
*/
#include "Messenger.h"
#define MAX_NAME_LENGTH 128
#define MIN(a,b) (((a)<(b))?(a):(b))
typedef struct
{
@ -35,6 +34,9 @@ typedef struct
uint8_t info[MAX_DATA_SIZE]; //the data that is sent during the friend requests we do
uint8_t name[MAX_NAME_LENGTH];
uint8_t name_sent;//0 if we didn't send our name to this friend 1 if we have.
uint8_t *userstatus;
uint16_t userstatus_length;
uint8_t userstatus_sent;
uint16_t info_size; //length of the info
}Friend;
@ -43,6 +45,8 @@ typedef struct
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
static uint8_t self_name[MAX_NAME_LENGTH];
static uint8_t *self_userstatus;
static uint16_t self_userstatus_len;
#define MAX_NUM_FRIENDS 256
@ -102,7 +106,7 @@ int getclient_id(int friend_id, uint8_t * client_id)
//return -1 if failure.
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))
{
return -1;
@ -125,7 +129,8 @@ int m_addfriend(uint8_t * client_id, uint8_t * data, uint16_t length)
friendlist[i].crypt_connection_id = -1;
friendlist[i].friend_request_id = -1;
memcpy(friendlist[i].client_id, client_id, CLIENT_ID_SIZE);
friendlist[i].userstatus = calloc(1, 1);
friendlist[i].userstatus_length = 1;
memcpy(friendlist[i].info, data, length);
friendlist[i].info_size = length;
@ -152,6 +157,8 @@ int m_addfriend_norequest(uint8_t * client_id)
friendlist[i].crypt_connection_id = -1;
friendlist[i].friend_request_id = -1;
memcpy(friendlist[i].client_id, client_id, CLIENT_ID_SIZE);
friendlist[i].userstatus = calloc(1, 1);
friendlist[i].userstatus_length = 1;
numfriends++;
return i;
}
@ -171,6 +178,7 @@ int m_delfriend(int friendnumber)
DHT_delfriend(friendlist[friendnumber].client_id);
crypto_kill(friendlist[friendnumber].crypt_connection_id);
free(friendlist[friendnumber].userstatus);
memset(&friendlist[friendnumber], 0, sizeof(Friend));
uint32_t i;
for(i = numfriends; i != 0; i--)
@ -212,7 +220,7 @@ int m_sendmessage(int friendnumber, uint8_t * message, uint32_t length)
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.
{
return 0;
return 0;
}
uint8_t temp[MAX_DATA_SIZE];
temp[0] = 64;
@ -278,6 +286,72 @@ int getname(int friendnumber, uint8_t * name)
return 0;
}
int m_set_userstatus(uint8_t *status, uint16_t length)
{
if(length > MAX_USERSTATUS_LENGTH)
{
return -1;
}
uint8_t *newstatus = calloc(length, 1);
memcpy(newstatus, status, length);
free(self_userstatus);
self_userstatus = newstatus;
self_userstatus_len = length;
uint32_t i;
for(i = 0; i < numfriends; i++)
{
friendlist[i].userstatus_sent = 0;
}
return 0;
}
// return the size of friendnumber's user status
// guaranteed to be at most MAX_USERSTATUS_LENGTH
int m_get_userstatus_size(int friendnumber)
{
if(friendnumber >= numfriends || friendnumber < 0)
{
return -1;
}
return friendlist[friendnumber].userstatus_length;
}
// copy the user status of friendnumber into buf, truncating if needed to maxlen
// bytes, use m_get_userstatus_size to find out how much you need to allocate
int m_copy_userstatus(int friendnumber, uint8_t * buf, uint32_t maxlen)
{
if(friendnumber >= numfriends || friendnumber < 0)
{
return -1;
}
memset(buf, 0, 1);
memcpy(buf, friendlist[friendnumber].userstatus, MIN(maxlen, MAX_USERSTATUS_LENGTH) - 1);
return 0;
}
static int send_userstatus(int friendnumber, uint8_t * status, uint16_t length)
{
uint8_t *thepacket = malloc(length + 1);
memcpy(thepacket + 1, status, length);
thepacket[0] = 70;
return write_cryptpacket(friendlist[friendnumber].crypt_connection_id, thepacket, length + 1);
}
static int set_friend_userstatus(int friendnumber, uint8_t * status, uint16_t length)
{
if(friendnumber >= numfriends || friendnumber < 0)
{
return -1;
}
uint8_t *newstatus = calloc(length, 1);
memcpy(newstatus, status, length);
free(friendlist[friendnumber].userstatus);
friendlist[friendnumber].userstatus = newstatus;
friendlist[friendnumber].userstatus_length = length;
return 0;
}
static void (*friend_request)(uint8_t *, uint8_t *, uint16_t);
//set the function that will be executed when a friend request is received.
@ -296,11 +370,24 @@ void m_callback_friendmessage(void (*function)(int, uint8_t *, uint16_t))
}
static void (*friend_namechange)(int, uint8_t *, uint16_t);
void m_callback_namechange(void (*function)(int, uint8_t *, uint16_t))
{
friend_namechange = function;
}
static void (*friend_statuschange)(int, uint8_t *, uint16_t);
void m_callback_userstatus(void (*function)(int, uint8_t *, uint16_t))
{
friend_statuschange = function;
}
#define PORT 33445
//run this at startup
void initMessenger()
{
new_keys();
m_set_userstatus((uint8_t*)"Online", sizeof("Online"));
initNetCrypto();
IP ip;
ip.i = 0;
@ -321,7 +408,7 @@ static void doFriends()
//printf("\n%u %u %u\n", friendip.ip.i, request, friendlist[i].friend_request_id);
if(friendip.ip.i > 1 && request == -1)
{
friendlist[i].friend_request_id = send_friendrequest(friendlist[i].client_id,
friendlist[i].friend_request_id = send_friendrequest(friendlist[i].client_id,
friendip, friendlist[i].info, friendlist[i].info_size);
friendlist[i].status = 2;
}
@ -356,19 +443,37 @@ static void doFriends()
friendlist[i].name_sent = 1;
}
}
if(friendlist[i].userstatus_sent == 0)
{
if(send_userstatus(i, self_userstatus, self_userstatus_len))
{
friendlist[i].userstatus_sent = 1;
}
}
len = read_cryptpacket(friendlist[i].crypt_connection_id, temp);
if(len > 0)
{
if(temp[0] == 48 && len == MAX_NAME_LENGTH + 1)//Username
{
memcpy(friendlist[i].name, temp + 1, MAX_NAME_LENGTH);
friendlist[i].name[MAX_NAME_LENGTH - 1] = 0;//make sure the NULL terminator is present.
}
else
if(temp[0] == 64)//Chat message
{
(*friend_message)(i, temp + 1, len - 1);
}
switch(temp[0]) {
case 48: {
if (len != MAX_NAME_LENGTH + 1) break;
friend_namechange(i, temp + 1, MAX_NAME_LENGTH); // todo: use the actual length
memcpy(friendlist[i].name, temp + 1, MAX_NAME_LENGTH);
friendlist[i].name[MAX_NAME_LENGTH - 1] = 0;//make sure the NULL terminator is present.
break;
}
case 64: {
(*friend_message)(i, temp + 1, len - 1);
break;
}
case 70: {
uint8_t *status = calloc(MIN(len - 1, MAX_USERSTATUS_LENGTH), 1);
memcpy(status, temp + 1, MIN(len - 1, MAX_USERSTATUS_LENGTH));
friend_statuschange(i, status, MIN(len - 1, MAX_USERSTATUS_LENGTH));
set_friend_userstatus(i, status, MIN(len - 1, MAX_USERSTATUS_LENGTH));
free(status);
break;
}
}
}
else
{
@ -410,7 +515,7 @@ static void doInbound()
if(friend_id != -1)
{
crypto_kill(friendlist[friend_id].crypt_connection_id);
friendlist[friend_id].crypt_connection_id =
friendlist[friend_id].crypt_connection_id =
accept_crypto_inbound(inconnection, public_key, secret_nonce, session_key);
friendlist[friend_id].status = 3;
@ -520,7 +625,9 @@ int Messenger_load(uint8_t * data, uint32_t length)
uint32_t i;
for(i = 0; i < num; i++)
{
setfriendname(m_addfriend_norequest(temp[i].client_id), temp[i].name);
int fnum = m_addfriend_norequest(temp[i].client_id);
setfriendname(fnum, temp[i].name);
set_friend_userstatus(fnum, temp[i].userstatus, temp[i].userstatus_length);
}
free(temp);
return 0;

View File

@ -1,7 +1,7 @@
/* Messenger.h
*
*
* An implementation of a simple text chat only messenger on the tox network core.
*
*
* NOTE: All the text in the messages must be encoded using UTF-8
Copyright (C) 2013 Tox project All Rights Reserved.
@ -24,12 +24,16 @@
*/
#ifndef MESSENGER_H
#define MESSENGER_H
#ifndef MESSENGER_H
#define MESSENGER_H
#include "net_crypto.h"
#include "DHT.h"
#define MAX_NAME_LENGTH 128
#define MAX_USERSTATUS_LENGTH 128
// don't assume MAX_USERSTATUS_LENGTH will stay at 128, it may be increased
// to an absurdly large number later
//add a friend
//set the data that will be sent along with friend request
@ -85,6 +89,20 @@ int setname(uint8_t * name, uint16_t length);
//return -1 if failure
int getname(int friendnumber, uint8_t * name);
// set our user status
// you are responsible for freeing status after
// returns 0 on success, -1 on failure
int m_set_userstatus(uint8_t *status, uint16_t length);
// return the length of friendnumber's user status,
// including null
// pass it into malloc
int m_get_userstatus_size(int friendnumber);
// copy friendnumber's userstatus into buf, truncating if size is over maxlen
// get the size you need to allocate from m_get_userstatus_size
int m_copy_userstatus(int friendnumber, uint8_t * buf, uint32_t maxlen);
//set the function that will be executed when a friend request is received.
//function format is function(uint8_t * public_key, uint8_t * data, uint16_t length)
void m_callback_friendrequest(void (*function)(uint8_t *, uint8_t *, uint16_t));
@ -94,6 +112,15 @@ void m_callback_friendrequest(void (*function)(uint8_t *, uint8_t *, uint16_t));
//function format is: function(int friendnumber, uint8_t * message, uint32_t length)
void m_callback_friendmessage(void (*function)(int, uint8_t *, uint16_t));
// set the callback for name changes
// function(int friendnumber, uint8_t *newname, uint16_t length)
// you are not responsible for freeing newname
void m_callback_namechange(void (*function)(int, uint8_t *, uint16_t));
// set the callback for user status changes
// function(int friendnumber, uint8_t *newstatus, uint16_t length)
// you are not responsible for freeing newstatus
void m_callback_userstatus(void (*function)(int, uint8_t *, uint16_t));
//run this at startup
void initMessenger();

View File

@ -2,8 +2,8 @@ Protocol for messages, data, etc..
Streaming audio/video will not use this protocol as they can absorb some data loss.
The protocol itself will run on top of the encryption which means it should be
impossible for someone to know what type of data is being transmitted.(Well they
The protocol itself will run on top of the encryption which means it should be
impossible for someone to know what type of data is being transmitted.(Well they
could just analyze how much data is being transmitted for a pretty good guess)
Because it runs on the encryption which itself runs on our Lossless UDP protocol
@ -29,4 +29,4 @@ ids 0 to 16 are reserved.
64 Chat message
6? File transmission.
70 Status change

View File

@ -72,6 +72,30 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line)
}
int num = atoi(numstring);
m_sendmessage(num, (uint8_t*) message, sizeof(message));
} else if (line[1] == 'n') {
uint8_t name[MAX_NAME_LENGTH];
int i = 0;
for (i=3; i<strlen(line); i++) {
if (line[i] == 0 || line[i] == '\n') break;
name[i - 3] = line[i];
}
name[i - 3] = 0;
setname(name, i);
char numstring[100];
sprintf(numstring, "Changed nick to: %s", (char*)name);
new_lines(numstring);
} else if (line[1] == 's') {
uint8_t status[MAX_USERSTATUS_LENGTH];
int i = 0;
for (i=3; i<strlen(line); i++) {
if (line[i] == 0 || line[i] == '\n') break;
status[i - 3] = line[i];
}
status[i - 3] = 0;
m_set_userstatus(status, strlen((char*)status));
char numstring[100];
sprintf(numstring, "Changed status to: %s", (char*)status);
new_lines(numstring);
} else if (line[1] == 'q') { //exit
endwin();
exit(EXIT_SUCCESS);
@ -81,7 +105,7 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *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);
@ -95,7 +119,7 @@ void wrap(char output[STRING_LENGTH], char input[STRING_LENGTH], int line_width)
}
}
int count_lines(char *string)
int count_lines(char *string)
{
int len = strlen(string);
int i;
@ -158,8 +182,27 @@ void print_request(uint8_t * public_key, uint8_t * data, uint16_t length)
}
void print_message(int friendnumber, uint8_t * string, uint16_t length)
{
char *name = malloc(MAX_NAME_LENGTH);
getname(friendnumber, (uint8_t*)name);
char msg[100+length+strlen(name)+1];
sprintf(msg, "[%d] <%s> %s", friendnumber, name, string);
free(name);
new_lines(msg);
}
void print_nickchange(int friendnumber, uint8_t *string, uint16_t length) {
char *name = malloc(MAX_NAME_LENGTH);
getname(friendnumber, (uint8_t*)name);
char msg[100+length];
sprintf(msg, "Message [%d]: %s", friendnumber, string);
sprintf(msg, "[%d] %s is now known as %s.", friendnumber, name, string);
free(name);
new_lines(msg);
}
void print_statuschange(int friendnumber, uint8_t *string, uint16_t length) {
char *name = malloc(MAX_NAME_LENGTH);
getname(friendnumber, (uint8_t*)name);
char msg[100+length+strlen(name)+1];
sprintf(msg, "[%d] %s's status changed to %s.", friendnumber, name, string);
free(name);
new_lines(msg);
}
int main(int argc, char *argv[])
@ -173,6 +216,8 @@ int main(int argc, char *argv[])
initMessenger();
m_callback_friendrequest(print_request);
m_callback_friendmessage(print_message);
m_callback_namechange(print_nickchange);
m_callback_userstatus(print_statuschange);
char idstring0[200];
char idstring1[32][5];
char idstring2[32][5];