diff --git a/extensions/soup-fly/ephy-soup-fly-extension.c b/extensions/soup-fly/ephy-soup-fly-extension.c
index 125824d..1b2ac40 100644
--- a/extensions/soup-fly/ephy-soup-fly-extension.c
+++ b/extensions/soup-fly/ephy-soup-fly-extension.c
@@ -137,6 +137,8 @@ ephy_soup_fly_extension_finalize (GObject *object)
 
   LOG ("EphySoupFlyExtension finalizing");
 
+  soup_fly_stop (extension->priv->fly);
+
   gtk_widget_destroy (GTK_WIDGET (extension->priv->fly));
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
diff --git a/extensions/soup-fly/soup-fly.c b/extensions/soup-fly/soup-fly.c
index e5d239c..1148c46 100644
--- a/extensions/soup-fly/soup-fly.c
+++ b/extensions/soup-fly/soup-fly.c
@@ -25,38 +25,75 @@
 #include "soup-fly.h"
 
 #include <glib/gi18n-lib.h>
+#include <glib/gprintf.h>
 #include <gtk/gtk.h>
+#include <glib.h>
 
 #define SOUP_FLY_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), TYPE_SOUP_FLY, SoupFlyPrivate))
 
 struct _SoupFlyPrivate {
-  GtkTreeModel *model;
-  GtkWidget *treeview;
+  GtkTreeModel *message_model;
+  GtkTreeModel *message_history_model;
+  GtkTreeModel *connection_model;
+  GtkTreeModel *connection_history_model;
+  GtkWidget *history_widget;
+  GtkLabel *history_label;
+  GtkWidget *message_treeview;
+  GtkWidget *connection_treeview;
+  GtkWidget *message_history_treeview;
+  GtkWidget *connection_history_treeview;
   GtkWidget *clear_button;
+  GtkWidget *message_history_widget;
+  GtkWidget *connection_history_widget;
+
+  GHashTable *message_data;
+  GHashTable *connection_data;
 
-  guint nth;
+  guint message_nth;
+  guint connection_nth;
   gboolean clean_finished;
 };
 
 enum {
-    COL_NUMBER,
-    COL_STATE,
-    COL_PROGRESS,
-    COL_URL,
-    N_COLUMNS
+  MESSAGE_COL_NUMBER,
+  MESSAGE_COL_STATE,
+  MESSAGE_COL_PROGRESS,
+  MESSAGE_COL_CONNECTION,
+  MESSAGE_COL_URL,
+  MESSAGE_N_COLUMNS
+};
+
+enum {
+  CONNECTION_COL_NUMBER,
+  CONNECTION_COL_STATE,
+  CONNECTION_COL_HOST,
+  CONNECTION_N_COLUMNS
+};
+
+enum {
+  MESSAGE_HISTORY_WHEN,
+  MESSAGE_HISTORY_STATE,
+  MESSAGE_HISTORY_N_COLUMNS
+};
+
+enum {
+  CONNECTION_HISTORY_WHEN,
+  CONNECTION_HISTORY_STATE,
+  CONNECTION_HISTORY_MESSAGE,
+  CONNECTION_HISTORY_N_COLUMNS
 };
 
 enum {
-  STATE_QUEUED,
-  STATE_SENDING,
-  STATE_WAITING,
-  STATE_RECEIVING,
-  STATE_FINISHED
+  MESSAGE_STATE_QUEUED,
+  MESSAGE_STATE_SENDING,
+  MESSAGE_STATE_WAITING,
+  MESSAGE_STATE_RECEIVING,
+  MESSAGE_STATE_FINISHED
 };
 
 const struct {
   const char *name, *color;
-} states[] = {
+} message_states[] = {
   { "Queued", "pink" },
   { "Sending", "green" },
   { "Waiting", "cyan" },
@@ -64,9 +101,68 @@ const struct {
   { "Finished", "gray" }
 };
 
+enum {
+  CONNECTION_STATE_NEW,
+  CONNECTION_STATE_DISCONNECTED,
+  CONNECTION_STATE_CONNECTING,
+  CONNECTION_STATE_IDLE,
+  CONNECTION_STATE_INUSE,
+  CONNECTION_STATE_CLEANEDUP
+};
+
+const struct {
+  const char *name, *color;
+} connection_states[] = {
+  { "New", "pink" },
+  { "Disconnected", "red" },
+  { "Connecting", "yellow" },
+  { "Idle", "blue" },
+  { "In use", "green" },
+  { "Cleaned up", "gray" }
+};
+
+typedef struct
+{
+  GTimeVal when;
+  gint state;
+} FlyMessageDataEntry;
+
+typedef struct
+{
+  GtkTreeIter iter;
+  SoupFly *logger;
+  goffset content_length, received;
+  GList *entries;
+  GList *connections;
+  gint message_number;
+  char *uri;
+} FlyMessageData;
+
+typedef struct
+{
+  GTimeVal when;
+  gint state;
+  gint message_number;
+} FlyConnectionDataEntry;
+
+typedef struct
+{
+  GtkTreeIter iter;
+  SoupFly *logger;
+  GList *entries;
+  gint connection_number;
+  gint current_message;
+} FlyConnectionData;
+
 static void soup_fly_class_init (SoupFlyClass *klass);
 static void soup_fly_init       (SoupFly *logger);
 
+static void message_selected_cb (GtkTreeSelection *selection,
+                                 SoupFly *logger);
+
+static void connection_selected_cb (GtkTreeSelection *selection,
+                                    SoupFly *logger);
+
 static GObjectClass *parent_class = NULL;
 static GType type = 0;
 
@@ -104,36 +200,144 @@ soup_fly_register_type (GTypeModule *module)
   return type_volatile;
 }
 
+static void soup_fly_dispose (GObject *);
+
 static void
 soup_fly_class_init (SoupFlyClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
   parent_class = g_type_class_peek_parent (klass);
+  object_class->dispose = soup_fly_dispose;
 
   g_type_class_add_private (object_class, sizeof (SoupFlyPrivate));
 }
 
 static void
