#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <gtk/gtk.h>

#include "../include/string.h"

#include "guiutils.h"
#include "cdialog.h"
#include "progressdialog.h"

#include "edvtypes.h"
#include "edvdate.h"
#include "cfg.h"
#include "edvid.h"
#include "edvobj.h"
#include "edvarchobj.h"
#include "edvarchfio.h"
#include "edvmimetypes.h"
#include "archiver.h"
#include "archivercb.h"
#include "archivercontents.h"
#include "endeavour.h"
#include "edvcb.h"
#include "edvutils.h"
#include "edvutilsgtk.h"
#include "edvcfglist.h"
#include "config.h"



static void EDVArchiverContentsResetColumns(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist
);
static void EDVArchiverContentsClear(GtkCList *clist);

static void EDVArchiverContentsSetCellName(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
);
static void EDVArchiverContentsSetCellSize(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	gboolean hide_dir_size, gboolean hide_link_size
);
static void EDVArchiverContentsSetCellCompressedSize(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	gboolean hide_dir_size, gboolean hide_link_size
);
static void EDVArchiverContentsSetCellType(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
);
static void EDVArchiverContentsSetCellPermissions(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column, gboolean hide_link_permissions
);
static void EDVArchiverContentsSetCellOwner(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
);
static void EDVArchiverContentsSetCellGroup(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
);
static void EDVArchiverContentsSetCellDateAccess(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	edv_date_relativity date_relativity, const gchar *date_format
);
static void EDVArchiverContentsSetCellDateModified(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	edv_date_relativity date_relativity, const gchar *date_format
);
static void EDVArchiverContentsSetCellDateChanged(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	edv_date_relativity date_relativity, const gchar *date_format
);
static void EDVArchiverContentsSetCellLocation(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
);
static void EDVArchiverContentsSetCellLinkedTo(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
);
static void EDVArchiverContentsSetCellDeviceType(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
);
static void EDVArchiverContentsSetCellCompression(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	gboolean hide_dir_size, gboolean hide_link_size
);
static void EDVArchiverContentsSetCellMethod(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
);
static void EDVArchiverContentsSetCellCRC(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
);
static void EDVArchiverContentsSetRow(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row
);

static gint EDVArchiverContentsAppendObject(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj
);
static void EDVArchiverContentsGetListing(
	edv_archiver_struct *archiver, gboolean update_status_bar
);

gint EDVArchiverContentsFindRowByPath(
	edv_archiver_struct *archiver, const gchar *path
);

void EDVArchiverContentsResetRows(edv_archiver_struct *archiver);
void EDVArchiverContentsDoUpdate(
	edv_archiver_struct *archiver, gboolean update_status_bar
);

void EDVArchiverContentsObjectModifiedNotify(
	edv_archiver_struct *archiver, const gchar *path,
	const gchar *new_path, const struct stat *lstat_buf
);
void EDVArchiverContentsObjectRemovedNotify(
	edv_archiver_struct *archiver, const gchar *path
);

