[gnome-disk-utility/wip/iscsi] Add back iSCSI bits



commit fc2a233964da35798c332179929736e10df7ab9e
Author: David Zeuthen <davidz redhat com>
Date:   Tue Feb 28 09:57:54 2012 -0500

    Add back iSCSI bits
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 data/ui/palimpsest.ui               |  331 +++++++++++++++++++++++++++++-
 src/palimpsest/Makefile.am          |    1 +
 src/palimpsest/gdudevicetreemodel.c |  279 +++++++++++++++++++++++++-
 src/palimpsest/gduiscsipathmodel.c  |  325 +++++++++++++++++++++++++++++
 src/palimpsest/gduiscsipathmodel.h  |   55 +++++
 src/palimpsest/gdutypes.h           |    3 +
 src/palimpsest/gduwindow.c          |  386 +++++++++++++++++++++++++++++++++++
 7 files changed, 1373 insertions(+), 7 deletions(-)
---
diff --git a/data/ui/palimpsest.ui b/data/ui/palimpsest.ui
index 4d45b79..5b72446 100644
--- a/data/ui/palimpsest.ui
+++ b/data/ui/palimpsest.ui
@@ -1162,17 +1162,316 @@
               </packing>
             </child>
             <child>
-              <object class="GtkVBox" id="newtab_vbox">
+              <object class="GtkVBox" id="iscsitab_vbox">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
+                <property name="spacing">12</property>
                 <child>
-                  <placeholder/>
+                  <object class="GtkTable" id="iscsitab-table">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">12</property>
+                    <child>
+                      <object class="GtkLabel" id="iscsitab-name-label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">Target Name</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="top_attach">0</property>
+                        <property name="bottom_attach">1</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                        <property name="y_padding">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="iscsitab-name-value-label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="xalign">0</property>
+                        <property name="selectable">True</property>
+                        <property name="ellipsize">end</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">0</property>
+                        <property name="bottom_attach">1</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                        <property name="y_padding">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="iscsitab-discovery-label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">Discovery</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="right_attach">1</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                        <property name="y_padding">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="iscsitab-discovery-value-label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="xalign">0</property>
+                        <property name="selectable">True</property>
+                        <property name="ellipsize">end</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                        <property name="y_padding">4</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
                 </child>
                 <child>
-                  <placeholder/>
+                  <object class="GtkLabel" id="iscsitab-main-label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">&lt;b&gt;_Connections&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">iscsi-connections-treeview</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
                 </child>
                 <child>
-                  <placeholder/>
+                  <object class="GtkAlignment" id="alignment2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="left_padding">24</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox2">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <child>
+                          <object class="GtkScrolledWindow" id="iscsitab-scrolledwindow">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="hscrollbar_policy">never</property>
+                            <property name="shadow_type">in</property>
+                            <child>
+                              <object class="GtkTreeView" id="iscsi-connections-treeview">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="show_expanders">False</property>
+                                <property name="level_indentation">12</property>
+                                <child internal-child="selection">
+                                  <object class="GtkTreeSelection" id="iscsi-treeview-selection"/>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkToolbar" id="iscsitab-toolbar">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="icon_size">1</property>
+                            <child>
+                              <object class="GtkToolButton" id="iscsitab-configure-toolbutton">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="icon_name">system-run-symbolic</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="homogeneous">True</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+
+                        <child>
+                          <object class="GtkTable" id="iscsitab-connection-table">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="n_rows">2</property>
+                            <property name="n_columns">2</property>
+                            <property name="column_spacing">12</property>
+
+                            <child>
+                              <object class="GtkLabel" id="iscsitab-connection-startup-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">Startup</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="left_attach">0</property>
+                                <property name="right_attach">1</property>
+                                <property name="top_attach">0</property>
+                                <property name="bottom_attach">1</property>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options"></property>
+                                <property name="y_padding">4</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="iscsitab-connection-startup-value-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="hexpand">True</property>
+                                <property name="xalign">0</property>
+                                <property name="selectable">True</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">0</property>
+                                <property name="bottom_attach">1</property>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options"></property>
+                                <property name="y_padding">4</property>
+                              </packing>
+                            </child>
+
+                            <child>
+                              <object class="GtkLabel" id="iscsitab-connection-timeout-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">Timeout</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="left_attach">0</property>
+                                <property name="right_attach">1</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options"></property>
+                                <property name="y_padding">4</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="iscsitab-connection-timeout-value-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="hexpand">True</property>
+                                <property name="xalign">0</property>
+                                <property name="selectable">True</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options"></property>
+                                <property name="y_padding">4</property>
+                              </packing>
+                            </child>
+
+                            <child>
+                              <object class="GtkLabel" id="iscsitab-connection-auth-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">Authentication</property>
+                                <style>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options"></property>
+                                <property name="y_padding">4</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="iscsitab-connection-auth-value-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="hexpand">True</property>
+                                <property name="xalign">0</property>
+                                <property name="selectable">True</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options"></property>
+                                <property name="y_padding">4</property>
+                              </packing>
+                            </child>
+
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                      </object>
+
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
                 </child>
               </object>
               <packing>
@@ -1180,10 +1479,10 @@
               </packing>
             </child>
             <child type="tab">
-              <object class="GtkLabel" id="newtab_label">
+              <object class="GtkLabel" id="iscsitab_label">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="label">new</property>
+                <property name="label" translatable="yes">iscsi target</property>
               </object>
               <packing>
                 <property name="position">3</property>
@@ -1191,6 +1490,26 @@
               </packing>
             </child>
             <child>
+              <object class="GtkVBox" id="newtab_vbox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+              </object>
+              <packing>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="newtab_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">new</property>
+              </object>
+              <packing>
+                <property name="position">4</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
               <placeholder/>
             </child>
             <child type="tab">