+soup_fly_show_cb (GtkWidget *widget, gpointer data)
+{
+  SoupFly *logger = SOUP_FLY (widget);
+  SoupFlyPrivate *priv = logger->priv;
+
+  gtk_widget_hide (priv->history_widget);
+}
+
+static gint
+connection_current_state (FlyConnectionData *data)
+{
+  GList *last_entry;
+  if ( (last_entry = g_list_last (data->entries)) )
+    return ((FlyConnectionDataEntry *)last_entry->data)->state;
+  else
+    return -1;
+}
+
+static gint
+message_current_state (FlyMessageData *data)
+{
+  GList *last_entry;
+  if ( (last_entry = g_list_last (data->entries)) )
+    return ((FlyMessageDataEntry *)last_entry->data)->state;
+  else
+    return -1;
+}
+
+static void
+free_message_data (FlyMessageData *data, SoupFly *logger)
+{
+  SoupFlyPrivate *priv = logger->priv;
+  GList *entry = data->entries;
+  while (entry) {
+    FlyMessageDataEntry *data_entry = entry->data;
+    g_slice_free (FlyMessageDataEntry, data_entry);
+    entry = entry->next;
+  }
+  g_list_free(data->entries);
+  if (data->connections == NULL) {
+    g_hash_table_remove (priv->message_data, &(data->message_number));
+    if (data->uri)
+      g_free (data->uri);
+    g_slice_free (FlyMessageData, data);
+  } else
+    data->entries = NULL;
+}
+
+static void
+free_connection_data (FlyConnectionData *data, SoupFly *logger)
+{
+  SoupFlyPrivate *priv = logger->priv;
+  GList *entry = data->entries;
+  FlyMessageData *msg_data;
+  while (entry) {
+    FlyConnectionDataEntry *data_entry = entry->data;
+    if ( (msg_data = g_hash_table_lookup (priv->message_data, &(data_entry->message_number))) ) {
+      msg_data->connections = g_list_remove (msg_data->connections, data);
+      if ( (msg_data->connections == NULL) &&
+           (message_current_state (msg_data) == MESSAGE_STATE_FINISHED) ) {
+        free_message_data (msg_data, logger);
+      }
+    }
+    entry = entry->next;
+  }
+  {
+    g_hash_table_remove (priv->connection_data, &(data->connection_number));
+    g_list_free (data->entries);
+    g_slice_free (FlyConnectionData, data);
+  }
+}
+
+static void
 clear_button_clicked_cb (GtkButton *button, SoupFly *logger)
 {
   GtkTreeIter iter;
   gboolean valid;
   SoupFlyPrivate *priv = logger->priv;
 
-  valid = gtk_tree_model_get_iter_first (priv->model, &iter);
+  valid = gtk_tree_model_get_iter_first (priv->connection_model, &iter);
 
   while (valid) {
     int state;
 
-    gtk_tree_model_get (priv->model, &iter,
-                        COL_STATE, &state,
+    gtk_tree_model_get (priv->connection_model, &iter,
+                        CONNECTION_COL_STATE, &state,
                         -1);
 
-    if (state == STATE_FINISHED)
-      valid = gtk_list_store_remove (GTK_LIST_STORE (priv->model), &iter);
+    if (state == CONNECTION_STATE_CLEANEDUP) {
+      int connection_number;
+      FlyConnectionData *con_data;
+      gtk_tree_model_get (priv->connection_model, &iter,
+                          CONNECTION_COL_NUMBER, &connection_number,
+                          -1);
+      if ( (con_data = g_hash_table_lookup (priv->connection_data, &connection_number)) )
+        free_connection_data(con_data, logger);
+      valid = gtk_list_store_remove (GTK_LIST_STORE (priv->connection_model), &iter);
+    }
     else
-      valid = gtk_tree_model_iter_next (priv->model, &iter);
+      valid = gtk_tree_model_iter_next (priv->connection_model, &iter);
+  }
+
+  valid = gtk_tree_model_get_iter_first (priv->message_model, &iter);
+
+  while (valid) {
+    int state;
+
+    gtk_tree_model_get (priv->message_model, &iter,
+                        MESSAGE_COL_STATE, &state,
+                        -1);
+
+    if (state == MESSAGE_STATE_FINISHED) {
+      int message_number;
+      FlyMessageData *msg_data;
+      gtk_tree_model_get (priv->message_model, &iter,
+                          MESSAGE_COL_NUMBER, &message_number,
+                          -1);
+      if ( (msg_data = g_hash_table_lookup(priv->message_data, &message_number)) ) {
+        if (msg_data->connections == NULL)
+          free_message_data(msg_data, logger);
+      }
+      valid = gtk_list_store_remove (GTK_LIST_STORE (priv->message_model), &iter);
+    } else
+      valid = gtk_tree_model_iter_next (priv->message_model, &iter);
   }
 }
 
@@ -143,53 +347,222 @@ check_button_toggled_cb (GtkToggleButton *toggle, SoupFly *logger)
   SoupFlyPrivate *priv = logger->priv;
 
   priv->clean_finished = gtk_toggle_button_get_active (toggle);
+  if (priv->clean_finished) {
+    clear_button_clicked_cb (GTK_BUTTON(priv->clear_button), logger);
+  }
+}
+
+static void
+message_state_data_func (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+                         GtkTreeModel *model, GtkTreeIter *iter,
+                         gpointer data)
+{
+  int state;
+
+  gtk_tree_model_get (model, iter, MESSAGE_COL_STATE, &state, -1);
+  g_object_set (G_OBJECT (cell),
+                "text", message_states[state].name,
+                "background", message_states[state].color,
+                NULL);
+}
+
+static void
+when_data_func (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+                GtkTreeModel *model, GtkTreeIter *iter,
+                gpointer data)
+{
+  SoupFlyPrivate *priv = ((SoupFly *)data)->priv;
+  double when;
+  int itime;
+  int iusec;
+  int hour;
+  int minute;
+  int mcol;
+  char buffer[16];
+
+  if (model == priv->connection_history_model)
+    mcol = CONNECTION_HISTORY_WHEN;
+  else if (model == priv->message_history_model)
+    mcol = MESSAGE_HISTORY_WHEN;
+  else return;
+
+  gtk_tree_model_get (model, iter, mcol, &when, -1);
+  itime = (int)when;
+  iusec = ((when - (double)itime) * 1000000);
+  hour = ((itime % 86400) / 3600);
+  minute = ((itime % 3600) / 60);
+  g_snprintf (buffer, sizeof(buffer), "%02d:%02d:%02d.%06d", hour, minute, itime%60, iusec);
+  g_object_set (G_OBJECT (cell),
+                "text", buffer,
+                NULL);
 }
 
 static void
