/*
 * Network Explorer
 *
 * Copyright (C) 1998, Mark Spencer
 * 
 * Distributed under the terms of the GNU GPL
 *
 */

#include <gtk/gtk.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
#ifdef USE_GNOME
#include <gnome.h>
#endif
#include "cheops.h"

static char defname[256] = "";
struct net_win main_window;
struct net_page *current_page=NULL;
static struct pixmap_cache *pc=NULL;

static void show_page_menu(struct net_win *n);
static void hide_page_menu(struct net_win *n);
	
void set_status(char *s)
{
	GtkWidget *bar = main_window.status;
	char *tmp;
	gtk_label_get(GTK_LABEL(GTK_STATUSBAR(bar)->label), &tmp);
	if (strcmp(tmp, s)) {
		gtk_statusbar_pop(GTK_STATUSBAR(bar), 1);
		gtk_statusbar_push(GTK_STATUSBAR(bar), 1, s);
	}
}

static struct pcache *get_cache(struct net_page *np, unsigned int addr)
{
	struct pcache *pc;
	struct in_addr ia;
	pc = np->pos;
	while(pc) {
		if (pc->addr == addr)
			return pc;
		pc=pc->next;
	}
	ia.s_addr = addr;
	pc = g_new(struct pcache, 1);
	pc->x=0;
	pc->y=0;
	pc->addr = addr;
	pc->next = np->pos;
	np->pos = pc;
	return pc;
}

static void arrange_cb(GtkWidget *w, int how)
{
	arrange(current_page, how);
}

static struct pcache *check_cache(struct net_page *np, unsigned int addr)
{
	struct pcache *pc;
	pc = np->pos;
	while(pc) {
		if (pc->addr == addr)
			return pc;
		pc=pc->next;
	}
	return pc;
}

static void do_save(GtkWidget *w, char *fn)
{
	GtkNotebookPage *page;
	struct net_page *p;
	struct network *nw;
	struct domain *d;
	struct in_addr ia;
	struct pcache *pc;
	GList *li;
	char *label;
	FILE *out;
	char filename[256];
	char buf[256];
	if (fn) {
		strncpy(filename,fn, sizeof(filename));
	} else {
		strncpy(filename, defname, sizeof(filename));
	}
	out = fopen(filename, "w+");
	if (!out) {
		perror("fopen");
		return;
	}
	li = g_list_first(GTK_NOTEBOOK(main_window.notebook)->first_tab);
	while(li) {
		page = (GtkNotebookPage *)(li->data);
		gtk_label_get(GTK_LABEL(page->tab_label), &label);
		fprintf(out, "[page %s]\n", label);
		p = (struct net_page *)gtk_object_get_user_data(GTK_OBJECT(page->child));
		fprintf(out, "[option map %d]\n", p->automap);
		fprintf(out, "[option smallicons %d]\n", p->small_icons);
		fprintf(out, "[option listview %d]\n", gtk_notebook_current_page(GTK_NOTEBOOK(p->notebook)));
		nw = p->ncontents;
		while(nw) {
			ia.s_addr = nw->net_addr;
			fprintf(out, "[network %s", inet_ntoa(ia));
			ia.s_addr = nw->net_mask;
			fprintf(out, " %s]\n", inet_ntoa(ia));
			nw=nw->next;
		}
		d = p->dcontents;
		while(d) {
			fprintf(out, "[domain %s %d]\n", d->domain, d->recursive);
			d=d->next;
		}
		if (option_remember_positions) {
			pc = p->pos;
			while(pc) {
				ia.s_addr = pc->addr;
				fprintf(out,"[position %s %d %d]\n", inet_ntoa(ia), pc->x, pc->y);
				pc = pc->next;
			}
		}
				
		li = g_list_next(li);
	}
	fclose(out);
	strncpy(defname, filename, sizeof(defname));
	snprintf(buf, sizeof(buf), "Saved '%s'", filename);
	set_status(buf);
}

static void make_saveas(GtkWidget *blah, GtkWidget *w)
{
	char *fn;
	fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION(w));
	if (strlen(fn)) {
		do_save(NULL, fn);
		gtk_widget_destroy(w);
	}
}

static void remove_page()
{
	struct net_object *no, *no2;
	struct network *n, *n2;
	struct domain *d, *d2;
	struct net_page *np;
	int l;
	np = current_page;
	current_page = NULL;
	if (!np)
		return;
	if ((l=g_list_length(GTK_NOTEBOOK(np->pane->parent)->children)) < 2)
		hide_page_menu(&main_window);
	no = np->objs;
	n = np->ncontents;
	d = np->dcontents;
	while(n) {
		n2=n;
		n=n->next;
		g_free(n2);
	}
	while(d) {
		d2=d;
		d=d->next;
		g_free(d2);
	}
	while(no) {
		no2=no;
		/* destroy graphical representation */
		gtk_widget_destroy(no->eventbox);
		gtk_widget_destroy(no->otherbox);
		no = no->next;
		g_free(no2);
	}
	if (np->pe) {
		gtk_widget_destroy(np->pe->window);
		g_free(np->pe);
	}
	gtk_widget_destroy(np->notebook);
	g_free(np);
}

static void refresh_page()
{
	struct network *net;
	struct domain *d;
	struct in_addr a,m;
	char netmask[80];
	char ip[80];
#if 0
	printf("refreshing...\n");
#endif
	if (!current_page)
		return;
	net = current_page->ncontents;
	while(net) {
		a.s_addr = net->net_addr;
		m.s_addr = net->net_mask;
		strcpy(ip, inet_ntoa(a));
		strcpy(netmask, inet_ntoa(m));
#if 0
		printf("refreshing '%s' (%s)\n",ip, netmask);
#endif
		discover_network_a(current_page, ip,netmask, 0);
		net=net->next;
	} 
	d = current_page->dcontents;
	while(d) {
#if 0
		printf("refreshing '%s'\n",d->domain);
#endif
		gather_hosts(current_page, d->domain, d->recursive, 0);
		d=d->next;
	} 
}

static int do_load(char *fn)
{
	char filename[256];
	char buf[256];
	char *c, *d, *e;
	FILE *f;
	int res=0;
	struct net_page *np=NULL;
	
	while(current_page)
	{
		remove_page();
	}
	
	if (fn) {
		strncpy(filename, fn, sizeof(filename));
	} else {
		strncpy(filename, defname, sizeof(filename));
	}
	f = fopen(filename, "r");
	if (!f) {
		snprintf(buf, sizeof(buf), "Unable to open '%s'", filename);
		if (fn)
			set_status(buf);
		return 0;
	}
	res=1;
	while(!feof(f)) {
		fgets(buf, sizeof(buf), f);
		if (feof(f)) break;
		if (!strncasecmp(buf,"[page",5)) {
			c = buf + 6;
			d = strchr(c, ']');
			if (!d)
				continue;
			*d='\0';
			np=add_network(&main_window, c);
			res++;
		} else 
		if (!strncasecmp(buf,"[option", 7)) {
			c = buf + 8;
			d = strchr(c, ' ');
			if (!d)
				continue;
			*d = '\0';
			d++;
			e =strchr(d, ']');
			if (!e)
				continue;
			*e='\0';
			if (!np)
				continue;
			if (!strcasecmp(c, "map")) {
				np->automap=atoi(d);
			}
			if (!strcasecmp(c, "smallicons")) {
				if (atoi(d) && !np->small_icons) {
					np->small_icons = 2;
					np->icon_height /= 2;
					np->icon_width /= 2;
				}
			}
			if (!strcasecmp(c, "listview")) {
				if (atoi(d)) 
					gtk_notebook_set_page(GTK_NOTEBOOK(np->notebook), 1);
				else
					gtk_notebook_set_page(GTK_NOTEBOOK(np->notebook), 0);
				
			}
		} else
		if (!strncasecmp(buf,"[network",8)) {
			c = buf + 9;
			d = strchr(c, ' ');
			if (!d)
				continue;
			*d='\0';
			d++;
			e =strchr(d, ']');
			if (!e)
				continue;
			*e='\0';
			if (!np)
				continue;
			discover_network_a(np, c, d, 1);
		} else
		if (!strncasecmp(buf,"[domain",7)) {
			c = buf + 8;
			d = strchr(c, ' ');
			if (!d)
				continue;
			*d='\0';
			d++;
			e =strchr(d, ']');
			if (!e)
				continue;
			*e='\0';
			if (!np)
				continue;
			gather_hosts(np, c, atoi(d), 1);
		} else 
		if (!strncasecmp(buf,"[position",9)) {
			int x, y;
			struct hostent *hp;
			struct pcache *pc;
			if (!np)
				continue;
			c = buf + 10;
			d = strchr(c, ' ');
			if (!d)
				continue;
			*d='\0';
			d++;
			e =strchr(d, ' ');
			if (!e)
				continue;
			*e='\0';
			e++;
			x = atoi(d);
			d = strchr(e,']');
			if (!d)
				continue;
			*d='\0';
			y = atoi(e);
			hp = gethostbyname(c);
			if (!hp) {
				fprintf(stderr, "Load Warning: No such host %s\n",c);
				continue;
			}
			pc = get_cache(np, *(unsigned int *)hp->h_addr);
			pc->x = x;
			pc->y = y;
		}
	}
	fclose(f);
	strncpy(defname, filename, sizeof(defname));
	snprintf(buf, sizeof(buf), "Loaded '%s'", filename);
	set_status(buf);
	return res;
}