void EDVArchiverContentsArchiveObjectAddedNotify(
	edv_archiver_struct *archiver, const gchar *arch_path,
	const gchar *path, edv_archive_object_struct *obj
);
void EDVArchiverContentsArchiveObjectModifiedNotify(
	edv_archiver_struct *archiver, const gchar *arch_path,
	const gchar *path, const gchar *new_path,
	edv_archive_object_struct *obj
);
void EDVArchiverContentsArchiveObjectRemovedNotify(
	edv_archiver_struct *archiver, const gchar *arch_path,
	const gchar *path
);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)       (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


/*
 *      Clears the titles of each column on the given clist.
 */
static void EDVArchiverContentsResetColumns(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist
)
{
	gint i, m, width, justify = GTK_JUSTIFY_LEFT;
	const gchar *title = NULL;
	edv_archiver_column_type column_type;
	GtkRcStyle *lists_rcstyle;
	const cfg_intlist_struct	*column_types_intlist,
					*column_width_intlist;
	const cfg_item_struct *cfg_list;


	if((core_ptr == NULL) || (archiver == NULL) || (clist == NULL))
	    return;

	cfg_list = core_ptr->cfg_list;
	lists_rcstyle = core_ptr->lists_rcstyle;

	/* Get column types mapping */
	column_types_intlist = CFGItemListGetValueIntList(
	    cfg_list, EDV_CFG_PARM_ARCHIVER_CONTENTS_COLUMN
	);
	if(column_types_intlist == NULL)
	    return;

	column_width_intlist = CFGItemListGetValueIntList(
	    cfg_list, EDV_CFG_PARM_ARCHIVER_CONTENTS_COLUMN_WIDTH
	);
	if(column_width_intlist == NULL)
	    return;

	/* Update clist column settings */
	gtk_clist_column_titles_active(clist);
	gtk_clist_column_titles_show(clist);
	gtk_clist_set_auto_sort(clist, FALSE);
	gtk_clist_set_sort_type(clist, GTK_SORT_DESCENDING);

#if 0
/* Already set */
	/* Change clist selection mode to GTK_SELECTION_EXTENDED
	 *
	 * The selection mode can change whenever the contents list is
	 * updated
	 */
	gtk_clist_set_selection_mode(clist, GTK_SELECTION_EXTENDED);
#endif

	/* Iterate through each column but not exceeding the number of
	 * columns specified by the column types or column widths
	 * intlists
	 */
	m = MIN(
	    MIN(clist->columns, column_types_intlist->total),
	    column_width_intlist->total
	);
	for(i = 0; i < m; i++)
	{
	    /* Get column's type which determines what will be listed on
	     * the current column i
	     */
	    column_type = (edv_archiver_column_type)column_types_intlist->i[i];

	    /* Get width of the column displaying this type */
	    if((column_type >= 0) && (column_type < column_width_intlist->total))
		width = column_width_intlist->i[column_type];
	    else
		width = 0;

	    /* Title based on column type */
	    switch(column_type)
	    {
	      case EDV_ARCHIVER_COLUMN_TYPE_NAME:
		title = "Name";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_SIZE:
		title = "Size";
		justify = GTK_JUSTIFY_RIGHT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_COMPRESSED_SIZE:
		title = "Compressed";
		justify = GTK_JUSTIFY_RIGHT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_TYPE:
		title = "Type";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_PERMISSIONS:
		title = "Permissions";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_OWNER:
		title = "Owner";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_GROUP:
		title = "Group";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_DATE_ACCESS:
		title = "Date Access";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_DATE_MODIFIED:
		title = "Date Modified";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_DATE_CHANGED:
		title = "Date Changed";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_LOCATION:
		title = "Location";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_LINKED_TO:
		title = "Linked To";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_DEVICE_TYPE:
		title = "Device Type";
		justify = GTK_JUSTIFY_RIGHT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_COMPRESSION:
		title = "Compression";
		justify = GTK_JUSTIFY_RIGHT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_METHOD:
		title = "Method";
		justify = GTK_JUSTIFY_LEFT;
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_CRC:
		title = "CRC";
		justify = GTK_JUSTIFY_LEFT;
		break;
	    }

	    gtk_clist_set_column_visibility(clist, i, TRUE);
	    gtk_clist_set_column_auto_resize(
		clist, i, FALSE
	    );
	    gtk_clist_set_column_title(clist, i, title);
	    gtk_clist_set_column_width(clist, i, width);
	    gtk_clist_set_column_justification(clist, i, justify);
	}
	/* Reset the rest of the columns incase the number of columns
	 * in the intlists were less than the columns specified by the
	 * clist
	 */
	for(; i < clist->columns; i++)
	    gtk_clist_set_column_visibility(clist, i, FALSE);

	/* Set RC style after column headings have been mapped */
	if(lists_rcstyle != NULL)
	    gtk_widget_modify_style_recursive(
		GTK_WIDGET(clist), lists_rcstyle
	    );
}

/*
 *      Deletes all items in the given clist.
 */
static void EDVArchiverContentsClear(GtkCList *clist)
{
	if(clist == NULL)
	    return;

	gtk_clist_clear(clist);
}


/*
 *	Sets the archive object name for the specified cell on the given
 *	clist.
 */
static void EDVArchiverContentsSetCellName(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
)
{
	const gchar *name = obj->name;
	GdkPixmap *pixmap, *pixmap_hid;
	GdkBitmap *mask, *mask_hid;

	if(STRISEMPTY(name))
	    name = obj->full_path;

	/* Get pixmap and mask for the given object */
	EDVMatchObjectIcon(
	    NULL, 0,
	    core_ptr->mimetype, core_ptr->total_mimetypes,
	    obj->type,
	    name,
	    TRUE,
	    obj->permissions,
	    0,                  /* Small icons */
	    &pixmap, &mask,
	    NULL, NULL,
	    NULL, NULL,
	    &pixmap_hid, &mask_hid
	);

	/* Hidden? */
	if((name != NULL) ?
	    ((*name == '.') && (pixmap_hid != NULL)) : FALSE
	)
	{
	    if(g_strcasecmp(name, "..") && g_strcasecmp(name, "."))
	    {
		pixmap = pixmap_hid;
		mask = mask_hid;
	    }
	}

	/* Set cell */
	if(pixmap != NULL)
	    gtk_clist_set_pixtext(
		clist, row, column,
		(name != NULL) ? name : "(null)",
		EDV_LIST_PIXMAP_TEXT_SPACING,
		pixmap, mask
	    );
	else
	    gtk_clist_set_text(
		clist, row, column,
		(name != NULL) ? name : "(null)"
	    );
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}

/*
 *      Sets the archive object size for the specified cell on the given
 *      clist.
 */
static void EDVArchiverContentsSetCellSize(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	gboolean hide_dir_size, gboolean hide_link_size
)
{
	gint	border_minor = 2,
		type = obj->type;
	const gchar *s;

	/* Get string for size */
	if(hide_dir_size && (type == EDV_OBJECT_TYPE_DIRECTORY))
	    s = "";
	else if(hide_link_size && (type == EDV_OBJECT_TYPE_LINK))
	    s = "";
	else
	    s = EDVGetObjectSizeStr(core_ptr, obj->size);

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, s
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, -border_minor
	);
}

