/*
 * Network Explorer
 *
 * Copyright (C) 1998, Mark Spencer
 * 
 * Distributed under the terms of the GNU GPL
 *
 */
#include <gtk/gtk.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pwd.h>
#include "cheops.h"

void immediate_setcursor(int c)
{
	GdkCursor *cursor;
	cursor = gdk_cursor_new(GDK_WATCH);
	gdk_window_set_cursor(main_window.window->window, cursor);
	gdk_cursor_destroy(cursor);
	while (gtk_events_pending())
               gtk_main_iteration();
}

static int telnet_connect(char *hostname, char *ip, char *username, int port)
{
	char buf[256];
	snprintf(buf, sizeof(buf), "xterm -T 'Telnet to %s' -e telnet %s %d &", hostname, ip, port);
	return system(buf);
}

static int ftp_connect(char *hostname, char *ip, char *username, int port)
{
	char buf[256];
	snprintf(buf, sizeof(buf), "xterm -T 'FTP to %s' -e ftp %s %d &", hostname, ip, port);
	return system(buf);
}

static int netscape_connect(char *hostname, char *ip, char *username, int port)
{
	char buf[256];
	snprintf(buf, sizeof(buf), "netscape -remote 'OpenURL(http://%s:%d)' &", ip, port);
	return system(buf);
}

static int ssh_connect(char *hostname, char *ip, char *username, int port)
{
	char buf[256];
	snprintf(buf, sizeof(buf), "xterm -T 'SSH to %s' -e ssh -l %s %s -p %d &",hostname, username, ip, port);
	return system(buf);
}

static int ping_connect(char *hostname, char *ip, char *username, int port)
{
	char buf[256];
	/* MTR might be nice, too */
	snprintf(buf, sizeof(buf), "xterm -T 'Ping to %s' -e /bin/ping %s &", hostname, ip);
	return system(buf);
}

static int traceroute_connect(char *hostname, char *ip, char *username, int port)
{
	char buf[256];
	/* MTR might be nice, too */
	snprintf(buf, sizeof(buf), "xterm -T 'Traceroute to %s' -e sh -c '/usr/sbin/traceroute %s && read a' &", hostname, ip);
	return system(buf);
}

static int finger_connect(char *hostname, char *ip, char *username, int port)
{
	char buf[256];
	snprintf(buf, sizeof(buf), "xterm -T 'Finger at %s' -e sh -c '/usr/bin/finger @%s && read a' &", hostname, ip);
	return system(buf);
}

#if 0
static int talk_connect(char *hostname, char *ip, char *username, int port)
{
	char buf[256];
	snprintf(buf, sizeof(buf), "xterm -T 'talk to %s@%s' -e sh -c '/usr/bin/talk %s@%s && read a' &", username, hostname, username, ip);
	return system(buf);
}
#endif

struct service services[] = 
{
	{ 0, "Ping", ping_connect, 0 },
	{ 0, "Traceroute", traceroute_connect, 0 },
	{ 21, "FTP", ftp_connect, 0 },
	{ 22, "Secure Shell", ssh_connect, FLAG_USERNAME },
	{ 23, "Telnet", telnet_connect, 0 },
	{ 79, "Finger", finger_connect, 0 },
	{ 80, "Netscape", netscape_connect, 0 },
};

int service_cnt = sizeof(services) / sizeof(struct service);

static void submit_username(GtkWidget *w, struct service *s)
{
	struct net_object *no;
	struct in_addr ia;
	char *username;
	username = gtk_entry_get_text(GTK_ENTRY(w));
	no = (struct net_object *)gtk_object_get_user_data(GTK_OBJECT(w));
	ia.s_addr = no->ip_addr;	
	gtk_widget_destroy(w->parent->parent);
	if (s->connect(no->hostname, inet_ntoa(ia), username, s->port) < 0)
		fprintf(stderr, "service '%s' failed to launch\n", s->name);
}

static void show_username(struct service *s, struct net_object *no)
{
	GtkWidget *window;
	GtkWidget *vbox;
	GtkWidget *label;
	GtkWidget *entry;
	struct passwd *pw;
	char buf[256];
	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_widget_realize(window);
	fix_icon(window->window);
	entry = gtk_entry_new();
	pw = getpwuid(getuid());
	if (pw) {
		gtk_entry_set_text(GTK_ENTRY(entry), pw->pw_name);
		gtk_entry_select_region(GTK_ENTRY(entry), 0, -1);
	}
	vbox = gtk_vbox_new(FALSE, 5);
	snprintf(buf, sizeof(buf), "Enter username for %s\n",no->hostname);
	label = gtk_label_new(buf);
	gtk_widget_show(entry);
	gtk_widget_show(label);
	gtk_widget_show(vbox);
	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 5);
	gtk_container_add(GTK_CONTAINER(window), vbox);
	gtk_container_border_width(GTK_CONTAINER(window), 10);
	gtk_object_set_user_data(GTK_OBJECT(entry), no);
	gtk_signal_connect(GTK_OBJECT(entry),
			  "activate",
			  GTK_SIGNAL_FUNC(submit_username), 
			  s);
	gtk_signal_connect(GTK_OBJECT(window), "delete_event",
			   GTK_SIGNAL_FUNC(gtk_widget_destroy),
			   window);
	gtk_window_set_title(GTK_WINDOW(window), "Username");
	gtk_widget_grab_focus(entry);
	gtk_widget_show(window);
}