-state_data_func (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+message_connection_data_func (GtkTreeViewColumn *column, GtkCellRenderer *cell,
                  GtkTreeModel *model, GtkTreeIter *iter,
                  gpointer data)
 {
+  int connection;
+  char text[16];
+
+  gtk_tree_model_get (model, iter, MESSAGE_COL_CONNECTION, &connection, -1);
+  if (connection >= 0) {
+    g_snprintf( text, sizeof(text), "%i", connection);
+    g_object_set (G_OBJECT (cell),
+                  "text", text,
+                  NULL);
+  } else {
+    g_object_set (G_OBJECT (cell),
+                  "text", "",
+                  NULL);
+  }
+}
+
+static void
+connection_state_data_func (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+                            GtkTreeModel *model, GtkTreeIter *iter,
+                            gpointer data)
+{
   int state;
 
-  gtk_tree_model_get (model, iter, COL_STATE, &state, -1);
+  gtk_tree_model_get (model, iter, CONNECTION_COL_STATE, &state, -1);
   g_object_set (G_OBJECT (cell),
-                "text", states[state].name,
-                "background", states[state].color,
+                "text", connection_states[state].name,
+                "background", connection_states[state].color,
                 NULL);
 }
 
 static void
-construct_ui (SoupFly *logger)
+connection_message_data_func (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+                 GtkTreeModel *model, GtkTreeIter *iter,
+                 gpointer data)
 {
-  GtkListStore *store;
-  GtkWidget *treeview;
-  GtkCellRenderer *renderer;
-  GtkWidget *scrolled, *hbox, *vbox, *button, *check_button;
-  GtkTreeViewColumn *column;
+  int state;
+  int message_number;
+  char text[16];
+
+  gtk_tree_model_get (model, iter, CONNECTION_HISTORY_STATE, &state, -1);
+  if (state == CONNECTION_STATE_INUSE) {
+    gtk_tree_model_get (model, iter, CONNECTION_HISTORY_MESSAGE, &message_number, -1);
+    g_snprintf(text, sizeof(text), "%i", message_number);
+    g_object_set (G_OBJECT (cell),
+                  "text", text,
+                  NULL);
+  } else {
+    g_object_set (G_OBJECT (cell),
+              "text", "",
+              NULL);
+  }
+}
+
+static void
+connection_messageuri_data_func (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+                 GtkTreeModel *model, GtkTreeIter *iter,
+                 gpointer data)
+{
+  SoupFly *logger = (SoupFly *)data;
+  int state;
+  int message_number;
+  FlyMessageData *message_data;
   SoupFlyPrivate *priv = logger->priv;
 
-  gtk_window_set_icon_name (GTK_WINDOW (logger),
-                            GTK_STOCK_DIALOG_INFO);
+  gtk_tree_model_get (model, iter, CONNECTION_HISTORY_STATE, &state, -1);
+  if (state == CONNECTION_STATE_INUSE) {
+    gtk_tree_model_get (model, iter, CONNECTION_HISTORY_MESSAGE, &message_number, -1);
+    message_data = g_hash_table_lookup (priv->message_data, &message_number);
+    if (message_data) {
+      g_object_set (G_OBJECT (cell),
+                    "text", message_data->uri,
+                    NULL);
+    } else {
+      g_object_set (G_OBJECT (cell),
+                    "text", _("Unknown"),
+                    NULL);
+    }
+  } else {
+    g_object_set (G_OBJECT (cell),
+                  "text", "",
+                  NULL);
+  }
+}
 
-  g_signal_connect (logger, "delete-event",
-                    G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+static void
+connection_host_data_func (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+                           GtkTreeModel *model, GtkTreeIter *iter,
+                           gpointer data)
+{
+  SoupAddress *host;
+  const char *hostName;
+  const char *physical;
+  guint port;
+  char buffer[256];
 
-  treeview = gtk_tree_view_new ();
-  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
+  gtk_tree_model_get (model, iter, CONNECTION_COL_HOST, &host, -1);
+
+  if ( !SOUP_IS_ADDRESS(host) )
+    return;
 
-  store = gtk_list_store_new (N_COLUMNS,
-                              G_TYPE_UINT,
-                              G_TYPE_INT,
-                              G_TYPE_INT,
-                              G_TYPE_STRING);
-  gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
+  hostName = soup_address_get_name (host);
+  physical = soup_address_get_physical (host);
+  port = soup_address_get_port (host);
+  if (hostName && physical)
+    g_snprintf(buffer, sizeof(buffer), "%s[%s]:%i", hostName, physical, port);
+  else if (hostName)
+    g_snprintf(buffer, sizeof(buffer), "%s:%i", hostName, port);
+  else if (physical)
+    g_snprintf(buffer, sizeof(buffer), "%s:%i", physical, port);
+  else
+    g_snprintf(buffer, sizeof(buffer), "[%s]:%i", _("Unknown"), port);
+
+  g_object_set (G_OBJECT (cell),
+                "text", buffer,
+                NULL);
+}
+
+static void
+generate_treemodels (SoupFly *logger)
+{
+  SoupFlyPrivate *priv = logger->priv;
+  priv->message_model = GTK_TREE_MODEL( gtk_list_store_new (MESSAGE_N_COLUMNS,
+                                        G_TYPE_UINT,
+                                        G_TYPE_INT,
+                                        G_TYPE_INT,
+                                        G_TYPE_INT,
+                                        G_TYPE_STRING) );
+
+  priv->connection_model = GTK_TREE_MODEL( gtk_list_store_new(CONNECTION_N_COLUMNS,
+                                           G_TYPE_UINT,
+                                           G_TYPE_INT,
+                                           G_TYPE_POINTER) );
+
+  priv->message_history_model = GTK_TREE_MODEL( gtk_list_store_new (MESSAGE_HISTORY_N_COLUMNS,
+                                                G_TYPE_DOUBLE, /* WHEN */
+                                                G_TYPE_INT     /* STATE */
+                                                ) );
+
+  priv->connection_history_model = GTK_TREE_MODEL( gtk_list_store_new (CONNECTION_HISTORY_N_COLUMNS,
+                                                   G_TYPE_DOUBLE,  /* WHEN */
+                                                   G_TYPE_INT,     /* STATE */
+                                                   G_TYPE_INT      /* Message number */
+                                                   ) );
+}
 
+static void
+generate_treeviews (SoupFly *logger)
+{
+  SoupFlyPrivate *priv = logger->priv;
+  GtkCellRenderer *renderer;
+  GtkTreeViewColumn *column;
+  GtkTreeView *treeview;
+
+  /* Message treeview */
+  treeview = GTK_TREE_VIEW(gtk_tree_view_new ());
+  priv->message_treeview = GTK_WIDGET(treeview);
   renderer = gtk_cell_renderer_text_new ();
-  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
-                                               COL_NUMBER, "#",
+  gtk_tree_view_insert_column_with_attributes (treeview,
+                                               MESSAGE_COL_NUMBER, "#",
                                                renderer,
-                                               "text", COL_NUMBER,
+                                               "text", MESSAGE_COL_NUMBER,
                                                NULL);
 
   column = gtk_tree_view_column_new ();
@@ -197,29 +570,191 @@ construct_ui (SoupFly *logger)
   renderer = gtk_cell_renderer_text_new ();
   gtk_tree_view_column_pack_start (column, renderer, FALSE);
   gtk_tree_view_column_set_cell_data_func (column, renderer,
-                                           state_data_func,
+                                           message_state_data_func,
                                            NULL, NULL);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); 
+  gtk_tree_view_append_column (treeview, column);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("Connection #"));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                           message_connection_data_func,
+                                           NULL, NULL);
+  gtk_tree_view_append_column (treeview, column);
 
   renderer = gtk_cell_renderer_progress_new ();
   g_object_set (G_OBJECT (renderer), "text-xalign", 0.0, NULL);