static void make_load(GtkWidget *blah, GtkWidget *w)
{
	char *fn;
	fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION(w));
	if (strlen(fn)) {
		do_load(fn);
		gtk_widget_destroy(w);
	}
}

static void cancel_saveas(GtkWidget *w, GtkWidget *w2)
{
	gtk_widget_destroy(w2);
}


static void do_saveas()
{
	GtkWidget *fs;
	fs = gtk_file_selection_new("Save As...");
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), "clicked", GTK_SIGNAL_FUNC(make_saveas), fs);
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->cancel_button), "clicked", GTK_SIGNAL_FUNC(cancel_saveas), fs);
	gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), defname);
	gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(fs));
	gtk_widget_show(fs);
}


static void do_open()
{
	GtkWidget *fs;
	fs = gtk_file_selection_new("Open...");
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), "clicked", GTK_SIGNAL_FUNC(make_load), fs);
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->cancel_button), "clicked", GTK_SIGNAL_FUNC(cancel_saveas), fs);
	gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), defname);
	gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(fs));
	gtk_widget_show(fs);
}

struct net_object *get_object(struct net_page *page, unsigned int addr)
{
	struct net_object *no;
	no = page->objs;
	while(no) {
		if (no->ip_addr == addr)
			break;
		no = no->next;
	}
	return no;
}

void do_quit()
{
	exit(0);
}

void object_link(struct net_page *np, struct net_object *no, struct net_object *no2)
{
	struct link *l1, *l2;
	if (no == no2) {
#if 0
		printf("Being asked to link an object to itself (%s)!\n", no->hostname);
#endif
		return;
	}
	l1 = g_new(struct link, 1);
	l1->linkw = gtk_link_new();
	l1->other = no2;
	l1->page = np;
	l1->next = no->links;
	no->links = l1;
	l2 = g_new(struct link, 1);
	l2->linkw = l1->linkw;
	l2->other = no;
	l2->page = np;
	l2->next = no2->links;
	gtk_widget_show(l2->linkw);
	gtk_fixed_put(GTK_FIXED(np->fixed), l1->linkw, 500, 500);
	no2->links = l2;
	gtk_link_set_coords(GTK_LINK(l1->linkw),
			    GTK_WIDGET(no->eventbox)->allocation.x + GTK_WIDGET(no->eventbox)->allocation.width/2,
			    GTK_WIDGET(no->eventbox)->allocation.y + GTK_WIDGET(no->eventbox)->allocation.height/2,
			    GTK_WIDGET(no2->eventbox)->allocation.x + GTK_WIDGET(no2->eventbox)->allocation.width/2,
			    GTK_WIDGET(no2->eventbox)->allocation.y + GTK_WIDGET(no2->eventbox)->allocation.height/2);
}

char *get_pm_name(char *fn, char *extn)
{
	static char filename[256];
	char *c;
	strncpy(filename, fn, sizeof(filename));
	if ((c = strstr(filename, ".xpm"))) {
		strncpy(c, extn, sizeof(filename) - (c - filename));
	}
	return filename;
}

struct pixmap_cache *get_pixmap(char *filename)
{
	struct pixmap_cache *tmp;
	GtkStyle *style = gtk_widget_get_default_style();
	tmp = pc;
	while(tmp) {
		if (!strcmp(filename,tmp->filename)) {
			break;
		}
		tmp=tmp->next;
	}
	if (!tmp) {
		tmp = g_new(struct pixmap_cache, 1);
		strncpy(tmp->filename, filename, sizeof(tmp->filename));
		tmp->pixmap = gdk_pixmap_create_from_xpm (main_window.window->window, &tmp->mask, 
					   &style->bg[GTK_STATE_NORMAL],
					   find_file(filename));
		tmp->next = pc;
		pc = tmp;
	}
	return tmp;
}



static void shrink_pixmap(struct net_object *no, int cnt)
{
	struct pixmap_cache *tmp;
	tmp = get_pixmap(get_pm_name(no->fn, "-small.xpm"));
	gtk_pixmap_set(GTK_PIXMAP(no->pixmap), tmp->pixmap, tmp->mask);
	gtk_widget_set_usize(no->eventbox, no->pixmap->requisition.width, no->pixmap->requisition.height);
	gtk_widget_shape_combine_mask(no->eventbox, NULL, 0, 0);
	gtk_widget_shape_combine_mask(no->eventbox, tmp->mask, 0, 0);

}

static void normal_pixmap(struct net_object *no)
{
	struct pixmap_cache *tmp;
	tmp = get_pixmap(no->fn);
	gtk_pixmap_set(GTK_PIXMAP(no->pixmap), tmp->pixmap, tmp->mask);
	gtk_widget_set_usize(no->eventbox, no->pixmap->requisition.width, no->pixmap->requisition.height);
	gtk_widget_shape_combine_mask(no->eventbox, NULL, 0, 0);
	gtk_widget_shape_combine_mask(no->eventbox, tmp->mask, 0, 0);

}


void add_object(struct net_page *page, struct net_object *no)
{

	struct pcache *pc;
	pc = check_cache(page, no->ip_addr);
	if (page->small_icons) {
		shrink_pixmap(no, page->small_icons);
	}
	if (pc) {
		gtk_fixed_put(GTK_FIXED(page->fixed), no->eventbox, pc->x, pc->y);
		gtk_fixed_put(GTK_FIXED(page->fixed), no->otherbox, pc->x , pc->y + page->icon_height - 15);
		if (pc->y + page->icon_height > page->fixed->allocation.height)
			gtk_widget_set_usize(page->fixed, 0, pc->y + page->icon_height);
	} else {
		gtk_fixed_put(GTK_FIXED(page->fixed), no->eventbox, page->lastx, page->lasty);
		gtk_fixed_put(GTK_FIXED(page->fixed), no->otherbox, page->lastx , page->lasty + page->icon_height - 15);
		page->lastx += page->icon_width;
		if (page->lastx > (option_use_visible_area ? page->pane->allocation.width : FIXED_WIDTH) - page->icon_width) {
			page->lastx = 20;
			page->lasty += page->icon_height;
			if (page->lasty + page->icon_height > page->eventbox->allocation.height) {
				gtk_widget_set_usize(page->eventbox, 0, page->fixed->allocation.height + page->icon_height);
			}
			
		}
	}
	add_to_list(page->list, no);
	gtk_widget_realize(no->eventbox);
	gtk_widget_realize(no->pixmap);
	gtk_widget_realize(no->otherbox);
	gtk_widget_realize(no->label);
	no->next = page->objs;
	page->objs = no;
	while(gtk_events_pending())
		gtk_main_iteration();
	check_connections(page, no);
	if (page->automap && option_automap && !no->mapped)
		start_mapping(no);
}