/*
 *	Sets the archive object compressed size for the specified cell
 *	on the given clist.
 */
static void EDVArchiverContentsSetCellCompressedSize(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	gboolean hide_dir_size, gboolean hide_link_size
)
{
	gint	border_minor = 2,
		type = obj->type;
	const gchar *s;

	/* Get string for size */
	if(hide_dir_size && (type == EDV_OBJECT_TYPE_DIRECTORY))
	    s = "";
	else if(hide_link_size && (type == EDV_OBJECT_TYPE_LINK))
	    s = "";
	else
	    s = EDVGetObjectSizeStr(core_ptr, obj->compressed_size);

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, s
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, -border_minor
	);
}

/*
 *      Sets the archive object type for the specified cell on the given
 *      clist.
 */
static void EDVArchiverContentsSetCellType(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
)
{
	gchar *type_str;

	/* Get MIME Type type string for the given object */
	EDVMatchObjectTypeString(
	    core_ptr->mimetype, core_ptr->total_mimetypes,
	    obj->type,
	    obj->permissions,
	    obj->name,
	    &type_str
	);

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, (type_str != NULL) ? type_str : ""
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}

/*
 *      Sets the archive object permissions for the specified cell on the given
 *      clist.
 */
static void EDVArchiverContentsSetCellPermissions(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column, gboolean hide_link_permissions
)
{
	edv_permission_flags permissions = obj->permissions;
	gchar s[80];

	/* Format permissions string */
	if(hide_link_permissions && (obj->type == EDV_OBJECT_TYPE_LINK))
	    *s = '\0';
	else
	    g_snprintf(
		s, sizeof(s),
		"%c%c%c%c%c%c%c%c%c",
	    (permissions & EDV_PERMISSION_UREAD) ? 'r' : '-',
	    (permissions & EDV_PERMISSION_UWRITE) ? 'w' : '-',
	    (permissions & EDV_PERMISSION_SETUID) ?
		'S' :
		((permissions & EDV_PERMISSION_UEXECUTE) ? 'x' : '-'),
	    (permissions & EDV_PERMISSION_GREAD) ? 'r' : '-',
	    (permissions & EDV_PERMISSION_GWRITE) ? 'w' : '-',
	    (permissions & EDV_PERMISSION_SETGID) ?
		'G' :
		((permissions & EDV_PERMISSION_GEXECUTE) ? 'x' : '-'),
	    (permissions & EDV_PERMISSION_AREAD) ? 'r' : '-',
	    (permissions & EDV_PERMISSION_AWRITE) ? 'w' : '-',
	    (permissions & EDV_PERMISSION_STICKY) ?
		'T' :
		((permissions & EDV_PERMISSION_AEXECUTE) ? 'x' : '-')
	    );

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, s
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}

/*
 *      Sets the archive object owner for the specified cell on the given
 *      clist.
 */
static void EDVArchiverContentsSetCellOwner(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
)
{
	/* Get owner name */
	const gchar *owner_name = obj->owner_name;
	if(owner_name == NULL)
	    owner_name = "";

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, owner_name
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}

/*
 *      Sets the archive object owner for the specified cell on the given
 *      clist.
 */
static void EDVArchiverContentsSetCellGroup(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
)
{
	/* Get group name */
	const gchar *group_name = obj->group_name;
	if(group_name == NULL)
	    group_name = "";

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, group_name
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}

/*
 *	Sets the archive object last access date for the specified cell
 *	on the given clist.
 */
static void EDVArchiverContentsSetCellDateAccess(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	edv_date_relativity date_relativity, const gchar *date_format
)
{
	const gchar *date_str;

	/* Get string for date accessed */
	gulong t = obj->access_time;
	if(t > 0)
	    date_str = EDVDateFormatString(
		t, date_format, date_relativity
	    );
	else
	    date_str = "";

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, date_str
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}

/*
 *      Sets the archive object last modified date for the specified cell
 *      on the given clist.
 */
static void EDVArchiverContentsSetCellDateModified(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	edv_date_relativity date_relativity, const gchar *date_format
)
{
	const gchar *date_str;

	/* Get string for date modified */
	gulong t = obj->modify_time;
	if(t > 0)
	    date_str = EDVDateFormatString(
		t, date_format, date_relativity
	    );
	else
	    date_str = "";

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, date_str
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}

/*
 *      Sets the archive object last changed date for the specified cell
 *      on the given clist.
 */
static void EDVArchiverContentsSetCellDateChanged(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	edv_date_relativity date_relativity, const gchar *date_format
)
{
	const gchar *date_str;

	/* Get string for date changed */
	gulong t = obj->change_time;
	if(t > 0)
	    date_str = EDVDateFormatString(
		t, date_format, date_relativity
	    );
	else
	    date_str = "";

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, date_str
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}

/*
 *	Sets the archive object location relative to the archive for the
 *	specified cell on the given clist.
 */
