#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <linux/ax25.h>
#include <linux/rose.h>

#include "axutils.h"
#include "axconfig.h"
#include "rsconfig.h"
#include "version.h"

char nodes_usage[]  = "usage: rsparms -node add|del nodeaddr[/mask] port neighbour [digis...]\n";

void nodes(int s, int argc, char *argv[])
{
	struct rose_route_struct rs_node;
	char *dev;
	char *mask;
	char nodeaddr[11];
	int i, n;

	if (ax25_config_load_ports() == 0) {
		fprintf(stderr, "rsparms: nodes: no AX.25 ports configured\n");
		exit(1);
	}

	if (argv[2][0] != 'a' && argv[2][0] != 'd') {
		fprintf(stderr, "rsparms: nodes: invalid operation %s\n", argv[2]);
		close(s);
		exit(1);
	}

	if ((mask = strchr(argv[3], '/')) != NULL) {
		*mask= (char)NULL;
		mask++;

		if (sscanf(mask, "%hd", &rs_node.mask) != 1) {
			fprintf(stderr, "rsparms: nodes: no mask supplied!\n");
			close(s);
			exit(1);
		}

		if (rs_node.mask > 10) {
			fprintf(stderr, "rsparms: nodes: invalid mask size: %s\n", mask);;
			close(s);
			exit(1);
		}
	} else {
		rs_node.mask = 10;
	}

	/* Make all non significant digits equal to zero */
	strcpy(nodeaddr, argv[3]);

	for (i = rs_node.mask; i < 10; i++)
		nodeaddr[i] = '0';

	nodeaddr[i] = '\0';

	if (convert_rose_address(nodeaddr, rs_node.address.rose_addr) != 0) {
		fprintf(stderr, "rsparms: nodes: invalid address %s\n", nodeaddr);
		close(s);
		exit(1);
	}

	if ((dev = ax25_config_get_dev(argv[4])) == NULL) {
		fprintf(stderr, "rsparms: nodes: invalid port name - %s\n", argv[4]);
		close(s);
		exit(1);
	}

	strcpy(rs_node.device, dev);

	if (convert_call_entry(argv[5], rs_node.neighbour.ax25_call) != 0) {
		fprintf(stderr, "rsparms: nodes: invalid callsign %s\n", argv[5]);
		close(s);
		exit(1);
	}

	for (i = 6, n = 0; i < argc && n < AX25_MAX_DIGIS; i++, n++) {
		if (convert_call_entry(argv[i], rs_node.digipeaters[n].ax25_call) != 0) {
			fprintf(stderr, "rsparms: nodes: invalid callsign %s\n", argv[i]);
			close(s);
			exit(1);
		}
	}

	rs_node.ndigis = n;

	if (argv[2][0] == 'a') {
		if (ioctl(s, SIOCADDRT, &rs_node) == -1) {
			perror("rsparms: SIOCADDRT");
			close(s);
			exit(1);
		}
	} else {
		if (ioctl(s, SIOCDELRT, &rs_node) == -1) {
			perror("rsparms: SIOCDELRT");
			close(s);
			exit(1);
		}
	}
}

int main(int argc, char *argv[])
{
	ax25_address rose_call;
	int s = 0;
	
	if (argc == 1) {
		fprintf(stderr, "usage: rsparms -call|-nodes|-version ...\n");
		return 1;
	}

	if (strncmp(argv[1], "-v", 2) == 0) {
		printf("rsparms: %s\n", version);
		return 0;
	}

	if (strncmp(argv[1], "-c", 2) == 0) {
		if (argc < 3) {
			fprintf(stderr, "usage: rsparms -call <callsign>|none\n");
			return 1;
		}

		if (strcmp(argv[2], "none") != 0) {
			if (convert_call_entry(argv[2], rose_call.ax25_call) == -1) {
				fprintf(stderr, "rsparms: invalid callsign %s\n", argv[2]);
				return 1;
			}
		} else {
			rose_call = null_ax25_address;
		}

		if ((s = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) {
			perror("rsparms: socket");
			return 1;
		}
		
		if (ioctl(s, SIOCRSL2CALL, &rose_call) == -1) {
			perror("rsparms: ioctl");
			close(s);
			return 1;
		}

		close(s);

		return 0;
	}

	if (strncmp(argv[1], "-n", 2) == 0) {
		if (argc < 6) {
			fprintf(stderr, nodes_usage);
			return 1;
		}

		if ((s = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) {
			perror("rsparms: socket");
			return 1;
		}

		nodes(s, argc, argv);

		close(s);

		return 0;
	}

	fprintf(stderr, "usage: rsparms -call|-nodes|-version ...\n");
	
	close(s);
	
	return 1;
}