static void move_object(GtkWidget *widget, GdkEventMotion *event, struct net_object *no)
{
	int xp, yp;
	struct net_page *np;
	struct pcache *pc;
	struct link *l;
	if (no->drag) {
		np = (struct net_page *)gtk_object_get_user_data(GTK_OBJECT(no->eventbox->parent));
		pc = get_cache(np, no->ip_addr);
		gtk_widget_get_pointer(no->eventbox->parent, &xp, &yp);
		gtk_widget_set_uposition(no->eventbox, 
					 xp - no->xo- (no->eventbox->allocation.width - np->icon_width)/2,
					 yp - no->yo);
		gtk_widget_set_uposition(no->otherbox, 
					 xp - no->xo - (no->otherbox->allocation.width - np->icon_width) / 2, 
					 yp - no->yo + np->icon_height - 15);
		pc->x = no->eventbox->allocation.x;
		pc->y = no->eventbox->allocation.y;
		l = no->links;
		if (!option_update_release)
		while(l) {
			/* Check validity of other widget? */
			gtk_link_set_coords(GTK_LINK(l->linkw),
				    no->eventbox->allocation.x + no->eventbox->allocation.width/2,				    no->eventbox->allocation.y + no->eventbox->allocation.height/2,
				    l->other->eventbox->allocation.x + l->other->eventbox->allocation.width / 2,
				    l->other->eventbox->allocation.y + l->other->eventbox->allocation.height / 2);
			l=l->next;
		}
	}
}

static int destroy_hand(void *data)
{
	struct net_page *np = (struct net_page *)gtk_object_get_user_data(GTK_OBJECT(data));
	GtkWidget *widget = GTK_WIDGET(data);
	np->lasthand = NULL;
	np->lastid=0;
	gtk_widget_destroy(widget);
	return FALSE;
}

static void push_page(GtkWidget *widget, GdkEventButton *event, struct net_page *np)
{
	static GtkMenuPath *gmp;
	if (!valid_np(np)) 
		return;
	if (np->sel)
		gtk_widget_set_state(np->sel->label, GTK_STATE_NORMAL);
	np->sel = NULL;
	if (event->button == 1) {
		if (event->type == GDK_2BUTTON_PRESS)
			printf("Double click!\n");
	} else {
		gmp = gtk_menu_factory_find(main_window.menuf, "<Main>/Page");
		gtk_menu_popup(GTK_MENU(GTK_MENU_ITEM(gmp->widget)->submenu), NULL, NULL, NULL, NULL, event->button, event->time);
	}
}

static void move_page(GtkWidget *w, GdkEventMotion *event, struct net_page *np)
{
	if (np->sel)
		move_object(NULL, event, np->sel);
}

static void push_object(GtkWidget *widget, GdkEventButton *event, struct net_object *no)
{
	int xp, yp;
	char buf[256];
	struct net_page *np;
	np = (struct net_page *)gtk_object_get_user_data(GTK_OBJECT(no->eventbox->parent));
	if (valid_np(np)) {
		if (np->sel)
			gtk_widget_set_state(np->sel->label, GTK_STATE_NORMAL);
		np->sel = no;
	}
	gtk_widget_set_state(no->label, GTK_STATE_SELECTED);
	gtk_widget_get_pointer(no->eventbox->parent, &xp, &yp);
	snprintf(buf, sizeof(buf), "Host '%s'", no->hostname);
	set_status(buf);
	if (event->button == 1) {
		if (event->type == GDK_2BUTTON_PRESS)
			printf("Double click!\n");
		else {
			no->xo = event->x - (no->eventbox->allocation.width - np->icon_width)/2;
			no->yo = event->y;
			if (widget == no->otherbox)
				no->yo += (no->eventbox->allocation.height);
			no->drag = 1;
		}
	} else 
		show_service_menu(no, event);
}


static void release_object(GtkWidget *widget, GdkEventButton *event, struct net_object *no)
{
	struct link *l;
		
	l = no->links;
	if (option_update_release)
	while(l) {
		/* Check validity of other widget? */
		gtk_link_set_coords(GTK_LINK(l->linkw),
				    no->eventbox->allocation.x + no->eventbox->allocation.width/2,				    no->eventbox->allocation.y + no->eventbox->allocation.height/2,
				    l->other->eventbox->allocation.x + l->other->eventbox->allocation.width / 2,
				    l->other->eventbox->allocation.y + l->other->eventbox->allocation.height / 2);
		l=l->next;
	}
	no->drag = 0;
}

static void add_hand(struct net_page *np, int x, int y, char *filename)
{
	GtkWidget *pixmap;
	GtkWidget *fixed = np->fixed;
	GtkWidget *hbar = GTK_SCROLLED_WINDOW(np->pane)->hscrollbar;
	GtkWidget *vbar = GTK_SCROLLED_WINDOW(np->pane)->vscrollbar;
	struct pixmap_cache *tmp;
	
	if (np->lastid) {
		gtk_timeout_remove(np->lastid);
		if (np->lasthand)
			gtk_widget_destroy(np->lasthand);
		np->lastid = 0;
	}
	
	tmp = get_pixmap(filename);
	pixmap = gtk_pixmap_new (tmp->pixmap, tmp->mask);
	gtk_object_set_user_data(GTK_OBJECT(pixmap), np);
#if 0
	gtk_widget_shape_combine_mask (pixmap, gdk_pixmap_mask, 0,0);
#endif
	gtk_widget_show(pixmap);
	np->lastid = gtk_timeout_add(6000, destroy_hand, pixmap);
	np->lasthand = pixmap;
	gtk_fixed_put(GTK_FIXED(fixed), pixmap, x + 20, y + np->icon_height - 30);
	x = x - np->pane->allocation.width/2;
	y = y - np->pane->allocation.height/2;
	if (x < 0)
		x=0;
	if (y < 0)
		y=0;
	gtk_adjustment_set_value(GTK_RANGE(hbar)->adjustment, x);
	gtk_adjustment_set_value(GTK_RANGE(vbar)->adjustment, y);
#if 0
	printf("max is %f, min is %f\n", GTK_RANGE(vbar)->adjustment->upper, GTK_RANGE(vbar)->adjustment->lower);
	printf("max is %f, min is %f\n", GTK_RANGE(hbar)->adjustment->upper, GTK_RANGE(hbar)->adjustment->lower);
#endif

}

void set_icon(struct net_object *no, char *filename)
{
	struct pixmap_cache *tmp;
	struct net_page *np;
	char *c, *cd;
	np = (struct net_page *)gtk_object_get_user_data(GTK_OBJECT(no->eventbox->parent));
	if (np->small_icons) {
		tmp = get_pixmap(get_pm_name(filename, "-small.xpm"));
	} else {
		tmp = get_pixmap(filename);
	}
	gtk_pixmap_set (GTK_PIXMAP(no->pixmap), tmp->pixmap, tmp->mask);
	gtk_widget_shape_combine_mask (no->eventbox, tmp->mask, 0,0);
	tmp = get_pixmap(get_pm_name(filename, "-tiny.xpm"));
	gtk_clist_get_text(GTK_CLIST(np->list), no->id, 0, &c);
	cd = strdup(c);
	gtk_clist_set_pixtext(GTK_CLIST(np->list), no->id, 0, cd, 4, tmp->pixmap, tmp->mask);
	free(cd);

}

static void grow_pixmaps()
{
	struct net_object *no;
	if (!current_page->small_icons)
		return;
	current_page->icon_height *= 2;
	current_page->icon_width *=2;
	no = current_page->objs;
	while(no) {
		normal_pixmap(no);
		place_object(no, no->eventbox->allocation.x, no->eventbox->allocation.y);
		no = no->next;
	}
	current_page->small_icons=0;
}

static void shrink_pixmaps()
{
	struct net_object *no;
	if (current_page->small_icons)
		return;
	current_page->small_icons=2;
	current_page->icon_height /= 2;
	current_page->icon_width /= 2;
	no = current_page->objs;
	while(no) {
		shrink_pixmap(no, current_page->small_icons);
		place_object(no, no->eventbox->allocation.x, no->eventbox->allocation.y);
		no = no->next;
	}
}