-  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
-                                               COL_URL, "URL",
+  gtk_tree_view_insert_column_with_attributes (treeview,
+                                               MESSAGE_COL_URL, "URL",
+                                               renderer,
+                                               "text", MESSAGE_COL_URL,
+                                               "value", MESSAGE_COL_PROGRESS,
+                                               NULL);
+  gtk_tree_view_set_rules_hint (treeview, TRUE);
+
+  /* Message history treeview */
+  treeview = GTK_TREE_VIEW(gtk_tree_view_new ());
+  priv->message_history_treeview = GTK_WIDGET(treeview);
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("When"));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                           when_data_func,
+                                           logger, NULL);
+  gtk_tree_view_append_column (treeview, column);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("State"));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                           message_state_data_func,
+                                           NULL, NULL);
+  gtk_tree_view_append_column (treeview, column);
+  gtk_tree_view_set_rules_hint (treeview, TRUE);
+
+  /* Connection treeview */
+  treeview = GTK_TREE_VIEW(gtk_tree_view_new ());
+  priv->connection_treeview = GTK_WIDGET(treeview);
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_insert_column_with_attributes (treeview,
+                                               CONNECTION_COL_NUMBER, "#",
                                                renderer,
-                                               "text", COL_URL,
-                                               "value", COL_PROGRESS,
+                                               "text", CONNECTION_COL_NUMBER,
                                                NULL);
 
-  scrolled = gtk_scrolled_window_new (NULL, NULL);
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("State"));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                           connection_state_data_func,
+                                           NULL, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("Host"));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                           connection_host_data_func,
+                                           logger, NULL);
+  gtk_tree_view_append_column (treeview, column);
+  gtk_tree_view_set_rules_hint (treeview, TRUE);
+
+  /* Connection history treeview */
+  treeview = GTK_TREE_VIEW(gtk_tree_view_new ());
+  priv->connection_history_treeview = GTK_WIDGET(treeview);
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("When"));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                           when_data_func,
+                                           logger, NULL);
+  gtk_tree_view_append_column (treeview, column);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("State"));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                           connection_state_data_func,
+                                           NULL, NULL);
+  gtk_tree_view_append_column (treeview, column);
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("Message #"));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                           connection_message_data_func,
+                                           NULL, NULL);
+  gtk_tree_view_append_column (treeview, column);
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("Message URL"));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                           connection_messageuri_data_func,
+                                           logger, NULL);
+  gtk_tree_view_append_column (treeview, column);
+  gtk_tree_view_set_rules_hint (treeview, TRUE);
+
+  g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->message_treeview)),
+                    "changed",
+                    G_CALLBACK (message_selected_cb),
+                    logger);
+
+  g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->connection_treeview)),
+                    "changed",
+                    G_CALLBACK (connection_selected_cb),
+                    logger);
+
+  gtk_tree_view_set_model (GTK_TREE_VIEW (priv->message_treeview), GTK_TREE_MODEL (priv->message_model));
+  gtk_tree_view_set_model (GTK_TREE_VIEW (priv->message_history_treeview), GTK_TREE_MODEL (priv->message_history_model));
+  gtk_tree_view_set_model (GTK_TREE_VIEW (priv->connection_treeview), GTK_TREE_MODEL(priv->connection_model));
+  gtk_tree_view_set_model (GTK_TREE_VIEW (priv->connection_history_treeview), GTK_TREE_MODEL(priv->connection_history_model));
+}
+
+static void
+generate_containers_and_buttons (SoupFly *logger)
+{
+  SoupFlyPrivate *priv = logger->priv;
+  GtkWidget *connection_scrolled, *message_scrolled, *scrolled2, *vpaned, *sup_area,
+            *hbox, *vbox, *check_button, *vhistorybox;
+
+  priv->history_label = GTK_LABEL (gtk_label_new ((const gchar *)""));
+  message_scrolled = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (message_scrolled),
+                                  GTK_POLICY_AUTOMATIC,
+                                  GTK_POLICY_AUTOMATIC);
+  gtk_container_add (GTK_CONTAINER (message_scrolled), priv->message_treeview);
+
+  connection_scrolled = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (connection_scrolled),
+                                  GTK_POLICY_AUTOMATIC,
+                                  GTK_POLICY_AUTOMATIC);
+  gtk_container_add (GTK_CONTAINER (connection_scrolled), priv->connection_treeview);
+
+  sup_area = gtk_hpaned_new ();
+  gtk_paned_pack1( GTK_PANED(sup_area), message_scrolled, TRUE, FALSE);
+  gtk_paned_pack2( GTK_PANED(sup_area), connection_scrolled, TRUE, FALSE);
+
+  priv->message_history_widget = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->message_history_widget),
+                                  GTK_POLICY_AUTOMATIC,
+                                  GTK_POLICY_AUTOMATIC);
+  gtk_container_add (GTK_CONTAINER (priv->message_history_widget), priv->message_history_treeview);
+
+  priv->connection_history_widget = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->connection_history_widget),
                                   GTK_POLICY_AUTOMATIC,
                                   GTK_POLICY_AUTOMATIC);