static void service_menu(GtkWidget *w, struct service *s)
{
	struct net_object *no;
	struct in_addr ia;
	no = (struct net_object *)gtk_object_get_user_data(GTK_OBJECT(w));
	gtk_widget_destroy(w->parent);
	if (s->flags & FLAG_USERNAME) {
		show_username(s, no);
	} else {
		ia.s_addr = no->ip_addr;
		if (s->connect(no->hostname, inet_ntoa(ia), "", s->port) < 0)
			fprintf(stderr, "service '%s' failed to launch\n", s->name);
	}
}

static void detect_object(GtkWidget *w, struct net_object *no)
{
	struct net_page *np;
	np = (struct net_page *)gtk_object_get_user_data(GTK_OBJECT(no->eventbox->parent));
	examine_host_queue(no->ip_addr, try_ports[0], np); 
}

static void map_object(GtkWidget *w, struct net_object *no)
{
	start_mapping(no);
}

void show_service_menu(struct net_object *no, GdkEventButton *event)
{
	GtkWidget *menu;
	GtkWidget *menuitem;
	struct in_addr me;
	struct port *p1=NULL, *p2;
	int x;
	menu = gtk_menu_new();
	if (option_port_scan) {
		for (x=0;x<service_cnt;x++) {
			if (services[x].port) {
				p2 = g_new(struct port, 1);
				p2->next = p1;
				p2->dport = services[x].port;
				p2->avail = -1;
				p2->sport = 0;
				p2->svc = &services[x];
				p1 = p2;
			} 
		}
		me = getlocalip(no->ip_addr);
		/* Wait up to 3 seconds for replies to come in */
		immediate_setcursor(GDK_WATCH);
		scan_ports(me.s_addr, no->ip_addr, p1, 3);
		gdk_window_set_cursor(main_window.window->window, NULL);
		while(p1) {
			p2 = p1;
			p1=p1->next;
			if (p2->avail>0) {
				menuitem = gtk_menu_item_new_with_label(p2->svc->name);
				gtk_menu_prepend(GTK_MENU(menu), menuitem);
				gtk_widget_show(menuitem);
				gtk_object_set_user_data(GTK_OBJECT(menuitem), no);
				gtk_signal_connect(GTK_OBJECT(menuitem),
					  "activate",
					  GTK_SIGNAL_FUNC(service_menu), 
					  p2->svc);
			}
			g_free(p2);
		}
	}
	for (x=0;x<service_cnt; x++) {
		if (!option_port_scan || services[x].port == 0) {
			menuitem = gtk_menu_item_new_with_label(services[x].name);
			if (option_port_scan)
				gtk_menu_prepend(GTK_MENU(menu), menuitem);
			else
				gtk_menu_append(GTK_MENU(menu), menuitem);
			gtk_widget_show(menuitem);
			gtk_object_set_user_data(GTK_OBJECT(menuitem), no);
			gtk_signal_connect(GTK_OBJECT(menuitem),
				  "activate",
				  GTK_SIGNAL_FUNC(service_menu), 
				  &services[x]);
		}
	}
	/* Add MAP option */
	menuitem = gtk_menu_item_new();
	gtk_widget_show(menuitem);
	gtk_menu_prepend(GTK_MENU(menu), menuitem);
	menuitem = gtk_menu_item_new_with_label("Map");
	gtk_signal_connect(GTK_OBJECT(menuitem),
			   "activate",
			   GTK_SIGNAL_FUNC(map_object), 
			   no);
	gtk_widget_show(menuitem);
	gtk_menu_prepend(GTK_MENU(menu), menuitem);
	/* Add Detect option */
	menuitem = gtk_menu_item_new();
	gtk_menu_prepend(GTK_MENU(menu), menuitem);
	menuitem = gtk_menu_item_new_with_label("Detect");
	gtk_signal_connect(GTK_OBJECT(menuitem),
			   "activate",
			   GTK_SIGNAL_FUNC(detect_object), 
			   no);
	gtk_widget_show(menuitem);
	gtk_menu_prepend(GTK_MENU(menu), menuitem);

	gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
}