static void view_pictures(GtkWidget *w, void *data)
{
	if (data)
		shrink_pixmaps();
	else
		grow_pixmaps();
	gtk_notebook_set_page(GTK_NOTEBOOK(current_page->notebook), 0);
}

static void view_list(GtkWidget *w)
{
	gtk_notebook_set_page(GTK_NOTEBOOK(current_page->notebook), 1);
}

struct net_object *network_object(GdkWindow *window, 
					 char *filename,
					 char *name)
{
	struct net_object *no;
	struct pixmap_cache *tmp;
#if 0
	static GdkColor *yellow = NULL;
	
	if (!yellow) {
		GdkColormap *map;
		map = gdk_window_get_colormap(main_window.window->window);
		yellow = g_new(GdkColor, 1);
		yellow->red = 65535;
		yellow->green = 65535;
		yellow->blue = 0;
		gdk_color_alloc(map, yellow);
	}
#endif	
	
	no = g_new(struct net_object, 1);

	no->eventbox = gtk_event_box_new();
	no->otherbox = gtk_event_box_new();
	no->label = gtk_label_new(name);
	no->id=-1;
	
#if 0
	style = gtk_widget_get_style(no->label);
	style->bg[GTK_STATE_SELECTED] = *yellow;
#endif
	
	no->drag = 0;
	no->next = NULL;
	no->links = NULL;
	no->hostname[0]='\0';
	no->aliases=NULL;
	no->mapped = 0;
	tmp = get_pixmap(filename);
	strncpy(no->fn, filename, sizeof(no->fn));
	no->pixmap = gtk_pixmap_new (tmp->pixmap, tmp->mask);
	gtk_container_add(GTK_CONTAINER(no->eventbox), no->pixmap);
	gtk_container_add(GTK_CONTAINER(no->otherbox), no->label);
	gtk_object_set_user_data(GTK_OBJECT(no->eventbox), no);
	gtk_signal_connect(GTK_OBJECT(no->eventbox), "button_press_event",
			   GTK_SIGNAL_FUNC (push_object), no);
	gtk_signal_connect(GTK_OBJECT(no->eventbox), "button_release_event",
			   GTK_SIGNAL_FUNC (release_object), no);
	gtk_signal_connect(GTK_OBJECT(no->eventbox), "motion_notify_event",
			   GTK_SIGNAL_FUNC (move_object), no);		

	gtk_object_set_user_data(GTK_OBJECT(no->otherbox), no);
	gtk_signal_connect(GTK_OBJECT(no->otherbox), "button_press_event",
			   GTK_SIGNAL_FUNC (push_object), no);
	gtk_signal_connect(GTK_OBJECT(no->otherbox), "button_release_event",
			   GTK_SIGNAL_FUNC (release_object), no);
	gtk_signal_connect(GTK_OBJECT(no->otherbox), "motion_notify_event",
			   GTK_SIGNAL_FUNC (move_object), no);		

	gtk_widget_shape_combine_mask (no->eventbox, tmp->mask, 0,0);
	gtk_widget_show(no->label);
	gtk_widget_show(no->otherbox);
	gtk_widget_show(no->pixmap);
	gtk_widget_show(no->eventbox);
	return no;
	
}

void click_column(GtkWidget *w, GdkEventButton *event, struct net_page *np)
{
	int row=-1;
	int column=-1;
	struct net_object *no;
	if (event->window != GTK_CLIST(w)->clist_window)
		return;
	if (event->button < 2)
		return;
	gtk_clist_get_selection_info(GTK_CLIST(w), event->x, event->y, &row, &column);
	if (row > -1) {
		gtk_clist_select_row(GTK_CLIST(w), row, -1);
		no = (struct net_object *)gtk_clist_get_row_data(GTK_CLIST(w), row);
		show_service_menu(no, event);
	}
}

struct net_page *add_network(struct net_win *n, char *title)
{
	struct net_page *np;
	static char *titles[] = { "Hostname", "IP", "OS", "Aliases" };
	
#if (GTK_MINOR_VERSION > 1) || ((GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 4))
	/* GTK 1.1.5 handles scrolled widgets differently and requires labels for
	   pages or it will subtly crash */
	GtkWidget *sw;
	GtkWidget *label, *label2;
	sw = gtk_scrolled_window_new(NULL, NULL);
	label = gtk_label_new("");
	label2 = gtk_label_new("");
	gtk_widget_show(label);
	gtk_widget_show(label2);
	gtk_widget_show(sw);
#endif 
	np = g_new(struct net_page, 1);
	np->pane = gtk_scrolled_window_new(NULL, NULL);
	np->label = gtk_label_new(title);
	np->fixed = gtk_fixed_new();
	np->list = gtk_clist_new_with_titles(4, titles);
	np->notebook = gtk_notebook_new();
	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(np->notebook), FALSE);
	gtk_notebook_set_show_border(GTK_NOTEBOOK(np->notebook), FALSE);
	np->eventbox = gtk_event_box_new();
	np->ncontents = NULL;
	np->dcontents = NULL;
	np->lastx = 20;
	np->lasty = 20;
	np->objs = NULL;
	np->last = NULL;
	np->laststr[0]='\0';
	np->lasthand = NULL;
	np->lastid = 0;
	np->pending = NULL;
	np->automap = 0;
	np->pos = NULL;
	np->pe = NULL;
	np->sel = NULL;
	np->small_icons = 0;
	np->icon_height = DEFAULT_ICON_HEIGHT;
	np->icon_width = DEFAULT_ICON_WIDTH;
	
#if ((GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 2))  || (GTK_MAJOR_VERSION > 1)
	gtk_clist_set_column_auto_resize(GTK_CLIST(np->list), 0, TRUE);
	gtk_clist_set_column_auto_resize(GTK_CLIST(np->list), 1, TRUE);
	gtk_clist_set_column_auto_resize(GTK_CLIST(np->list), 2, TRUE);
	gtk_clist_set_column_auto_resize(GTK_CLIST(np->list), 3, TRUE);
#else
	gtk_clist_set_column_width(GTK_CLIST(np->list), 0,200);
	gtk_clist_set_column_width(GTK_CLIST(np->list), 1,100);
	gtk_clist_set_column_width(GTK_CLIST(np->list), 2,300);
	gtk_clist_set_column_width(GTK_CLIST(np->list), 3,200);
#endif	
	gtk_widget_set_usize(np->fixed, FIXED_WIDTH, FIXED_HEIGHT);
	gtk_container_add(GTK_CONTAINER(np->eventbox), np->fixed);
#if (GTK_MINOR_VERSION > 1) || ((GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 4))
	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(np->pane),
					      np->eventbox);
	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw),
					      np->list);
	gtk_object_set_user_data(GTK_OBJECT(sw), np);
	gtk_notebook_append_page(GTK_NOTEBOOK(np->notebook), np->pane, label);
	gtk_notebook_append_page(GTK_NOTEBOOK(np->notebook), sw, label2);
#else
	gtk_container_add(GTK_CONTAINER(np->pane), np->eventbox);
	gtk_notebook_append_page(GTK_NOTEBOOK(np->notebook), np->pane, NULL);
	gtk_notebook_append_page(GTK_NOTEBOOK(np->notebook), np->list, NULL);
#endif
	gtk_widget_show(np->label);
	gtk_widget_show(np->fixed);
	gtk_widget_show(np->eventbox);
	gtk_widget_show(np->list);
	gtk_widget_show(np->pane);
	gtk_widget_show(np->notebook);
	gtk_object_set_user_data(GTK_OBJECT(np->pane), np);
	gtk_object_set_user_data(GTK_OBJECT(np->fixed), np);
	gtk_object_set_user_data(GTK_OBJECT(np->eventbox), np);
	gtk_object_set_user_data(GTK_OBJECT(np->notebook), np);
	gtk_object_set_user_data(GTK_OBJECT(np->list), np);
	gtk_signal_connect(GTK_OBJECT(np->list), "button_press_event", GTK_SIGNAL_FUNC(click_column), np);
	gtk_signal_connect(GTK_OBJECT(np->eventbox), "button_press_event", GTK_SIGNAL_FUNC(push_page), np);
	gtk_signal_connect(GTK_OBJECT(np->eventbox), "motion_notify_event", GTK_SIGNAL_FUNC(move_page), np);
	gtk_notebook_set_page(GTK_NOTEBOOK(np->notebook), 0);
	gtk_notebook_append_page(GTK_NOTEBOOK(n->notebook), np->notebook, np->label);
	return np;
}