-  gtk_container_add (GTK_CONTAINER (scrolled), treeview);
+  gtk_container_add (GTK_CONTAINER (priv->connection_history_widget), priv->connection_history_treeview);
+
+  vhistorybox = gtk_vbox_new (FALSE, 10);
+  gtk_box_pack_start (GTK_BOX(vhistorybox), GTK_WIDGET(priv->history_label), FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX(vhistorybox), GTK_WIDGET(priv->message_history_widget), TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX(vhistorybox), GTK_WIDGET(priv->connection_history_widget), TRUE, TRUE, 0);
+
+  priv->history_widget = GTK_WIDGET(vhistorybox);
+
+  scrolled2 = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled2),
+                                  GTK_POLICY_AUTOMATIC,
+                                  GTK_POLICY_AUTOMATIC);
+  gtk_container_add (GTK_CONTAINER (scrolled2), vhistorybox);
+
+  vpaned = gtk_vpaned_new ();
+  gtk_paned_pack1( GTK_PANED(vpaned), sup_area, TRUE, FALSE);
+  gtk_paned_pack2( GTK_PANED(vpaned), scrolled2, FALSE, FALSE);
 
   hbox = gtk_hbox_new (FALSE, 10);
-  button = gtk_button_new_with_label (_("Clear finished"));
-  g_signal_connect (button, "clicked", G_CALLBACK (clear_button_clicked_cb), logger);
-  gtk_container_add (GTK_CONTAINER (hbox), button);
+  priv->clear_button = gtk_button_new_with_label (_("Clear finished"));
+  g_signal_connect (priv->clear_button, "clicked", G_CALLBACK (clear_button_clicked_cb), logger);
+  gtk_container_add (GTK_CONTAINER (hbox), priv->clear_button);
 
   check_button = gtk_check_button_new_with_label (_("Automatically remove finished messages"));
   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), priv->clean_finished);
@@ -227,50 +762,89 @@ construct_ui (SoupFly *logger)
   gtk_container_add (GTK_CONTAINER (hbox), check_button);
 
   vbox = gtk_vbox_new (FALSE, 10);
-  gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), vpaned, TRUE, TRUE, 0);
   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
 
   gtk_container_add (GTK_CONTAINER (logger), vbox);
+}
+
+static void
+construct_ui (SoupFly *logger)
+{
+  gtk_window_set_icon_name (GTK_WINDOW (logger),
+                            GTK_STOCK_DIALOG_INFO);
+
+  g_signal_connect (logger, "delete-event",
+                    G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+
+  generate_treemodels (logger);
+  generate_treeviews (logger);
+  generate_containers_and_buttons (logger);
 
   gtk_window_set_title (GTK_WINDOW (logger), "Soup Fly");
   gtk_container_set_border_width (GTK_CONTAINER (logger), 5);
   gtk_window_set_default_size (GTK_WINDOW (logger), 640, 480);
 
-  priv->model = GTK_TREE_MODEL (store);
-  priv->treeview = treeview;
-  priv->clear_button = button;
+  g_signal_connect (logger, "show",
+                    G_CALLBACK (soup_fly_show_cb), NULL);
 }
 
 static void
 soup_fly_init (SoupFly *logger)
 {
   logger->priv = SOUP_FLY_GET_PRIVATE (logger);
-  
-  logger->priv->nth = 0;
+
+  logger->priv->message_nth = 0;
+
+  logger->priv->message_data = g_hash_table_new (g_int_hash, g_int_equal);
+  logger->priv->connection_data = g_hash_table_new (g_int_hash, g_int_equal);
 
   construct_ui (logger);
 }
 
-typedef struct
+static void
+message_add_entry (FlyMessageData *data, gint state)
 {
-  GtkTreeIter iter;
-  SoupFly *logger;
-  goffset content_length, received;
-} FlyMessageData;
+  FlyMessageDataEntry *new_entry = g_slice_new (FlyMessageDataEntry);
+	gint old_state = message_current_state(data);
+	if (state == old_state) return;
+  g_get_current_time (&(new_entry->when));
+  new_entry->state = state;
+  data->entries = g_list_append (data->entries, new_entry);
+}
+
+static void
+connection_add_entry (FlyConnectionData *data, gint state)
+{
+  SoupFlyPrivate *priv = data->logger->priv;
+  FlyConnectionDataEntry *new_entry = g_slice_new (FlyConnectionDataEntry);
+  gint old_state = connection_current_state(data);
+  if (state == old_state) return;
+	g_get_current_time (&(new_entry->when));
+  if (old_state == CONNECTION_STATE_INUSE)
+    data->current_message = -1;
+  new_entry->state = state;
+  new_entry->message_number = -1;
+  data->entries = g_list_append (data->entries, new_entry);
+
+  gtk_list_store_set (GTK_LIST_STORE (priv->connection_model), &(data->iter),
+                      CONNECTION_COL_STATE, state,
+                      -1);
+}
 
 static void
 message_finished_cb (SoupMessage *message, FlyMessageData *data)
 {
   SoupFlyPrivate *priv = data->logger->priv;
 
+  message_add_entry (data, MESSAGE_STATE_FINISHED);
+  gtk_list_store_set (GTK_LIST_STORE (priv->message_model), &data->iter,
+                      MESSAGE_COL_PROGRESS, 0,
+                      MESSAGE_COL_STATE, MESSAGE_STATE_FINISHED,
+                      -1);
+
   if (priv->clean_finished)
-    gtk_list_store_remove (GTK_LIST_STORE (priv->model), &data->iter);
-  else
-    gtk_list_store_set (GTK_LIST_STORE (priv->model), &data->iter,
-                        COL_PROGRESS, 0,
-                        COL_STATE, STATE_FINISHED,
-                        -1);
-  g_slice_free (FlyMessageData, data);
+    clear_button_clicked_cb (GTK_BUTTON(priv->clear_button), data->logger);
 }
 
 static void