static void EDVArchiverContentsSetCellLocation(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
)
{
	gchar *path, *location;
	const gchar *full_path = obj->full_path;
	GdkBitmap *mask = NULL;
	GdkPixmap *pixmap = NULL;


	/* Get copy of path that we want displayed */
	if(STRISEMPTY(full_path))
	    path = STRDUP("");
	else if(g_path_is_absolute(full_path))
	    path = STRDUP(full_path);
	else
	    path = g_strdup_printf(
		".%c%s",
		G_DIR_SEPARATOR, full_path
	    );

	/* Get location */
	location = g_dirname(path);
	if(location == NULL)
	    location = STRDUP("");

	if(!STRISEMPTY(location))
	{
	    edv_mimetype_struct *m = EDVMimeTypeMatchListByType(
		core_ptr->mimetype, core_ptr->total_mimetypes,
		NULL,
		EDV_MIMETYPE_STR_DIRECTORY,
		FALSE
	    );
	    if(m != NULL)
	    {
		pixmap = m->small_pixmap[EDV_MIMETYPE_ICON_STATE_STANDARD];
		mask = m->small_mask[EDV_MIMETYPE_ICON_STATE_STANDARD];
	    }
	}

	/* Set cell */
	if(pixmap != NULL)
	    gtk_clist_set_pixtext(
		clist, row, column,
		location,
		EDV_LIST_PIXMAP_TEXT_SPACING,
		pixmap, mask
	    );
	else
	    gtk_clist_set_text(
		clist, row, column, location
	    );
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);

	g_free(path);
	g_free(location);
}

/*
 *      Sets the archive object linked to path for the specified cell
 *      on the given clist.
 */
static void EDVArchiverContentsSetCellLinkedTo(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
)
{
	/* Get link destination */
	const gchar *link_dest = (obj->linked_to != NULL) ?
	    obj->linked_to : "";

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, link_dest
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}

/*
 *      Sets the object device type for the specified cell on the given
 *      clist.
 */
static void EDVArchiverContentsSetCellDeviceType(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
)
{
	gint	border_minor = 2,
		type = obj->type,
		major, minor;
	gchar num_str[2 * 80];


	/* Is object a block or character device? */
	if((type == EDV_OBJECT_TYPE_DEVICE_BLOCK) ||
	   (type == EDV_OBJECT_TYPE_DEVICE_CHARACTER)
	)
	{
	    EDVGetDeviceNumbers(
		(dev_t)obj->device_type, &major, &minor
	    );
	    g_snprintf(
		num_str, sizeof(num_str),
		"%i, %i",
		major, minor
	    );
	}
	else
	{
	    *num_str = '\0';
	}

	/* Set cell */
	gtk_clist_set_text(
	    clist, row, column, num_str
	);
	gtk_clist_set_shift(
	    clist, row, column, 0, -border_minor
	);
}

/*
 *      Sets the object compression for the specified cell on the given
 *      clist.
 */
static void EDVArchiverContentsSetCellCompression(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column,
	gboolean hide_dir_size, gboolean hide_link_size
)
{
	gint border_minor = 2;
	gchar s[80];

	/* Get compression ratio and compression type string */
	if(hide_dir_size && (obj->type == EDV_OBJECT_TYPE_DIRECTORY))
	{
	    *s = '\0';
	}
	else if(hide_link_size && (obj->type == EDV_OBJECT_TYPE_LINK))
	{
	    *s = '\0';
	}
	else
	{
	    gfloat ratio = obj->compression_ratio;
	    if(ratio >= 0.0f)
		g_snprintf(
		    s, sizeof(s),
		    "%.1f%%",
		    ratio * 100.0f
		);
	    else
		*s = '\0';
	}

	/* Set cell */
	gtk_clist_set_text(clist, row, column, s);
	gtk_clist_set_shift(
	    clist, row, column, 0, -border_minor
	);
}

/*
 *	Sets the object method of storage for the specified cell on the
 *	given clist.
 */
static void EDVArchiverContentsSetCellMethod(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
)
{
	const gchar *method = obj->method;
	if(method == NULL)
	    method = "";

	/* Set cell */
	gtk_clist_set_text(clist, row, column, method);
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}

/*
 *	Sets the object CRC checksum for the specified cell on the
 *      given clist.
 */
static void EDVArchiverContentsSetCellCRC(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row, gint column
)
{
	const gchar *crc = obj->crc;
	if(crc == NULL)
	    crc = "";

	/* Set cell */
	gtk_clist_set_text(clist, row, column, crc);
	gtk_clist_set_shift(
	    clist, row, column, 0, 0
	);
}


/*
 *      Sets all cells of the specified row of the given contents clist
 *      with the values of the given object.
 *
 *      The clist row's client data will not be updated.
 */
