Index: embed/ephy-embed-persist.c
===================================================================
diff -u -r1.4 ephy-embed-persist.c
--- embed/ephy-embed-persist.c	17 May 2003 12:43:23 -0000	1.4
+++ embed/ephy-embed-persist.c	12 Jul 2003 20:49:19 -0000
@@ -379,6 +379,13 @@
 	return klass->save (persist);
 }
 
+char *
+ephy_embed_persist_get_content (EphyEmbedPersist *persist)
+{
+	EphyEmbedPersistClass *klass = EPHY_EMBED_PERSIST_GET_CLASS (persist);
+	return klass->get_content (persist);
+}
+
 gresult
 ephy_embed_persist_set_max_size (EphyEmbedPersist *persist,
 			           int kb_size)
Index: embed/ephy-embed-persist.h
diff -u -r1.2 ephy-embed-persist.h
--- embed/ephy-embed-persist.h	11 Jan 2003 12:56:53 -0000	1.2
+++ embed/ephy-embed-persist.h	12 Jul 2003 20:49:19 -0000
@@ -73,6 +73,7 @@
 	gresult (* set_dest)     (EphyEmbedPersist *persist,
 				  const char *dir);
 
+	char *  (* get_content)  (EphyEmbedPersist *persist);
 	gresult (* save)         (EphyEmbedPersist *persist);
 
 	gresult (* cancel)       (EphyEmbedPersist *persist);
@@ -127,6 +128,8 @@
 						    EmbedPersistFlags *flags);
 
 gresult		    ephy_embed_persist_save        (EphyEmbedPersist *persist);
+
+char               *ephy_embed_persist_get_content (EphyEmbedPersist *persist);
 
 gresult		    ephy_embed_persist_cancel      (EphyEmbedPersist *persist);
 
Index: embed/mozilla/mozilla-embed-persist.cpp
===================================================================
RCS file: /cvs/gnome/epiphany/embed/mozilla/mozilla-embed-persist.cpp,v
retrieving revision 1.10
diff -u -r1.10 mozilla-embed-persist.cpp
--- embed/mozilla/mozilla-embed-persist.cpp	18 Jun 2003 19:50:59 -0000	1.10
+++ embed/mozilla/mozilla-embed-persist.cpp	12 Jul 2003 20:49:19 -0000
@@ -26,6 +26,7 @@
 #include <nsString.h>
 #include <nsCWebBrowserPersist.h>
 #include <nsNetUtil.h>
+#include <nsIDocumentEncoder.h>
 
 static void
 mozilla_embed_persist_class_init (MozillaEmbedPersistClass *klass);
@@ -36,6 +37,8 @@
 
 static gresult 
 impl_save (EphyEmbedPersist *persist);
+static char *
+impl_get_content (EphyEmbedPersist *persist);
 static gresult 
 impl_cancel (EphyEmbedPersist *persist);
 
@@ -87,6 +90,7 @@
 	
         object_class->finalize = mozilla_embed_persist_finalize;
 
+	persist_class->get_content = impl_get_content;
 	persist_class->save = impl_save;
 	persist_class->cancel = impl_cancel;
 }
@@ -143,6 +147,38 @@
 	g_object_unref (persist);
 
 	return G_OK;
+}
+
+static char *
+impl_get_content (EphyEmbedPersist *persist)
+{
+	nsresult rv = NS_OK;
+	EphyEmbed *embed;
+	EphyWrapper *wrapper;
+	nsCOMPtr<nsIDOMDocument> DOMDocument;
+
+	g_object_get (persist, "embed", &embed, NULL);
+
+	g_return_val_if_fail (embed != NULL, NULL);
+
+	wrapper = (EphyWrapper *) mozilla_embed_get_ephy_wrapper (MOZILLA_EMBED(embed));
+
+	rv = wrapper->GetMainDOMDocument (getter_AddRefs(DOMDocument));
+	if (NS_FAILED(rv) || !DOMDocument) return NULL;
+
+	nsCOMPtr<nsIDocument> doc = do_QueryInterface(DOMDocument);
+	if(!doc) return NULL;
+
+	nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/html");
+	NS_ENSURE_SUCCESS(rv, NULL);
+
+	rv = encoder->Init(doc, NS_LITERAL_STRING("text/html"), 0);
+	NS_ENSURE_SUCCESS(rv, NULL);
+
+	nsAutoString aOutputString;
+	encoder->EncodeToString(aOutputString);
+
+	return g_strdup (NS_ConvertUCS2toUTF8(aOutputString).get());
 }
 
 static gresult 