@@ -281,8 +855,8 @@ message_got_chunk_cb (SoupMessage *message, SoupBuffer *chunk, FlyMessageData *d
   data->received += chunk->length;
   if (data->content_length && data->received) {
     gint percentage = CLAMP ((int)(data->received * 100 / data->content_length), 0, 100);
-    gtk_list_store_set (GTK_LIST_STORE (priv->model), &data->iter,
-                        COL_PROGRESS, percentage,
+    gtk_list_store_set (GTK_LIST_STORE (priv->message_model), &data->iter,
+                        MESSAGE_COL_PROGRESS, percentage,
                         -1);
   }
 }
@@ -293,10 +867,11 @@ message_got_headers_cb (SoupMessage *message, FlyMessageData *data)
   SoupFlyPrivate *priv = data->logger->priv;
 
   data->content_length = soup_message_headers_get_content_length (message->response_headers);
-  gtk_list_store_set (GTK_LIST_STORE (priv->model), &data->iter,
-                      COL_STATE, STATE_RECEIVING,
-                      COL_PROGRESS, 0,
+  gtk_list_store_set (GTK_LIST_STORE (priv->message_model), &data->iter,
+                      MESSAGE_COL_STATE, MESSAGE_STATE_RECEIVING,
+                      MESSAGE_COL_PROGRESS, 0,
                       -1);
+  message_add_entry (data, MESSAGE_STATE_RECEIVING);
 }
 
 static void
@@ -304,12 +879,242 @@ message_wrote_body_cb (SoupMessage *message, FlyMessageData *data)
 {
   SoupFlyPrivate *priv = data->logger->priv;
 
-  gtk_list_store_set (GTK_LIST_STORE (priv->model), &data->iter,
-                      COL_STATE, STATE_WAITING,
+  gtk_list_store_set (GTK_LIST_STORE (priv->message_model), &data->iter,
+                      MESSAGE_COL_STATE, MESSAGE_STATE_WAITING,
+                      -1);
+  message_add_entry (data, MESSAGE_STATE_WAITING);
+}
+
+static void add_message_data_entry (gpointer data,
+                                    gpointer udata)
+{
+  FlyMessageDataEntry *entry = (FlyMessageDataEntry *)data;
+  GtkListStore *model = GTK_LIST_STORE(udata);
+  GtkTreeIter iter;
+  double dwhen;
+
+  gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+  dwhen = entry->when.tv_sec + entry->when.tv_usec / 1000000.0;
+  gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                      MESSAGE_HISTORY_WHEN, dwhen,
+                      MESSAGE_HISTORY_STATE, entry->state,
+                      -1);
+}
+
+static void add_connection_data_entry (gpointer data,
+                                       gpointer udata)
+{
+  FlyConnectionDataEntry *entry = (FlyConnectionDataEntry *)data;
+  GtkListStore *model = GTK_LIST_STORE(udata);
+  GtkTreeIter iter;
+  double dwhen;
+
+  gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+  dwhen = entry->when.tv_sec + entry->when.tv_usec / 1000000.0;
+  gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                      CONNECTION_HISTORY_WHEN, dwhen,
+                      CONNECTION_HISTORY_STATE, entry->state,
+                      CONNECTION_HISTORY_MESSAGE, entry->message_number,
+                      -1);
+}
+
+static void message_selected_cb (GtkTreeSelection *selection,
+                                 SoupFly *logger)
+{
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  SoupFlyPrivate *priv = logger->priv;
+  FlyMessageData *message_data;
+  gint message_number;
+  char label_text[40];
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+    gtk_tree_model_get (model, &iter, MESSAGE_COL_NUMBER, &message_number, -1);
+    g_return_if_fail ((message_data = g_hash_table_lookup (priv->message_data, &message_number)));
+    g_snprintf (label_text, sizeof(label_text),
+                _("Message #%i state history:"),
+                message_data->message_number);
+    gtk_label_set_text (priv->history_label, label_text);
+    gtk_list_store_clear (GTK_LIST_STORE(priv->message_history_model));
+    g_list_foreach (message_data->entries, add_message_data_entry, priv->message_history_model);
+    gtk_widget_show (priv->history_widget);
+    gtk_widget_show (priv->message_history_widget);
+    gtk_widget_hide (priv->connection_history_widget);
+  }
+}
+
+static void connection_selected_cb (GtkTreeSelection *selection,
+                                    SoupFly *logger)
+{
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  SoupFlyPrivate *priv = logger->priv;
+  FlyConnectionData *connection_data;
+  gint connection_number;
+  char label_text[40];
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+    gtk_tree_model_get (model, &iter,
+                        MESSAGE_COL_NUMBER, &connection_number,
+                        -1);
+    g_return_if_fail ((connection_data = g_hash_table_lookup (priv->connection_data,
+                                                              &connection_number)));
+    g_snprintf (label_text, sizeof(label_text),
+                _("Connection #%i state history"),
+                connection_data->connection_number);
+    gtk_label_set_text (priv->history_label, label_text);
+    gtk_list_store_clear (GTK_LIST_STORE (priv->connection_history_model));
+    g_list_foreach (connection_data->entries, add_connection_data_entry,
+                    priv->connection_history_model);
+    gtk_widget_show (priv->history_widget);
+    gtk_widget_show (priv->connection_history_widget);
+    gtk_widget_hide (priv->message_history_widget);
+  }
+}
+
+static void
+connection_update_host (void *connection, GtkTreeModel *model,
+                        FlyConnectionData *data)
+{
+  SoupAddress *address;
+  g_object_get (connection, "remote-address", &address, NULL);
+
+  gtk_list_store_set (GTK_LIST_STORE (model), &(data->iter),
+                      CONNECTION_COL_HOST, address,
                       -1);
 }
 
 static void
