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

#include "../include/string.h"
#include "../include/fio.h"
#include "../include/disk.h"

#include "edv_types.h"
#include "edv_mime_type.h"
#include "edv_mime_types_list.h"
#include "edv_utils.h"
#include "config.h"


edv_mime_type_struct *EDVMimeTypesListMatchType(
	edv_mime_type_struct **list, const gint total,
	gint *n,
	const gchar *type, const gboolean case_sensitive
);
edv_mime_type_struct *EDVMimeTypesListMatchPath(
	edv_mime_type_struct **list, const gint total,
	const gchar *path
);

void EDVMimeTypesListSystemFileOpen(
	edv_mime_type_struct ***list, gint *total,
	const gint insert_index,
	gint (*progress_cb)(gpointer, const gulong, const gulong),
	gpointer progress_data,
	void (*added_cb)(const gint, edv_mime_type_struct *, gpointer),
	gpointer added_data,
	const gboolean mark_all_loaded_read_only
);

void EDVMimeTypesListFileOpen(
	const gchar *path,
	edv_mime_type_struct ***list, gint *total,
	const gint insert_index,
	const gboolean update, const gboolean only_newer,
	gint (*progress_cb)(gpointer, const gulong, const gulong),
	gpointer progress_data,
	void (*added_cb)(const gint, edv_mime_type_struct *, gpointer),
	gpointer added_data,
	void (*modified_cb)(const gint, edv_mime_type_struct *, gpointer),
	gpointer modified_data,
	const gboolean mark_all_loaded_read_only
);
void EDVMimeTypesListFileSave(
	const gchar *path,
	edv_mime_type_struct **list, const gint total,
	const gboolean include_read_only,
	gint (*progress_cb)(gpointer, const gulong, const gulong),
	gpointer progress_data
);


#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)

#define ISCR(c)		(((c) == '\n') || ((c) == '\r'))
#define BLANK(c)	(((c) == ' ') || ((c) == '\t'))


/*
 *	Matches a MIME Type by type name.
 *
 *	The type specifies the MIME Type's type name.
 */
edv_mime_type_struct *EDVMimeTypesListMatchType(
	edv_mime_type_struct **list, const gint total,
	gint *n,
	const gchar *type, const gboolean case_sensitive
)
{
	gint i;
	edv_mime_type_struct *m;

	if(n != NULL)
	    *n = -1;

	if(type == NULL)
	    return(NULL);

	/* Iterate through mimetypes list */
	for(i = 0; i < total; i++)
	{
	    m = list[i];
	    if(m == NULL)
		continue;

	    if(m->type == NULL)
		continue;

	    if(m->type == type)
	    {
                if(n != NULL)
                   *n = i;
                return(m);
	    }

	    if(case_sensitive)
	    {
		if(!strcmp(m->type, type))
		{
		    if(n != NULL)
		       *n = i;
		    return(m);
		}
	    }
	    else
	    {
		if(!g_strcasecmp(m->type, type))
		{
		    if(n != NULL)
		       *n = i;
		    return(m);
		}
	    }
	}

	return(NULL);
}

/*
 *	Matches a MIME Type by path.
 *
 *	The path specifies the full path to the object.
 *
 *	The returned MIME Type will be of class
 *	EDV_MIME_TYPE_CLASS_FORMAT, EDV_MIME_TYPE_CLASS_PROGRAM, or
 *	EDV_MIME_TYPE_CLASS_UNIQUE. If no MIME Type is matched then NULL
 *	is returned.
 */
edv_mime_type_struct *EDVMimeTypesListMatchPath(
	edv_mime_type_struct **list, const gint total,
	const gchar *path
)
{
	gint i;
	const gchar *name;
	edv_mime_type_struct *m;

	if(STRISEMPTY(path))
	    return(NULL);

	name = g_basename(path);

	for(i = 0; i < total; i++)
	{
	    m = list[i];
	    if(m == NULL)
		continue;

	    /* Handle by the MIME Type's class */
	    switch(m->mt_class)
	    {
	      case EDV_MIME_TYPE_CLASS_SYSTEM:
		break;
	      case EDV_MIME_TYPE_CLASS_FORMAT:
		if(EDVIsExtension(name, m->value))
		    return(m);
		break;
	      case EDV_MIME_TYPE_CLASS_PROGRAM:
		if(m->value != NULL)
		{
		    if(path == m->value)
			return(m);
		    else if(!strcmp(path, m->value))
			return(m);
		}
		break;
	      case EDV_MIME_TYPE_CLASS_UNIQUE:
		if(m->value != NULL)
		{
		    if(path == m->value)
			return(m);
		    else if(!strcmp(path, m->value))
			return(m);
		}
		break;
	    }
	}

	return(NULL);
}