Index: src/ephy-tab.c
===================================================================
RCS file: /cvs/gnome/epiphany/src/ephy-tab.c,v
retrieving revision 1.47
diff -u -r1.47 ephy-tab.c
--- src/ephy-tab.c	7 Jul 2003 17:06:08 -0000	1.47
+++ src/ephy-tab.c	12 Jul 2003 20:49:19 -0000
@@ -20,6 +20,9 @@
 #include "config.h"
 #endif
 
+#include <stdio.h>
+#include <string.h>
+
 #include "ephy-tab.h"
 #include "ephy-shell.h"
 #include "eel-gconf-extensions.h"
@@ -45,7 +50,7 @@
 #include <gtk/gtkselection.h>
 #include <gtk/gtkmain.h>
 #include <gtk/gtkmenu.h>
-#include <string.h>
+#include <glib.h>
 
 struct EphyTabPrivate
 {
@@ -73,6 +78,7 @@
 static void ephy_tab_class_init		(EphyTabClass *klass);
 static void ephy_tab_init		(EphyTab *tab);
 static void ephy_tab_finalize		(GObject *object);
+static void ephy_tab_send_cluepacket    (EphyTab *tab, gboolean send_content);
 
 enum
 {
@@ -488,9 +494,14 @@
 {
 	g_return_if_fail (IS_EPHY_TAB (tab));
 
+	if (tab->priv->visibility == visible)
+		return;
+
 	tab->priv->visibility = visible;
 
 	g_object_notify (G_OBJECT (tab), "visible");
+
+	ephy_tab_send_cluepacket (tab, FALSE);
 }
 
 static void
@@ -1020,6 +1031,37 @@
 				 tab,  0);
 }
 
+static void
+ephy_tab_send_cluepacket (EphyTab *tab, gboolean send_content)
+{
+	char *content;
+	char *cluepacket;
+
+	/* do dashboard stuff */
+	EphyEmbedPersist *persist =
+		ephy_embed_persist_new (ephy_tab_get_embed (tab));
+
+	if (send_content)
+		content = ephy_embed_persist_get_content (persist);
+	else
+		content = NULL;
+
+
+	cluepacket = dashboard_build_cluepacket_then_free_clues (
+		"Web Browser",
+		tab->priv->visibility,
+		tab->priv->address,
+		dashboard_build_clue (tab->priv->address, "url", 10),
+		dashboard_build_clue (tab->priv->title, "title", 10),
+		dashboard_build_clue (content, "content", 10),
+		NULL);
+
+	dashboard_send_raw_cluepacket (cluepacket);
+	g_free (cluepacket);
+	g_free (content);
+	g_object_unref (G_OBJECT (persist));
+}
+
 void
 ephy_tab_set_load_percent (EphyTab *tab, int percent)
 {
@@ -1030,6 +1072,10 @@
 		tab->priv->load_percent = percent;
 
 		g_object_notify (G_OBJECT (tab), "load-progress");
+
+		if (percent == 100) {
+			ephy_tab_send_cluepacket (tab, TRUE);
+		}
 	}
 }
 
*** src/Makefile.am.orig	Wed Oct 15 17:20:51 2003
--- src/Makefile.am	Wed Oct 15 17:23:13 2003
***************
*** 124,130 ****
  
  CLEANFILES = $(CORBA_SOURCE)
  
! EXTRA_DIST = $(top_srcdir)/idl/EphyAutomation.idl
  
  dist-hook:
  	cd $(distdir); rm -f $(BUILT_SOURCES)
--- 124,130 ----
  
  CLEANFILES = $(CORBA_SOURCE)
  
! EXTRA_DIST = $(top_srcdir)/idl/EphyAutomation.idl dashboard-frontend.c
  
  dist-hook:
  	cd $(distdir); rm -f $(BUILT_SOURCES)
*** src/ephy-tab.c.orig	Wed Oct 15 17:24:23 2003
--- src/ephy-tab.c	Wed Oct 15 17:21:44 2003
***************
*** 38,43 ****
--- 38,45 ----
  #include "ephy-zoom.h"
  #include "session.h"
  #include "ephy-favicon-cache.h"
+ #include "ephy-embed-persist.h"
+ #include "dashboard-frontend.c"
  
  #include <bonobo/bonobo-i18n.h>
  #include <libgnomevfs/gnome-vfs-uri.h>