struct widgets {
	int data;
	GtkWidget *one;
	GtkWidget *two;
	GtkWidget *status;
	GtkWidget *toggle;
	struct net_page *np;
};

static void make_network(GtkWidget *w, GtkWidget *dialog)
{
	struct widgets *wids = (struct widgets *)gtk_object_get_user_data(GTK_OBJECT(w));
	
	char hostaddr[80];
	struct hostent *hp;
	unsigned int nm, addr;
	int res;
	int recursive;
	struct domain *d;
	struct network *n;
	if (!valid_np(wids->np)) {
		g_free(wids);
		gtk_widget_destroy(dialog);
		return;
	}
	if (wids->data == 2) {
		d = wids->np->dcontents;
		while(d) {
			if (!strcasecmp(d->domain, gtk_entry_get_text(GTK_ENTRY(wids->one))))
				break;
			d=d->next;
		}
		if (d) {
			gtk_widget_show(wids->status);
			gtk_statusbar_pop(GTK_STATUSBAR(wids->status), 1);
			gtk_statusbar_push(GTK_STATUSBAR(wids->status), 1, "Already there");
			gtk_entry_select_region(GTK_ENTRY(wids->one), 0, -1);
			return;
		}
		recursive = GTK_TOGGLE_BUTTON(wids->toggle)->active;
		/* Special case: request a domain */
		if (!get_server(gtk_entry_get_text(GTK_ENTRY(wids->one)),1)) {
			gtk_widget_show(wids->status);
			gtk_entry_select_region(GTK_ENTRY(wids->one), 0, -1);
			gtk_statusbar_pop(GTK_STATUSBAR(wids->status), 1);
			gtk_statusbar_push(GTK_STATUSBAR(wids->status), 1, "Invalid Domain");
			return;
		}
		res = gather_hosts(wids->np, gtk_entry_get_text(GTK_ENTRY(wids->one)), recursive, 1);
		if (res < 1) {
			/* Give it one more try, just in case */
			get_server(gtk_entry_get_text(GTK_ENTRY(wids->one)), 1);
			res = gather_hosts(wids->np, gtk_entry_get_text(GTK_ENTRY(wids->one)), recursive, 0);
		}
			
		if (res < 1) {
			gtk_widget_show(wids->status);
			gtk_statusbar_pop(GTK_STATUSBAR(wids->status), 1);
			gtk_statusbar_push(GTK_STATUSBAR(wids->status), 1, res ? "Invalid Domain" : "No hosts available");
			gtk_entry_select_region(GTK_ENTRY(wids->one), 0, -1);
			return;
		}
	} else {
		/* Network or host */
		
		hp = gethostbyname(gtk_entry_get_text(GTK_ENTRY(wids->one)));
		if (!hp) {
			gtk_widget_show(wids->status);
			gtk_entry_select_region(GTK_ENTRY(wids->one), 0, -1);
			gtk_statusbar_pop(GTK_STATUSBAR(wids->status), 1);
			gtk_statusbar_push(GTK_STATUSBAR(wids->status), 1, "Invalid Host");
			return;
		}
		addr = *(unsigned int *)(hp->h_addr);
		strncpy(hostaddr, inet_ntoa(*(struct in_addr *)hp->h_addr), sizeof(hostaddr));
		if (wids->two) {
			hp = gethostbyname(gtk_entry_get_text(GTK_ENTRY(wids->two)));
			if (!hp) {
				gtk_widget_show(wids->status);
				gtk_entry_select_region(GTK_ENTRY(wids->two), 0, -1);
				gtk_statusbar_pop(GTK_STATUSBAR(wids->status), 1);
				gtk_statusbar_push(GTK_STATUSBAR(wids->status), 1, "Invalid Netmask");
				return;
			}
			nm = htonl(*(unsigned int *)hp->h_addr);
			while(nm & 0x80000000)
				nm = (nm << 1) & 0xFFFFFFFE;
			if (nm) {
				gtk_widget_show(wids->status);
				gtk_entry_select_region(GTK_ENTRY(wids->two), 0, -1);
				gtk_statusbar_pop(GTK_STATUSBAR(wids->status), 1);
				gtk_statusbar_push(GTK_STATUSBAR(wids->status), 1, "Invalid Netmask");
				return;
			}
			nm = htonl(*(unsigned int *)hp->h_addr);
		} else 
			nm = 0xFFFFFFFF;
		n  = wids->np->ncontents;
		while(n) {
			if ((nm == ntohl(n->net_mask)) && (addr == n->net_addr))
				break;
			n=n->next;
		}
		if (n) {
			gtk_widget_show(wids->status);
			gtk_entry_select_region(GTK_ENTRY(wids->one), 0, -1);
			gtk_statusbar_pop(GTK_STATUSBAR(wids->status), 1);
			gtk_statusbar_push(GTK_STATUSBAR(wids->status), 1, "Already there");
			return;
		}
	}
	
	if (wids->two)
		discover_network_a(wids->np, hostaddr,
					 	gtk_entry_get_text(GTK_ENTRY(wids->two)), 1); 
	else
		discover_network_a(wids->np, hostaddr,
						"255.255.255.255", 1);
	g_free(wids);
	gtk_widget_destroy(dialog);
}

static int search(struct net_object *no, char *srch, int exact)
{
	char *str;
	struct in_addr ia;
	int res=0;
	gtk_label_get(GTK_LABEL(no->label), &str);
	if (exact) {
		if (!strcasecmp(str, srch))
			res=1;
	} else {
		if (strstr(str, srch))
			res=1;
	}
	if (exact) {
		if (!strcasecmp(no->hostname, srch))
			res=1;
	} else {
		if (strstr(no->hostname, srch))
			res=1;
	}
	ia.s_addr = no->ip_addr;
	if (exact) {
		if (!strcasecmp(inet_ntoa(ia), srch))
			res=1;;
	} else {
		if (strstr(inet_ntoa(ia), srch))
			res=1;
	}
	return res;
}

static void search_again()
{
	char *srch;
	int first;
	struct net_object *no;
	int x=0;
	if (!current_page)	
		return;
	srch = current_page->laststr;
	if (!strlen(srch)) {
		set_status("No previous search");
		return;
	}
	if (current_page->last) {
		if (gtk_notebook_current_page(GTK_NOTEBOOK(current_page->notebook))) {
			no = (struct net_object *)
				gtk_clist_get_row_data(GTK_CLIST(current_page->list), 
					current_page->last->id + 1);
			first = 0;
		} else {
			no = current_page->last->next;
			first = 0;
		}
		first=0;
	} else {
		if (gtk_notebook_current_page(GTK_NOTEBOOK(current_page->notebook))) {
			no = (struct net_object *)
				gtk_clist_get_row_data(GTK_CLIST(current_page->list), 0);
			first = 1;
		} else {
			no = current_page->objs;
			first = 1;
		}
	}
	if (gtk_notebook_current_page(GTK_NOTEBOOK(current_page->notebook)) && no) {
		for(x=no->id; x < GTK_CLIST(current_page->list)->rows;x++) {
			no = (struct net_object *)
				gtk_clist_get_row_data(GTK_CLIST(current_page->list), x);
			if (search(no, srch, 0))
				break;
		}
		if ( x >= GTK_CLIST(current_page->list)->rows)
			no=NULL;
	} else {
		while(no) {
			if (search(no, srch, 0))
				break;
			no=no->next;
		}
	}
	current_page->last = no;
	if (no) {
		char buf[256];
		snprintf(buf, sizeof(buf), "Found '%s'",no->hostname);
		set_status(buf);
		if (gtk_notebook_current_page(GTK_NOTEBOOK(current_page->notebook))) {
			gtk_clist_select_row(GTK_CLIST(current_page->list), no->id, -1);
			gtk_clist_moveto(GTK_CLIST(current_page->list), no->id, 0, 0.5, 0.5);
		} else
			add_hand(current_page, no->eventbox->allocation.x, no->eventbox->allocation.y, find_file("point.xpm"));
	} else {
		set_status(first ? "No matching hosts" : "No more matching hosts");
	}
}