/*
 *	Opens the MIME Types that are specified on the system.
 *
 *	The list and total specifies the pointers to the MIME Types
 *	list.
 *
 *	The insert_index specifies the position at which to insert the
 *	MIME Types read from file to the list, or it can be -1 to
 *	append to the list.
 *
 *	If progress_cb is not NULL then it will be called during the
 *	operation to report the progress. If it returns non-zero then
 *	the operation will be aborted.   
 *
 *	The progress_data specifies the user data which will be passed
 *	to the progress_cb function.
 *
 *	If added_cb is not NULL then it will be called after each new
 *	MIME Type is added to the list.
 *
 *	The added_data specifies the user data which will be passed to
 *	the added_cb function.
 *
 *	If mark_all_loaded_read_only is TRUE then all MIME Types read
 *	from this file will be marked as read only.
 */
void EDVMimeTypesListSystemFileOpen(
	edv_mime_type_struct ***list, gint *total,
	const gint insert_index,
	gint (*progress_cb)(gpointer, const gulong, const gulong),
	gpointer progress_data,
	void (*added_cb)(const gint, edv_mime_type_struct *, gpointer),
	gpointer added_data,
	const gboolean mark_all_loaded_read_only
)
{
	const gchar     *icon_file_s[EDV_MIME_TYPE_TOTAL_ICON_STATES],
			*icon_file_m[EDV_MIME_TYPE_TOTAL_ICON_STATES],
			*icon_file_l[EDV_MIME_TYPE_TOTAL_ICON_STATES];
	edv_mime_type_struct *m;
	gint cur_insert_index = insert_index;

	memset(icon_file_s, 0x00, EDV_MIME_TYPE_TOTAL_ICON_STATES * sizeof(const gchar *));
	memset(icon_file_m, 0x00, EDV_MIME_TYPE_TOTAL_ICON_STATES * sizeof(const gchar *));
	memset(icon_file_l, 0x00, EDV_MIME_TYPE_TOTAL_ICON_STATES * sizeof(const gchar *));

#define EDV_ICONS_DIR   PREFIX "/share/endeavour2/icons"

#define APPEND_MIMETYPE(			\
 _val_,_type_,_desc_,				\
 _icon_file_s_,					\
 _icon_file_m_,					\
 _icon_file_l_					\
) {						\
 gint mt_num;					\
						\
 /* Insert? */					\
 if((cur_insert_index >= 0) &&			\
    (cur_insert_index < *total)			\
 ) {						\
  gint i = MAX(*total, 0);			\
  *total = i + 1;				\
  *list = (edv_mime_type_struct **)g_realloc(	\
   *list,					\
   (*total) * sizeof(edv_mime_type_struct *)	\
  );						\
  if(*list == NULL) {				\
   *total = 0;					\
   return;					\
  }						\
  mt_num = cur_insert_index;			\
  for(i = (*total) - 1; i > mt_num; i--)	\
   (*list)[i] = (*list)[i - 1];			\
						\
  (*list)[mt_num] = m = EDVMimeTypeNew(		\
   EDV_MIME_TYPE_CLASS_SYSTEM, (_val_),		\
   (_type_), (_desc_)				\
  );						\
  cur_insert_index++;				\
 } else {					\
  mt_num = MAX(*total, 0);			\
  *total = mt_num + 1;				\
  *list = (edv_mime_type_struct **)g_realloc(	\
   *list,					\
   (*total) * sizeof(edv_mime_type_struct *)	\
  );						\
  if(*list == NULL) {				\
   *total = 0;					\
   return;					\
  }						\
  (*list)[mt_num] = m = EDVMimeTypeNew(		\
   EDV_MIME_TYPE_CLASS_SYSTEM, (_val_),		\
   (_type_), (_desc_)				\
  );						\
  cur_insert_index = -1;			\
 }						\
						\
 if(m != NULL) {				\
  gint n;					\
						\
  m->read_only = mark_all_loaded_read_only;	\
  m->realized = FALSE;				\
						\
  for(n = 0; n < EDV_MIME_TYPE_TOTAL_ICON_STATES; n++) { \
   m->small_icon_file[n] = STRDUP(PrefixPaths(	\
    EDV_ICONS_DIR, (_icon_file_s_)[n]		\
   ));						\
   m->medium_icon_file[n] = STRDUP(PrefixPaths(	\
    EDV_ICONS_DIR, (_icon_file_m_)[n]		\
   ));						\
   m->large_icon_file[n] = STRDUP(PrefixPaths(	\
    EDV_ICONS_DIR, (_icon_file_l_)[n]		\
   ));						\
						\
   if(added_cb != NULL)				\
    added_cb(mt_num, m, added_data);		\
  }						\
 }						\
}

	icon_file_s[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_object_misc_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_SELECTED] =
	    "icon_object_misc_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_object_misc_20x20.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_object_misc_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_SELECTED] =
	    "icon_object_misc_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_object_misc_32x32.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_object_misc_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_SELECTED] =
	    "icon_object_misc_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_object_misc_48x48.xpm";
	APPEND_MIMETYPE(
	    NULL, EDV_MIME_TYPE_TYPE_INODE_UNKNOWN, NULL,
	    icon_file_s, icon_file_m, icon_file_l
	);

	icon_file_s[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_object_error_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_SELECTED] =
	    "icon_object_error_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_object_error_20x20.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_object_error_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_SELECTED] =
	    "icon_object_error_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_object_error_32x32.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_object_error_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_SELECTED] =
	    "icon_object_error_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_object_error_48x48.xpm";
	APPEND_MIMETYPE(
	    NULL, EDV_MIME_TYPE_TYPE_INODE_ERROR, NULL,
	    icon_file_s, icon_file_m, icon_file_l
	);

	icon_file_s[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_file_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_file_hidden_20x20.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_STANDARD] =      
	    "icon_file_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_file_hidden_32x32.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_STANDARD] =      
	    "icon_file_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_file_hidden_48x48.xpm";
	APPEND_MIMETYPE(
	    NULL, EDV_MIME_TYPE_TYPE_INODE_FILE, NULL,
	    icon_file_s, icon_file_m, icon_file_l
	);

	icon_file_s[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_executable_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_executable_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_executable_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	APPEND_MIMETYPE(
	    NULL, EDV_MIME_TYPE_TYPE_INODE_EXECUTABLE, NULL,
	    icon_file_s, icon_file_m, icon_file_l
	);

	icon_file_s[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_folder_closed_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_SELECTED] =
	    "icon_folder_opened_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_folder_hidden_20x20.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_folder_closed_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_SELECTED] =      
	    "icon_folder_opened_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_folder_hidden_32x32.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_folder_closed_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_SELECTED] =
	    "icon_folder_opened_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_HIDDEN] =
	    "icon_folder_hidden_48x48.xpm";
	APPEND_MIMETYPE(
	    NULL, EDV_MIME_TYPE_TYPE_INODE_DIRECTORY, NULL,
	    icon_file_s, icon_file_m, icon_file_l
	);

	icon_file_s[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_link2_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = 
	    "icon_link_broken_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_link2_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_EXTENDED] =
	    "icon_link_broken_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_link2_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_EXTENDED] =  
	    "icon_link_broken_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	APPEND_MIMETYPE(
	    NULL, EDV_MIME_TYPE_TYPE_INODE_LINK, NULL,
	    icon_file_s, icon_file_m, icon_file_l
	);

	icon_file_s[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_device_block_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_STANDARD] =      
	    "icon_device_block_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_device_block_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	APPEND_MIMETYPE(
	    NULL, EDV_MIME_TYPE_TYPE_INODE_DEV_BLOCK, NULL,
	    icon_file_s, icon_file_m, icon_file_l
	);

	icon_file_s[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_device_character_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_device_character_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_device_character_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	APPEND_MIMETYPE(
	    NULL, EDV_MIME_TYPE_TYPE_INODE_DEV_CHARACTER, NULL,
	    icon_file_s, icon_file_m, icon_file_l
	);

	icon_file_s[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_pipe_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_pipe_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_pipe_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	APPEND_MIMETYPE(
	    NULL, EDV_MIME_TYPE_TYPE_INODE_FIFO, NULL,
	    icon_file_s, icon_file_m, icon_file_l
	);

	icon_file_s[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_socket_20x20.xpm";
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_s[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_socket_32x32.xpm";
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_m[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_STANDARD] =
	    "icon_socket_48x48.xpm";
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_SELECTED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_EXTENDED] = NULL;
	icon_file_l[EDV_MIME_TYPE_ICON_STATE_HIDDEN] = NULL;
	APPEND_MIMETYPE(
	    NULL, EDV_MIME_TYPE_TYPE_INODE_SOCKET, NULL,
	    icon_file_s, icon_file_m, icon_file_l
	);

#undef APPEND_MIMETYPE
#undef EDV_ICONS_DIR
}


/*
 *	Opens the MIME Types from the MIME Types file.
 *
 *	The path specifies the MIME Types file.
 *
 *	The list and total specifies the pointers to the MIME Types
 *	list.
 *
 *      The insert_index specifies the position at which to insert the
 *	MIME Types read from file to the list, or it can be -1 to
 *	append to the list.
 *
 *	If update is TRUE then if a MIME Type from the file already
 *	exists in the MIME Types list then it will be updated instead
 *	of a new MIME Type being added.
 *
 *	If only_newer is TRUE and update is TRUE then if a MIME Type
 *	from the file already exists in the MIME Types list then it
 *	will only be updated if the one from the file has a newer
 *	modified time.
 *
 *	If progress_cb is not NULL then it will be called during the
 *	operation to report the progress. If it returns non-zero then
 *	the operation will be aborted.   
 *
 *	The progress_data specifies the user data which will be passed
 *	to the progress_cb function.
 *
 *	If added_cb is not NULL then it will be called after each new
 *	MIME Type is added to the list.
 *
 *	The added_data specifies the user data which will be passed to
 *	the added_cb function.
 *
 *	If mark_all_loaded_read_only is TRUE then all MIME Types read
 *	from this file will be marked as read only.
 *
 *	Reminder: There is a sister function in
 *	lib/edv_mime_types_list.c which needs to perform equvilently
 *	to this function.
 */
void EDVMimeTypesListFileOpen(
	const gchar *path,
	edv_mime_type_struct ***list, gint *total,
	const gint insert_index,
	const gboolean update, const gboolean only_newer,
	gint (*progress_cb)(gpointer, const gulong, const gulong),
	gpointer progress_data,
	void (*added_cb)(const gint, edv_mime_type_struct *, gpointer),
	gpointer added_data,
	void (*modified_cb)(const gint, edv_mime_type_struct *, gpointer),
	gpointer modified_data,
	const gboolean mark_all_loaded_read_only
)
{
	gboolean aborted = FALSE;
	FILE *fp;
	struct stat stat_buf;
	gulong file_size = 0l;
	gint cur_insert_index = insert_index;
	gchar *parm;
	edv_mime_type_struct *mt = NULL;

	if((list == NULL) || (total == NULL) || STRISEMPTY(path))
	    return;

	/* Open the MIME Types file for reading */
	fp = fopen((const char *)path, "rb");
	if(fp == NULL)
	    return;

	/* Get the file's stats */
	if(!fstat(fileno(fp), &stat_buf))
	{
	    file_size = (gulong)stat_buf.st_size;
	}

	/* Report the initial progress */
	if(progress_cb != NULL)
	{
	    if(progress_cb(
		progress_data, 0l, file_size
	    ))
		aborted = TRUE;
	}

	/* Begin reading the MIME Types file */
	parm = NULL;
	while(!aborted)
	{
	    /* Report the progress */
	    if(progress_cb != NULL)
	    {
		if(progress_cb(
		    progress_data, (gulong)ftell(fp), file_size
		))
		{
		    aborted = TRUE;
		    break;
		}
	    }

	    /* Read the next parameter */
	    parm = (gchar *)FSeekNextParm(
		fp, (char *)parm,
		EDV_CFG_COMMENT_CHAR,
		EDV_CFG_DELIMINATOR_CHAR
	    );
	    if(parm == NULL)
		break;

	    /* Handle by parameter */

	    /* BeginMIMEType */
	    if(!g_strcasecmp(parm, "BeginMIMEType"))
	    {
		gint value[1];
		edv_mime_type_class mt_class;

		/* Get the class, which is the value for BeginMIMEType */
		FGetValuesI(fp, (int *)value, 1);
		mt_class = (edv_mime_type_class)value[0];

		/* Create a new MIME Type */
		if(mt == NULL)
		    mt = EDVMimeTypeNew(mt_class, NULL, NULL, NULL);
		if(mt != NULL)
		{
		    /* Mark as read only? */
		    if(mark_all_loaded_read_only)
			mt->read_only = TRUE;
		}
	    }
	    /* Type */
	    else if(!g_strcasecmp(parm, "Type"))
	    {
		gchar *type = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    g_free(mt->type);
		    mt->type = STRDUP(type);
		}
		g_free(type);
	    }
	    /* Value */
	    else if(!g_strcasecmp(parm, "Value"))
	    {
		gchar *value = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    g_free(mt->value);
		    mt->value = STRDUP(value);
		}
		g_free(value);
	    }
	    /* Description */
	    else if(!g_strcasecmp(parm, "Description"))
	    {
		gchar *description = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    g_free(mt->description);
		    mt->description = STRDUP(description);
		}
		g_free(description);
	    }

	    /* IconSmallStandard */
	    else if(!g_strcasecmp(parm, "IconSmallStandard"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->small_icon_file[
			EDV_MIME_TYPE_ICON_STATE_STANDARD
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconSmallSelected */
	    else if(!g_strcasecmp(parm, "IconSmallSelected"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->small_icon_file[
			EDV_MIME_TYPE_ICON_STATE_SELECTED
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconSmallExtended */
	    else if(!g_strcasecmp(parm, "IconSmallExtended"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->small_icon_file[
			EDV_MIME_TYPE_ICON_STATE_EXTENDED
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconSmallHidden */
	    else if(!g_strcasecmp(parm, "IconSmallHidden"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->small_icon_file[
			EDV_MIME_TYPE_ICON_STATE_HIDDEN
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }

	    /* IconMediumStandard */
	    else if(!g_strcasecmp(parm, "IconMediumStandard"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->medium_icon_file[
			EDV_MIME_TYPE_ICON_STATE_STANDARD
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconMediumSelected */
	    else if(!g_strcasecmp(parm, "IconMediumSelected"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->medium_icon_file[
			EDV_MIME_TYPE_ICON_STATE_SELECTED
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconMediumExtended */
	    else if(!g_strcasecmp(parm, "IconMediumExtended"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->medium_icon_file[
			EDV_MIME_TYPE_ICON_STATE_EXTENDED
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconMediumHidden */
	    else if(!g_strcasecmp(parm, "IconMediumHidden"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->medium_icon_file[
			EDV_MIME_TYPE_ICON_STATE_HIDDEN
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }

	    /* IconLargeStandard */
	    else if(!g_strcasecmp(parm, "IconLargeStandard"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->large_icon_file[
			EDV_MIME_TYPE_ICON_STATE_STANDARD
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconLargeSelected */
	    else if(!g_strcasecmp(parm, "IconLargeSelected"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->large_icon_file[
			EDV_MIME_TYPE_ICON_STATE_SELECTED
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconLargeExtended */
	    else if(!g_strcasecmp(parm, "IconLargeExtended"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->large_icon_file[
			EDV_MIME_TYPE_ICON_STATE_EXTENDED
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }
	    /* IconLargeHidden */
	    else if(!g_strcasecmp(parm, "IconLargeHidden"))
	    {
		gchar *path = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    gchar **p = &mt->large_icon_file[
			EDV_MIME_TYPE_ICON_STATE_HIDDEN
		    ];
		    g_free(*p);
		    *p = STRDUP(path);
		}
		g_free(path);
	    }

	    /* Handler */
	    else if(!g_strcasecmp(parm, "Handler"))
	    {
		gchar *s = (gchar *)FGetString(fp);
		if(mt != NULL)
		{
		    if(!g_strcasecmp(s, "Archiver"))
			mt->handler = EDV_MIME_TYPE_HANDLER_EDV_ARCHIVER;
		    else if(!g_strcasecmp(s, "ImageBrowser"))
			mt->handler = EDV_MIME_TYPE_HANDLER_EDV_IMAGE_BROWSER;
		    else if(!g_strcasecmp(s, "RecycleBin"))
			mt->handler = EDV_MIME_TYPE_HANDLER_EDV_RECYCLE_BIN;
		    else
			mt->handler = EDV_MIME_TYPE_HANDLER_COMMAND;
		}
		g_free(s);
	    }

	    /* Command */
	    else if(!g_strcasecmp(parm, "Command"))
	    {
		gchar *command = (gchar *)FGetString(fp);
		if((mt != NULL) && !STRISEMPTY(command))
		{
		    edv_mime_type_command_struct *cmd = EDVMimeTypeCommandNew();
		    if(cmd != NULL)
		    {
			/* Seek s to the name and command deliminator */
			gchar *s_cmd = (gchar *)strchr(
			    (char *)command,
			    EDV_CFG_DELIMINATOR_CHAR
			);
			if(s_cmd != NULL)
			{
			    gchar *s_end = s_cmd;
			    gint len = (gint)(s_end - command);

			    s_cmd++;

			    cmd->name = (gchar *)g_malloc((len + 1) * sizeof(gchar));
			    if(len > 0)
				memcpy(cmd->name, command, len * sizeof(gchar));
			    cmd->name[len] = '\0';
			    strstrip((char *)cmd->name);

			    cmd->command = STRDUP(s_cmd);
			    strstrip((char *)cmd->command);
			}
			else
			{
			    /* No command deliminator, implying there is
			     * only a command
			     *
			     * Create an arbitrary name for this command
			     */
			    cmd->name = g_strdup_printf(
				"Command #%i",
				g_list_length(mt->commands_list) + 1
			    );

			    cmd->command = STRDUP(command);
			    strstrip((char *)cmd->command);
			}

			mt->commands_list = g_list_append(
			    mt->commands_list, cmd
			);
		    }
		}
		g_free(command);
	    }

	    /* AccessTime */
	    else if(!g_strcasecmp(parm, "AccessTime"))
	    {
		glong value[1];
		FGetValuesL(fp, (long *)value, 1);
		if(mt != NULL)
		    mt->access_time = (gulong)value[0];
	    }
	    /* ModifyTime */
	    else if(!g_strcasecmp(parm, "ModifyTime"))
	    {
		glong value[1];
		FGetValuesL(fp, (long *)value, 1);
		if(mt != NULL)
		    mt->modify_time = (gulong)value[0];
	    }
	    /* ChangeTime */
	    else if(!g_strcasecmp(parm, "ChangeTime"))
	    {
		glong value[1];
		FGetValuesL(fp, (long *)value, 1);
		if(mt != NULL)
		    mt->change_time = (gulong)value[0];
	    }

	    /* EndMIMEType */
	    else if(!g_strcasecmp(parm, "EndMIMEType"))
	    {
		FSeekNextLine(fp);

		/* Is there a loaded MIME Type to be added or updated? */
		if(mt != NULL)
		{
		    gint mt_num = -1;

		    /* Update MIME Types if they already exist in the
		     * list?
		     */
		    if(update)
		    {
			/* Check if this MIME Type is already in the list */
			edv_mime_type_struct *src_mt = EDVMimeTypesListMatchType(
			    *list, *total,
			    &mt_num,
			    mt->type, FALSE
			);
			/* Found a matching MIME Type in the list? */
			if((mt_num > -1) && (src_mt != NULL))
			{
			    /* Only update if the one from this file
			     * is newer than the one from the
			     * specified list?
			     */
			    if(only_newer)
			    {
				/* If the one from this file is older
				 * than the one from the list then
				 * delete it
				 */
				if((mt->modify_time <= src_mt->modify_time) &&
				   (mt != src_mt)
				)
				{
				    /* Delete it and set it NULL so
				     * that it neither gets added nor
				     * updated
				     */
				    EDVMimeTypeDelete(mt);
				    mt = NULL;
				    mt_num = -1;
				}
			    }
			}
		    }

		    /* Update this MIME Type that is already in the
		     * list?
		     */
		    if((mt_num > -1) && (mt != NULL))
		    {
			/* Delete the MIME Type that is in the list
			 * and then replace it with the one from the
			 * file
			 */
			EDVMimeTypeDelete((*list)[mt_num]);
			(*list)[mt_num] = mt;

			if(modified_cb != NULL)
			    modified_cb(mt_num, mt, modified_data);
		    }
		    /* Add this MIME Type to the list? */
		    else if(mt != NULL)
		    {
			if((cur_insert_index >= 0) && (cur_insert_index < *total))
			{
			    /* Insert MIME Type */

			    /* Allocate more pointers */
			    gint i = MAX(*total, 0);
			    *total = i + 1;
			    *list = (edv_mime_type_struct **)g_realloc(
				*list,
				(*total) * sizeof(edv_mime_type_struct *)
			    );
			    if(*list == NULL)
			    {
				EDVMimeTypeDelete(mt);
				mt = NULL;
				*total = 0;
				break;
			    }

			    /* Get the current insert index */
			    mt_num = cur_insert_index;

			    /* Shift pointers */
			    for(i = (*total) - 1; i > mt_num; i--)
				(*list)[i] = (*list)[i - 1];

			    (*list)[mt_num] = mt;

			    cur_insert_index++;	/* Account for position shift */
			}
			else
			{
			    /* Append MIME Type */

			    /* Allocate more pointers */
			    mt_num = MAX(*total, 0);
			    *total = mt_num + 1;
			    *list = (edv_mime_type_struct **)g_realloc(
				*list,
				(*total) * sizeof(edv_mime_type_struct *)
			    );
			    if(*list == NULL)
			    {
				EDVMimeTypeDelete(mt);
				mt = NULL;
				*total = 0;
				break;
			    }

			    (*list)[mt_num] = mt;

			    cur_insert_index = -1;
			}

			/* Report this MIME Type as added */
			if(added_cb != NULL)
			    added_cb(mt_num, mt, added_data);
		    }
		}

		/* Reset the contexts */
		mt = NULL;
	    }
	    /* Unsupported parameter */
	    else
	    {
		/* Ignore unsupported parameter */
		FSeekNextLine(fp);
	    }
	}

	/* Delete the current MIME Type if it was not added */
	EDVMimeTypeDelete(mt);

	/* Delete the parameter */
	g_free(parm);

	/* Close the MIME Types file */
	fclose(fp);

	/* Report the final progress */
	if((progress_cb != NULL) && !aborted)
	{
	    if(progress_cb(progress_data, file_size, file_size))
		aborted = TRUE;
	}
}

/*
 *	Saves the MIME Types list to the MIME Types file.
 *
 *	The path specifies the MIME Types file.
 *
 *	The list and total specifies the MIME Types list.
 *
 *	If include_read_only is TRUE then MIME Types that are marked
 *	as read only will also be saved.
 *
 *	If progress_cb is not NULL then it will be called during the
 *	operation to report the progress. If it returns non-zero then
 *	the operation will be aborted.   
 *
 *	The progress_data specifies the user data which will be passed
 *	to the progress_cb function.
 */
void EDVMimeTypesListFileSave(
	const gchar *path,
	edv_mime_type_struct **list, const gint total,
	const gboolean include_read_only,
	gint (*progress_cb)(gpointer, const gulong, const gulong),
	gpointer progress_data
)
{
	gboolean aborted = FALSE;
	const gchar *s, *icon_path;
	gchar *parent;
	FILE *fp;
	gint mt_num;
	edv_mime_type_struct *mt;

	if((list == NULL) || STRISEMPTY(path))
	    return;

	/* Get parent directory and create it as needed */
	parent = g_dirname(path);
	if(parent != NULL)
	{
	    rmkdir((char *)parent, S_IRUSR | S_IWUSR | S_IXUSR);
	    g_free(parent);
	}

	/* Open the MIME Types file for writing */
	fp = fopen((const char *)path, "wb");
	if(fp == NULL)
	    return;

	/* Report the initial progress */
	if(progress_cb != NULL)
	{
	    if(progress_cb(progress_data, 0l, (gulong)total))
		aborted = TRUE;
	}

	/* Iterate through the MIME Types list */
	for(mt_num = 0; mt_num < total; mt_num++)
	{
	    if(aborted)
		break;

	    mt = list[mt_num];
	    if(mt == NULL)
		continue;

	    /* Skip MIME Types that are marked read only, meaning they
	     * should not be saved to file since they are created
	     * internally or are loaded from a global configuration
	     */
	    if(!include_read_only && mt->read_only)
		continue;

	    /* Report progress */
	    if(progress_cb != NULL)
	    {
		if(progress_cb(
		    progress_data,
		    (gulong)(mt_num + 1), (gulong)total
		))
		{
		    aborted = TRUE;
		    break;
		}
	    }


	    /* Begin saving this MIME Type */

	    /* BeginMIMEType */
	    fprintf(
		fp,
		"BeginMIMEType = %i\n",
		(int)mt->mt_class
	    );

	    /* Type */
	    if(!STRISEMPTY(mt->type))
		fprintf(
		    fp,
		    "\tType = %s\n",
		    (const char *)mt->type
		);

	    /* Value */
	    if(!STRISEMPTY(mt->value))
		fprintf(
		    fp,
		    "\tValue = %s\n",
		    (const char *)mt->value
		);

	    /* Description */
	    if(!STRISEMPTY(mt->description))
		fprintf(
		    fp,
		    "\tDescription = %s\n",
		    (const char *)mt->description
		);

	    /* IconSmallStandard */
	    icon_path = mt->small_icon_file[EDV_MIME_TYPE_ICON_STATE_STANDARD];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconSmallStandard = %s\n",
		    (const char *)icon_path
		);
	    /* IconSmallSelected */
	    icon_path = mt->small_icon_file[EDV_MIME_TYPE_ICON_STATE_SELECTED];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconSmallSelected = %s\n",
		    (const char *)icon_path
		);
	    /* IconSmallExtended */
	    icon_path = mt->small_icon_file[EDV_MIME_TYPE_ICON_STATE_EXTENDED];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconSmallExtended = %s\n",
		    (const char *)icon_path
		);
	    /* IconSmallHidden */
	    icon_path = mt->small_icon_file[EDV_MIME_TYPE_ICON_STATE_HIDDEN];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconSmallHidden = %s\n",
		    (const char *)icon_path
		);

	    /* IconMediumStandard */
	    icon_path = mt->medium_icon_file[EDV_MIME_TYPE_ICON_STATE_STANDARD];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconMediumStandard = %s\n",
		    (const char *)icon_path
		);
	    /* IconMediumSelected */
	    icon_path = mt->medium_icon_file[EDV_MIME_TYPE_ICON_STATE_SELECTED];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconMediumSelected = %s\n",
		    (const char *)icon_path
		);
	    /* IconMediumExtended */
	    icon_path = mt->medium_icon_file[EDV_MIME_TYPE_ICON_STATE_EXTENDED];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconMediumExtended = %s\n",
		    (const char *)icon_path
		);
	    /* IconMediumHidden */
	    icon_path = mt->medium_icon_file[EDV_MIME_TYPE_ICON_STATE_HIDDEN];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconMediumHidden = %s\n",
		    (const char *)icon_path
		);

	    /* IconLargeStandard */
	    icon_path = mt->large_icon_file[EDV_MIME_TYPE_ICON_STATE_STANDARD];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconLargeStandard = %s\n",
		    (const char *)icon_path
		);
	    /* IconLargeSelected */
	    icon_path = mt->large_icon_file[EDV_MIME_TYPE_ICON_STATE_SELECTED];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconLargeSelected = %s\n",
		    (const char *)icon_path
		);
	    /* IconLargeExtended */
	    icon_path = mt->large_icon_file[EDV_MIME_TYPE_ICON_STATE_EXTENDED];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconLargeExtended = %s\n",
		    (const char *)icon_path
		);
	    /* IconLargeHidden */
	    icon_path = mt->large_icon_file[EDV_MIME_TYPE_ICON_STATE_HIDDEN];
	    if(!STRISEMPTY(icon_path))
		fprintf(
		    fp,
		    "\tIconLargeHidden = %s\n",
		    (const char *)icon_path
		);

	    /* Handler */
	    switch(mt->handler)
	    {
	      case EDV_MIME_TYPE_HANDLER_EDV_ARCHIVER:
		s = "Archiver";
		break;
	      case EDV_MIME_TYPE_HANDLER_EDV_IMAGE_BROWSER:
		s = "ImageBrowser";
		break;
	      case EDV_MIME_TYPE_HANDLER_EDV_RECYCLE_BIN:
		s = "RecycleBin";
		break;
	      default:	/* EDV_MIME_TYPE_HANDLER_COMMAND */
		s = "Command";
		break;
	    }
	    fprintf(
		fp,
		"\tHandler = %s\n",
		(const char *)s
	    );

	    /* Commands */
	    if(mt->commands_list != NULL)
	    {
		GList *glist;
		edv_mime_type_command_struct *cmd;

		for(glist = mt->commands_list; glist != NULL; glist = g_list_next(glist))
		{
		    cmd = EDV_MIME_TYPE_COMMAND(glist->data);
		    if(cmd == NULL)
			continue;

		    fprintf(
			fp,
			"\tCommand = %s=%s\n",
			(const char *)cmd->name,
			(const char *)cmd->command
		    );
		}
	    }

	    /* AccessTime */
	    if(mt->access_time > 0l)
		fprintf(
		    fp,
		    "\tAccessTime = %ld\n",
		    (unsigned long)mt->access_time
	        );
	    /* ModifyTime */
	    if(mt->modify_time > 0l)
		fprintf(
		    fp,
		    "\tModifyTime = %ld\n",
		    (unsigned long)mt->modify_time
		);
	    /* ChangeTime */
	    if(mt->change_time > 0l)
		fprintf(
		    fp,
		    "\tChangeTime = %ld\n",
		    (unsigned long)mt->change_time
		);

	    /* EndMIMEType */
	    fprintf(
		fp,
		"EndMIMEType\n"
	    );
	}

	/* Close the MIME Types file */
	fclose(fp);

	/* Report the final progress */
	if((progress_cb != NULL) && !aborted)
	{
	    if(progress_cb(progress_data, (gulong)total, (gulong)total))
		aborted = TRUE;
	}
}
