gboolean plugin_done(void)
{
  hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
  hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
  hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
  hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
  hooks_unregister_hook(MAIN_WINDOW_CLOSE, hook_mw_close);
  hooks_unregister_hook(MAIN_WINDOW_GOT_ICONIFIED, hook_got_iconified);
  hooks_unregister_hook(ACCOUNT_LIST_CHANGED_HOOKLIST, hook_account);
  hooks_unregister_hook(THEME_CHANGED_HOOKLIST, hook_theme_changed);

  notify_save_config();

  notify_gtk_done();

  /* foldercheck cleanup */
  notification_foldercheck_write_array();
  notification_free_folder_specific_array();

#ifdef NOTIFICATION_BANNER
  notification_collected_msgs_free(banner_collected_msgs);
  banner_collected_msgs = NULL;
  notification_banner_destroy();
#endif
#ifdef NOTIFICATION_LCDPROC
  notification_lcdproc_disconnect();
#endif
#ifdef NOTIFICATION_TRAYICON
  notification_trayicon_destroy();
#endif
#ifdef NOTIFICATION_INDICATOR
  notification_indicator_destroy();
#endif
  notification_core_free();

#ifdef HAVE_LIBNOTIFY
  if(notify_is_initted())
    notify_uninit();
#endif

#ifdef NOTIFICATION_HOTKEYS
  notification_hotkeys_unbind_all();
#endif

  notification_pixbuf_free_all();

  debug_print("Notification plugin unloaded\n");

  /* Returning FALSE here means that g_module_close() will not be called on the plugin.
   * This is necessary, as needed libraries are not designed to be unloaded. */
  return FALSE;
}
/* Read selections from a common xml-file. Called when loading the plugin.
 * Returns TRUE if data has been read, FALSE if no data is available
 * or an error occurred.
 * This is analog to folder.h::folder_read_list. */
gboolean notification_foldercheck_read_array(void)
{
  gchar *path;
  GNode *rootnode, *node, *branchnode;
  XMLNode *xmlnode;
  gboolean success = FALSE;

  path = foldercheck_get_array_path();
  if(!is_file_exist(path)) {
    path = NULL;
    return FALSE;
  }

  /* We don't do merging, so if the file existed, clear what we
     have stored in memory right now.. */
  notification_free_folder_specific_array();

  /* .. and evaluate the file */
  rootnode = xml_parse_file(path);
  path = NULL;
  if(!rootnode)
    return FALSE;

  xmlnode = rootnode->data;

  /* Check that root entry is "foldercheckarray" */
  if(strcmp2(xmlnode->tag->tag, "foldercheckarray") != 0) {
    g_warning("wrong foldercheck array file");
    xml_free_tree(rootnode);
    return FALSE;
  }

  /* Process branch entries */
  for(branchnode = rootnode->children; branchnode != NULL;
      branchnode = branchnode->next) {
    GList *list;
    guint id;
    SpecificFolderArrayEntry *entry = NULL;

    xmlnode = branchnode->data;
    if(strcmp2(xmlnode->tag->tag, "branch") != 0) {
      g_warning("tag name != \"branch\"");
      return FALSE;
    }

    /* Attributes of the branch nodes */
    list = xmlnode->tag->attr;
    for(; list != NULL; list = list->next) {
      XMLAttr *attr = list->data;

      if(attr && attr->name && attr->value &&  !strcmp2(attr->name, "name")) {
	id = notification_register_folder_specific_list(attr->value);
	entry = foldercheck_get_entry_from_id(id);
	/* We have found something */
	success = TRUE;
	break;
      }
    }
    if((list == NULL) || (entry == NULL)) {
      g_warning("Did not find attribute \"name\" in tag \"branch\"");
      continue; /* with next branch */
    }

    /* Now descent into the children of the brach, which are the folderitems */
    for(node = branchnode->children; node != NULL; node = node->next) {
      FolderItem *item = NULL;

      /* These should all be leaves. */
      if(!G_NODE_IS_LEAF(node))
	g_warning("Subnodes in \"branch\" nodes should all be leaves. "
		  "Ignoring deeper subnodes.");

      /* Check if tag is "folderitem" */
      xmlnode = node->data;
      if(strcmp2(xmlnode->tag->tag, "folderitem") != 0) {
	g_warning("tag name != \"folderitem\"");
	continue; /* to next node in branch */
      }

      /* Attributes of the leaf nodes */
      list = xmlnode->tag->attr;
      for(; list != NULL; list = list->next) {
	XMLAttr *attr = list->data;

	if(attr && attr->name && attr->value &&
	   !strcmp2(attr->name, "identifier")) {
	  item = folder_find_item_from_identifier(attr->value);
	  break;
	}
      }
      if((list == NULL) || (item == NULL)) {
	g_warning("Did not find attribute \"identifier\" in tag "
		  "\"folderitem\"");
	continue; /* with next leaf node */
      }
      
      /* Store all FolderItems in the list */
      /* We started with a cleared array, so we don't need to check if
	 it's already in there. */
      entry->list = g_slist_prepend(entry->list, item);

    } /* for all subnodes in branch */

  } /* for all branches */
  return success;
}