diff --git a/src/palimpsest/Makefile.am b/src/palimpsest/Makefile.am
index 6cfeaca..703b140 100644
--- a/src/palimpsest/Makefile.am
+++ b/src/palimpsest/Makefile.am
@@ -47,6 +47,7 @@ palimpsest_SOURCES = 							\
 	gdupasswordstrengthwidget.h	gdupasswordstrengthwidget.c	\
 	gduestimator.h			gduestimator.c			\
 	gduchangepassphrasedialog.h	gduchangepassphrasedialog.c	\
+	gduiscsipathmodel.h		gduiscsipathmodel.c		\
 	$(enum_built_sources)						\
 	$(NULL)
 
diff --git a/src/palimpsest/gdudevicetreemodel.c b/src/palimpsest/gdudevicetreemodel.c
index f84f26b..37b7626 100644
--- a/src/palimpsest/gdudevicetreemodel.c
+++ b/src/palimpsest/gdudevicetreemodel.c
@@ -43,6 +43,10 @@ struct _GduDeviceTreeModel
   GtkTreeIter block_iter;
   gboolean block_iter_valid;
 
+  GList *current_iscsi_objects;
+  GtkTreeIter iscsi_iter;
+  gboolean iscsi_iter_valid;
+
   guint spinner_timeout;
 };
 
@@ -209,6 +213,28 @@ find_iter_for_object (GduDeviceTreeModel *model,
   return data.found;
 }
 