static void make_search(GtkWidget *w, GtkWidget *dialog)
{
	struct widgets *wids = (struct widgets *)gtk_object_get_user_data(GTK_OBJECT(w));
	
	int exact;
	char *srch;
	struct net_object *no;
	int x;
	exact = GTK_TOGGLE_BUTTON(wids->toggle)->active;
	srch = gtk_entry_get_text(GTK_ENTRY(wids->one));
	if (!strlen(srch))
		return;
#if 0
	printf("Searching%s for %s\n",exact ? " exactly" : "", srch);
#endif
	if (gtk_notebook_current_page(GTK_NOTEBOOK(current_page->notebook))) {
		no = (struct net_object *)
			gtk_clist_get_row_data(GTK_CLIST(current_page->list), 0);
	} else {
		no = current_page->objs;
	}
	if (gtk_notebook_current_page(GTK_NOTEBOOK(current_page->notebook))) {
		for(x=no->id; x < GTK_CLIST(current_page->list)->rows;x++) {
			no = (struct net_object *)
				gtk_clist_get_row_data(GTK_CLIST(current_page->list), x);
			if (search(no, srch, 0))
				break;
		}
	} else {
		while(no) {
			if (search(no, srch, 0))
				break;
			no=no->next;
		}
	}
	current_page->last = no;
	strncpy(current_page->laststr, srch, sizeof(current_page->laststr));
	if (no) {
		char buf[256];
		snprintf(buf, sizeof(buf), "Found '%s'",no->hostname);
		set_status(buf);
		if (gtk_notebook_current_page(GTK_NOTEBOOK(current_page->notebook))) {
			gtk_clist_select_row(GTK_CLIST(current_page->list), no->id, -1);
			gtk_clist_moveto(GTK_CLIST(current_page->list), no->id, 0, 0.5, 0.5);
		} else 
			add_hand(current_page, no->eventbox->allocation.x, no->eventbox->allocation.y, find_file("point.xpm"));
		g_free(wids);
		gtk_widget_destroy(dialog);
	} else {
		gtk_widget_show(wids->status);
		gtk_statusbar_pop(GTK_STATUSBAR(wids->status), 1);
		gtk_statusbar_push(GTK_STATUSBAR(wids->status), 1, "Host not found");
		gtk_entry_select_region(GTK_ENTRY(wids->one), 0, -1);
		return;
	}
}

static void cancel_network(GtkWidget *w, GtkWidget *win)
{
	struct widgets *wids = (struct widgets *)gtk_object_get_user_data(GTK_OBJECT(w));
	if (wids)
		g_free(wids);
	gtk_widget_destroy(win);
}

static void cancel_page(GtkWidget *w, GtkWidget *win)
{
	gtk_widget_destroy(win);
}

static void netmask_focus(GtkWidget *w, GtkWidget *w2)
{
	char *c;
	struct hostent *hp;
	struct in_addr ia;
	char hostaddr[80];
	c = gtk_entry_get_text(GTK_ENTRY(w));
	hp = gethostbyname(c);
	if (hp) {
		memcpy(&ia, hp->h_addr, sizeof(ia));
		strncpy(hostaddr, inet_ntoa(ia), sizeof(hostaddr));
		gtk_entry_set_text(GTK_ENTRY(w), hostaddr);
	} else {
		gtk_entry_set_text(GTK_ENTRY(w), "");
	}
	c = gtk_entry_get_text(GTK_ENTRY(w));
	gtk_entry_set_text(GTK_ENTRY(w2), "255.255.255.255");
	if (strlen(c) > 2) {
		if (!strcmp(&c[strlen(c)-2], ".0"))
			gtk_entry_set_text(GTK_ENTRY(w2), "255.255.255.0");
	}
	if (strlen(c) > 4) {
		if (!strcmp(&c[strlen(c)-4], ".0.0"))
			gtk_entry_set_text(GTK_ENTRY(w2), "255.255.0.0");
	}
	if (strlen(c) > 6) {
		if (!strcmp(&c[strlen(c)-2], ".0.0.0"))
			gtk_entry_set_text(GTK_ENTRY(w2), "255.0.0.0");
	}
	
	gtk_widget_grab_focus(w2);
}

void do_network(GtkWidget *ign, int data)
{
	GtkWidget *dialog;
	GtkWidget *ok;
	GtkWidget *cancel;
	GtkWidget *label;
	GtkWidget *label2 = NULL;
	GtkWidget *hbox;
	GtkWidget *entry;
	GtkWidget *status;
	GtkWidget *netmask = NULL;
	GtkWidget *toggle = NULL;
	struct widgets *w;
	

	if (!GTK_NOTEBOOK(main_window.notebook)->children)
		return;
	
	w = g_new(struct widgets, 1);
	dialog = gtk_dialog_new();
	hbox = gtk_hbox_new(FALSE, 5);
	w->one = entry = gtk_entry_new();
	w->np = current_page;
	if (data)
		w->two = netmask = gtk_entry_new();
	else
		w->two = NULL;
	if (data == 1)
		label = gtk_label_new("Network address");
	else if (data == 2)
		label = gtk_label_new("Domain name");
	else
		label = gtk_label_new("Host name/address");
	if (data == 1)
		label2 = gtk_label_new("Netmask");
	cancel = gtk_button_new_with_label("Cancel");
	ok = gtk_button_new_with_label("OK");
	w->status = status = gtk_statusbar_new();
	if (data == 2) 
		w->toggle = toggle = gtk_check_button_new_with_label("Recurse Subdomains");
	w->data = data;
	if (data == 1)
		gtk_window_set_title(GTK_WINDOW(dialog), "Add Network");
	else if (data == 2)
		gtk_window_set_title(GTK_WINDOW(dialog), "Add Domain");
	else
		gtk_window_set_title(GTK_WINDOW(dialog), "Add Host");
		
	gtk_object_set_user_data(GTK_OBJECT(ok), w);
	gtk_object_set_user_data(GTK_OBJECT(cancel), w);
	gtk_object_set_user_data(GTK_OBJECT(entry), w);
	if (data == 1)
		gtk_object_set_user_data(GTK_OBJECT(netmask), w);
	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
	if (data == 1) {
		gtk_box_pack_start(GTK_BOX(hbox), label2, FALSE, FALSE, 5);
		gtk_box_pack_start(GTK_BOX(hbox), netmask, FALSE, FALSE, 5);
	}

	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE,
                           TRUE, 0);
	if (data == 2)
		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), toggle, TRUE,
                           TRUE, 0);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), status, TRUE,
                           TRUE, 0);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), ok, TRUE,
                           TRUE, 0);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), cancel, TRUE,
                           TRUE, 0);
	gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(make_network), dialog);
	if (data == 1) {
		gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(netmask_focus), netmask);
#if 0
		gtk_signal_connect(GTK_OBJECT(entry), "leave_notify_event", GTK_SIGNAL_FUNC(netmask_focus), netmask);
#endif
	} else
		gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(make_network), dialog);
	if (data == 1)
		gtk_signal_connect(GTK_OBJECT(netmask), "activate", GTK_SIGNAL_FUNC(make_network), dialog);
	gtk_signal_connect(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(cancel_network), dialog);
	gtk_widget_show(hbox);
	gtk_widget_show(entry);
	if (data == 1) {
		gtk_widget_show(label2);
		gtk_widget_show(netmask);
	} else if (data == 2) 
		gtk_widget_show(toggle);
	
	gtk_widget_show(label);
	gtk_widget_show(cancel);
	gtk_widget_show(ok);
	gtk_widget_grab_focus(entry);
	gtk_widget_show(dialog);
}