*** src/dashboard-frontend.c.orig	Thu Jan  1 12:00:00 1970
--- src/dashboard-frontend.c	Wed Oct 15 19:17:23 2003
***************
*** 0 ****
--- 1,427 ----
+ #ifndef __DASHBOARD_FRONTEND_H__
+ #define __DASHBOARD_FRONTEND_H__
+ 
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <sys/socket.h>
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <stdlib.h>
+ #include <glib.h>
+ 
+ #if GLIB_CHECK_VERSION (2,0,0)
+ #include <glib/giochannel.h>
+ #endif
+ 
+ #define DASHBOARD_PORT 5913
+ #define NATMIN(a,b) ((a) < (b) ? (a) : (b))
+ 
+ /*
+  * Open a connection to the dashboard.  We never block and at
+  * the first sign of a problem we bail.
+  */
+ static int
+ dashboard_connect_with_timeout (int  *fd,
+ 				long  timeout_usecs)
+ {
+ 	struct sockaddr_in  sock;
+ 	struct timeval      timeout;
+ 	fd_set write_fds;
+ 
+ 	*fd = socket (PF_INET, SOCK_STREAM, 0);
+ 	if (*fd < 0) {
+ 		perror ("Dashboard: socket");
+ 		return 0;
+ 	}
+ 
+ 	/*
+ 	 * Set the socket to be non-blocking so that connect ()
+ 	 * doesn't block.
+ 	 */
+ 	if (fcntl (*fd, F_SETFL, O_NONBLOCK) < 0) {
+ 		perror ("Dashboard: setting O_NONBLOCK");
+ 		return 0;
+ 	}
+ 
+ 	bzero ((char *) &sock, sizeof (sock));
+ 	sock.sin_family      = AF_INET;
+ 	sock.sin_port        = htons (DASHBOARD_PORT);
+ 	sock.sin_addr.s_addr = inet_addr ("127.0.0.1");
+ 
+ 	timeout.tv_sec = 0;
+ 	timeout.tv_usec = timeout_usecs;
+ 
+ 	while (1) {
+ 
+ 		/*
+ 		 * Try to connect.
+ 		 */
+ 		if (connect (*fd, (struct sockaddr *) &sock,
+ 			     sizeof (struct sockaddr_in)) < 0) {
+ 
+ 			if (errno != EAGAIN &&
+ 			    errno != EINPROGRESS) {
+ 				perror ("Dashboard: connect");
+ 				return 0;
+ 			}
+ 				
+ 		} else
+ 			return 1;
+ 
+ 		/*
+ 		 * We couldn't connect, so we select on the fd and
+ 		 * wait for the timer to run out, or for the fd to be
+ 		 * ready.
+ 		 */
+ 		FD_ZERO (&write_fds);
+ 		FD_SET (*fd, &write_fds);
+ 
+ 		while (select (getdtablesize (), NULL, &write_fds, NULL, &timeout) < 0) {
+ 			if (errno != EINTR) {
+ 				perror ("Dashboard: select");
+ 				return 0;
+ 			}
+ 		}
+ 
+ 		if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+ 			fprintf (stderr, "Dashboard: Connection timed out.\n");
+ 			return 0;
+ 		}
+ 		
+ 	}
+ 
+ 	return 1;
+ }
+ 
+ typedef struct {
+ 	char *rawcluepacket;
+ 	int bytes_written;
+ } CluepacketInfo;
+ 
+ #if GLIB_CHECK_VERSION(2,0,0)
+ 
+ static gboolean
+ cluepacket_write_cb (GIOChannel   *channel,
+ 		     GIOCondition  cond,
+ 		     gpointer      user_data)
+ {
+ 	CluepacketInfo *info = user_data;
+ 	GIOError err;
+ 	int total_bytes;
+ 
+ 	total_bytes = strlen (info->rawcluepacket);
+ 
+ 	do {
+ 		int b;
+ 
+ 		err = g_io_channel_write (channel,
+ 					  info->rawcluepacket + info->bytes_written,
+ 					  total_bytes - info->bytes_written,
+ 					  &b);
+ 		info->bytes_written += b;
+ 	} while (info->bytes_written < total_bytes && err == G_IO_ERROR_NONE);
+ 
+ 	if (err == G_IO_ERROR_NONE) {
+ 		/* We're all done sending */
+ 		fprintf (stderr, "Dashboard: Sent.\n");
+ 		goto cleanup;
+ 	}
+ 
+ 	if (err == G_IO_ERROR_AGAIN) {
+ 		/* Hand control back to the main loop */
+ 		return TRUE;
+ 	}
+ 
+ 	/* Otherwise... */
+ 	fprintf (stderr, "Dashboard: Error trying to send cluepacket.\n");
+ 
+ cleanup:
+ 	g_io_channel_close (channel);
+ 	g_free (info->rawcluepacket);
+ 	g_free (info);
+ 
+ 	return FALSE;
+ }
+ 
+ static void
+ dashboard_send_raw_cluepacket (const char *rawcluepacket)
+ {
+ 	int fd;
+ 	GIOChannel *channel;
+ 	CluepacketInfo *info;
+ 
+ 	fprintf (stderr, "Dashboard: Sending cluepacket...\n");
+ 
+ 	/* Connect. */
+ 	if (! dashboard_connect_with_timeout (&fd, 200000))
+ 		return;
+ 
+ 	channel = g_io_channel_unix_new (fd);
+ 
+ 	info = g_new0 (CluepacketInfo, 1);
+ 	info->rawcluepacket = g_strdup (rawcluepacket);
+ 
+ 	g_io_add_watch (channel,
+ 			G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ 			cluepacket_write_cb,
+ 			info);
+ 
+ 	g_io_channel_unref (channel);
+ }
+ 
+ #endif /* GLIB_CHECK_VERSION (2,0,0) */
+ 
+ /*
+  * Sends a raw cluepacket to the dashboard.
+  */
+ static void
+ dashboard_send_raw_cluepacket_sync (const char *rawcluepacket)
+ {
+ 	int                 fd;
+ 	int                 total_bytes;
+ 	int                 bytes_written;
+ 	const char         *p;
+ 	int                 eagain_count;
+ 
+ 	fprintf (stderr, "Dashboard: Sending cluepacket...\n");
+ 	fprintf (stderr, "Cluepacket: %s\n", rawcluepacket);
+ 
+ 	/* Connect. */
+ 	if (! dashboard_connect_with_timeout (&fd, 200000))
+ 		return;
+ 
+ 	/* Write out the cluepacket */
+ 	total_bytes = strlen (rawcluepacket);
+ 	bytes_written = 0;
+ 	p = rawcluepacket;
+ 	eagain_count = 0;
+ 	while (bytes_written < total_bytes) {
+ 		int b;
+ 
+ 		b = write (fd, p, total_bytes - bytes_written);
+ 		if (b < 0) {
+ 			fprintf (stderr, "Dashboard: Error writing: %s\n", strerror (errno));
+ 
+ 			if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ 				close (fd);
+ 				return;
+ 			}
+ 
+ 			eagain_count ++;
+ 
+ 			if (eagain_count > 10) {
+ 				close (fd);
+ 				return;
+ 			}
+ 		}
+ 
+ 		bytes_written += b;
+ 		p += b;
+ 	}
+ 
+ 	close (fd);
+ 
+ 	fprintf (stderr, "Dashboard: Sent.\n");
+ }
+ 
+ #if !GLIB_CHECK_VERSION (2,0,0)
+ static char *
+ lame_xml_quote (const char *str)
+ {
+ 	char       *retval;
+ 	const char *p;
+ 	char       *q;
+ 
+ 	if (str == NULL || strlen (str) == 0)
+ 		return g_strdup ("");
+ 
+ 	retval = g_new (char, strlen (str) * 3);
+ 
+ 	q = retval;
+ 	for (p = str; *p != '\0'; p ++) {
+ 		switch (*p) {
+ 
+ 		case '<':
+ 			*q ++ = '&';
+ 			*q ++ = 'l';
+ 			*q ++ = 't';
+ 			*q ++ = ';';
+ 			break;
+ 
+ 		case '>':
+ 			*q ++ = '&';
+ 			*q ++ = 'g';
+ 			*q ++ = 't';
+ 			*q ++ = ';';
+ 			break;
+ 			
+ 		case '&':
+ 			*q ++ = '&';
+ 			*q ++ = 'a';
+ 			*q ++ = 'm';
+ 			*q ++ = 'p';
+ 			*q ++ = ';';
+ 			break;
+ 		default:
+ 			*q ++ = *p;
+ 			break;
+ 		}
+ 	}
+ 
+ 	*q = '\0';
+ 
+ 	return retval;
+ }
+ #endif
+ 
+ static char *
+ dashboard_xml_quote (const char *str)
+ {
+ #if GLIB_CHECK_VERSION (2,0,0)
+ 	return g_markup_escape_text (str, strlen (str));
+ #else
+ 	return lame_xml_quote (str);
+ #endif
+ }
+ 
+ static char *
+ dashboard_build_clue (const char *text,
+ 		      const char *type,
+ 		      int         relevance)
+ {
+ 	char *text_xml;
+ 	char *clue;
+ 
+ 	if (text == NULL || strlen (text) == 0)
+ 		return g_strdup ("");
+ 
+ 	text_xml = dashboard_xml_quote (text);
+ 
+ 	clue = g_strdup_printf ("    <Clue Type=\"%s\" Relevance=\"%d\">%s</Clue>\n",
+ 				type, relevance, text_xml);
+ 
+ 	g_free (text_xml);
+ 
+ 	return clue;
+ }
+ 
+ static char *
+ dashboard_build_cluepacket_from_cluelist (const char *frontend,
+ 					  gboolean    focused,
+ 					  const char *context,
+ 					  GList      *clues)
+ {
+ 	char  *cluepacket;
+ 	char  *new_cluepacket;
+ 	GList *l;
+ 
+ 	g_return_val_if_fail (frontend != NULL, NULL);
+ 	g_return_val_if_fail (clues    != NULL, NULL);
+ 
+ 	cluepacket = g_strdup_printf (
+ 		"<CluePacket>\n"
+ 		"    <Frontend>%s</Frontend>\n"
+ 		"    <Context>%s</Context>\n"
+ 		"    <Focused>%s</Focused>\n",
+ 		frontend,
+ 		context,
+ 		focused ? "true" : "false");
+ 
+ 	for (l = clues; l != NULL; l = l->next) {
+ 		const char *clue = (const char *) l->data;
+ 
+ 		new_cluepacket = g_strconcat (cluepacket, clue, NULL);
+ 		g_free (cluepacket);
+ 
+ 		cluepacket = new_cluepacket;
+ 	}
+ 
+ 	new_cluepacket = g_strconcat (cluepacket, "</CluePacket>\n", NULL);
+ 	g_free (cluepacket);
+ 
+ 	cluepacket = new_cluepacket;
+ 
+ 	return cluepacket;
+ }
+ 
+ static char *
+ dashboard_build_cluepacket_v (const char *frontend,
+ 			      gboolean    focused,
+ 			      const char *context,
+ 			      va_list     args)
+ {
+ 	char    *cluep;
+ 	GList   *clue_list;
+ 	char    *retval;
+ 
+ 	g_return_val_if_fail (frontend != NULL, NULL);
+ 
+ 	cluep     = va_arg (args, char *);
+ 	clue_list = NULL;
+ 	while (cluep) {
+ 		clue_list = g_list_append (clue_list, cluep);
+ 		cluep = va_arg (args, char *);
+ 	}
+ 
+ 	retval = dashboard_build_cluepacket_from_cluelist (frontend, focused, context, clue_list);
+ 
+ 	g_list_free (clue_list);
+ 
+ 	return retval;
+ }
+ 
+ static char *
+ dashboard_build_cluepacket (const char *frontend,
+ 			    gboolean    focused,
+ 			    const char *context,
+ 			    ...)
+ {
+ 	char    *retval;
+ 	va_list  args;
+ 
+ 	g_return_val_if_fail (frontend != NULL, NULL);
+ 
+ 	va_start (args, context);
+ 
+ 	retval = dashboard_build_cluepacket_v (frontend, focused, context, args);
+ 
+ 	va_end (args);
+ 
+ 	return retval;
+ }
+ 
+ 
+ static char *
+ dashboard_build_cluepacket_then_free_clues (const char *frontend,
+ 					    gboolean    focused,
+ 					    const char *context,
+ 					    ...)
+ {
+ 	char    *retval;
+ 	char    *cluep;
+ 	va_list  args;
+ 
+ 	g_return_val_if_fail (frontend != NULL, NULL);
+ 
+ 	/* Build the cluepacket */
+ 	va_start (args, context);
+ 	retval = dashboard_build_cluepacket_v (frontend, focused, context, args);
+ 	va_end (args);
+ 
+ 	/* Free the clues */
+ 	va_start (args, context);
+ 	cluep = va_arg (args, char *);
+ 	while (cluep) {
+ 		g_free (cluep);
+ 		cluep = va_arg (args, char *);
+ 	}
+ 
+ 	va_end (args);
+ 
+ 	return retval;
+ }
+ 
+ #endif /* ! __DASHBOARD_FRONTEND_H__ */
