diff --git a/INSTALL.md b/INSTALL.md
index 4e96a30..12d9749 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -9,17 +9,18 @@
## Dependencies
-| Name | Needed by | Debian package |
-|------------------------------------------------------|----------------------------|------------------|
-| [Tox Core](https://github.com/irungentoo/toxcore) | BASE | *None* |
-| [NCurses](https://www.gnu.org/software/ncurses) | BASE | libncursesw5-dev |
-| [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev |
-| [GNUmake](https://www.gnu.org/software/make) | BASE | make |
-| [Tox Core AV](https://github.com/irungentoo/toxcore) | AUDIO | *None* |
-| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
-| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
-| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
-| [AsciiDoc](http://asciidoc.org/index.html) | DOCUMENTATION1 | asciidoc |
+| Name | Needed by | Debian package |
+|------------------------------------------------------|----------------------------|---------------------|
+| [Tox Core](https://github.com/irungentoo/toxcore) | BASE | *None* |
+| [NCurses](https://www.gnu.org/software/ncurses) | BASE | libncursesw5-dev |
+| [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev |
+| [GNUmake](https://www.gnu.org/software/make) | BASE | make |
+| [libcurl](http://curl.haxx.se/) | BASE | libcurl4-openssl-dev|
+| [Tox Core AV](https://github.com/irungentoo/toxcore) | AUDIO | *None* |
+| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
+| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
+| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
+| [AsciiDoc](http://asciidoc.org/index.html) | DOCUMENTATION1 | asciidoc |
1: see [Documentation](#docs)
@@ -31,7 +32,7 @@ brew install https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/l
brew install https://raw.githubusercontent.com/Homebrew/homebrew-x11/master/libnotify.rb
```
-You can omit `libnotify` if you intend to build without desktop notifications enabled.
+You can omit `libnotify` if you intend to build without desktop notifications enabled.
## Compiling
diff --git a/Makefile b/Makefile
index 392b257..1de0582 100644
--- a/Makefile
+++ b/Makefile
@@ -11,10 +11,10 @@ CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
CFLAGS += $(USER_CFLAGS)
LDFLAGS = $(USER_LDFLAGS)
-OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_transfers.o notify.o
+OBJ = chat.o chat_commands.o configdir.o execute.o file_transfers.o notify.o
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o
-OBJ += group_commands.o term_mplex.o avatars.o
+OBJ += group_commands.o term_mplex.o avatars.o name_lookup.o
# Check on wich system we are running
UNAME_S = $(shell uname -s)
diff --git a/cfg/global_vars.mk b/cfg/global_vars.mk
index a62d277..de60c24 100644
--- a/cfg/global_vars.mk
+++ b/cfg/global_vars.mk
@@ -16,7 +16,7 @@ MISC_DIR = $(BASE_DIR)/misc
# Project files
MANFILES = toxic.1 toxic.conf.5
-DATAFILES = DHTnodes DNSservers toxic.conf.example
+DATAFILES = DHTnodes nameservers toxic.conf.example
DESKFILE = toxic.desktop
SNDFILES = ToxicContactOnline.wav ToxicContactOffline.wav ToxicError.wav
SNDFILES += ToxicRecvMessage.wav ToxicOutgoingCall.wav ToxicIncomingCall.wav
diff --git a/cfg/systems/Darwin.mk b/cfg/systems/Darwin.mk
index f33a4be..1fc579b 100644
--- a/cfg/systems/Darwin.mk
+++ b/cfg/systems/Darwin.mk
@@ -6,5 +6,5 @@ PKG_CONFIG_PATH = $(shell export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/o
LIBS := $(filter-out ncursesw, $(LIBS))
# OS X ships a usable, recent version of ncurses, but calls it ncurses not ncursesw.
-LDFLAGS += -lncurses -lalut -ltoxav -ltoxcore -ltoxdns -lresolv -lconfig -ltoxencryptsave -g
+LDFLAGS += -lncurses -lalut -ltoxav -ltoxcore -lcurl -lconfig -ltoxencryptsave -g
CFLAGS += -I/usr/local/opt/freealut/include/AL -I/usr/local/opt/glib/include/glib-2.0 -g
diff --git a/cfg/systems/Linux.mk b/cfg/systems/Linux.mk
index 9a67614..6bd4075 100644
--- a/cfg/systems/Linux.mk
+++ b/cfg/systems/Linux.mk
@@ -1,4 +1,4 @@
# Specials options for linux systems
CFLAGS +=
-LDFLAGS += -ldl -lresolv -lrt
+LDFLAGS += -ldl -lrt -lcurl
MANDIR = $(PREFIX)/share/man
diff --git a/doc/toxic.1 b/doc/toxic.1
index af74931..79d06a5 100644
--- a/doc/toxic.1
+++ b/doc/toxic.1
@@ -2,12 +2,12 @@
.\" Title: toxic
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1
-.\" Date: 2015-03-28
+.\" Date: 2015-07-08
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
-.TH "TOXIC" "1" "2015\-03\-28" "toxic __VERSION__" "Toxic Manual"
+.TH "TOXIC" "1" "2015\-07\-08" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -101,9 +101,9 @@ Use a SOCKS5 proxy: Requires [IP] [port]
Use a HTTP proxy: Requires [IP] [port]
.RE
.PP
-\-r, \-\-dnslist
+\-r, \-\-namelist
.RS 4
-Use specified DNSservers file
+Use specified nameservers list
.RE
.PP
\-t, \-\-force\-tcp
diff --git a/doc/toxic.1.asc b/doc/toxic.1.asc
index 4950c6b..8384091 100644
--- a/doc/toxic.1.asc
+++ b/doc/toxic.1.asc
@@ -53,8 +53,8 @@ OPTIONS
-P, --HTTP-proxy::
Use a HTTP proxy: Requires [IP] [port]
--r, --dnslist::
- Use specified DNSservers file
+-r, --namelist::
+ Use specified nameservers list
-t, --force-tcp::
Force TCP connection (use this with proxies)
diff --git a/misc/DNSservers b/misc/nameservers
similarity index 50%
rename from misc/DNSservers
rename to misc/nameservers
index 379637d..94f6aab 100644
--- a/misc/DNSservers
+++ b/misc/nameservers
@@ -1,3 +1,2 @@
-utox.org d3154f65d28a5b41a05d4ac7e4b39c6b1c233cc857fb365c56e8392737462a12
toxme.io 1A39E7A5D5FA9CF155C751570A32E625698A60A55F6D88028F949F66144F4F25
diff --git a/src/dns.c b/src/dns.c
deleted file mode 100644
index c5457a7..0000000
--- a/src/dns.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/* dns.c
- *
- *
- * Copyright (C) 2014 Toxic All Rights Reserved.
- *
- * This file is part of Toxic.
- *
- * Toxic is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Toxic is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Toxic. If not, see .
- *
- */
-
-#include
-#include
-#include /* for u_char */
-#include
-#include
-
-#ifdef __APPLE__
- #include
-#else
- #include
-#endif /* ifdef __APPLE__ */
-
-#include
-
-#include "toxic.h"
-#include "windows.h"
-#include "line_info.h"
-#include "dns.h"
-#include "global_commands.h"
-#include "misc_tools.h"
-#include "configdir.h"
-
-#define DNS3_KEY_SIZE 32
-#define MAX_DNS_REQST_SIZE 255
-#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
-
-extern struct Winthread Winthread;
-extern struct dns3_servers dns3_servers;
-extern struct arg_opts arg_opts;
-
-static struct thread_data {
- ToxWindow *self;
- char id_bin[TOX_ADDRESS_SIZE];
- char addr[MAX_STR_SIZE];
- char msg[MAX_STR_SIZE];
- uint8_t busy;
- Tox *m;
-} t_data;
-
-static struct dns_thread {
- pthread_t tid;
- pthread_attr_t attr;
-} dns_thread;
-
-
-#define MAX_DNS_SERVERS 50
-#define MAX_DOMAIN_SIZE 32
-#define MAX_DNS_LINE MAX_DOMAIN_SIZE + (DNS3_KEY_SIZE * 2) + 3
-
-struct dns3_servers {
- bool loaded;
- int lines;
- char names[MAX_DNS_SERVERS][MAX_DOMAIN_SIZE];
- char keys[MAX_DNS_SERVERS][DNS3_KEY_SIZE];
-} dns3_servers;
-
-static int load_dns_domainlist(const char *path)
-{
- FILE *fp = fopen(path, "r");
-
- if (fp == NULL)
- return -1;
-
- char line[MAX_DNS_LINE];
-
- while (fgets(line, sizeof(line), fp) && dns3_servers.lines < MAX_DNS_SERVERS) {
- int linelen = strlen(line);
-
- if (linelen < DNS3_KEY_SIZE * 2 + 5)
- continue;
-
- if (line[linelen - 1] == '\n')
- line[--linelen] = '\0';
-
- const char *name = strtok(line, " ");
- const char *keystr = strtok(NULL, " ");
-
- if (name == NULL || keystr == NULL)
- continue;
-
- if (strlen(keystr) != DNS3_KEY_SIZE * 2)
- continue;
-
- snprintf(dns3_servers.names[dns3_servers.lines], sizeof(dns3_servers.names[dns3_servers.lines]), "%s", name);
- int res = hex_string_to_bytes(dns3_servers.keys[dns3_servers.lines], DNS3_KEY_SIZE, keystr);
-
- if (res == -1)
- continue;
-
- ++dns3_servers.lines;
- }
-
- fclose(fp);
-
- if (dns3_servers.lines < 1)
- return -2;
-
- return 0;
-}
-
-static int dns_error(ToxWindow *self, const char *errmsg)
-{
- pthread_mutex_lock(&Winthread.lock);
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "User lookup failed: %s", errmsg);
- pthread_mutex_unlock(&Winthread.lock);
-
- return -1;
-}
-
-static void killdns_thread(void *dns_obj)
-{
- if (dns_obj)
- tox_dns3_kill(dns_obj);
-
- memset(&t_data, 0, sizeof(struct thread_data));
- pthread_attr_destroy(&dns_thread.attr);
- pthread_exit(NULL);
-}
-
-/* puts TXT from dns response in buf. Returns length of TXT on success, -1 on fail.*/
-static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char *buf)
-{
- uint8_t *ans_pt = answer + sizeof(HEADER);
- uint8_t *ans_end = answer + ans_len;
- char exp_ans[PACKETSZ];
-
- int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
-
- if (len == -1)
- return dns_error(self, "dn_expand failed.");
-
- ans_pt += len;
-
- if (ans_pt > ans_end - 4)
- return dns_error(self, "DNS reply was too short.");
-
- int type;
- GETSHORT(type, ans_pt);
-
- if (type != T_TXT)
- return dns_error(self, "Broken DNS reply.");
-
-
- ans_pt += INT16SZ; /* class */
- uint32_t size = 0;
-
- /* recurse through CNAME rr's */
- do {
- ans_pt += size;
- len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
-
- if (len == -1)
- return dns_error(self, "Second dn_expand failed.");
-
- ans_pt += len;
-
- if (ans_pt > ans_end - 10)
- return dns_error(self, "DNS reply was too short.");
-
- GETSHORT(type, ans_pt);
- ans_pt += INT16SZ;
- ans_pt += 4;
- GETSHORT(size, ans_pt);
-
- if (ans_pt + size < answer || ans_pt + size > ans_end)
- return dns_error(self, "RR overflow.");
-
- } while (type == T_CNAME);
-
- if (type != T_TXT)
- return dns_error(self, "DNS response failed.");
-
- uint32_t txt_len = *ans_pt;
-
- if (!size || txt_len >= size || !txt_len)
- return dns_error(self, "No record found.");
-
- if (txt_len > MAX_DNS_REQST_SIZE)
- return dns_error(self, "Invalid DNS response.");
-
- ans_pt++;
- ans_pt[txt_len] = '\0';
- memcpy(buf, ans_pt, txt_len + 1);
-
- return txt_len;
-}
-
-/* Takes address addr in the form "username@domain", puts the username in namebuf,
- and the domain in dombuf.
-
- return length of username on success, -1 on failure */
-static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *dombuf, size_t dombuf_sz)
-{
- if (strlen(addr) >= MAX_STR_SIZE)
- return -1;
-
- char tmpaddr[MAX_STR_SIZE];
- char *tmpname = NULL;
- char *tmpdom = NULL;
-
- snprintf(tmpaddr, sizeof(tmpaddr), "%s", addr);
- tmpname = strtok(tmpaddr, "@");
- tmpdom = strtok(NULL, "");
-
- if (tmpname == NULL || tmpdom == NULL)
- return -1;
-
- str_to_lower(tmpdom);
- snprintf(namebuf, namebuf_sz, "%s", tmpname);
- snprintf(dombuf, dombuf_sz, "%s", tmpdom);
-
- return strlen(namebuf);
-}
-
-/* matches input domain name with domains in list and obtains key. Return 0 on success, -1 on failure */
-static int get_domain_match(char *pubkey, char *domain, const char *inputdomain)
-{
- int i;
-
- for (i = 0; i < dns3_servers.lines; ++i) {
- if (strcmp(dns3_servers.names[i], inputdomain) == 0) {
- memcpy(pubkey, dns3_servers.keys[i], DNS3_KEY_SIZE);
- snprintf(domain, MAX_DOMAIN_SIZE, "%s", dns3_servers.names[i]);
- return 0;
- }
- }
-
- return -1;
-}
-
-/* Does DNS lookup for addr and puts resulting tox id in id_bin. */
-void *dns3_lookup_thread(void *data)
-{
- ToxWindow *self = t_data.self;
-
- char inputdomain[MAX_STR_SIZE];
- char name[MAX_STR_SIZE];
-
- int namelen = parse_addr(t_data.addr, name, sizeof(name), inputdomain, sizeof(inputdomain));
-
- if (namelen == -1) {
- dns_error(self, "Must be a Tox ID or an address in the form username@domain");
- killdns_thread(NULL);
- }
-
- char DNS_pubkey[DNS3_KEY_SIZE];
- char domain[MAX_DOMAIN_SIZE];
-
- int match = get_domain_match(DNS_pubkey, domain, inputdomain);
-
- if (match == -1) {
- dns_error(self, "Domain not found.");
- killdns_thread(NULL);
- }
-
- void *dns_obj = tox_dns3_new((uint8_t *) DNS_pubkey);
-
- if (dns_obj == NULL) {
- dns_error(self, "Core failed to create DNS object.");
- killdns_thread(NULL);
- }
-
- char string[MAX_DNS_REQST_SIZE + 1];
- uint32_t request_id;
-
- int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id,
- (uint8_t *) name, namelen);
-
- if (str_len == -1) {
- dns_error(self, "Core failed to generate DNS3 string.");
- killdns_thread(dns_obj);
- }
-
- string[str_len] = '\0';
-
- u_char answer[PACKETSZ];
- char d_string[MAX_DOMAIN_SIZE + MAX_DNS_REQST_SIZE + 10];
-
- /* format string and create dns query */
- snprintf(d_string, sizeof(d_string), "_%s._tox.%s", string, domain);
- int ans_len = res_query(d_string, C_IN, T_TXT, answer, sizeof(answer));
-
- if (ans_len <= 0) {
- dns_error(self, "DNS query failed.");
- killdns_thread(dns_obj);
- }
-
- char ans_id[MAX_DNS_REQST_SIZE + 1];
-
- /* extract TXT from DNS response */
- if (parse_dns_response(self, answer, ans_len, ans_id) == -1)
- killdns_thread(dns_obj);
-
- char encrypted_id[MAX_DNS_REQST_SIZE + 1];
- int prfx_len = strlen(TOX_DNS3_TXT_PREFIX);
-
- /* extract the encrypted ID from TXT response */
- if (strncmp(ans_id, TOX_DNS3_TXT_PREFIX, prfx_len) != 0) {
- dns_error(self, "Bad DNS3 TXT response.");
- killdns_thread(dns_obj);
- }
-
- memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len);
-
- if (tox_decrypt_dns3_TXT(dns_obj, (uint8_t *) t_data.id_bin, (uint8_t *) encrypted_id,
- strlen(encrypted_id), request_id) == -1) {
- dns_error(self, "Core failed to decrypt DNS response.");
- killdns_thread(dns_obj);
- }
-
- pthread_mutex_lock(&Winthread.lock);
- cmd_add_helper(self, t_data.m, t_data.id_bin, t_data.msg);
- pthread_mutex_unlock(&Winthread.lock);
-
- killdns_thread(dns_obj);
- return 0;
-}
-
-/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
-void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg)
-{
- if (arg_opts.proxy_type != TOX_PROXY_TYPE_NONE && arg_opts.force_tcp) {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "DNS lookups are disabled.");
- return;
- }
-
- if (t_data.busy) {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please wait for previous user lookup to finish.");
- return;
- }
-
- if (!dns3_servers.loaded) {
- const char *path = arg_opts.dns_path[0] ? arg_opts.dns_path : PACKAGE_DATADIR "/DNSservers";
- dns3_servers.loaded = true;
- int ret = load_dns_domainlist(path);
-
- if (ret < 0) {
- const char *errmsg = "DNS server list failed to load with error code %d. Falling back to hard-coded list.";
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg, ret);
- }
- }
-
- snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin);
- snprintf(t_data.addr, sizeof(t_data.addr), "%s", addr);
- snprintf(t_data.msg, sizeof(t_data.msg), "%s", msg);
- t_data.self = self;
- t_data.m = m;
- t_data.busy = 1;
-
- if (pthread_attr_init(&dns_thread.attr) != 0) {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: DNS thread attr failed to init");
- memset(&t_data, 0, sizeof(struct thread_data));
- return;
- }
-
- if (pthread_attr_setdetachstate(&dns_thread.attr, PTHREAD_CREATE_DETACHED) != 0) {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: DNS thread attr failed to set");
- pthread_attr_destroy(&dns_thread.attr);
- memset(&t_data, 0, sizeof(struct thread_data));
- return;
- }
-
- if (pthread_create(&dns_thread.tid, &dns_thread.attr, dns3_lookup_thread, NULL) != 0) {
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: DNS thread failed to init");
- pthread_attr_destroy(&dns_thread.attr);
- memset(&t_data, 0, sizeof(struct thread_data));
- return;
- }
-}
diff --git a/src/global_commands.c b/src/global_commands.c
index 134a854..a15bc69 100644
--- a/src/global_commands.c
+++ b/src/global_commands.c
@@ -30,12 +30,12 @@
#include "friendlist.h"
#include "log.h"
#include "line_info.h"
-#include "dns.h"
#include "groupchat.h"
#include "prompt.h"
#include "help.h"
#include "term_mplex.h"
#include "avatars.h"
+#include "name_lookup.h"
extern char *DATA_FILE;
extern ToxWindow *prompt;
@@ -192,8 +192,8 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
}
cmd_add_helper(self, m, id_bin, msg);
- } else { /* assume id is a username@domain address and do DNS lookup */
- dns3_lookup(self, m, id_bin, id, msg);
+ } else { /* assume id is a username@domain address and do http name server lookup */
+ name_lookup(self, m, id_bin, id, msg);
}
}
diff --git a/src/name_lookup.c b/src/name_lookup.c
new file mode 100644
index 0000000..5fdd21a
--- /dev/null
+++ b/src/name_lookup.c
@@ -0,0 +1,391 @@
+/* name_lookup.c
+ *
+ *
+ * Copyright (C) 2015 Toxic All Rights Reserved.
+ *
+ * This file is part of Toxic.
+ *
+ * Toxic is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Toxic is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Toxic. If not, see .
+ *
+ */
+
+#include
+#include
+#include /* for u_char */
+#include
+
+#include "toxic.h"
+#include "windows.h"
+#include "line_info.h"
+#include "global_commands.h"
+#include "misc_tools.h"
+#include "configdir.h"
+
+extern struct arg_opts arg_opts;
+extern struct Winthread Winthread;;
+
+#define NAMESERVER_API_PATH "api"
+#define SERVER_KEY_SIZE 32
+#define MAX_SERVERS 50
+#define MAX_DOMAIN_SIZE 32
+#define MAX_SERVER_LINE MAX_DOMAIN_SIZE + (SERVER_KEY_SIZE * 2) + 3
+
+struct Nameservers {
+ int lines;
+ char names[MAX_SERVERS][MAX_DOMAIN_SIZE];
+ char keys[MAX_SERVERS][SERVER_KEY_SIZE];
+} Nameservers;
+
+static struct thread_data {
+ Tox *m;
+ ToxWindow *self;
+ char id_bin[TOX_ADDRESS_SIZE];
+ char addr[MAX_STR_SIZE];
+ char msg[MAX_STR_SIZE];
+ bool busy;
+ bool disabled;
+} t_data;
+
+static struct lookup_thread {
+ pthread_t tid;
+ pthread_attr_t attr;
+} lookup_thread;
+
+static int lookup_error(ToxWindow *self, const char *errmsg)
+{
+ pthread_mutex_lock(&Winthread.lock);
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "name lookup failed: %s", errmsg);
+ pthread_mutex_unlock(&Winthread.lock);
+
+ return -1;
+}
+
+static void kill_lookup_thread(void)
+{
+ memset(&t_data, 0, sizeof(struct thread_data));
+ pthread_attr_destroy(&lookup_thread.attr);
+ pthread_exit(NULL);
+}
+
+/* Attempts to load the nameserver list pointed at by path into the Nameservers structure.
+ *
+ * Returns 0 on success.
+ * -1 is reserved.
+ * Returns -2 if the supplied path does not exist.
+ * Returns -3 if the list does not contain any valid entries.
+ */
+static int load_nameserver_list(const char *path)
+{
+ FILE *fp = fopen(path, "r");
+
+ if (fp == NULL)
+ return -2;
+
+ char line[MAX_SERVER_LINE];
+
+ while (fgets(line, sizeof(line), fp) && Nameservers.lines < MAX_SERVERS) {
+ int linelen = strlen(line);
+
+ if (linelen < SERVER_KEY_SIZE * 2 + 5)
+ continue;
+
+ if (line[linelen - 1] == '\n')
+ line[--linelen] = '\0';
+
+ const char *name = strtok(line, " ");
+ const char *keystr = strtok(NULL, " ");
+
+ if (name == NULL || keystr == NULL)
+ continue;
+
+ if (strlen(keystr) != SERVER_KEY_SIZE * 2)
+ continue;
+
+ snprintf(Nameservers.names[Nameservers.lines], sizeof(Nameservers.names[Nameservers.lines]), "%s", name);
+ int res = hex_string_to_bytes(Nameservers.keys[Nameservers.lines], SERVER_KEY_SIZE, keystr);
+
+ if (res == -1)
+ continue;
+
+ ++Nameservers.lines;
+ }
+
+ fclose(fp);
+
+ if (Nameservers.lines < 1)
+ return -3;
+
+ return 0;
+}
+
+/* Takes address addr in the form "username@domain", puts the username in namebuf,
+ * and the domain in dombuf.
+ *
+ * Returns 0 on success.
+ * Returns -1 on failure
+ */
+static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *dombuf, size_t dombuf_sz)
+{
+ if (strlen(addr) >= (MAX_STR_SIZE - strlen(NAMESERVER_API_PATH)))
+ return -1;
+
+ char tmpaddr[MAX_STR_SIZE];
+ char *tmpname = NULL;
+ char *tmpdom = NULL;
+
+ snprintf(tmpaddr, sizeof(tmpaddr), "%s", addr);
+ tmpname = strtok(tmpaddr, "@");
+ tmpdom = strtok(NULL, "");
+
+ if (tmpname == NULL || tmpdom == NULL)
+ return -1;
+
+ str_to_lower(tmpdom);
+ snprintf(namebuf, namebuf_sz, "%s", tmpname);
+ snprintf(dombuf, dombuf_sz, "%s", tmpdom);
+
+ return 0;
+}
+
+/* matches input domain name with domains in list and obtains key.
+ * Turns out_domain into the full domain we need to make a POST request.
+ *
+ * Return true on match.
+ * Returns false on no match.
+ */
+static bool get_domain_match(char *pubkey, char *out_domain, size_t out_domain_size, const char *inputdomain)
+{
+ int i;
+
+ for (i = 0; i < Nameservers.lines; ++i) {
+ if (strcmp(Nameservers.names[i], inputdomain) == 0) {
+ memcpy(pubkey, Nameservers.keys[i], SERVER_KEY_SIZE);
+ snprintf(out_domain, out_domain_size, "https://%s/%s", Nameservers.names[i], NAMESERVER_API_PATH);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+#define MAX_RECV_LOOKUP_DATA_SIZE 1024
+
+/* Holds raw data received from name server */
+struct Recv_Data {
+ char data[MAX_RECV_LOOKUP_DATA_SIZE];
+ size_t size;
+};
+
+size_t write_lookup_data(void *data, size_t size, size_t nmemb, void *user_pointer)
+{
+ struct Recv_Data *recv_data = (struct Recv_Data *) user_pointer;
+ size_t real_size = size * nmemb;
+
+ if (real_size > MAX_RECV_LOOKUP_DATA_SIZE)
+ return 0;
+
+ memcpy(&recv_data->data, data, real_size);
+ recv_data->size = real_size;
+ recv_data->data[real_size] = 0;
+
+ return real_size;
+}
+
+/* Converts Tox ID string contained in recv_data to binary format and puts it in thread's ID buffer.
+ *
+ * Returns 0 on success.
+ * Returns -1 on failure.
+ */
+#define ID_PREFIX "\"tox_id\": \""
+static int process_response(struct Recv_Data *recv_data)
+{
+ size_t prefix_size = strlen(ID_PREFIX);
+
+ if (recv_data->size < TOX_ADDRESS_SIZE * 2 + prefix_size)
+ return -1;
+
+ const char *IDstart = strstr(recv_data->data, ID_PREFIX);
+
+ if (IDstart == NULL)
+ return -1;
+
+ if (strlen(IDstart) < TOX_ADDRESS_SIZE * 2 + prefix_size)
+ return -1;
+
+ char ID_string[TOX_ADDRESS_SIZE * 2 + 1];
+ memcpy(ID_string, IDstart + prefix_size, TOX_ADDRESS_SIZE * 2);
+ ID_string[TOX_ADDRESS_SIZE * 2] = 0;
+
+ if (hex_string_to_bin(ID_string, strlen(ID_string), t_data.id_bin, sizeof(t_data.id_bin)) == -1)
+ return -1;
+
+ return 0;
+}
+
+void *lookup_thread_func(void *data)
+{
+ ToxWindow *self = t_data.self;
+
+ char input_domain[MAX_STR_SIZE];
+ char name[MAX_STR_SIZE];
+
+ if (parse_addr(t_data.addr, name, sizeof(name), input_domain, sizeof(input_domain)) == -1) {
+ lookup_error(self, "Input must be a 76 character Tox ID or an address in the form: username@domain");
+ kill_lookup_thread();
+ }
+
+ char nameserver_key[SERVER_KEY_SIZE];
+ char real_domain[MAX_DOMAIN_SIZE];
+
+ if (!get_domain_match(nameserver_key, real_domain, sizeof(real_domain), input_domain)) {
+ if (!strcasecmp(input_domain, "utox.org"))
+ lookup_error(self, "utox.org uses deprecated DNS-based lookups and is no longer supported by Toxic");
+ else
+ lookup_error(self, "Name server domain not found.");
+
+ kill_lookup_thread();
+ }
+
+ CURL *c_handle = curl_easy_init();
+
+ if (!c_handle) {
+ lookup_error(self, "curl handler error");
+ kill_lookup_thread();
+ }
+
+ struct Recv_Data recv_data;
+ memset(&recv_data, 0, sizeof(struct Recv_Data));
+
+ char post_data[MAX_STR_SIZE];
+ snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name);
+
+ struct curl_slist *headers = NULL;
+
+ headers = curl_slist_append(headers, "Content-Type: application/json");
+ headers = curl_slist_append(headers, "charsets: utf-8");
+
+ curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(c_handle, CURLOPT_URL, real_domain);
+ curl_easy_setopt(c_handle, CURLOPT_WRITEFUNCTION, write_lookup_data);
+ curl_easy_setopt(c_handle, CURLOPT_WRITEDATA, (void *) &recv_data);
+ curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
+ curl_easy_setopt(c_handle, CURLOPT_POSTFIELDS, post_data);
+
+ if (curl_easy_setopt(c_handle, CURLOPT_USE_SSL, CURLUSESSL_ALL) != CURLE_OK) {
+ lookup_error(self, "Failed to enable TLS.");
+ goto on_exit;
+ }
+
+ if (curl_easy_setopt(c_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2) != CURLE_OK) {
+ lookup_error(self, "TLSv1.2 could not be set.");
+ goto on_exit;
+ }
+
+ if (curl_easy_perform(c_handle) != CURLE_OK) {
+ lookup_error(self, "curl lookup error.");
+ goto on_exit;
+ }
+
+ if (process_response(&recv_data) == -1) {
+ lookup_error(self, "parsing error.");
+ goto on_exit;
+ }
+
+ pthread_mutex_lock(&Winthread.lock);
+ cmd_add_helper(self, t_data.m, t_data.id_bin, t_data.msg);
+ pthread_mutex_unlock(&Winthread.lock);
+
+on_exit:
+ curl_slist_free_all(headers);
+ curl_easy_cleanup(c_handle);
+ kill_lookup_thread();
+
+ return 0;
+}
+
+void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message)
+{
+ if (t_data.disabled) {
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "name lookups are disabled.");
+ return;
+ }
+
+ if (arg_opts.proxy_type != TOX_PROXY_TYPE_NONE && arg_opts.force_tcp) {
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "name lookups are disabled.");
+ return;
+ }
+
+ if (t_data.busy) {
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please wait for previous name lookup to finish.");
+ return;
+ }
+
+ snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin);
+ snprintf(t_data.addr, sizeof(t_data.addr), "%s", addr);
+ snprintf(t_data.msg, sizeof(t_data.msg), "%s", message);
+ t_data.self = self;
+ t_data.m = m;
+ t_data.busy = true;
+
+ if (pthread_attr_init(&lookup_thread.attr) != 0) {
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to init");
+ memset(&t_data, 0, sizeof(struct thread_data));
+ return;
+ }
+
+ if (pthread_attr_setdetachstate(&lookup_thread.attr, PTHREAD_CREATE_DETACHED) != 0) {
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to set");
+ pthread_attr_destroy(&lookup_thread.attr);
+ memset(&t_data, 0, sizeof(struct thread_data));
+ return;
+ }
+
+ if (pthread_create(&lookup_thread.tid, &lookup_thread.attr, lookup_thread_func, NULL) != 0) {
+ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread failed to init");
+ pthread_attr_destroy(&lookup_thread.attr);
+ memset(&t_data, 0, sizeof(struct thread_data));
+ return;
+ }
+}
+
+/* Initializes http based name lookups. Note: This function must be called only once before additional
+ * threads are spawned.
+ *
+ * Returns 0 on success.
+ * Returns -1 if curl failed to init.
+ * Returns -2 if the nameserver list cannot be found.
+ * Returns -3 if the nameserver list does not contain any valid entries.
+ */
+int name_lookup_init(void)
+{
+ if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
+ t_data.disabled = true;
+ return -1;
+ }
+
+ const char *path = arg_opts.nameserver_path[0] ? arg_opts.nameserver_path : PACKAGE_DATADIR "/nameservers";
+ int ret = load_nameserver_list(path);
+
+ if (ret != 0) {
+ t_data.disabled = true;
+ return ret;
+ }
+
+ return 0;
+}
+
+void name_lookup_cleanup(void)
+{
+ curl_global_cleanup();
+}
diff --git a/src/dns.h b/src/name_lookup.h
similarity index 59%
rename from src/dns.h
rename to src/name_lookup.h
index 9e6852e..c1419d8 100644
--- a/src/dns.h
+++ b/src/name_lookup.h
@@ -1,7 +1,7 @@
-/* dns.c
+/* name_lookup.h
*
*
- * Copyright (C) 2014 Toxic All Rights Reserved.
+ * Copyright (C) 2015 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
@@ -20,13 +20,18 @@
*
*/
-/* Does DNS lookup for addr and puts resulting tox id in id_bin.
- Return 0 on success, -1 on failure. */
+#ifndef NAME_LOOKUP
+#define NAME_LOOKUP
-#ifndef DNS_H
-#define DNS_H
+/* Initializes http based name lookups. Note: This function must be called only once before additional
+ * threads are spawned.
+ *
+ * Returns 0 on success.
+ * Returns -1 on failure.
+ */
+int name_lookup_init(void);
+void name_lookup_cleanup(void);
-/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
-void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg);
+int name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message);
-#endif /* #define DNS_H */
+#endif /* NAME_LOOKUP */
diff --git a/src/toxic.c b/src/toxic.c
index 6dcf558..4bfc647 100644
--- a/src/toxic.c
+++ b/src/toxic.c
@@ -58,6 +58,7 @@
#include "message_queue.h"
#include "execute.h"
#include "term_mplex.h"
+#include "name_lookup.h"
#ifdef X11
#include "xtra.h"
@@ -155,6 +156,7 @@ void exit_toxic_success(Tox *m)
free_global_data();
tox_kill(m);
endwin();
+ name_lookup_cleanup();
#ifdef X11
/* We have to terminate xtra last coz reasons
@@ -904,7 +906,7 @@ static void print_usage(void)
fprintf(stderr, " -o, --noconnect Do not connect to the DHT network\n");
fprintf(stderr, " -p, --SOCKS5-proxy Use SOCKS5 proxy: Requires [IP] [port]\n");
fprintf(stderr, " -P, --HTTP-proxy Use HTTP proxy: Requires [IP] [port]\n");
- fprintf(stderr, " -r, --dnslist Use specified DNSservers file\n");
+ fprintf(stderr, " -r, --namelist Use specified name lookup server list\n");
fprintf(stderr, " -t, --force-tcp Force toxic to use a TCP connection (use with proxies)\n");
fprintf(stderr, " -T, --tcp-server Act as a TCP relay server: Requires [port]\n");
fprintf(stderr, " -u, --unencrypt-data Unencrypt an encrypted data file\n");
@@ -932,7 +934,7 @@ static void parse_args(int argc, char *argv[])
{"nodes", required_argument, 0, 'n'},
{"help", no_argument, 0, 'h'},
{"noconnect", no_argument, 0, 'o'},
- {"dnslist", required_argument, 0, 'r'},
+ {"namelist", required_argument, 0, 'r'},
{"force-tcp", no_argument, 0, 't'},
{"tcp-server", required_argument, 0, 'T'},
{"SOCKS5-proxy", required_argument, 0, 'p'},
@@ -1044,10 +1046,10 @@ static void parse_args(int argc, char *argv[])
break;
case 'r':
- snprintf(arg_opts.dns_path, sizeof(arg_opts.dns_path), "%s", optarg);
+ snprintf(arg_opts.nameserver_path, sizeof(arg_opts.nameserver_path), "%s", optarg);
- if (!file_exists(arg_opts.dns_path))
- queue_init_message("DNSservers file not found");
+ if (!file_exists(arg_opts.nameserver_path))
+ queue_init_message("nameserver list not found");
break;
@@ -1222,7 +1224,18 @@ int main(int argc, char **argv)
exit_toxic_err("failed in main", FATALERR_MEMORY);
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
- int settings_err = settings_load(user_settings, p);
+
+ if (settings_load(user_settings, p) == -1)
+ queue_init_message("Failed to load user settings");
+
+ int nameserver_ret = name_lookup_init();
+
+ if (nameserver_ret == -1)
+ queue_init_message("curl failed to initialize; name lookup service is disabled.");
+ else if (nameserver_ret == -2)
+ queue_init_message("Name lookup server list could not be found.");
+ else if (nameserver_ret == -3)
+ queue_init_message("Name lookup server list does not contain any valid entries.");
#ifdef X11
if (init_xtra(DnD_callback) == -1)
@@ -1271,9 +1284,6 @@ int main(int argc, char **argv)
init_notify(60, 3000);
- if (settings_err == -1)
- queue_init_message("Failed to load user settings");
-
/* screen/tmux auto-away timer */
if (init_mplex_away_timer(m) == -1)
queue_init_message("Failed to init mplex auto-away.");
diff --git a/src/windows.h b/src/windows.h
index 21e90bf..fded1e8 100644
--- a/src/windows.h
+++ b/src/windows.h
@@ -90,7 +90,7 @@ struct arg_opts {
bool encrypt_data;
bool unencrypt_data;
- char dns_path[MAX_STR_SIZE];
+ char nameserver_path[MAX_STR_SIZE];
char config_path[MAX_STR_SIZE];
char nodes_path[MAX_STR_SIZE];