static void reverse_dns()
{
	struct net_object *no;
	char lab[256];
	char *name;
	struct hostent *hp;
	struct in_addr ia;
	if (!current_page)
		return;
	set_status("Doing Reverse DNS...");
	immediate_setcursor(GDK_WATCH);
	no = current_page->objs;
	while(no) {
		ia.s_addr = no->ip_addr;
		/* Don't bother if it already is different */
		if (strcmp((name=inet_ntoa(ia)), no->hostname)) {
			no = no->next;
			continue;
		}
		hp = gethostbyaddr((char *)&no->ip_addr, sizeof(no->ip_addr), AF_INET);
		if (hp) 
			name = hp->h_name;
		strncpy(lab, name, sizeof(lab));
 		if (option_trim) {
			char *c;
			c = lab;
			/* Don't trim IP addresses */
			if (atoi(lab))
				strncpy(lab,name, sizeof(lab));
			else {
				do {
					c = strchr(c,'.');
					/* See if this is a domain name */
					if (c) {
						if (get_server(c+1, 0)) {
							*c = '\0';
							break;
						} else
							c++;
					}
				} while (c);
			}
			
		}
		strncpy(no->hostname, name, sizeof(no->hostname));
		gtk_label_set(GTK_LABEL(no->label), lab);
		fix_tooltip(no);
		no = no->next;
	}
	gdk_window_set_cursor(main_window.window->window, NULL);
	set_status("Reverse DNS lookups complete");
}

static void do_search(GtkWidget *ign)
{
	GtkWidget *dialog;
	GtkWidget *ok;
	GtkWidget *cancel;
	GtkWidget *label;
	GtkWidget *hbox;
	GtkWidget *entry;
	GtkWidget *status;
	GtkWidget *toggle;
	struct widgets *w;
	

	if (!GTK_NOTEBOOK(main_window.notebook)->children)
		return;
	
	w = g_new(struct widgets, 1);
	dialog = gtk_dialog_new();
	hbox = gtk_hbox_new(FALSE, 5);
	w->one = entry = gtk_entry_new();
	label = gtk_label_new("Find Host");
	cancel = gtk_button_new_with_label("Cancel");
	ok = gtk_button_new_with_label("OK");
	w->status = status = gtk_statusbar_new();
	w->toggle = toggle = gtk_check_button_new_with_label("Exact Match");
	gtk_window_set_title(GTK_WINDOW(dialog), "Find Host");
		
	gtk_object_set_user_data(GTK_OBJECT(ok), w);
	gtk_object_set_user_data(GTK_OBJECT(cancel), w);
	gtk_object_set_user_data(GTK_OBJECT(entry), w);
	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE,
                           TRUE, 0);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), toggle, TRUE,
                           TRUE, 0);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), status, TRUE,
                           TRUE, 0);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), ok, TRUE,
                           TRUE, 0);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), cancel, TRUE,
                           TRUE, 0);
	gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(make_search), dialog);
	gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(make_search), dialog);
	gtk_signal_connect(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(cancel_network), dialog);
	gtk_widget_show(hbox);
	gtk_widget_show(entry);
	gtk_widget_show(toggle);	
	gtk_widget_show(label);
	gtk_widget_show(cancel);
	gtk_widget_show(ok);
	gtk_widget_grab_focus(entry);
	gtk_widget_show(dialog);
}

static void make_page(GtkWidget *w, GtkWidget *dialog)
{
	char *c;
	GtkWidget *entry;
	entry = GTK_WIDGET(gtk_object_get_user_data(GTK_OBJECT(w)));
	c = gtk_entry_get_text(GTK_ENTRY(entry));
	if (strlen(c)) {
		add_network(&main_window, c);
	}
	gtk_widget_destroy(dialog);	
}

static void do_map(void *data)
{
	struct net_object *no;
	int style = (data - NULL);
	if (!current_page)
		return;
	no = current_page->objs;
	current_page->automap = 1;
	while(no) {
		if ((style == 2)) no->mapped = 0;
		if ((style == 1) && (no->links == NULL)) no->mapped = 0;
		if (!no->mapped)
			start_mapping(no);
		no = no->next;
	}
}

static void do_page()
{
	GtkWidget *dialog;
	GtkWidget *ok;
	GtkWidget *cancel;
	GtkWidget *label;
	GtkWidget *hbox;
	GtkWidget *entry;
	dialog = gtk_dialog_new();
	hbox = gtk_hbox_new(FALSE, 5);
	entry = gtk_entry_new();
	label = gtk_label_new("New page name:");
	cancel = gtk_button_new_with_label("Cancel");
	ok = gtk_button_new_with_label("OK");
	gtk_window_set_title(GTK_WINDOW(dialog), "Add Page");
	gtk_object_set_user_data(GTK_OBJECT(ok), entry);
	gtk_object_set_user_data(GTK_OBJECT(entry), entry);
	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5);

	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE,
                           TRUE, 0);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), ok, TRUE,
                           TRUE, 0);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), cancel, TRUE,
                           TRUE, 0);
	gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(make_page), dialog);
	gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(make_page), dialog);
	gtk_signal_connect(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(cancel_page), dialog);
	gtk_widget_show(hbox);
	gtk_widget_show(entry);
	gtk_widget_show(label);
	gtk_widget_show(cancel);
	gtk_widget_show(ok);
	gtk_widget_grab_focus(entry);
	gtk_widget_show(dialog);
}

void destroy_object(struct net_page *np, struct net_object *no)
{
	struct link *l, *l2;
	struct alias *a, *a2;
	/* destroy graphical representation */
	gtk_widget_destroy(no->eventbox);
	gtk_widget_destroy(no->otherbox);
	l = no->links;
	while(l) {
		l2 = l;
		l = l->next;
		/* Only other objects should unlink */
		if (l2->other < no)
			gtk_widget_destroy(l2->linkw);
		g_free(l2);
	}
	a = no->aliases;
	while(a) {
		a2 = a;
		a=a->next;
		g_free(a2);
	}
	g_free(no);
}

static void clear_page()
{
	struct net_object *no;
	if (!current_page)
		return;
	no = current_page->objs;
	while(no) {
		destroy_object(current_page, no);
		no = no->next;
	}
	gtk_clist_clear(GTK_CLIST(current_page->list));
	current_page->lastx=20;
	current_page->lasty=20;
	current_page->objs=NULL;
	current_page->sel = NULL;
}

void reload_page()
{
	clear_page();
	refresh_page();
}

static void unmap_page()
{
	struct net_object *no;
	struct link *l, *l2;
	if (!current_page)
		return;
	no = current_page->objs;
	while(no) {
		l = no->links;
		while(l) {
			l2 = l;
			l = l->next;
			/* Only other objects should unlink */
			if (l2->other < no)
				gtk_widget_destroy(l2->linkw);
			g_free(l2);
		}
		no->links = NULL;
		no->mapped = 0;
		no = no->next;
	}
	current_page->automap = 0;

}

static void page_click(GtkWidget *w, GtkNotebookPage *page)
{
	struct net_page *np;
	char buf[256];
	int cnt=0;
	struct net_object *no;
	np = (struct net_page *)gtk_object_get_user_data(GTK_OBJECT(page->child));
	if (np && !current_page)
		show_page_menu(&main_window);
	if (np)
		current_page = np;
	else
		printf("np is null!\n");
	no = np->objs;
	while(no) {
		cnt++;
		no=no->next;
	}
	snprintf(buf, sizeof(buf), "%d host%s", cnt, (cnt == 1) ? "" : "s");
	set_status(buf);
}

static void show_page_menu(struct net_win *n)
{
	GtkMenuPath *gmp;
	gmp = gtk_menu_factory_find(n->menuf, "<Main>/Page");
	gtk_widget_set_sensitive(gmp->widget, TRUE);
}

static void hide_page_menu(struct net_win *n)
{
	GtkMenuPath *gmp;
	gmp = gtk_menu_factory_find(n->menuf, "<Main>/Page");
	gtk_widget_set_sensitive(gmp->widget, FALSE);
}

static void do_edit()
{
	if (!current_page)
		return;
	show_edit(current_page);
}

