/*
 * Copyright (c) 2010-2022 Belledonne Communications SARL.
 *
 * This file is part of Liblinphone
 * (see https://gitlab.linphone.org/BC/public/liblinphone).
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/* enum lookup code */

#ifndef _WIN32_WCE
#include <errno.h>
#endif

#include <string.h>

#include "enum.h"

#define DNS_ANSWER_MAX_SIZE 2048

static char *create_enum_domain(const char *number) {
	long len = (long)strlen(number);
	char *domain = reinterpret_cast<char *>(ms_malloc((size_t)(len * 2) + 10));
	long i, j;

	for (i = 0, j = len - 1; j >= 0; j--) {
		domain[i] = number[j];
		i++;
		domain[i] = '.';
		i++;
	}
	strcpy(&domain[i], "e164.arpa");
	ms_message("enum domain for %s is %s", number, domain);
	return domain;
}

static bool_t is_a_number(const char *str) {
	char *p = (char *)str;
	bool_t res = FALSE;
	bool_t space_found = FALSE;
	for (;; p++) {
		switch (p[0]) {
			case '9':
			case '8':
			case '7':
			case '6':
			case '5':
			case '4':
			case '3':
			case '2':
			case '1':
			case '0':
				res = TRUE;
				if (space_found) return FALSE; /* avoid splited numbers */
				break;
			case '\0':
				return res;
				break;
			case ' ':
				space_found = TRUE;
				break;
			default:
				return FALSE;
		}
	}
	return FALSE;
}
// 4970072278724
bool_t is_enum(const char *sipaddress, char **enum_domain) {
	const char *p;
	p = strstr(sipaddress, "sip:");
	if (p == NULL) return FALSE; /* enum should look like sip:4369959250*/
	else p += 4;
	if (is_a_number(p)) {
		if (enum_domain != NULL) {
			*enum_domain = create_enum_domain(p);
		}
		return TRUE;
	}
	return FALSE;
}

int enum_lookup(const char *enum_domain, enum_lookup_res_t **res) {
	int err;
	// char dns_answer[DNS_ANSWER_MAX_SIZE];
	char *begin, *end;
	char *host_result, *command;
	int i;
	bool_t forkok;
	/*
	ns_msg handle;
	int count;

	memset(&handle,0,sizeof(handle));
	*res=NULL;
	ms_message("Resolving %s...",enum_domain);

	err=res_search(enum_domain,ns_c_in,ns_t_naptr,dns_answer,DNS_ANSWER_MAX_SIZE);
	if (err<0){
	    ms_warning("Error resolving enum:",herror(h_errno));
	    return -1;
	}
	ns_initparse(dns_answer,DNS_ANSWER_MAX_SIZE,&handle);
	count=ns_msg_count(handle,ns_s_an);

	for(i=0;i<count;i++){
	    ns_rr rr;
	    memset(&rr,0,sizeof(rr));
	    ns_parserr(&handle,ns_s_an,i,&rr);
	    ms_message("data=%s",ns_rr_rdata(rr));
	}
	*/
	command = ms_strdup_printf("host -t naptr %s", enum_domain);
	forkok = lp_spawn_command_line_sync(command, &host_result, &err);
	ms_free(command);
	if (forkok) {
		if (err != 0) {
			ms_warning("Host exited with %i error status.", err);
			return -1;
		}
	} else {
		ms_warning("Could not spawn the \'host\' command.");
		return -1;
	}
	ms_message("Answer received from dns (err=%i): %s", err, host_result);

	begin = strstr(host_result, "sip:");
	if (begin == 0) {
		ms_warning("No sip address found in dns naptr answer.");
		return -1;
	}
	*res = reinterpret_cast<enum_lookup_res_t *>(ms_malloc0(sizeof(enum_lookup_res_t)));
	err = 0;
	for (i = 0; i < MAX_ENUM_LOOKUP_RESULTS; i++) {
		end = strstr(begin, "!");
		if (end == NULL) goto parse_error;
		end[0] = '\0';
		(*res)->sip_address[i] = ms_strdup(begin);
		err++;
		begin = strstr(end + 1, "sip:");
		if (begin == NULL) break;
	}
	ms_free(host_result);
	return err;

parse_error:
	ms_free(*res);
	ms_free(host_result);
	*res = NULL;
	ms_warning("Parse error in enum_lookup().");
	return -1;
}

void enum_lookup_res_free(enum_lookup_res_t *res) {
	int i;
	for (i = 0; i < MAX_ENUM_LOOKUP_RESULTS; i++) {
		if (res->sip_address[i] != NULL) ms_free(res->sip_address[i]);
	}
	ms_free(res);
}