+connection_created_cb (SoupSession *session, void *connection,
+                       SoupFly *logger)
+{
+  FlyConnectionData *data;
+  GObject *obj;
+  g_return_if_fail ( (obj = G_OBJECT (connection)) );
+  g_return_if_fail ( !g_object_get_data (obj, "FlyConnectionData") );
+  data = g_slice_new0 (FlyConnectionData);
+  data->connection_number = logger->priv->connection_nth++;
+  g_object_set_data (obj, "FlyConnectionData", data);
+  g_hash_table_insert (logger->priv->connection_data,
+                       &(data->connection_number), data);
+  data->logger = logger;
+  data->entries = NULL;
+
+  gtk_list_store_append (GTK_LIST_STORE (logger->priv->connection_model),
+                         &(data->iter));
+
+  gtk_list_store_set (GTK_LIST_STORE (logger->priv->connection_model), &(data->iter),
+                      CONNECTION_COL_NUMBER, data->connection_number,
+                      -1);
+  connection_add_entry (data, CONNECTION_STATE_NEW);
+  connection_update_host (connection, logger->priv->connection_model, data);
+}
+
+static void
+connection_destroyed_cb (SoupSession *session, void *connection,
+                         SoupFly *logger)
+{
+  SoupFlyPrivate *priv = logger->priv;
+  FlyConnectionData *data;
+  GObject *obj;
+
+  g_return_if_fail ( (obj = G_OBJECT(connection)) );
+  g_return_if_fail ( (data = g_object_get_data(obj, "FlyConnectionData")) );
+  connection_add_entry (data, CONNECTION_STATE_CLEANEDUP);
+
+  g_object_set_data(obj, "FlyConnectionData", NULL);
+  if (priv->clean_finished) {
+    clear_button_clicked_cb (GTK_BUTTON (priv->clear_button), logger);
+  }
+}
+
+static void
+connection_connecting_cb (SoupSession *session, void *connection,
+                    SoupFly *logger)
+{
+  FlyConnectionData *data;
+  GObject *obj;
+
+  g_return_if_fail ( (obj = G_OBJECT (connection)) );
+  g_return_if_fail ( (data = g_object_get_data (obj, "FlyConnectionData")) );
+
+  connection_add_entry (data, CONNECTION_STATE_CONNECTING);
+  connection_update_host (connection, logger->priv->connection_model, data);
+}
+
+static void
+connection_in_use_cb (SoupSession *session, void *connection,
+                      SoupFly *logger)
+{
+  FlyConnectionData *data;
+  GObject *obj;
+
+  g_return_if_fail ( (obj = G_OBJECT (connection)) );
+  g_return_if_fail ( (data = g_object_get_data (obj, "FlyConnectionData")) );
+
+  connection_add_entry (data, CONNECTION_STATE_INUSE);
+  connection_update_host (connection, logger->priv->connection_model, data);
+}
+
+static void
+connection_disconnected_cb (SoupSession *session, void *connection,
+                            SoupFly *logger)
+{
+  FlyConnectionData *data;
+  GObject *obj;
+
+  g_return_if_fail ( (obj = G_OBJECT (connection)) );
+  g_return_if_fail ( (data = g_object_get_data (obj, "FlyConnectionData")) );
+
+  connection_add_entry (data, CONNECTION_STATE_DISCONNECTED);
+  connection_update_host (connection, logger->priv->connection_model, data);
+}
+
+static void
+connection_changed_message_cb (SoupSession *session, void *connection,
+                               SoupMessage *message, SoupFly *logger)
+{
+  SoupFlyPrivate *priv = logger->priv;
+  FlyConnectionData *data;
+  FlyMessageData *msg_data;
+  GObject *obj;
+
+  g_return_if_fail ( (obj = G_OBJECT (connection)) );
+  g_return_if_fail ( (data = g_object_get_data (obj, "FlyConnectionData")) );
+  msg_data = g_object_get_data (G_OBJECT (message), "FlyMessageData");
+
+  if (!msg_data)
+    data->current_message = -1;
+  else {
+    GList *current_entry;
+		if ( !g_list_find (msg_data->connections, data) )
+			msg_data->connections = g_list_append(msg_data->connections, data);
+    data->current_message = msg_data->message_number;
+    current_entry = g_list_last (data->entries);
+    if ((connection_current_state (data)) && current_entry) {
+      ((FlyConnectionDataEntry *)current_entry->data)->message_number = msg_data->message_number;
+    }
+    gtk_list_store_set (GTK_LIST_STORE (priv->message_model), &(msg_data->iter),
+                        MESSAGE_COL_CONNECTION, data->connection_number,
+                        -1);
+  }
+}
+
+static void
+connection_idle_cb (SoupSession *session, void *connection,
+                    SoupFly *logger)
+{
+  FlyConnectionData *data;
+  GObject *obj;
+
+  g_return_if_fail ( (obj = G_OBJECT(connection)) );
+  g_return_if_fail ( (data = g_object_get_data(obj, "FlyConnectionData")) );
+
+  connection_add_entry (data, CONNECTION_STATE_IDLE);
+  connection_update_host (connection, logger->priv->connection_model, data);
+}
+
+static void
 request_started_cb (SoupSession *session, SoupMessage *message,
                     SoupSocket *socket, SoupFly *logger)
 {
@@ -318,9 +1123,10 @@ request_started_cb (SoupSession *session, SoupMessage *message,
 
   if (!data)
     return;
-  gtk_list_store_set (GTK_LIST_STORE (priv->model), &data->iter,
-                      COL_STATE, STATE_SENDING,
+  gtk_list_store_set (GTK_LIST_STORE (priv->message_model), &data->iter,
+                      MESSAGE_COL_STATE, MESSAGE_STATE_SENDING,
                       -1);
+  message_add_entry (data, MESSAGE_STATE_SENDING);
 }
 
 static void
@@ -335,17 +1141,22 @@ request_queued_cb (SoupSession *session, SoupMessage *message, SoupFly *logger)
   uri = soup_message_get_uri (message);
   uri_string = soup_uri_to_string (uri, FALSE);
 
-  gtk_list_store_append (GTK_LIST_STORE (priv->model), &iter);
-  gtk_list_store_set (GTK_LIST_STORE (priv->model), &iter,
-                      COL_NUMBER, priv->nth++,
-                      COL_URL, uri_string,
-                      COL_STATE, STATE_QUEUED,
-                      -1);
-  g_free (uri_string);
-  
+  gtk_list_store_append (GTK_LIST_STORE (priv->message_model), &iter);
+
   data = g_slice_new0 (FlyMessageData);
+  data->message_number = priv->message_nth++;
+  data->uri = uri_string;
+  g_hash_table_insert (priv->message_data, &(data->message_number), data);
+
+  gtk_list_store_set (GTK_LIST_STORE (priv->message_model), &iter,
+                      MESSAGE_COL_NUMBER, data->message_number,
+                      MESSAGE_COL_URL, uri_string,
+                      MESSAGE_COL_STATE, MESSAGE_STATE_QUEUED,
+                      -1);
+
   data->iter = iter;
   data->logger = logger;
+  message_add_entry (data, MESSAGE_STATE_QUEUED);
   g_object_set_data (G_OBJECT (message), "FlyMessageData", data);
   g_signal_connect (message, "wrote-body", G_CALLBACK (message_wrote_body_cb), data);
   g_signal_connect (message, "got-headers", G_CALLBACK (message_got_headers_cb), data);
@@ -353,6 +1164,42 @@ request_queued_cb (SoupSession *session, SoupMessage *message, SoupFly *logger)
   g_signal_connect (message, "finished", G_CALLBACK (message_finished_cb), data);
 }
 
+static void
+soup_fly_dispose (GObject *o)
+{
+  SoupFly *logger = SOUP_FLY (o);
+  SoupFlyPrivate *priv;
+  GList *hash_values;
+  GList *value;
+  g_return_if_fail (logger);
+  priv = logger->priv;
+
+  g_object_unref (priv->message_model);
+  g_object_unref (priv->message_history_model);
+  g_object_unref (priv->connection_model);
+  g_object_unref (priv->connection_history_model);
+
+  hash_values = g_hash_table_get_values (priv->message_data);
+  value = hash_values;
+  while (value) {
+    g_slice_free (FlyMessageData, value->data);
+    value = value->next;
+  }
+
+  g_list_free (hash_values);
+  hash_values = g_hash_table_get_values (priv->connection_data);
+  value = hash_values;
+
+  while (value) {
+    g_slice_free (FlyConnectionData, value->data);
+    value = value->next;
+  }
+
+  g_list_free (hash_values);
+  g_hash_table_destroy (priv->connection_data);
+  g_hash_table_destroy (priv->message_data);
+}
+
 /* Public API */
 
 /**
@@ -368,12 +1215,20 @@ soup_fly_start (SoupFly *logger)
   SoupFlyPrivate *priv;
 
   g_return_if_fail (IS_SOUP_FLY (logger));
-  
+
   priv = logger->priv;
   session = webkit_get_default_session ();
   g_return_if_fail (session);
   g_signal_connect (session, "request-queued", G_CALLBACK (request_queued_cb), logger);
   g_signal_connect (session, "request-started", G_CALLBACK (request_started_cb), logger);
+
+  g_signal_connect (session, "connection-created", G_CALLBACK (connection_created_cb), logger);
+  g_signal_connect (session, "connection-idle", G_CALLBACK (connection_idle_cb), logger);
+  g_signal_connect (session, "connection-connecting", G_CALLBACK (connection_connecting_cb), logger);
+  g_signal_connect (session, "connection-in-use", G_CALLBACK (connection_in_use_cb), logger);
+  g_signal_connect (session, "connection-disconnected", G_CALLBACK (connection_disconnected_cb), logger);
+  g_signal_connect (session, "connection-changed-message", G_CALLBACK (connection_changed_message_cb), logger);
+  g_signal_connect (session, "connection-destroyed", G_CALLBACK (connection_destroyed_cb), logger);
 }
 
 /**
@@ -388,9 +1243,18 @@ soup_fly_stop (SoupFly *logger)
   SoupSession *session;
 
   g_return_if_fail (IS_SOUP_FLY (logger));
-  
+
   session = webkit_get_default_session ();
   g_signal_handlers_disconnect_by_func (session, G_CALLBACK (request_queued_cb), logger);
+  g_signal_handlers_disconnect_by_func (session, G_CALLBACK (request_started_cb), logger);
+
+  g_signal_handlers_disconnect_by_func (session, G_CALLBACK (connection_created_cb), logger);
+  g_signal_handlers_disconnect_by_func (session, G_CALLBACK (connection_idle_cb), logger);
+  g_signal_handlers_disconnect_by_func (session, G_CALLBACK (connection_connecting_cb), logger);
+  g_signal_handlers_disconnect_by_func (session, G_CALLBACK (connection_in_use_cb), logger);
+  g_signal_handlers_disconnect_by_func (session, G_CALLBACK (connection_disconnected_cb), logger);
+  g_signal_handlers_disconnect_by_func (session, G_CALLBACK (connection_changed_message_cb), logger);
+  g_signal_handlers_disconnect_by_func (session, G_CALLBACK (connection_destroyed_cb), logger);
 }
 
 /**
@@ -404,4 +1268,3 @@ soup_fly_new (void)
 {
   return SOUP_FLY (g_object_new (TYPE_SOUP_FLY, NULL));
 }
-