static void EDVArchiverContentsSetRow(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj,
	gint row
)
{
	gint i, columns, date_relativity;
	gboolean hide_dir_size, hide_link_size, hide_link_permissions;
	const gchar *date_format;
	edv_archiver_column_type column_type;
	const cfg_item_struct *cfg_list;
	cfg_intlist_struct *column_types_intlist;


	if((core_ptr == NULL) || (archiver == NULL) ||
	   (clist == NULL) || (obj == NULL)
	)
	    return;

	cfg_list = core_ptr->cfg_list;

	/* Get column types mapping */
	column_types_intlist = CFGItemListGetValueIntList(
	    cfg_list, EDV_CFG_PARM_ARCHIVER_CONTENTS_COLUMN
	);
	if(column_types_intlist == NULL)
	    return;

	/* Get additional display options */
	date_relativity = CFGItemListGetValueI(
	    cfg_list, EDV_CFG_PARM_DATE_RELATIVITY
	);
	date_format = CFGItemListGetValueS(
	    cfg_list, EDV_CFG_PARM_DATE_FORMAT
	);
	hide_dir_size = CFGItemListGetValueI(
	    cfg_list, EDV_CFG_PARM_ARCHIVER_CONTENTS_HIDE_DIR_SIZE
	);
	hide_link_size = CFGItemListGetValueI(
	    cfg_list, EDV_CFG_PARM_ARCHIVER_CONTENTS_HIDE_LINK_SIZE
	);
	hide_link_permissions = CFGItemListGetValueI(
	    cfg_list, EDV_CFG_PARM_ARCHIVER_CONTENTS_HIDE_LINK_PERMISSIONS
	);

	/* Get total number of columns on the contents clist */
	columns = MIN(clist->columns, column_types_intlist->total);

	/* Iterate through each column but not more than the columns
	 * specified by the column types intlist.
	 */
	for(i = 0; i < columns; i++)
	{
	    /* Check column references on configuration list, see which
	     * one this column should show
	     */
	    column_type = (edv_archiver_column_type)column_types_intlist->i[i];
	    switch(column_type)
	    {
	      case EDV_ARCHIVER_COLUMN_TYPE_NAME:
		EDVArchiverContentsSetCellName(
		    core_ptr, archiver, clist, obj,
		    row, i
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_SIZE:
		EDVArchiverContentsSetCellSize(
		    core_ptr, archiver, clist, obj,
		    row, i,
		    hide_dir_size, hide_link_size
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_COMPRESSED_SIZE:
		EDVArchiverContentsSetCellCompressedSize(
		    core_ptr, archiver, clist, obj,
		    row, i,
		    hide_dir_size, hide_link_size
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_TYPE:
		EDVArchiverContentsSetCellType(
		    core_ptr, archiver, clist, obj,
		    row, i
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_PERMISSIONS:
		EDVArchiverContentsSetCellPermissions(
		    core_ptr, archiver, clist, obj,
		    row, i, hide_link_permissions
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_OWNER:
		EDVArchiverContentsSetCellOwner(
		    core_ptr, archiver, clist, obj,
		    row, i
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_GROUP:
		EDVArchiverContentsSetCellGroup(
		    core_ptr, archiver, clist, obj,
		    row, i
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_DATE_ACCESS:
		EDVArchiverContentsSetCellDateAccess(
		    core_ptr, archiver, clist, obj,
		    row, i, date_relativity, date_format
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_DATE_MODIFIED:
		EDVArchiverContentsSetCellDateModified(
		    core_ptr, archiver, clist, obj,
		    row, i, date_relativity, date_format
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_DATE_CHANGED:
		EDVArchiverContentsSetCellDateChanged(
		    core_ptr, archiver, clist, obj,
		    row, i, date_relativity, date_format
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_LOCATION:
		EDVArchiverContentsSetCellLocation(
		    core_ptr, archiver, clist, obj,
		    row, i
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_LINKED_TO:
		EDVArchiverContentsSetCellLinkedTo(
		    core_ptr, archiver, clist, obj,
		    row, i
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_DEVICE_TYPE:
		EDVArchiverContentsSetCellDeviceType(
		    core_ptr, archiver, clist, obj,
		    row, i
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_COMPRESSION:
		EDVArchiverContentsSetCellCompression(
		    core_ptr, archiver, clist, obj,
		    row, i,
		    hide_dir_size, hide_link_size
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_METHOD:
		EDVArchiverContentsSetCellMethod(
		    core_ptr, archiver, clist, obj,
		    row, i
		);
		break;
	      case EDV_ARCHIVER_COLUMN_TYPE_CRC:
		EDVArchiverContentsSetCellCRC(
		    core_ptr, archiver, clist, obj,
		    row, i
		);
		break;
	    }
	}
}

/*
 *	Appends the archive object to the contents clist. The given
 *	archive object structure will be transfered to the new row and
 *	should not be referenced again after this call.
 *
 *      Returns the row number that it was appended to or -1 on failure.
 */
static gint EDVArchiverContentsAppendObject(
	edv_core_struct *core_ptr, edv_archiver_struct *archiver,
	GtkCList *clist, edv_archive_object_struct *obj
)
{
	gint i, new_row, columns;
	gchar **strv;

	if((core_ptr == NULL) || (archiver == NULL) ||
	   (clist == NULL) || (obj == NULL)
	)
	{
	    EDVArchObjectDelete(obj);
	    return(-1);
	}

	columns = MAX(clist->columns, 1);

	/* Allocate row cell values */
	strv = (gchar **)g_malloc0(columns * sizeof(gchar *));
	for(i = 0; i < columns; i++)
	    strv[i] = "";

	/* Append a new row */
	new_row = gtk_clist_append(clist, strv);

	/* Delete row cell values */
	g_free(strv);

	/* Failed to appended row? */
	if(new_row < 0)
	{
	    EDVArchObjectDelete(obj);
	    return(-1);
	}

	/* Update each cell of the new row with the object's values
	 * and transfer the object to the row data
	 */
	EDVArchiverContentsSetRow(
	    core_ptr, archiver, clist, obj, new_row
	);
	gtk_clist_set_row_data_full(
	    clist, new_row,
	    obj, EDVArchiverContentsItemDestroyCB
	);

	return(new_row);
}

/*
 *	Gets all archive objects in the currently opened archive and appends
 *	them to the contents clist.
 */
static void EDVArchiverContentsGetListing(
	edv_archiver_struct *archiver, gboolean update_status_bar
)
{
	gint i, new_row, last_progress_percent, progress_percent;
	gint archive_objects_loaded, total_archive_objects;
	GtkCList *clist;
	edv_core_struct *core_ptr;
	edv_archive_object_struct **archive_object, *obj;


	if(archiver == NULL)
	    return;

	core_ptr = EDV_CORE(archiver->core_ptr);
	clist = (GtkCList *)archiver->contents_clist;
	if((core_ptr == NULL) || (clist == NULL))
	    return;

	/* Get listing of archive objects */
	archive_object = EDVArchFIOGetListing(
	    core_ptr,
	    EDVArchiverCurrentLocation(archiver), &total_archive_objects,
	    NULL, 0,	/* No filter, get all objects */
	    EDVArchiverCurrentPassword(archiver)
	);

	last_progress_percent = -1;     /* None/undefined */
	progress_percent = 0;
	archive_objects_loaded = 0;

	/* Iterate through archive objects */
	for(i = 0; i < total_archive_objects; i++)
	{
	    obj = archive_object[i];
	    if(obj == NULL)
		continue;

	    /* Append row, transfering the archive object structure obj
	     * to the new row. The archive object structure should not
	     * be referenced after this point
	     */
	    new_row = EDVArchiverContentsAppendObject(
		core_ptr, archiver, clist, obj
	    );
	    archive_object[i] = obj = NULL;

	    /* Increment total number of archive objects loaded */
	    archive_objects_loaded++;


	    /* Update progress? */
	    if(update_status_bar && (total_archive_objects > 0))
	    {
		progress_percent = archive_objects_loaded * 100 /
		    total_archive_objects;
		if(progress_percent > last_progress_percent)
		{
		    EDVStatusBarProgress(
			archiver->status_bar,
			(gfloat)archive_objects_loaded /
			    (gfloat)total_archive_objects,
			TRUE
		    );
		    progress_percent = last_progress_percent;
		}
	    }
	}

	/* Deallocate archive objects pointer array but not each object
	 * since they have already been transfered or deallocated in
	 * the above loop
	 */
	g_free(archive_object);
	archive_object = NULL;
	total_archive_objects = 0;
}

/*
 *      Returns the row index of the contents clist that contains an
 *	archive object structure who's full_path matches the given path.
 *
 *      Can return -1 on failed match.
 */
gint EDVArchiverContentsFindRowByPath(
	edv_archiver_struct *archiver, const gchar *path
)
{
	gint i;
	GtkCList *clist;
	edv_archive_object_struct *obj;


	if((archiver == NULL) || (path == NULL))
	    return(-1);

	clist = (GtkCList *)archiver->contents_clist;
	if(clist == NULL)
	    return(-1);

	/* Iterate through all rows */
	for(i = 0; i < clist->rows; i++)
	{
	    obj = EDV_ARCHIVE_OBJECT(
		gtk_clist_get_row_data(clist, i)
	    );
	    if((obj != NULL) ? (obj->full_path == NULL) : TRUE)
		continue;

	    if(!strcmp(obj->full_path, path))
		return(i);
	}

	return(-1);
}

/*
 *      Updates all rows on the contents clist by getting the row data
 *      and updates the clist's rows.
 *
 *      This is designed to be called whenever the displayed values
 *      of each row need to be set again from internal data, usually
 *      when a MIME Type has been added/modified/removed. This function
 *      should not be used to `refresh' the list (get new values of
 *      disk object structures), use EDVArchiverContentsDoUpdate()
 *      instead.
 */
void EDVArchiverContentsResetRows(edv_archiver_struct *archiver)
{
	gint i;
	GtkWidget *w;
	GtkCList *clist;
	edv_core_struct *core_ptr;
	edv_archive_object_struct *obj;


	if(archiver == NULL)
	    return;

	w = archiver->contents_clist;
	core_ptr = EDV_CORE(archiver->core_ptr);
	if((w == NULL) || (core_ptr == NULL))
	    return;

	clist = GTK_CLIST(w);

	/* Update columns */
	EDVArchiverContentsResetColumns(core_ptr, archiver, clist);

	/* Update rows */
	for(i = 0; i < clist->rows; i++)
	{
	    obj = EDV_ARCHIVE_OBJECT(
		gtk_clist_get_row_data(clist, i)
	    );
	    if(obj == NULL)
		continue;

	    EDVArchiverContentsSetRow(
		core_ptr, archiver, clist, obj, i
	    );
	}
}

/*
 *	Procedure to clear and re update the contents list with the
 *	archive objects found in the current archive.
 */
void EDVArchiverContentsDoUpdate(
	edv_archiver_struct *archiver, gboolean update_status_bar
)
{
	GtkWidget *w;
	GtkCList *clist;
	edv_core_struct *core_ptr;


	if(archiver == NULL)
	    return;

	core_ptr = EDV_CORE(archiver->core_ptr);
	if(core_ptr == NULL)
	    return;

	w = archiver->contents_clist;
	if(w == NULL)
	    return;
	else
	    clist = GTK_CLIST(w);


	if(update_status_bar)
	{
	    /* Reset progress */
	    EDVStatusBarMessage(
		archiver->status_bar,
		"Loading archive objects...",
		FALSE
	    );
	    EDVStatusBarProgress(
		archiver->status_bar, 0.0, TRUE
	    );
	}


	/* Delete all entries */
	EDVArchiverContentsClear(clist);


	/* Update columns */
	EDVArchiverContentsResetColumns(
	    core_ptr, archiver, clist
	);

	/* Get listing of archive objects */
	EDVArchiverContentsGetListing(archiver, update_status_bar);


	if(update_status_bar)
	{
	    /* Reset progress */
	    EDVStatusBarMessage(
		archiver->status_bar,
		"Archive objects loaded",
		FALSE
	    );
	    EDVStatusBarProgress(
		archiver->status_bar, 0.0f, TRUE
	    );
	}
}

/*
 *      Called whenever a disk object has been modified.
 */
void EDVArchiverContentsObjectModifiedNotify(
	edv_archiver_struct *archiver, const gchar *path,
	const gchar *new_path, const struct stat *lstat_buf
)
{
	gchar *cur_path = NULL, *parent_path = NULL;
	GtkCList *clist;
	const cfg_item_struct *cfg_list;
	edv_core_struct *core_ptr;

	if((archiver == NULL) || (path == NULL) || (lstat_buf == NULL))
	    return;

	if(new_path == NULL)
	    new_path = path;

	clist = (GtkCList *)archiver->contents_clist;  
	core_ptr = EDV_CORE(archiver->core_ptr);
	if((clist == NULL) || (core_ptr == NULL))
	    return;

	cfg_list = core_ptr->cfg_list;

#define DO_FREE_LOCALS	{	\
 g_free(cur_path);		\
 cur_path = NULL;		\
 g_free(parent_path);		\
 parent_path = NULL;		\
}

	/* Get parent of the given path and current location */
	cur_path = STRDUP(EDVArchiverCurrentLocation(archiver));
	parent_path = g_dirname(new_path);
	if((cur_path == NULL) || (parent_path == NULL))
	{
	    DO_FREE_LOCALS
	    return;
	}

	/* Is given path that has been modified the same as the current
	 * location?
	 */
	if(!strcmp(new_path, cur_path))
	{
	    /* Reget listing */
	    gtk_clist_freeze(clist);
	    EDVArchiverContentsDoUpdate(
		archiver,
		EDV_GET_B(EDV_CFG_PARM_LISTS_ANIMATE_UPDATES)
	    );
	    gtk_clist_thaw(clist);
	}

	DO_FREE_LOCALS
#undef DO_FREE_LOCALS
}

/*
 *	Called whenever a disk object has been removed.
 */
void EDVArchiverContentsObjectRemovedNotify(
	edv_archiver_struct *archiver, const gchar *path
)
{
	GtkWidget *w;
	GtkCList *clist;
	edv_core_struct *core_ptr;
	gchar *cur_path, *parent_path;


	if(archiver == NULL)
	    return;

	core_ptr = EDV_CORE(archiver->core_ptr);
	if(core_ptr == NULL)
	    return;

	w = archiver->contents_clist;
	if(w == NULL)
	    return;
	else
	    clist = GTK_CLIST(w);

#define DO_FREE_LOCALS		\
{				\
 g_free(cur_path);		\
 cur_path = NULL;		\
 g_free(parent_path);		\
 parent_path = NULL;		\
}
	/* Get parent of the given path and current location */
	cur_path = STRDUP(EDVArchiverCurrentLocation(archiver));
	parent_path = g_dirname(path);
	if((cur_path == NULL) || (parent_path == NULL))
	{
	    DO_FREE_LOCALS
	    return;
	}

	/* Is given path that has been removed the same as the current
	 * location?
	 */
	if(!strcmp(path, cur_path))
	{
	    /* Clear contents list */
	    gtk_clist_freeze(clist);
	    EDVArchiverContentsClear(clist);
	    gtk_clist_thaw(clist);
	}

	DO_FREE_LOCALS
#undef DO_FREE_LOCALS
}

/*
 *      Called whenever an archive object has been add to the
 *      specified archive arch_path which is gauranteed to the
 *	archive currently opened by the given archiver.
 */
void EDVArchiverContentsArchiveObjectAddedNotify(
	edv_archiver_struct *archiver, const gchar *arch_path,
	const gchar *path, edv_archive_object_struct *obj
)
{
	GtkWidget *w;
	gint row;
	GtkCList *clist;
	edv_core_struct *core_ptr;


	if(archiver == NULL)
	    return;

	core_ptr = EDV_CORE(archiver->core_ptr);
	if(core_ptr == NULL)
	    return;

	w = archiver->contents_clist;
	if(w == NULL)
	    return;
	else
	    clist = GTK_CLIST(w);


	/* Check if the path of the added archive object is one that this
	 * archiver is already has in its contents list.
	 */
	row = EDVArchiverContentsFindRowByPath(archiver, path);
	if((row >= 0) && (row < clist->rows))
	{
	    /* New archive object is already listed, so just update the row.
	     * First delete the old archive object structure and then copy
	     * the given archive object structure to it.
	     */
	    edv_archive_object_struct *old_obj;


	    /* Get old archive object from row data and delete it */
	    old_obj = EDV_ARCHIVE_OBJECT(
		gtk_clist_get_row_data(clist, row)
	    );
	    EDVArchObjectDelete(old_obj);
	    old_obj = NULL;

	    /* Copy given archive object and set it as the new archive
	     * object structure.
	     */
	    obj = EDVArchObjectCopy(obj);
	    gtk_clist_set_row_data_full(
		clist, row,
		obj, (GtkDestroyNotify)EDVArchiverContentsItemDestroyCB
	    );

	    /* Update row values */
	    EDVArchiverContentsSetRow(
		core_ptr, archiver, clist, obj, row
	    );
	}
	else
	{
	    /* Copy given archive object structure */
	    obj = EDVArchObjectCopy(obj);

	    /* Append row using coppied archive object structure. The
	     * archive object structure will be set as row data so it
	     * should not be referenced again.
	     */
	    row = EDVArchiverContentsAppendObject(
		core_ptr, archiver, clist, obj
	    );
	    obj = NULL;
	}
}

/*
 *      Called whenever an archive object has been modified in the
 *      specified archive arch_path which is gauranteed to the
 *      archive currently opened by the given archiver.
 */
void EDVArchiverContentsArchiveObjectModifiedNotify(
	edv_archiver_struct *archiver, const gchar *arch_path,
	const gchar *path, const gchar *new_path,
	edv_archive_object_struct *obj
)
{
	GtkWidget *w;
	gint row;
	GtkCList *clist;
	edv_core_struct *core_ptr;


	if(archiver == NULL)
	    return;

	core_ptr = EDV_CORE(archiver->core_ptr);
	if(core_ptr == NULL)
	    return;

	w = archiver->contents_clist;
	if(w == NULL)
	    return;
	else
	    clist = GTK_CLIST(w);

	if(new_path == NULL)
	    new_path = path;


	/* Check if the old path of the modified archive object is in
	 * this archiver's contents list.
	 */
	row = EDVArchiverContentsFindRowByPath(archiver, path);
	if((row >= 0) && (row < clist->rows))
	{
	    /* New archive object is already listed, so just update the row.
	     * First delete the old archive object structure and then copy
	     * the given archive object structure to it.
	     */
	    edv_archive_object_struct *old_obj;


	    /* Get old archive object from row data and delete it */
	    old_obj = EDV_ARCHIVE_OBJECT(
		gtk_clist_get_row_data(clist, row)
	    );
	    EDVArchObjectDelete(old_obj);
	    old_obj = NULL;

	    /* Copy given archive object and set it as the new archive
	     * object structure.
	     */
	    obj = EDVArchObjectCopy(obj);
	    gtk_clist_set_row_data_full(
		clist, row,
		obj, (GtkDestroyNotify)EDVArchiverContentsItemDestroyCB
	    );

	    /* Update row values */
	    EDVArchiverContentsSetRow(
		core_ptr, archiver, clist, obj, row
	    );
	}
}

/*
 *      Called whenever an archive object has been removed from the
 *      specified archive arch_path which is gauranteed to the
 *      archive currently opened by the given archiver.
 */
void EDVArchiverContentsArchiveObjectRemovedNotify(
	edv_archiver_struct *archiver, const gchar *arch_path,
	const gchar *path
)
{
	GtkWidget *w;
	gint row;
	GtkCList *clist;
	edv_core_struct *core_ptr;


	if(archiver == NULL)
	    return;

	core_ptr = EDV_CORE(archiver->core_ptr);
	if(core_ptr == NULL)
	    return;

	w = archiver->contents_clist;
	if(w == NULL)
	    return;
	else
	    clist = GTK_CLIST(w);


	/* Check if the path of the removed archive object is in this
	 * archiver's contents list.
	 */
	row = EDVArchiverContentsFindRowByPath(archiver, path);
	if((row >= 0) && (row < clist->rows))
	{
	    /* Remove matched row */
	    gtk_clist_remove(clist, row);
	}
}
