You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
299 lines
8.3 KiB
299 lines
8.3 KiB
3 years ago
|
#include <ctype.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include <libconfig.h>
|
||
|
#include <sodium/utils.h>
|
||
|
#include <tox/tox.h>
|
||
|
|
||
|
#include "misc.h"
|
||
|
#include "commands.h"
|
||
|
|
||
|
typedef struct DHT_node {
|
||
|
const char *ip;
|
||
|
uint16_t port;
|
||
|
const char key_hex[TOX_PUBLIC_KEY_SIZE*2 + 1];
|
||
|
} DHT_node;
|
||
|
|
||
|
const char *SAVEDATA_FILENAME = "savedata.tox";
|
||
|
const char *SAVEDATA_TMP_FILENAME = "savedata.tox.tmp";
|
||
|
const char *MASTERLIST_FILE = "masterkeys.txt";
|
||
|
const char *CFG_FILE = "bot.cfg";
|
||
|
|
||
|
/* -------------------------------------------------------------------------- */
|
||
|
|
||
|
Tox *create_tox()
|
||
|
{
|
||
|
Tox *tox;
|
||
|
|
||
|
struct Tox_Options options;
|
||
|
|
||
|
tox_options_default(&options);
|
||
|
|
||
|
FILE *f = fopen(SAVEDATA_FILENAME, "rb");
|
||
|
if (f) {
|
||
|
fseek(f, 0, SEEK_END);
|
||
|
long fsize = ftell(f);
|
||
|
fseek(f, 0, SEEK_SET);
|
||
|
|
||
|
uint8_t *savedata = malloc(fsize);
|
||
|
|
||
|
fread(savedata, fsize, 1, f);
|
||
|
fclose(f);
|
||
|
|
||
|
options.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
|
||
|
options.savedata_data = savedata;
|
||
|
options.savedata_length = fsize;
|
||
|
|
||
|
tox = tox_new(&options, NULL);
|
||
|
|
||
|
free(savedata);
|
||
|
} else {
|
||
|
tox = tox_new(&options, NULL);
|
||
|
}
|
||
|
|
||
|
return tox;
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------------- */
|
||
|
|
||
|
int config_tox(Tox *tox)
|
||
|
{
|
||
|
config_t cfg;
|
||
|
config_setting_t *setting;
|
||
|
const char *str;
|
||
|
|
||
|
config_init(&cfg);
|
||
|
|
||
|
if (!config_read_file(&cfg, CFG_FILE)) {
|
||
|
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
|
||
|
config_error_line(&cfg), config_error_text(&cfg));
|
||
|
config_destroy(&cfg);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
const char *name;
|
||
|
|
||
|
if (config_lookup_string(&cfg, "Tox_Bot_Name", &str)) {
|
||
|
printf("Tox bot name: %s\n", str);
|
||
|
name = str;
|
||
|
}
|
||
|
else {
|
||
|
name = "Tox Bot test";
|
||
|
fprintf(stderr, "No 'Tox_Bot_Name' setting in configuration file. ");
|
||
|
printf("The default name is used\n");
|
||
|
}
|
||
|
|
||
|
const char *status_message;
|
||
|
|
||
|
if (config_lookup_string(&cfg, "Tox_Bot_Status", &str)) {
|
||
|
printf("Tox bot status: %s\n", str);
|
||
|
status_message = str;
|
||
|
}
|
||
|
else {
|
||
|
status_message = "Hello, World!";
|
||
|
fprintf(stderr, "No 'Tox_Bot_Status' setting in configuration file. ");
|
||
|
printf("The default status is used\n");
|
||
|
}
|
||
|
|
||
|
tox_self_set_name(tox, name, strlen(name), NULL);
|
||
|
|
||
|
tox_self_set_status_message(tox, status_message, strlen(status_message), NULL);
|
||
|
|
||
|
config_destroy(&cfg);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int write_conf(Tox *tox, uint8_t *name, uint8_t *status_message)
|
||
|
{
|
||
|
config_t cfg;
|
||
|
config_setting_t *setting;
|
||
|
const char *str;
|
||
|
|
||
|
config_init(&cfg);
|
||
|
|
||
|
if (!config_read_file(&cfg, CFG_FILE)) {
|
||
|
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
|
||
|
config_error_line(&cfg), config_error_text(&cfg));
|
||
|
config_destroy(&cfg);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
if (name != NULL) {
|
||
|
setting = config_lookup(&cfg, "Tox_Bot_Name");
|
||
|
config_setting_set_string(setting, name);
|
||
|
}
|
||
|
|
||
|
if (status_message != NULL) {
|
||
|
setting = config_lookup(&cfg, "Tox_Bot_Status");
|
||
|
config_setting_set_string(setting, status_message);
|
||
|
}
|
||
|
|
||
|
if(! config_write_file(&cfg, CFG_FILE))
|
||
|
{
|
||
|
fprintf(stderr, "Error while writing file.\n");
|
||
|
config_destroy(&cfg);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
config_destroy(&cfg);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------------- */
|
||
|
|
||
|
void update_savedata_file(const Tox *tox)
|
||
|
{
|
||
|
size_t size = tox_get_savedata_size(tox);
|
||
|
uint8_t *savedata = malloc(size);
|
||
|
tox_get_savedata(tox, savedata);
|
||
|
|
||
|
FILE *f = fopen(SAVEDATA_TMP_FILENAME, "wb");
|
||
|
fwrite(savedata, size, 1, f);
|
||
|
fclose(f);
|
||
|
|
||
|
rename(SAVEDATA_TMP_FILENAME, SAVEDATA_FILENAME);
|
||
|
|
||
|
free(savedata);
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------------- */
|
||
|
|
||
|
void bootstrap(Tox *tox)
|
||
|
{
|
||
|
DHT_node nodes[] =
|
||
|
{
|
||
|
{"85.143.221.42", 33445, "DA4E4ED4B697F2E9B000EEFE3A34B554ACD3F45F5C96EAEA2516DD7FF9AF7B43"},
|
||
|
{"2a04:ac00:1:9f00:5054:ff:fe01:becd", 33445, "DA4E4ED4B697F2E9B000EEFE3A34B554ACD3F45F5C96EAEA2516DD7FF9AF7B43"},
|
||
|
{"78.46.73.141", 33445, "02807CF4F8BB8FB390CC3794BDF1E8449E9A8392C5D3F2200019DA9F1E812E46"},
|
||
|
{"2a01:4f8:120:4091::3", 33445, "02807CF4F8BB8FB390CC3794BDF1E8449E9A8392C5D3F2200019DA9F1E812E46"},
|
||
|
{"tox.initramfs.io", 33445, "3F0A45A268367C1BEA652F258C85F4A66DA76BCAA667A49E770BCC4917AB6A25"},
|
||
|
{"tox2.abilinski.com", 33445, "7A6098B590BDC73F9723FC59F82B3F9085A64D1B213AAF8E610FD351930D052D"},
|
||
|
{"205.185.115.131", 53, "3091C6BEB2A993F1C6300C16549FABA67098FF3D62C6D253828B531470B53D68"},
|
||
|
{"tox.kurnevsky.net", 33445, "82EF82BA33445A1F91A7DB27189ECFC0C013E06E3DA71F588ED692BED625EC23"}
|
||
|
};
|
||
|
|
||
|
for (size_t i = 0; i < sizeof(nodes)/sizeof(DHT_node); i ++) {
|
||
|
unsigned char key_bin[TOX_PUBLIC_KEY_SIZE];
|
||
|
sodium_hex2bin(key_bin, sizeof(key_bin), nodes[i].key_hex, sizeof(nodes[i].key_hex)-1,
|
||
|
NULL, NULL, NULL);
|
||
|
tox_bootstrap(tox, nodes[i].ip, nodes[i].port, key_bin, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------------- */
|
||
|
|
||
|
void print_tox_id(Tox *tox)
|
||
|
{
|
||
|
uint8_t tox_id_bin[TOX_ADDRESS_SIZE];
|
||
|
tox_self_get_address(tox, tox_id_bin);
|
||
|
|
||
|
char tox_id_hex[TOX_ADDRESS_SIZE*2 + 1];
|
||
|
sodium_bin2hex(tox_id_hex, sizeof(tox_id_hex), tox_id_bin, sizeof(tox_id_bin));
|
||
|
|
||
|
for (size_t i = 0; i < sizeof(tox_id_hex)-1; i ++) {
|
||
|
tox_id_hex[i] = toupper(tox_id_hex[i]);
|
||
|
}
|
||
|
|
||
|
printf("Tox ID: %s\n", tox_id_hex);
|
||
|
}
|
||
|
|
||
|
|
||
|
/** CallBacks **/
|
||
|
/** **/
|
||
|
static void friend_request_cb(Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length,
|
||
|
void *user_data)
|
||
|
{
|
||
|
|
||
|
char tox_id_hex[TOX_ADDRESS_SIZE*2 + 1];
|
||
|
uint8_t tox_id_bin[TOX_ADDRESS_SIZE];
|
||
|
|
||
|
sodium_bin2hex(tox_id_hex, sizeof(tox_id_hex), public_key, sizeof(tox_id_bin));
|
||
|
|
||
|
for (size_t i = 0; i < sizeof(tox_id_hex)-1; i ++) {
|
||
|
tox_id_hex[i] = toupper(tox_id_hex[i]);
|
||
|
}
|
||
|
|
||
|
if (file_contains_key(public_key, MASTERLIST_FILE) == 1) {
|
||
|
printf("New friend is Master: %s\n", tox_id_hex);
|
||
|
tox_friend_add_norequest(tox, public_key, NULL);
|
||
|
update_savedata_file(tox);
|
||
|
}
|
||
|
else {
|
||
|
printf("New friend not on the list: %s\n", tox_id_hex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------------- */
|
||
|
|
||
|
void friend_message_cb(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *inmsg,
|
||
|
size_t length, void *user_data)
|
||
|
{
|
||
|
bool user = true;
|
||
|
log_msg(tox, inmsg, friend_number, user);
|
||
|
|
||
|
const char *outmsg;
|
||
|
char message[TOX_MAX_MESSAGE_LENGTH];
|
||
|
length = copy_tox_str(message, sizeof(message), (const char *) inmsg, length);
|
||
|
message[length] = '\0';
|
||
|
|
||
|
user = false;
|
||
|
|
||
|
if (length && execute(tox, friend_number, message, length, user) == -1) {
|
||
|
outmsg = "Invalid command. Type 'help' for a list of commands";
|
||
|
tox_friend_send_message(tox, friend_number, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) outmsg, strlen(outmsg), NULL);
|
||
|
log_msg(tox, outmsg, friend_number, user);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------------- */
|
||
|
|
||
|
void self_connection_status_cb(Tox *tox, TOX_CONNECTION connection_status, void *user_data)
|
||
|
{
|
||
|
switch (connection_status) {
|
||
|
case TOX_CONNECTION_NONE:
|
||
|
printf("Offline\n");
|
||
|
break;
|
||
|
case TOX_CONNECTION_TCP:
|
||
|
printf("Online, using TCP\n");
|
||
|
break;
|
||
|
case TOX_CONNECTION_UDP:
|
||
|
printf("Online, using UDP\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
/** **/
|
||
|
/** CallBacks END**/
|
||
|
|
||
|
|
||
|
int main()
|
||
|
{
|
||
|
Tox *tox = create_tox();
|
||
|
|
||
|
config_tox(tox);
|
||
|
bootstrap(tox);
|
||
|
print_tox_id(tox);
|
||
|
|
||
|
tox_callback_friend_request(tox, friend_request_cb);
|
||
|
tox_callback_friend_message(tox, friend_message_cb);
|
||
|
|
||
|
tox_callback_self_connection_status(tox, self_connection_status_cb);
|
||
|
|
||
|
update_savedata_file(tox);
|
||
|
|
||
|
printf("Connecting...\n");
|
||
|
|
||
|
while (1) {
|
||
|
tox_iterate(tox, NULL);
|
||
|
usleep(tox_iteration_interval(tox) * 1000);
|
||
|
}
|
||
|
|
||
|
tox_kill(tox);
|
||
|
|
||
|
return 0;
|
||
|
}
|