+static gboolean
+find_iter_for_object_path (GduDeviceTreeModel *model,
+                           const gchar        *object_path,
+                           GtkTreeIter        *out_iter)
+{
+  FindIterData data;
+
+  memset (&data, 0, sizeof (data));
+  data.object_path = object_path;
+  data.found = FALSE;
+  gtk_tree_model_foreach (GTK_TREE_MODEL (model),
+                          find_iter_for_object_cb,
+                          &data);
+  if (data.found)
+    {
+      if (out_iter != NULL)
+        *out_iter = data.iter;
+    }
+
+  return data.found;
+}
+
 gboolean
 gdu_device_tree_model_get_iter_for_object (GduDeviceTreeModel *model,
                                            UDisksObject       *object,
@@ -736,6 +762,27 @@ update_drive (GduDeviceTreeModel *model,
   return jobs_running;
 }
 
+static gboolean
+should_include_drive (UDisksObject *object,
+                      gboolean      allow_iscsi)
+{
+  UDisksDrive *drive;
+  gboolean ret;
+
+  ret = FALSE;
+
+  drive = udisks_object_peek_drive (object);
+
+  /* unless specificlly allowed, don't show DRIVEs paired with an iSCSI target */
+  if (!allow_iscsi && g_strcmp0 (udisks_drive_get_iscsi_target (drive), "/") != 0)
+    goto out;
+
+  ret = TRUE;
+
+ out:
+  return ret;
+}
+
 static void
 update_drives (GduDeviceTreeModel *model)
 {
@@ -759,7 +806,8 @@ update_drives (GduDeviceTreeModel *model)
       if (drive == NULL)
         continue;
 
-      drives = g_list_prepend (drives, g_object_ref (object));
+      if (should_include_drive (object, FALSE))
+        drives = g_list_prepend (drives, g_object_ref (object));
     }
 
   drives = g_list_sort (drives, (GCompareFunc) _g_dbus_object_compare);
@@ -1115,12 +1163,241 @@ update_blocks (GduDeviceTreeModel *model)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static GtkTreeIter *
+get_iscsi_iter (GduDeviceTreeModel *model)
+{
+  gchar *s;
+
+  if (model->iscsi_iter_valid)
+    goto out;
+
+  /* TODO: once https://bugzilla.gnome.org/show_bug.cgi?id=657194 is resolved, use that instead
+   * of hard-coding the color
+   */
+  s = g_strdup_printf ("<small><span foreground=\"#555555\">%s</span></small>",
+                       _("iSCSI Targets"));
+  gtk_tree_store_insert_with_values (GTK_TREE_STORE (model),
+                                     &model->iscsi_iter,
+                                     NULL, /* GtkTreeIter *parent */
+                                     0,
+                                     GDU_DEVICE_TREE_MODEL_COLUMN_IS_HEADING, TRUE,
+                                     GDU_DEVICE_TREE_MODEL_COLUMN_HEADING_TEXT, s,
+                                     GDU_DEVICE_TREE_MODEL_COLUMN_SORT_KEY, "02_iscsi",
+                                     -1);
+  g_free (s);
+
+  model->iscsi_iter_valid = TRUE;
+
+ out:
+  return &model->iscsi_iter;
+}
+
+static void
+nuke_iscsi_iter (GduDeviceTreeModel *model)
+{
+  if (model->iscsi_iter_valid)
+    {
+      gtk_tree_store_remove (GTK_TREE_STORE (model), &model->iscsi_iter);
+      model->iscsi_iter_valid = FALSE;
+    }
+}
+
+static void
+add_iscsi_target (GduDeviceTreeModel  *model,
+                  UDisksObject        *object,
+                  GtkTreeIter         *parent)
+{
+  UDisksiSCSITarget *target;
+  GIcon *icon;
+  gchar *s;
+  gchar *sort_key;
+  GtkTreeIter iter;
+
+  target = udisks_object_peek_iscsi_target (object);
+
+#if 0
+  GIcon *base_icon;
+  GIcon *emblem_icon;
+  GEmblem *emblem;
+  emblem_icon = g_themed_icon_new_with_default_fallbacks ("emblem-web");
+  emblem = g_emblem_new (emblem_icon);
+  base_icon = g_themed_icon_new_with_default_fallbacks ("drive-harddisk");
+  icon = g_emblemed_icon_new (base_icon, emblem);
+  g_object_unref (emblem);
+  g_object_unref (base_icon);
+  g_object_unref (emblem_icon);
+#endif
+  icon = g_themed_icon_new_with_default_fallbacks ("network-server");
+
+  s = g_strdup_printf ("%s\n"
+                       "<small><span foreground=\"#555555\">%s</span></small>",
+                       "iSCSI Target", /* TODO: alias */
+                       udisks_iscsi_target_get_name (target));
+
+  sort_key = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); /* for now */
+  gtk_tree_store_insert_with_values (GTK_TREE_STORE (model),
+                                     &iter,
+                                     parent,
+                                     0,
+                                     GDU_DEVICE_TREE_MODEL_COLUMN_ICON, icon,
+                                     GDU_DEVICE_TREE_MODEL_COLUMN_NAME, s,
+                                     GDU_DEVICE_TREE_MODEL_COLUMN_SORT_KEY, sort_key,
+                                     GDU_DEVICE_TREE_MODEL_COLUMN_OBJECT, object,
+                                     -1);
+  g_object_unref (icon);
+  g_free (sort_key);
+  g_free (s);
+}
+
+static void
+remove_iscsi_target (GduDeviceTreeModel  *model,
+                     UDisksObject        *object)
+{
+  GtkTreeIter iter;
+  if (!find_iter_for_object (model,
+                             object,
+                             &iter))
+    {
+      g_warning ("Error finding iter for object at %s",
+                 g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
+      goto out;
+    }
+  gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
+
+ out:
+  ;
+}
+
+static void
+update_iscsi_targets (GduDeviceTreeModel *model)
+{
+  GDBusObjectManager *object_manager;
+  GList *objects;
+  GList *iscsi_objects;
+  GList *added;
+  GList *removed;
+  GList *l;
+
+  object_manager = udisks_client_get_object_manager (model->client);
+  objects = g_dbus_object_manager_get_objects (object_manager);
+
+  iscsi_objects = NULL;
+  for (l = objects; l != NULL; l = l->next)
+    {
+      UDisksObject *object = UDISKS_OBJECT (l->data);
+      UDisksiSCSITarget *target;
+      target = udisks_object_peek_iscsi_target (object);
+      if (target != NULL)
+        {
+          GList *ll;
+          const gchar *target_object_path;
+
+          iscsi_objects = g_list_prepend (iscsi_objects, g_object_ref (object));
+
+          /* also include the drives that are associated with this target */
+          target_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
+          for (ll = objects; ll != NULL; ll = ll->next)
+            {
+              UDisksObject *drive_object = UDISKS_OBJECT (ll->data);
+              UDisksDrive *drive;
+              drive = udisks_object_peek_drive (drive_object);
+              if (drive != NULL)
+                {
+                  if (g_strcmp0 (udisks_drive_get_iscsi_target (drive), target_object_path) == 0)
+                    {
+                      if (should_include_drive (drive_object, TRUE))
+                        iscsi_objects = g_list_prepend (iscsi_objects, g_object_ref (drive_object));
+                    }
+                }
+            }
+        }
+    }
+
+  iscsi_objects = g_list_sort (iscsi_objects, (GCompareFunc) _g_dbus_object_compare);
+  model->current_iscsi_objects = g_list_sort (model->current_iscsi_objects, (GCompareFunc) _g_dbus_object_compare);
+  diff_sorted_lists (model->current_iscsi_objects,
+                     iscsi_objects,
+                     (GCompareFunc) _g_dbus_object_compare,
+                     &added,
+                     &removed);
+
+  for (l = removed; l != NULL; l = l->next)
+    {
+      UDisksObject *object = UDISKS_OBJECT (l->data);
+
+      g_assert (g_list_find (model->current_iscsi_objects, object) != NULL);
+
+      model->current_iscsi_objects = g_list_remove (model->current_iscsi_objects, object);
+      if (udisks_object_peek_iscsi_target (object) != NULL)
+        {
+          remove_iscsi_target (model, object);
+        }
+      else if (udisks_object_peek_drive (object) != NULL)
+        {
+          remove_drive (model, object);
+        }
+      g_object_unref (object);
+    }
+
+  /* Add targets */
+  for (l = added; l != NULL; l = l->next)
+    {
+      UDisksObject *object = UDISKS_OBJECT (l->data);
+      if (udisks_object_peek_iscsi_target (object) != NULL)
+        {
+          model->current_iscsi_objects = g_list_prepend (model->current_iscsi_objects,
+                                                         g_object_ref (object));
+          add_iscsi_target (model, object, get_iscsi_iter (model));
+        }
+    }
+
+  /* ... then add drives */
+  for (l = added; l != NULL; l = l->next)
+    {
+      UDisksObject *object = UDISKS_OBJECT (l->data);
+      if (udisks_object_peek_drive (object) != NULL)
+        {
+          GtkTreeIter iter;
+          model->current_iscsi_objects = g_list_prepend (model->current_iscsi_objects,
+                                                         g_object_ref (object));
+          g_warn_if_fail (find_iter_for_object_path (model,
+                                                     udisks_drive_get_iscsi_target (udisks_object_peek_drive (object)),
+                                                     &iter));
+          add_drive (model, object, &iter);
+        }
+    }
+
+  /* update all drives (newly added as well as the existing ones) */
+  for (l = model->current_iscsi_objects; l != NULL; l = l->next)
+    {
+      UDisksObject *object = UDISKS_OBJECT (l->data);
+      if (udisks_object_peek_drive (object) != NULL)
+        {
+          update_drive (model, object, FALSE);
+        }
+    }
+
+  if (g_list_length (model->current_iscsi_objects) == 0)
+    nuke_iscsi_iter (model);
+
+  g_list_free (added);
+  g_list_free (removed);
+  g_list_foreach (iscsi_objects, (GFunc) g_object_unref, NULL);
+  g_list_free (iscsi_objects);
+
+  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
+  g_list_free (objects);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
 update_all (GduDeviceTreeModel *model)
 {
   /* TODO: if this is CPU intensive we could coalesce all updates / schedule timeouts */
   update_drives (model);
   update_blocks (model);
+  update_iscsi_targets (model);
 }
 
 static void
diff --git a/src/palimpsest/gduiscsipathmodel.c b/src/palimpsest/gduiscsipathmodel.c
new file mode 100644
index 0000000..fc62ee5
--- /dev/null
+++ b/src/palimpsest/gduiscsipathmodel.c
@@ -0,0 +1,325 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+#include <glib/gi18n.h>
+
+#include "gduiscsipathmodel.h"
+#include "gduutils.h"
+
+struct _GduiSCSIPathModel
+{
+  GtkListStore parent_instance;
+
+  UDisksClient *client;
+
+  UDisksiSCSITarget *iscsi_target;
+  UDisksObject *object;
+};
+
+typedef struct
+{
+  GtkListStoreClass parent_class;
+} GduiSCSIPathModelClass;
+
+enum
+{
+  PROP_0,
+  PROP_CLIENT,
+  PROP_OBJECT
+};
+
+static void update_all (GduiSCSIPathModel *model);
+static void on_notify_for_iscsi_target (GObject    *object,
+                                        GParamSpec *pspec,
+                                        gpointer    user_data);
+
+G_DEFINE_TYPE (GduiSCSIPathModel, gdu_iscsi_path_model, GTK_TYPE_LIST_STORE);
+
+static void
+gdu_iscsi_path_model_finalize (GObject *object)
+{
+  GduiSCSIPathModel *model = GDU_ISCSI_PATH_MODEL (object);
+
+  g_signal_handlers_disconnect_by_func (model->iscsi_target,
+                                        G_CALLBACK (on_notify_for_iscsi_target),
+                                        model);
+  g_object_unref (model->iscsi_target);
+  g_object_unref (model->client);
+
+  G_OBJECT_CLASS (gdu_iscsi_path_model_parent_class)->finalize (object);
+}
+
+static void
+gdu_iscsi_path_model_init (GduiSCSIPathModel *model)
+{
+}
+
+static void
+gdu_iscsi_path_model_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GduiSCSIPathModel *model = GDU_ISCSI_PATH_MODEL (object);
+
+  switch (prop_id)
+    {
+    case PROP_CLIENT:
+      g_value_set_object (value, gdu_iscsi_path_model_get_client (model));
+      break;
+
+    case PROP_OBJECT:
+      g_value_set_object (value, gdu_iscsi_path_model_get_object (model));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gdu_iscsi_path_model_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  GduiSCSIPathModel *model = GDU_ISCSI_PATH_MODEL (object);
+
+  switch (prop_id)
+    {
+    case PROP_CLIENT:
+      model->client = g_value_dup_object (value);
+      break;
+
+    case PROP_OBJECT:
+      model->object = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_iscsi_path_model_constructed (GObject *object)
+{
+  GduiSCSIPathModel *model = GDU_ISCSI_PATH_MODEL (object);
+  GType types[GDU_ISCSI_PATH_MODEL_N_COLUMNS];
+  /* GDBusObjectManager *object_manager; */
+
+  model->iscsi_target = udisks_object_get_iscsi_target (model->object);
+  g_assert (model->iscsi_target != NULL);
+
+  types[0] = G_TYPE_BOOLEAN;
+  types[1] = G_TYPE_STRING;
+  types[2] = G_TYPE_INT;
+  types[3] = G_TYPE_INT;
+  types[4] = G_TYPE_STRING;
+  types[5] = G_TYPE_STRING;
+  G_STATIC_ASSERT (6 == GDU_ISCSI_PATH_MODEL_N_COLUMNS);
+  gtk_list_store_set_column_types (GTK_LIST_STORE (model),
+                                   GDU_ISCSI_PATH_MODEL_N_COLUMNS,
+                                   types);
+
+  update_all (model);
+  g_signal_connect (model->iscsi_target,
+                    "notify",
+                    G_CALLBACK (on_notify_for_iscsi_target),
+                    model);
+
+  if (G_OBJECT_CLASS (gdu_iscsi_path_model_parent_class)->constructed != NULL)
+    G_OBJECT_CLASS (gdu_iscsi_path_model_parent_class)->constructed (object);
+}
+
+static void
+gdu_iscsi_path_model_class_init (GduiSCSIPathModelClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize     = gdu_iscsi_path_model_finalize;
+  gobject_class->constructed  = gdu_iscsi_path_model_constructed;
+  gobject_class->get_property = gdu_iscsi_path_model_get_property;
+  gobject_class->set_property = gdu_iscsi_path_model_set_property;
+
+  /**
+   * GduiSCSIPathModel:client:
+   *
+   * The #UDisksClient used by the #GduiSCSIPathModel instance.
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_CLIENT,
+                                   g_param_spec_object ("client",
+                                                        "Client",
+                                                        "The client used by the tree model",
+                                                        UDISKS_TYPE_CLIENT,
+                                                        G_PARAM_READABLE |
+                                                        G_PARAM_WRITABLE |
+                                                        G_PARAM_CONSTRUCT_ONLY |
+                                                        G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GduiSCSIPathModel:object:
+   *
+   * The #UDisksObject that is a iSCSI target.
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_OBJECT,
+                                   g_param_spec_object ("object",
+                                                        "Object",
+                                                        "The iSCSI target",
+                                                        UDISKS_TYPE_OBJECT,
+                                                        G_PARAM_READABLE |
+                                                        G_PARAM_WRITABLE |
+                                                        G_PARAM_CONSTRUCT_ONLY |
+                                                        G_PARAM_STATIC_STRINGS));
+}
+
+/**
+ * gdu_iscsi_path_model_new:
+ * @client: A #UDisksClient.
+ * @object: A #UDisksObject.
+ *
+ * Creates a new #GduiSCSIPathModel for viewing the paths on the iSCSI
+ * target on @object.
+ *
+ * Returns: A #GduiSCSIPathModel. Free with g_object_unref().
+ */
+GduiSCSIPathModel *
+gdu_iscsi_path_model_new (UDisksClient  *client,
+                          UDisksObject  *object)
+{
+  return GDU_ISCSI_PATH_MODEL (g_object_new (GDU_TYPE_ISCSI_PATH_MODEL,
+                                             "client", client,
+                                             "object", object,
+                                             NULL));
+}
+
+/**
+ * gdu_iscsi_path_model_get_client:
+ * @model: A #GduiSCSIPathModel.
+ *
+ * Gets the #UDisksClient used by @model.
+ *
+ * Returns: (transfer none): A #UDisksClient. Do not free, the object
+ * belongs to @model.
+ */
+UDisksClient *
+gdu_iscsi_path_model_get_client (GduiSCSIPathModel *model)
+{
+  g_return_val_if_fail (GDU_IS_ISCSI_PATH_MODEL (model), NULL);
+  return model->client;
+}
+
+/**
+ * gdu_iscsi_path_model_get_object:
+ * @model: A #GduiSCSIPathModel.
+ *
+ * Gets the #UDisksObject used by @model.
+ *
+ * Returns: (transfer none): A #UDisksObject. Do not free, the object
+ * belongs to @model.
+ */
+UDisksObject *
+gdu_iscsi_path_model_get_object (GduiSCSIPathModel *model)
+{
+  g_return_val_if_fail (GDU_IS_ISCSI_PATH_MODEL (model), NULL);
+  return model->object;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update_all (GduiSCSIPathModel *model)
+{
+  GVariant *portals_and_interfaces;
+  GVariantIter portal_iter;
+  const gchar *portal_name;
+  gint port;
+  gint group;
+  const gchar *iface_name;
+  const gchar *state;
+
+  gtk_list_store_clear (GTK_LIST_STORE (model));
+
+  portals_and_interfaces = udisks_iscsi_target_get_connections (model->iscsi_target);
+  g_variant_iter_init (&portal_iter, portals_and_interfaces);
+
+  while (g_variant_iter_next (&portal_iter,
+                              "(&sii&s&sa{sv})",
+                              &portal_name,
+                              &port,
+                              &group,
+                              &iface_name,
+                              &state,
+                              NULL)) /* expansion */
+    {
+      gchar *status;
+      gboolean active;
+      if (g_strcmp0 (state, "LOGGED_IN") == 0)
+        {
+          active = TRUE;
+          status = g_strdup (_("Logged In"));
+        }
+      else if (g_strcmp0 (state, "FAILED") == 0)
+        {
+          active = TRUE;
+          status = g_strdup_printf ("<span foreground=\"#ff0000\"><b>%s</b></span>", _("FAILED"));
+        }
+      else if (g_strcmp0 (state, "") == 0)
+        {
+          active = FALSE;
+          status = g_strdup (_("Not Logged In"));
+        }
+      else
+        {
+          active = TRUE;
+          status = g_strdup (state);
+        }
+
+      gtk_list_store_insert_with_values (GTK_LIST_STORE (model),
+                                         NULL, /* GtkTreeIter *out */
+                                         G_MAXINT, /* position */
+                                         GDU_ISCSI_PATH_MODEL_COLUMN_ACTIVE, active,
+                                         GDU_ISCSI_PATH_MODEL_COLUMN_PORTAL_ADDRESS, portal_name,
+                                         GDU_ISCSI_PATH_MODEL_COLUMN_PORTAL_PORT, port,
+                                         GDU_ISCSI_PATH_MODEL_COLUMN_TPGT, group,
+                                         GDU_ISCSI_PATH_MODEL_COLUMN_INTERFACE, iface_name,
+                                         GDU_ISCSI_PATH_MODEL_COLUMN_STATUS, status,
+                                         -1);
+      g_free (status);
+    }
+}
+
+static void
+on_notify_for_iscsi_target (GObject    *object,
+                            GParamSpec *pspec,
+                            gpointer    user_data)
+{
+  GduiSCSIPathModel *model = GDU_ISCSI_PATH_MODEL (user_data);
+  update_all (model);
+}
diff --git a/src/palimpsest/gduiscsipathmodel.h b/src/palimpsest/gduiscsipathmodel.h
new file mode 100644
index 0000000..938ab36
--- /dev/null
+++ b/src/palimpsest/gduiscsipathmodel.h
@@ -0,0 +1,55 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __GDU_ISCSI_PATH_MODEL_H__
+#define __GDU_ISCSI_PATH_MODEL_H__
+
+#include <gtk/gtk.h>
+#include "gdutypes.h"
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_ISCSI_PATH_MODEL         (gdu_iscsi_path_model_get_type ())
+#define GDU_ISCSI_PATH_MODEL(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_ISCSI_PATH_MODEL, GduiSCSIPathModel))
+#define GDU_IS_ISCSI_PATH_MODEL(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_ISCSI_PATH_MODEL))
+
+enum
+{
+  GDU_ISCSI_PATH_MODEL_COLUMN_ACTIVE,
+  GDU_ISCSI_PATH_MODEL_COLUMN_PORTAL_ADDRESS,
+  GDU_ISCSI_PATH_MODEL_COLUMN_PORTAL_PORT,
+  GDU_ISCSI_PATH_MODEL_COLUMN_TPGT,
+  GDU_ISCSI_PATH_MODEL_COLUMN_INTERFACE,
+  GDU_ISCSI_PATH_MODEL_COLUMN_STATUS,
+  GDU_ISCSI_PATH_MODEL_N_COLUMNS
+};
+
+GType               gdu_iscsi_path_model_get_type   (void) G_GNUC_CONST;
+GduiSCSIPathModel  *gdu_iscsi_path_model_new        (UDisksClient      *client,
+                                                     UDisksObject      *object);
+UDisksClient       *gdu_iscsi_path_model_get_client (GduiSCSIPathModel *model);
+UDisksObject       *gdu_iscsi_path_model_get_object (GduiSCSIPathModel *model);
+
+
+G_END_DECLS
+
+#endif /* __GDU_ISCSI_PATH_MODEL_H__ */
diff --git a/src/palimpsest/gdutypes.h b/src/palimpsest/gdutypes.h
index 917908a..9728722 100644
--- a/src/palimpsest/gdutypes.h
+++ b/src/palimpsest/gdutypes.h
@@ -52,6 +52,9 @@ typedef struct _GduPasswordStrengthWidget GduPasswordStrengthWidget;
 struct _GduEstimator;
 typedef struct _GduEstimator GduEstimator;
 
+struct _GduiSCSIPathModel;
+typedef struct _GduiSCSIPathModel GduiSCSIPathModel;
+
 G_END_DECLS
 
 #endif /* __GDU_TYPES_H__ */
diff --git a/src/palimpsest/gduwindow.c b/src/palimpsest/gduwindow.c
index 607e9d6..9dc79aa 100644
--- a/src/palimpsest/gduwindow.c
+++ b/src/palimpsest/gduwindow.c
@@ -49,6 +49,7 @@
 #include "gducreatediskimagedialog.h"
 #include "gdurestorediskimagedialog.h"
 #include "gduchangepassphrasedialog.h"
+#include "gduiscsipathmodel.h"
 
 /* Keep in sync with tabs in palimpsest.ui file */
 typedef enum
@@ -56,6 +57,7 @@ typedef enum
   DETAILS_PAGE_NOT_SELECTED,
   DETAILS_PAGE_NOT_IMPLEMENTED,
   DETAILS_PAGE_DEVICE,
+  DETAILS_PAGE_ISCSI_TARGET,
 } DetailsPage;
 
 struct _GduWindow
@@ -106,6 +108,11 @@ struct _GduWindow
   GtkWidget *devtab_action_deactivate_swap;
   GtkWidget *devtab_action_generic_drive;
 
+  GtkWidget *iscsitab_scrolledwindow;
+  GtkWidget *iscsitab_table;
+  GtkWidget *iscsitab_toolbar;
+  GtkWidget *iscsitab_connections_treeview;
+
   GtkWidget *generic_drive_menu;
   GtkWidget *generic_drive_menu_item_view_smart;
   GtkWidget *generic_drive_menu_item_format_disk;
@@ -161,6 +168,11 @@ static const struct {
   {G_STRUCT_OFFSET (GduWindow, devtab_action_deactivate_swap), "devtab-action-deactivate-swap"},
   {G_STRUCT_OFFSET (GduWindow, devtab_action_generic_drive), "devtab-action-generic-drive"},
 
+  {G_STRUCT_OFFSET (GduWindow, iscsitab_scrolledwindow), "iscsitab-scrolledwindow"},
+  {G_STRUCT_OFFSET (GduWindow, iscsitab_table), "iscsitab-table"},
+  {G_STRUCT_OFFSET (GduWindow, iscsitab_toolbar), "iscsitab-toolbar"},
+  {G_STRUCT_OFFSET (GduWindow, iscsitab_connections_treeview), "iscsi-connections-treeview"},
+
   {G_STRUCT_OFFSET (GduWindow, generic_drive_menu), "generic-drive-menu"},
   {G_STRUCT_OFFSET (GduWindow, generic_drive_menu_item_create_disk_image), "generic-drive-menu-item-create-disk-image"},
   {G_STRUCT_OFFSET (GduWindow, generic_drive_menu_item_restore_disk_image), "generic-drive-menu-item-restore-disk-image"},
@@ -232,6 +244,10 @@ static void setup_device_page (GduWindow *window, UDisksObject *object);
 static void update_device_page (GduWindow *window, ShowFlags *show_flags);
 static void teardown_device_page (GduWindow *window);
 
+static void setup_iscsi_target_page (GduWindow *window, UDisksObject *object);
+static void update_iscsi_target_page (GduWindow *window);
+static void teardown_iscsi_target_page (GduWindow *window);
+
 static void on_volume_grid_changed (GduVolumeGrid  *grid,
                                     gpointer        user_data);
 
@@ -444,6 +460,10 @@ set_selected_object (GduWindow    *window,
         {
           select_details_page (window, object, DETAILS_PAGE_DEVICE, &show_flags);
         }
+      else if (udisks_object_peek_iscsi_target (object) != NULL)
+        {
+          select_details_page (window, object, DETAILS_PAGE_ISCSI_TARGET, &show_flags);
+        }
       else
         {
           g_warning ("no page for object %s", g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
@@ -913,6 +933,12 @@ gdu_window_constructed (GObject *object)
   gtk_style_context_add_class (context, GTK_STYLE_CLASS_INLINE_TOOLBAR);
   gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
 
+  context = gtk_widget_get_style_context (window->iscsitab_scrolledwindow);
+  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
+  context = gtk_widget_get_style_context (window->iscsitab_toolbar);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_INLINE_TOOLBAR);
+  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
+
   window->model = gdu_device_tree_model_new (window->client);
 
   /* set up mnemonic */
@@ -1254,6 +1280,10 @@ teardown_details_page (GduWindow    *window,
     case DETAILS_PAGE_DEVICE:
       teardown_device_page (window);
       break;
+
+    case DETAILS_PAGE_ISCSI_TARGET:
+      teardown_iscsi_target_page (window);
+      break;
     }
 }
 
@@ -1372,6 +1402,10 @@ setup_details_page (GduWindow     *window,
     case DETAILS_PAGE_DEVICE:
       setup_device_page (window, object);
       break;
+
+    case DETAILS_PAGE_ISCSI_TARGET:
+      setup_iscsi_target_page (window, object);
+      break;
     }
 }
 
@@ -1398,6 +1432,10 @@ update_details_page (GduWindow      *window,
     case DETAILS_PAGE_DEVICE:
       update_device_page (window, show_flags);
       break;
+
+    case DETAILS_PAGE_ISCSI_TARGET:
+      update_iscsi_target_page (window);
+      break;
     }
 }
 
@@ -1445,6 +1483,12 @@ update_all (GduWindow     *window)
       update_details_page (window, window->current_page, &show_flags);
       update_for_show_flags (window, show_flags);
       break;
+
+    case DETAILS_PAGE_ISCSI_TARGET:
+      show_flags = SHOW_FLAGS_NONE;
+      update_details_page (window, window->current_page, &show_flags);
+      update_for_show_flags (window, show_flags);
+      break;
     }
 }
 
@@ -2146,6 +2190,348 @@ teardown_device_page (GduWindow *window)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static void
+iscsi_target_format_portal_address (GtkCellLayout   *cell_layout,
+                                    GtkCellRenderer *renderer,
+                                    GtkTreeModel    *tree_model,
+                                    GtkTreeIter     *iter,
+                                    gpointer         user_data)
+{
+  /* GduWindow *window = GDU_WINDOW (user_data); */
+  gchar *portal_address;
+  gint portal_port;
+  gchar *markup;
+
+  gtk_tree_model_get (tree_model,
+                      iter,
+                      GDU_ISCSI_PATH_MODEL_COLUMN_PORTAL_ADDRESS, &portal_address,
+                      GDU_ISCSI_PATH_MODEL_COLUMN_PORTAL_PORT, &portal_port,
+                      -1);
+
+  /* only show port if it is non-standard */
+  if (portal_port != 3260)
+    markup = g_strdup_printf ("%s:%d", portal_address, portal_port);
+  else
+    markup = g_strdup (portal_address);
+
+  g_object_set (renderer,
+                "markup", markup,
+                NULL);
+
+  g_free (markup);
+  g_free (portal_address);
+}
+
+static void
+iscsi_target_login_cb (UDisksiSCSITarget *target,
+                       GAsyncResult      *res,
+                       gpointer           user_data)
+{
+  GduWindow *window = GDU_WINDOW (user_data);
+  GError *error;
+  error = NULL;
+  if (!udisks_iscsi_target_call_login_finish (target, res, &error))
+    {
+      gdu_window_show_error (window,
+                             _("Error logging in to iSCSI target"),
+                             error);
+      g_error_free (error);
+    }
+  g_object_unref (window);
+}
+
+static void
+iscsi_target_logout_cb (UDisksiSCSITarget *target,
+                        GAsyncResult      *res,
+                        gpointer           user_data)
+{
+  GduWindow *window = GDU_WINDOW (user_data);
+  GError *error;
+  error = NULL;
+  if (!udisks_iscsi_target_call_logout_finish (target, res, &error))
+    {
+      gdu_window_show_error (window,
+                             _("Error logging out of iSCSI target"),
+                             error);
+      g_error_free (error);
+    }
+  g_object_unref (window);
+}
+
+static void
+on_iscsi_active_toggled (GtkCellRendererToggle *renderer,
+                         gchar                 *path,
+                         gpointer               user_data)
+{
+  GduWindow *window = GDU_WINDOW (user_data);
+  gboolean is_active;
+  GtkTreeModel *tree_model;
+  GtkTreeIter iter;
+  gchar *portal_address;
+  gchar *iface_name;
+  gint portal_port;
+  gint tpgt;
+  UDisksiSCSITarget *target;
+
+  portal_address = NULL;
+  iface_name = NULL;
+
+  tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (window->iscsitab_connections_treeview));
+
+  target = udisks_object_peek_iscsi_target (window->current_object);
+  if (target == NULL)
+    {
+      g_warning ("Expected selected object to be an iSCSI target");
+      goto out;
+    }
+
+  if (!gtk_tree_model_get_iter_from_string (tree_model,
+                                            &iter,
+                                            path))
+    {
+      g_warning ("Unable to get tree iter");
+      goto out;
+    }
+
+  gtk_tree_model_get (tree_model,
+                      &iter,
+                      GDU_ISCSI_PATH_MODEL_COLUMN_PORTAL_ADDRESS, &portal_address,
+                      GDU_ISCSI_PATH_MODEL_COLUMN_PORTAL_PORT, &portal_port,
+                      GDU_ISCSI_PATH_MODEL_COLUMN_TPGT, &tpgt,
+                      GDU_ISCSI_PATH_MODEL_COLUMN_INTERFACE, &iface_name,
+                      -1);
+
+  is_active = gtk_cell_renderer_toggle_get_active (renderer);
+  if (is_active)
+    {
+          udisks_iscsi_target_call_logout (target,
+                                           portal_address,
+                                           portal_port,
+                                           tpgt,
+                                           iface_name,
+                                           g_variant_new ("a{sv}", NULL), /* options */
+                                           NULL,  /* GCancellable* */
+                                           (GAsyncReadyCallback) iscsi_target_logout_cb,
+                                           g_object_ref (window));
+    }
+  else
+    {
+          udisks_iscsi_target_call_login (target,
+                                          portal_address,
+                                          portal_port,
+                                          tpgt,
+                                          iface_name,
+                                          g_variant_new ("a{sv}", NULL), /* options */
+                                          NULL,  /* GCancellable* */
+                                          (GAsyncReadyCallback) iscsi_target_login_cb,
+                                          g_object_ref (window));
+    }
+
+ out:
+  g_free (portal_address);
+  g_free (iface_name);
+}
+
+static void
+init_iscsi_target_page (GduWindow   *window)
+{
+  static volatile gsize init_val = 0;
+  GtkTreeView *tree_view;
+  /* GtkTreeSelection *selection; */
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+
+  if (!g_once_init_enter (&init_val))
+    goto out;
+
+  tree_view = GTK_TREE_VIEW (window->iscsitab_connections_treeview);
+  gtk_tree_view_set_rules_hint (tree_view, TRUE);
+#if 0
+  selection = gtk_tree_view_get_selection (tree_view);
+  gtk_tree_selection_set_select_function (selection, dont_select_headings, NULL, NULL);
+  g_signal_connect (selection,
+                    "changed",
+                    G_CALLBACK (on_tree_selection_changed),
+                    window);
+#endif
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_append_column (tree_view, column);
+  renderer = gtk_cell_renderer_toggle_new ();
+  gtk_tree_view_column_pack_end (column, renderer, FALSE);
+  gtk_tree_view_column_set_attributes (column, renderer,
+                                       "active", GDU_ISCSI_PATH_MODEL_COLUMN_ACTIVE, NULL);
+  g_signal_connect (renderer,
+                    "toggled",
+                    G_CALLBACK (on_iscsi_active_toggled),
+                    window);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("Portal"));
+  gtk_tree_view_append_column (tree_view, column);
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, TRUE);
+  gtk_tree_view_column_set_alignment (column, 0.0);
+  gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+                                      renderer,
+                                      iscsi_target_format_portal_address,
+                                      window,
+                                      NULL);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("Interface"));
+  gtk_tree_view_append_column (tree_view, column);
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_attributes (column, renderer,
+                                       "markup", GDU_ISCSI_PATH_MODEL_COLUMN_INTERFACE, NULL);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("TPGT"));
+  gtk_tree_view_append_column (tree_view, column);
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_attributes (column, renderer,
+                                       "markup", GDU_ISCSI_PATH_MODEL_COLUMN_TPGT, NULL);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_title (column, _("Status"));
+  gtk_tree_view_append_column (tree_view, column);
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_attributes (column, renderer,
+                                       "markup", GDU_ISCSI_PATH_MODEL_COLUMN_STATUS, NULL);
+
+  g_once_init_leave (&init_val, 1);
+ out:
+  ;
+}
+
+static gboolean
+iscsi_target_has_active_connections (UDisksiSCSITarget *target)
+{
+  gboolean ret = FALSE;
+  GVariant *portals_and_interfaces;
+  GVariantIter portal_iter;
+  const gchar *state;
+
+  portals_and_interfaces = udisks_iscsi_target_get_connections (target);
+  g_variant_iter_init (&portal_iter, portals_and_interfaces);
+  while (g_variant_iter_next (&portal_iter,
+                              "(^&siis&sa{sv})",
+                              NULL,   /* &portal_adress */
+                              NULL,   /* &port */
+                              NULL,   /* &tpgt */
+                              NULL,   /* iface_name */
+                              &state,
+                              NULL))  /* expansion */
+    {
+      if (g_strcmp0 (state, "LOGGED_IN") == 0)
+        {
+          ret = TRUE;
+          goto out;
+        }
+    }
+ out:
+  return ret;
+}
+
+
+static void
+update_iscsi_target_page (GduWindow   *window)
+{
+  GList *children;
+  GList *l;
+  UDisksiSCSITarget *target;
+  UDisksObject *source_object = NULL;
+  UDisksiSCSISource *source = NULL;
+  gchar *discovery = NULL;
+
+  /* first hide everything */
+  children = gtk_container_get_children (GTK_CONTAINER (window->iscsitab_table));
+  for (l = children; l != NULL; l = l->next)
+    {
+      GtkWidget *child = GTK_WIDGET (l->data);
+      gtk_widget_hide (child);
+    }
+  g_list_free (children);
+
+  target = udisks_object_peek_iscsi_target (window->current_object);
+  set_markup (window,
+              "iscsitab-name-label",
+              "iscsitab-name-value-label",
+              udisks_iscsi_target_get_name (target), SET_MARKUP_FLAGS_NONE);
+
+  /* TODO: also show Alias for the target */
+
+  source_object = udisks_client_peek_object (window->client, udisks_iscsi_target_get_source (target));
+  if (source_object != NULL)
+    source = udisks_object_peek_iscsi_source (source_object);
+  if (source != NULL)
+    {
+      const gchar *mechanism = udisks_iscsi_source_get_mechanism (source);
+      if (g_strcmp0 (mechanism, "static") == 0)
+        {
+          discovery = g_strdup (_("Statically configured"));
+        }
+      else if (g_strcmp0 (mechanism, "firmware") == 0)
+        {
+          discovery = g_strdup (_("Configured in firmware"));
+        }
+      else if (g_strcmp0 (mechanism, "sendtargets") == 0)
+        {
+          discovery = g_strdup_printf (_("%s (SendTargets protocol)"),
+                                       udisks_iscsi_source_get_address (source));
+        }
+      else if (g_strcmp0 (mechanism, "isns") == 0)
+        {
+          discovery = g_strdup_printf (_("%s (iSNS server)"),
+                                       udisks_iscsi_source_get_address (source));
+        }
+      else
+        {
+          discovery = g_strdup_printf (_("%s (Mechanism: %s)"),
+                                       mechanism,
+                                       udisks_iscsi_source_get_address (source));
+        }
+    }
+  set_markup (window,
+              "iscsitab-discovery-label",
+              "iscsitab-discovery-value-label",
+              discovery, SET_MARKUP_FLAGS_HYPHEN_IF_EMPTY);
+  g_free (discovery);
+}
+
+static void
+setup_iscsi_target_page (GduWindow    *window,
+                         UDisksObject *object)
+{
+  GtkTreeView *tree_view;
+  GduiSCSIPathModel *model;
+  GtkTreeIter first_iter;
+
+  init_iscsi_target_page (window);
+
+  tree_view = GTK_TREE_VIEW (window->iscsitab_connections_treeview);
+  model = gdu_iscsi_path_model_new (window->client, object);
+  gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (model));
+  /* select the first row */
+  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &first_iter))
+    gtk_tree_selection_select_iter (gtk_tree_view_get_selection (tree_view), &first_iter);
+  g_object_unref (model);
+}
+
+static void
+teardown_iscsi_target_page (GduWindow *window)
+{
+  GtkTreeView *tree_view;
+
+  tree_view = GTK_TREE_VIEW (window->iscsitab_connections_treeview);
+  gtk_tree_view_set_model (tree_view, NULL);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /* TODO: right now we show a MessageDialog but we could do things like an InfoBar etc */
 void
 gdu_window_show_error (GduWindow   *window,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]