void fix_icon(GdkWindow *w)
{
	GdkPixmap *gdk_pixmap;
	GdkBitmap *gdk_pixmap_mask;
	gdk_pixmap = gdk_pixmap_create_from_xpm(w, &gdk_pixmap_mask, NULL, find_file("icon.xpm"));
	gdk_window_set_icon(w, w, gdk_pixmap, gdk_pixmap_mask);
}

static void show_window(struct net_win *n)
{
	GtkMenuFactory *subfactory;
	GtkMenuPath *gmp;
	static GdkColor *yellow;
	static GtkMenuEntry menu_items[] = 
	{
		{"<Main>/File/New page...", NULL, do_page, NULL },
		{"<Main>/File/Open...", "<control>O", GTK_MENU_FUNC(do_open), NULL },
		{"<Main>/File/Save","<control>S", GTK_MENU_FUNC(do_save), NULL },
		{"<Main>/File/Save as...", NULL, GTK_MENU_FUNC(do_saveas), NULL },
		{"<Main>/File/<separator>",NULL, NULL, NULL },
		{"<Main>/File/Options",NULL, GTK_MENU_FUNC(show_options), NULL },
		{"<Main>/File/<separator>",NULL, NULL, NULL },
		{"<Main>/File/Quit","<control>Q", do_quit, NULL },
		{"<Main>/Page/New...","<control>N", do_page, NULL },
		{"<Main>/Page/Edit...", "<control>E", do_edit, NULL },
		{"<Main>/Page/Remove",NULL, GTK_MENU_FUNC(remove_page), NULL }, 
		{"<Main>/Page/<separator>",NULL, NULL, NULL },
		{"<Main>/Page/Add host...","<control>H", GTK_MENU_FUNC(do_network), (void *)0},
		{"<Main>/Page/Add network...","<control>A", GTK_MENU_FUNC(do_network), (void *)1},
		{"<Main>/Page/Add domain...","<control>D", GTK_MENU_FUNC(do_network), (void *)2},
		{"<Main>/Page/<separator>",NULL, NULL, NULL },
		{"<Main>/Page/View/List",NULL, GTK_MENU_FUNC(view_list), NULL },
		{"<Main>/Page/View/Icons",NULL, GTK_MENU_FUNC(view_pictures), (void *)0 },
		{"<Main>/Page/View/Small Icons",NULL, GTK_MENU_FUNC(view_pictures), (void *)1 },
		{"<Main>/Page/Arrange/By domain", NULL, GTK_MENU_FUNC(arrange_cb), (void *)BY_DOMAIN },
		{"<Main>/Page/Arrange/By hostname", NULL, GTK_MENU_FUNC(arrange_cb), (void *)BY_NAME },
		{"<Main>/Page/Arrange/By address", NULL, GTK_MENU_FUNC(arrange_cb), (void *)BY_ADDR },
		{"<Main>/Page/Arrange/By type", NULL, GTK_MENU_FUNC(arrange_cb), (void *)BY_OS },
		{"<Main>/Page/Map/Map","<control>M", GTK_MENU_FUNC(do_map), NULL },
		{"<Main>/Page/Map/Unlinked hosts",NULL, GTK_MENU_FUNC(do_map), (void *)1 },
		{"<Main>/Page/Map/Remap everything",NULL, GTK_MENU_FUNC(do_map), (void *)2 },
		{"<Main>/Page/Map/Unmap","<control>U", GTK_MENU_FUNC(unmap_page), NULL },
		{"<Main>/Page/Reverse DNS everything",NULL, GTK_MENU_FUNC(reverse_dns), NULL },
		{"<Main>/Page/<separator>",NULL, NULL, NULL },
		{"<Main>/Page/Find on page...", "<control>F", GTK_MENU_FUNC(do_search), NULL},
		{"<Main>/Page/Find again...", "<control>G", GTK_MENU_FUNC(search_again), NULL},
		{"<Main>/Page/<separator>",NULL, NULL, NULL },
		{"<Main>/Page/Refresh","<control>R", GTK_MENU_FUNC(refresh_page), NULL},
		{"<Main>/Page/Reload","<control>L", GTK_MENU_FUNC(reload_page), NULL},
		{"<Main>/Page/Clear","<control>C", GTK_MENU_FUNC(clear_page), NULL},
		{"<Main>/Help/About...",NULL, GTK_MENU_FUNC(show_about), NULL},
		{"<Main>/Help/License...",NULL, GTK_MENU_FUNC(show_gpl), NULL},
	};

	int nmenu_items = sizeof(menu_items)/sizeof(menu_items[0]);
	
	n->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_widget_realize(n->window);
	if (!yellow) {
		yellow = g_new(GdkColor, 1);
		yellow->red = 65535;
		yellow->green = 65535;
		yellow->blue = 65535;
		gdk_color_alloc(gdk_window_get_colormap(n->window->window), yellow);
	}		
	n->tips = gtk_tooltips_new();
	gtk_tooltips_set_colors(n->tips, NULL, yellow);
	gtk_tooltips_enable(n->tips);
	gtk_signal_connect(GTK_OBJECT(n->window), "delete_event", GTK_SIGNAL_FUNC(do_quit), NULL);
	n->menuf = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
	subfactory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
	gtk_menu_factory_add_subfactory(n->menuf, subfactory, "<Main>");
        gtk_menu_factory_add_entries(n->menuf, menu_items, nmenu_items);
	hide_page_menu(n);
#if (GTK_MINOR_VERSION < 1)
        gtk_window_add_accelerator_table(GTK_WINDOW(n->window), subfactory->table);
#else
	gtk_window_add_accel_group(GTK_WINDOW(n->window), subfactory->accel_group);
#endif
	
	/* Right Justify Help Menu */
	n->menu = subfactory->widget;
	gmp = gtk_menu_factory_find(n->menuf, "<Main>/Help");
	gtk_menu_item_right_justify(GTK_MENU_ITEM(gmp->widget));
	
	n->notebook = gtk_notebook_new();
	gtk_notebook_set_show_border(GTK_NOTEBOOK(n->notebook), FALSE);
	n->vbox = gtk_vbox_new(FALSE, 0);
	n->status = gtk_statusbar_new();
	gtk_signal_connect(GTK_OBJECT(n->notebook), "switch_page", GTK_SIGNAL_FUNC(page_click), NULL);
	gtk_box_pack_start(GTK_BOX(n->vbox), n->menu, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(n->vbox), n->notebook, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(n->vbox), n->status, FALSE, FALSE, 0);
	gtk_widget_show(n->status);
	gtk_widget_show(n->notebook);
	gtk_widget_show(n->menu);
	gtk_widget_show(n->vbox);
	gtk_object_set_user_data(GTK_OBJECT(n->window), n);
	gtk_container_add(GTK_CONTAINER(n->window), n->vbox);
	gtk_window_set_title(GTK_WINDOW(n->window), "Cheops Network User Interface");

	gtk_widget_set_usize(n->window, 640, 480);
	fix_icon(n->window->window);
	gtk_window_set_policy(GTK_WINDOW(n->window), TRUE, TRUE, FALSE);
	
} 


int main(int argc, char *argv[])
{
	int doshow=0, loaded;
	main_window.next = NULL;
	if (geteuid()) {
		fprintf(stderr, "Must be root\n");
		exit(1);
	}
	/* Ping */
	net_init();
	/* queso */
	init_tcpip();
	/* halfscan */
	init_halfscan();
	setuid(getuid());
	if (!load_options())
		doshow = -1;

#ifdef USE_GNOME
	gnome_init("Cheops",NULL, argc, argv, 0, NULL);
#else
	gtk_init(&argc, &argv);
#endif

	if (!getenv("HOME")) {
		fprintf(stderr, "No home directory!\n");
		return 1;
	}
	snprintf(defname, sizeof(defname), "%s/.cheops-map", getenv("HOME"));
	show_window(&main_window);
	doshow |= (loaded = do_load(NULL));
	gtk_widget_show(main_window.window);
	if (!doshow) {
		save_options();
		show_about(NULL, 8000);
	}
	if (!loaded) {
		load_interfaces();
	}
	gtk_main();
	return 0;
}
