[Commits] Makefile.am NONE 1.1.2.1 claws.def NONE 1.1.2.1 notification_banner.c NONE 1.1.2.1 notification_banner.h NONE 1.1.2.1 notification_command.c NONE 1.1.2.1 notification_command.h NONE 1.1.2.1 notification_core.c NONE 1.1.2.1 notification_core.h NONE 1.1.2.1 notification_foldercheck.c NONE 1.1.2.1 notification_foldercheck.h NONE 1.1.2.1 notification_hotkeys.c NONE 1.1.2.1 notification_hotkeys.h NONE 1.1.2.1 notification_indicator.c NONE 1.1.2.1 notification_indicator.h NONE 1.1.2.1 notification_lcdproc.c NONE 1.1.2.1 notification_lcdproc.h NONE 1.1.2.1 notification_pixbuf.c NONE 1.1.2.1 notification_pixbuf.h NONE 1.1.2.1 notification_plugin.c NONE 1.1.2.1 notification_plugin.h NONE 1.1.2.1 notification_popup.c NONE 1.1.2.1 notification_popup.h NONE 1.1.2.1 notification_prefs.c NONE 1.1.2.1 notification_prefs.h NONE 1.1.2.1 notification_trayicon.c NONE 1.1.2.1 notification_trayicon.h NONE 1.1.2.1 placeholder.txt 1.1.2.1 NONE plugin.def NONE 1.1.2.1 raw_claws_mail_logo_64x64.h NONE 1.1.2.1 version.rc NONE 1.1.2.1

colin at claws-mail.org colin at claws-mail.org
Sun Feb 17 22:22:01 CET 2013


Update of /home/claws-mail/claws/src/plugins/notification
In directory srv:/tmp/cvs-serv7104/src/plugins/notification

Added Files:
      Tag: gtk2
	Makefile.am claws.def notification_banner.c 
	notification_banner.h notification_command.c 
	notification_command.h notification_core.c notification_core.h 
	notification_foldercheck.c notification_foldercheck.h 
	notification_hotkeys.c notification_hotkeys.h 
	notification_indicator.c notification_indicator.h 
	notification_lcdproc.c notification_lcdproc.h 
	notification_pixbuf.c notification_pixbuf.h 
	notification_plugin.c notification_plugin.h 
	notification_popup.c notification_popup.h notification_prefs.c 
	notification_prefs.h notification_trayicon.c 
	notification_trayicon.h plugin.def raw_claws_mail_logo_64x64.h 
	version.rc 
Removed Files:
      Tag: gtk2
	placeholder.txt 
Log Message:
2013-02-17 [colin]	3.9.0cvs75

	* src/plugins/Makefile.am
	* src/plugins/archive/Makefile.am
	* src/plugins/clamd/Makefile.am
	* src/plugins/clamd/clamav_plugin.c
	* src/plugins/clamd/clamav_plugin.h
	* src/plugins/clamd/clamav_plugin_gtk.c
	* src/plugins/clamd/placeholder.txt
	* src/plugins/clamd/libclamd/Makefile.am
	* src/plugins/clamd/libclamd/clamd-plugin.c
	* src/plugins/clamd/libclamd/clamd-plugin.h
	* src/plugins/fetchinfo/Makefile.am
	* src/plugins/fetchinfo/fetchinfo_plugin.c
	* src/plugins/fetchinfo/fetchinfo_plugin.h
	* src/plugins/fetchinfo/fetchinfo_plugin_gtk.c
	* src/plugins/fetchinfo/placeholder.txt
	* src/plugins/gdata/Makefile.am
	* src/plugins/gdata/cm_gdata_contacts.c
	* src/plugins/gdata/cm_gdata_contacts.h
	* src/plugins/gdata/cm_gdata_prefs.c
	* src/plugins/gdata/cm_gdata_prefs.h
	* src/plugins/gdata/gdata_plugin.c
	* src/plugins/gdata/gdata_plugin.h
	* src/plugins/gdata/placeholder.txt
	* src/plugins/geolocation/placeholder.txt
	* src/plugins/gtkhtml2_viewer/placeholder.txt
	* src/plugins/mailmbox/Makefile.am
	* src/plugins/mailmbox/carray.c
	* src/plugins/mailmbox/carray.h
	* src/plugins/mailmbox/chash.c
	* src/plugins/mailmbox/chash.h
	* src/plugins/mailmbox/clist.c
	* src/plugins/mailmbox/clist.h
	* src/plugins/mailmbox/mailimf.c
	* src/plugins/mailmbox/mailimf.h
	* src/plugins/mailmbox/mailimf_types.c
	* src/plugins/mailmbox/mailimf_types.h
	* src/plugins/mailmbox/mailimf_types_helper.c
	* src/plugins/mailmbox/mailimf_types_helper.h
	* src/plugins/mailmbox/mailimf_write.c
	* src/plugins/mailmbox/mailimf_write.h
	* src/plugins/mailmbox/maillock.c
	* src/plugins/mailmbox/maillock.h
	* src/plugins/mailmbox/mailmbox.c
	* src/plugins/mailmbox/mailmbox.h
	* src/plugins/mailmbox/mailmbox_folder.c
	* src/plugins/mailmbox/mailmbox_folder.h
	* src/plugins/mailmbox/mailmbox_gtk.deps
	* src/plugins/mailmbox/mailmbox_parse.c
	* src/plugins/mailmbox/mailmbox_parse.h
	* src/plugins/mailmbox/mailmbox_types.c
	* src/plugins/mailmbox/mailmbox_types.h
	* src/plugins/mailmbox/mmapstring.c
	* src/plugins/mailmbox/mmapstring.h
	* src/plugins/mailmbox/placeholder.txt
	* src/plugins/mailmbox/plugin.c
	* src/plugins/mailmbox/plugin_gtk.c
	* src/plugins/mailmbox/plugin_gtk.h
	* src/plugins/newmail/Makefile.am
	* src/plugins/newmail/newmail.c
	* src/plugins/newmail/placeholder.txt
	* src/plugins/notification/Makefile.am
	* src/plugins/notification/claws.def
	* src/plugins/notification/notification_banner.c
	* src/plugins/notification/notification_banner.h
	* src/plugins/notification/notification_command.c
	* src/plugins/notification/notification_command.h
	* src/plugins/notification/notification_core.c
	* src/plugins/notification/notification_core.h
	* src/plugins/notification/notification_foldercheck.c
	* src/plugins/notification/notification_foldercheck.h
	* src/plugins/notification/notification_hotkeys.c
	* src/plugins/notification/notification_hotkeys.h
	* src/plugins/notification/notification_indicator.c
	* src/plugins/notification/notification_indicator.h
	* src/plugins/notification/notification_lcdproc.c
	* src/plugins/notification/notification_lcdproc.h
	* src/plugins/notification/notification_pixbuf.c
	* src/plugins/notification/notification_pixbuf.h
	* src/plugins/notification/notification_plugin.c
	* src/plugins/notification/notification_plugin.h
	* src/plugins/notification/notification_popup.c
	* src/plugins/notification/notification_popup.h
	* src/plugins/notification/notification_prefs.c
	* src/plugins/notification/notification_prefs.h
	* src/plugins/notification/notification_trayicon.c
	* src/plugins/notification/notification_trayicon.h
	* src/plugins/notification/placeholder.txt
	* src/plugins/notification/plugin.def
	* src/plugins/notification/raw_claws_mail_logo_64x64.h
	* src/plugins/notification/version.rc
	* src/plugins/pdf_viewer/Makefile.am
	* src/plugins/pdf_viewer/doc_index.xpm
	* src/plugins/pdf_viewer/doc_index_close.xpm
	* src/plugins/pdf_viewer/doc_info.xpm
	* src/plugins/pdf_viewer/first_arrow.xpm
	* src/plugins/pdf_viewer/last_arrow.xpm
	* src/plugins/pdf_viewer/left_arrow.xpm
	* src/plugins/pdf_viewer/placeholder.txt
	* src/plugins/pdf_viewer/poppler_viewer.c
	* src/plugins/pdf_viewer/poppler_viewer.h
	* src/plugins/pdf_viewer/right_arrow.xpm
	* src/plugins/pdf_viewer/rotate_left.xpm
	* src/plugins/pdf_viewer/rotate_right.xpm
	* src/plugins/pdf_viewer/zoom_fit.xpm
	* src/plugins/pdf_viewer/zoom_in.xpm
	* src/plugins/pdf_viewer/zoom_out.xpm
	* src/plugins/pdf_viewer/zoom_width.xpm
	* src/plugins/perl/Makefile.am
	* src/plugins/perl/perl_gtk.c
	* src/plugins/perl/perl_gtk.h
	* src/plugins/perl/perl_plugin.c
	* src/plugins/perl/perl_plugin.h
	* src/plugins/perl/placeholder.txt
	* src/plugins/python/Makefile.am
	* src/plugins/python/clawsmailmodule.c
	* src/plugins/python/clawsmailmodule.h
	* src/plugins/python/composewindowtype.c
	* src/plugins/python/composewindowtype.h
	* src/plugins/python/foldertype.c
	* src/plugins/python/foldertype.h
	* src/plugins/python/messageinfotype.c
	* src/plugins/python/messageinfotype.h
	* src/plugins/python/nodetype.c
	* src/plugins/python/nodetype.h
	* src/plugins/python/placeholder.txt
	* src/plugins/python/python-hooks.c
	* src/plugins/python/python-hooks.h
	* src/plugins/python/python-shell.c
	* src/plugins/python/python-shell.h
	* src/plugins/python/python_plugin.c
	* src/plugins/vcalendar/Makefile.in
		Add some plugins (clamd, fetchinfo, gdata, mailmbox, newmail,
		notification, pdf_viewer, perl, python). Notification not yet
		enabled because it has too much autoconf switches for my taste.

--- NEW FILE: notification_foldercheck.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_FOLDERCHECK_H
#define NOTIFICATION_FOLDERCHECK_H NOTIFICATION_FOLDERCHECK_H

#include <gtk/gtk.h>

#include "pluginconfig.h"

void     notification_foldercheck_sel_folders_cb(GtkButton*, gpointer);
guint    notification_register_folder_specific_list(gchar*);
GSList*  notification_foldercheck_get_list(guint);
void     notification_free_folder_specific_array(void);
void     notification_foldercheck_write_array(void);
gboolean notification_foldercheck_read_array(void);

#endif /* NOTIFICATION_FOLDERCHECK_H */

--- NEW FILE: notification_banner.c ---
/* Notification plugin for Claws Mail
 * Copyright (C) 2005-2008 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "pluginconfig.h"

#ifdef NOTIFICATION_BANNER

#include <gtk/gtk.h>

#include "gtk/gtkutils.h"

#include "prefs_common.h"
#include "mainwindow.h"
#include "menu.h"
#include "procmsg.h"
#include "messageview.h"
#include "compose.h"
#include "menu.h"

#include "notification_core.h"
#include "notification_prefs.h"
#include "notification_banner.h"

typedef struct {
  GtkWidget *table;
} NotificationBannerEntry;

typedef struct {
  GtkWidget *window;
  GtkWidget *scrolled_win;
	GtkWidget *viewport;

  NotificationBannerEntry *entries;
  guint timeout_id;
  gboolean scrolling;
} NotificationBanner;

typedef struct {
  gint banner_width;
  GtkAdjustment *adj;
} ScrollingData;


static void       notification_banner_create(GSList*);
static gboolean   scroller(gpointer data);
static GtkWidget* create_entrybox(GSList*);
static gboolean   notification_banner_configure(GtkWidget*, GdkEventConfigure*,
						gpointer);
static gboolean notification_banner_swap_colors(GtkWidget*,GdkEventCrossing*,gpointer);
static gboolean notification_banner_button_press(GtkWidget*,GdkEventButton*,gpointer);
static void notification_banner_show_popup(GtkWidget*,GdkEventButton*);
static void notification_banner_popup_done(GtkMenuShell*,gpointer);

static void banner_menu_reply_cb(GtkAction *,gpointer);


static NotificationBanner banner;
static ScrollingData      sdata;

static GtkWidget *banner_popup;
static GtkUIManager *banner_ui_manager;
static GtkActionGroup *banner_action_group;

static gboolean banner_popup_open = FALSE;

static MsgInfo *current_msginfo = NULL;

/* Corresponding mutexes */
G_LOCK_DEFINE_STATIC(banner);
G_LOCK_DEFINE_STATIC(sdata);

static GtkActionEntry banner_popup_entries[] = 
{
	{"BannerPopup",		NULL, "BannerPopup" },
	{"BannerPopup/Reply",	NULL, N_("_Reply"), NULL, NULL, G_CALLBACK(banner_menu_reply_cb) },
};


void notification_banner_show(GSList *msg_list)
{
  G_LOCK(banner);
  if((notify_config.banner_show != NOTIFY_BANNER_SHOW_NEVER) &&
     (g_slist_length(msg_list) ||
      (notify_config.banner_show == NOTIFY_BANNER_SHOW_ALWAYS)))
    notification_banner_create(msg_list);
  else 
    notification_banner_destroy();
  G_UNLOCK(banner);
}

void notification_banner_destroy(void)
{
  if(banner.window) {
    if(banner.entries) {
      g_free(banner.entries);
      banner.entries = NULL;
    }
    gtk_widget_destroy(banner.window);
    banner.window = NULL;
    G_LOCK(sdata);
    sdata.adj = NULL;
    sdata.banner_width = 0;
    G_UNLOCK(sdata);
    if(banner.timeout_id) {
      g_source_remove(banner.timeout_id);
      banner.timeout_id = 0;
    }
  }
}

static void notification_banner_create(GSList *msg_list)
{
  GtkRequisition requisition, requisition_after;
	GtkWidget *viewport;
	GtkWidget *hbox;
	GtkWidget *entrybox;
	GdkColor bg;
	gint banner_width;

  /* Window */
  if(!banner.window) {

    banner.window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "notification_banner");
    gtk_window_set_decorated(GTK_WINDOW(banner.window), FALSE);
		if(notify_config.banner_width > 0)
			gtk_widget_set_size_request(banner.window, notify_config.banner_width, -1);
		else
			gtk_widget_set_size_request(banner.window, gdk_screen_width(), -1);
    gtk_window_set_keep_above(GTK_WINDOW(banner.window), TRUE);
    gtk_window_set_accept_focus(GTK_WINDOW(banner.window), FALSE);
    gtk_window_set_skip_taskbar_hint(GTK_WINDOW(banner.window), TRUE);
    gtk_window_move(GTK_WINDOW(banner.window),
										notify_config.banner_root_x, notify_config.banner_root_y);
    g_signal_connect(banner.window, "configure-event",
										 G_CALLBACK(notification_banner_configure), NULL);
  }
  else {
    if(banner.entries) {
      g_free(banner.entries);
      banner.entries = NULL;
    }
    gtk_widget_destroy(banner.scrolled_win);
  }
  if(notify_config.banner_sticky)
    gtk_window_stick(GTK_WINDOW(banner.window));
  else
    gtk_window_unstick(GTK_WINDOW(banner.window));

  /* Scrolled window */
  banner.scrolled_win = gtk_scrolled_window_new(NULL, NULL);
  gtk_container_add(GTK_CONTAINER(banner.window), banner.scrolled_win);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(banner.scrolled_win),
																 GTK_POLICY_NEVER, GTK_POLICY_NEVER);

	/* Viewport */
	viewport = gtk_viewport_new(NULL,NULL);
	banner.viewport = viewport;
	gtk_container_add(GTK_CONTAINER(banner.scrolled_win),viewport);
	if(notify_config.banner_enable_colors) {
		gtkut_convert_int_to_gdk_color(notify_config.banner_color_bg,&bg);
		gtk_widget_modify_bg(viewport,GTK_STATE_NORMAL,&bg);
	}

  /* Hbox */
  hbox = gtk_hbox_new(FALSE, 5);
	gtk_container_add(GTK_CONTAINER(viewport),hbox);

  /* Entrybox */
  entrybox = create_entrybox(msg_list);
  gtk_box_pack_start(GTK_BOX(hbox), entrybox, FALSE, FALSE, 0);

  gtk_widget_show_all(banner.window);

  /* Scrolling */
  gtk_widget_size_request(hbox, &requisition);
  if(notify_config.banner_width > 0)
		banner_width = notify_config.banner_width;
	else
		banner_width = gdk_screen_width();
  if(requisition.width > banner_width) {
    /* Line is too big for screen! */
    /* Double the entrybox into hbox */
    GtkWidget *separator, *second_entrybox;

    separator = gtk_vseparator_new();
    gtk_box_pack_start(GTK_BOX(hbox), separator,
		       FALSE, FALSE, 0);
    second_entrybox = create_entrybox(msg_list);
    gtk_box_pack_start(GTK_BOX(hbox), second_entrybox, FALSE, FALSE, 0);

    gtk_widget_show_all(banner.window);
    gtk_widget_size_request(hbox, &requisition_after);

    G_LOCK(sdata);
    sdata.banner_width = requisition_after.width - requisition.width;
    sdata.adj =
      gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW
					  (banner.scrolled_win));
    G_UNLOCK(sdata);
    
    banner.scrolling = TRUE;
    if(banner.timeout_id) {
      g_source_remove(banner.timeout_id);
      banner.timeout_id = 0;
    }
    banner.timeout_id = 
      g_timeout_add(notify_config.banner_speed, scroller, NULL);
  }
  else {
    banner.scrolling = FALSE;
    if(banner.timeout_id) {
      g_source_remove(banner.timeout_id);
      banner.timeout_id = 0;
    }
    G_LOCK(sdata);
    sdata.banner_width = 0;
    sdata.adj = NULL;
    G_UNLOCK(sdata);
  }

	/* menu */
  banner_ui_manager = gtk_ui_manager_new();
  banner_action_group = cm_menu_create_action_group_full(banner_ui_manager,"BannerPopup", banner_popup_entries,
			G_N_ELEMENTS(banner_popup_entries), (gpointer)NULL);
  MENUITEM_ADDUI_MANAGER(banner_ui_manager, "/", "Menus", "Menus", GTK_UI_MANAGER_MENUBAR)
  MENUITEM_ADDUI_MANAGER(banner_ui_manager, "/Menus", "BannerPopup", "BannerPopup", GTK_UI_MANAGER_MENU)
  MENUITEM_ADDUI_MANAGER(banner_ui_manager, "/Menus/BannerPopup", "Reply", "BannerPopup/Reply", GTK_UI_MANAGER_MENUITEM)

  banner_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
				gtk_ui_manager_get_widget(banner_ui_manager, "/Menus/BannerPopup")) );
	g_signal_connect(banner_popup,"selection-done",
									 G_CALLBACK(notification_banner_popup_done), NULL);
}

static gboolean notification_banner_configure(GtkWidget *widget,
					      GdkEventConfigure *event,
					      gpointer data)
{
  gtk_window_get_position(GTK_WINDOW(gtk_widget_get_toplevel(widget)),
			  &(notify_config.banner_root_x),
			  &(notify_config.banner_root_y));
  return TRUE;
}

static gboolean scroller(gpointer data)
{
	// don't scroll during popup open
	if(banner_popup_open)
		return banner.scrolling;

	while(gtk_events_pending())
		gtk_main_iteration();
  G_LOCK(sdata);
  if(sdata.adj && GTK_IS_ADJUSTMENT(sdata.adj)) {
    if(sdata.adj->value != sdata.banner_width)
      gtk_adjustment_set_value(sdata.adj, sdata.adj->value + 1);
    else
      gtk_adjustment_set_value(sdata.adj, 0);
		gtk_adjustment_value_changed(sdata.adj);
  }
  G_UNLOCK(sdata);
	while(gtk_events_pending())
		gtk_main_iteration();
  return banner.scrolling;
}

static GtkWidget* create_entrybox(GSList *msg_list)
{
  GtkWidget *entrybox;
  GdkColor fg;
	GdkColor bg;
  gint list_length;

  list_length = g_slist_length(msg_list);

  if(notify_config.banner_enable_colors) {
    gtkut_convert_int_to_gdk_color(notify_config.banner_color_bg,&bg);
		gtkut_convert_int_to_gdk_color(notify_config.banner_color_fg,&fg);
  }

  if(banner.entries) {
    g_free(banner.entries);
    banner.entries = NULL;
  }

  entrybox = gtk_hbox_new(FALSE, 5);
  if(list_length) {
    GSList *walk;
    gint ii = 0;
    banner.entries = g_new(NotificationBannerEntry, list_length);
    for(walk = msg_list; walk != NULL; walk = g_slist_next(walk)) {
      GtkWidget *label1;
      GtkWidget *label2;
      GtkWidget *label3;
      GtkWidget *label4;
      GtkWidget *label5;
      GtkWidget *label6;
			GtkWidget *ebox;
      CollectedMsg *cmsg = walk->data;
      
      if(ii > 0) {
				GtkWidget *separator;
				separator = gtk_vseparator_new();
				gtk_box_pack_start(GTK_BOX(entrybox), separator, FALSE, FALSE, 0);
      }

			ebox = gtk_event_box_new();
			gtk_box_pack_start(GTK_BOX(entrybox), ebox, FALSE, FALSE, 0);
			gtk_widget_set_events(ebox,
														GDK_POINTER_MOTION_MASK |
														GDK_BUTTON_PRESS_MASK);

			if(notify_config.banner_enable_colors)
				gtk_widget_modify_bg(ebox,GTK_STATE_NORMAL,&bg);

      banner.entries[ii].table = gtk_table_new(3, 2, FALSE);
			gtk_container_add(GTK_CONTAINER(ebox),banner.entries[ii].table);
			g_signal_connect(ebox, "enter-notify-event",
											 G_CALLBACK(notification_banner_swap_colors),
											 banner.entries[ii].table);
			g_signal_connect(ebox, "leave-notify-event",
											 G_CALLBACK(notification_banner_swap_colors),
											 banner.entries[ii].table);
			g_signal_connect(ebox, "button-press-event",
											 G_CALLBACK(notification_banner_button_press),
											 cmsg);

      label1 = gtk_label_new(prefs_common_translated_header_name("From:"));
      gtk_misc_set_alignment(GTK_MISC(label1), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table), 
				label1, 0, 1, 0, 1);
      label2 = gtk_label_new(prefs_common_translated_header_name("Subject:"));
      gtk_misc_set_alignment(GTK_MISC(label2), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table),
				label2, 0, 1, 1, 2);
      label3 = gtk_label_new(_("Folder:"));
      gtk_misc_set_alignment(GTK_MISC(label3), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table),
				label3, 0, 1, 2, 3);
      
      label4 = gtk_label_new(cmsg->from);
      gtk_misc_set_alignment(GTK_MISC(label4), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table),
				label4, 1, 2, 0, 1);
      label5 = gtk_label_new(cmsg->subject);
      gtk_misc_set_alignment(GTK_MISC(label5), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table),
				label5, 1, 2, 1, 2);
      label6 = gtk_label_new(cmsg->folderitem_name);
      gtk_misc_set_alignment(GTK_MISC(label6), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table),
				label6, 1, 2, 2, 3);
      gtk_table_set_col_spacings(GTK_TABLE(banner.entries[ii].table), 5);
			ii++;
      /* Color */
      if(notify_config.banner_enable_colors) {
				gtk_widget_modify_fg(label1,GTK_STATE_NORMAL,&fg);
				gtk_widget_modify_fg(label2,GTK_STATE_NORMAL,&fg);
				gtk_widget_modify_fg(label3,GTK_STATE_NORMAL,&fg);
				gtk_widget_modify_fg(label4,GTK_STATE_NORMAL,&fg);
				gtk_widget_modify_fg(label5,GTK_STATE_NORMAL,&fg);
				gtk_widget_modify_fg(label6,GTK_STATE_NORMAL,&fg);
      }
    }
  }
  else {
    /* We have an empty list -- create an empty dummy element */
    GtkWidget *label;

    banner.entries = g_new(NotificationBannerEntry, 1);
    banner.entries[0].table = gtk_table_new(3, 1, FALSE);
    label = gtk_label_new("");
    gtk_table_attach_defaults(GTK_TABLE(banner.entries[0].table), 
			      label, 0, 1, 0, 1);
    label = gtk_label_new("");
    gtk_table_attach_defaults(GTK_TABLE(banner.entries[0].table), 
			      label, 0, 1, 1, 2);
    label = gtk_label_new("");
    gtk_table_attach_defaults(GTK_TABLE(banner.entries[0].table), 
			      label, 0, 1, 2, 3);
    gtk_box_pack_start(GTK_BOX(entrybox), banner.entries[0].table,
		       FALSE, FALSE, 0);
  }
  return entrybox;
}

static gboolean notification_banner_swap_colors(GtkWidget *widget,
																								GdkEventCrossing *event,
																								gpointer data)
{
	GList *children;
	GList *walk;
	GdkColor *old_bg;
	
	children = gtk_container_get_children(GTK_CONTAINER(data));

	old_bg = gdk_color_copy(&(gtk_widget_get_style(widget)->bg[GTK_STATE_NORMAL]));
	if(children)
		gtk_widget_modify_bg(widget,GTK_STATE_NORMAL,
												 &(gtk_widget_get_style(GTK_WIDGET(children->data))->fg[GTK_STATE_NORMAL]));
	
	for(walk = children; walk; walk = walk->next)
		gtk_widget_modify_fg(GTK_WIDGET(walk->data),GTK_STATE_NORMAL,old_bg);
	
	g_list_free(children);
	gdk_color_free(old_bg);
	return FALSE;
}

static gboolean notification_banner_button_press(GtkWidget *widget,
																								 GdkEventButton *button,
																								 gpointer data)
{
	gboolean done;
	done = FALSE;
	if(button->type == GDK_BUTTON_PRESS) {
		CollectedMsg *cmsg = (CollectedMsg*) data;
    if(button->button == 1) {
			/* jump to that message */
			if(cmsg->msginfo) {
				gchar *path;
				path = procmsg_get_message_file_path(cmsg->msginfo);
				mainwindow_jump_to(path, TRUE);
				g_free(path);
			}
			done = TRUE;
		}
		else if(button->button == 2) {
      gtk_window_begin_move_drag(GTK_WINDOW(gtk_widget_get_toplevel(widget)), 
																 button->button, button->x_root, button->y_root,
																 button->time);
		}
		else if(button->button == 3) {
			current_msginfo = cmsg->msginfo;
			notification_banner_show_popup(widget, button);
			banner_popup_open = TRUE;
			done = TRUE;
		}
	}
	return done;
}

static void notification_banner_show_popup(GtkWidget *widget,
																					 GdkEventButton *event)
{
  int button, event_time;

  if(event) {
		button = event->button;
		event_time = event->time;
	}
  else {
		button = 0;
		event_time = gtk_get_current_event_time();
	}

  gtk_menu_popup(GTK_MENU(banner_popup), NULL, NULL, NULL, NULL,
								 button, event_time);
}

static void notification_banner_popup_done(GtkMenuShell *menushell,
																					 gpointer      user_data)
{
	current_msginfo = NULL;
	banner_popup_open = FALSE;
}

static void banner_menu_reply_cb(GtkAction *action, gpointer data)
{
	MainWindow *mainwin;
	MessageView *messageview;
	GSList *msginfo_list = NULL;

	if(!(mainwin = mainwindow_get_mainwindow()))
		return;

	if(!(messageview = (MessageView*)mainwin->messageview))
		return;

	g_return_if_fail(current_msginfo);

	msginfo_list = g_slist_prepend(msginfo_list, current_msginfo);
	compose_reply_from_messageview(messageview, msginfo_list,
				       prefs_common_get_prefs()->reply_with_quote ?
				       COMPOSE_REPLY_WITH_QUOTE : COMPOSE_REPLY_WITHOUT_QUOTE);
	g_slist_free(msginfo_list);
}

#endif /* NOTIFICATION_BANNER */

--- NEW FILE: notification_banner.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_BANNER_H
#define NOTIFICATION_BANNER_H NOTIFICATION_BANNER_H

#include "pluginconfig.h"

#ifdef NOTIFICATION_BANNER

#define BANNER_SPECIFIC_FOLDER_ID_STR "banner"

void notification_banner_show(GSList*);
void notification_banner_destroy(void);

#endif /* NOTIFICATION_BANNER */

#endif /* NOTIFICATION_BANNER_H */

--- placeholder.txt DELETED ---

--- NEW FILE: notification_foldercheck.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/* This code is based on foldersel.c in Claws Mail.
 * Some functions are only slightly modified, almost 1:1 copies from there. */
[...963 lines suppressed...]
    FolderItem *item = hookdata->item;

    /* If that folder is in anywhere in the array, cut it out. */
    for(ii = 0; ii < specific_folder_array_size; ii++) {
      entry = foldercheck_get_entry_from_id(ii);
      entry->list = g_slist_remove(entry->list, item);
    } /* for all entries in the array */
  } /* A FolderItem was deleted */

  return FALSE;
}

static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
  if(event && (event->keyval == GDK_Escape)) {
    foldercheck_cancel(NULL, data);
    return TRUE;
  }
  return FALSE;
}

--- NEW FILE: notification_prefs.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_PREFS_H
#define NOTIFICATION_PREFS_H NOTIFICATION_PREFS_H

#include "pluginconfig.h"

#include <glib.h>

#include "prefs_gtk.h"

#include "notification_banner.h"

#ifdef NOTIFICATION_BANNER
typedef enum {
  NOTIFY_BANNER_SHOW_NEVER = 0,
  NOTIFY_BANNER_SHOW_ALWAYS,
  NOTIFY_BANNER_SHOW_NONEMPTY
} NotifyBannerShow;
#endif

typedef struct {
  gboolean         include_mail;
  gboolean         include_news;
  gboolean         include_rss;
  gboolean         include_calendar;
  gboolean         urgency_hint_new;
  gboolean         urgency_hint_unread;
#ifdef HAVE_LIBCANBERRA_GTK
  gboolean         canberra_play_sounds;
#endif
#ifdef NOTIFICATION_BANNER
  NotifyBannerShow banner_show;
  gint             banner_speed;
  gboolean         banner_include_unread;
  gint             banner_max_msgs;
  gboolean         banner_sticky;
  gint             banner_root_x;
  gint             banner_root_y;
  gboolean         banner_folder_specific;
  gboolean         banner_enable_colors;
  gulong           banner_color_bg;
  gulong           banner_color_fg;
	gint             banner_width;
#endif
#ifdef NOTIFICATION_POPUP
  gboolean         popup_show;
  gint             popup_timeout;
  gboolean         popup_folder_specific;
#ifndef HAVE_LIBNOTIFY
  gboolean         popup_sticky;
  gint             popup_root_x;
  gint             popup_root_y;
  gint             popup_width;
  gboolean         popup_enable_colors;
  gulong           popup_color_bg;
  gulong           popup_color_fg;
#else /* HAVE_LIBNOTIFY */
  gboolean         popup_display_folder_name;
#endif /* HAVE_LIBNOTIFY */
#endif /* Popup */
#ifdef NOTIFICATION_COMMAND
  gboolean         command_enabled;
  gint             command_timeout;
  gboolean         command_folder_specific;
  gchar*           command_line;
#endif
#ifdef NOTIFICATION_LCDPROC
  gboolean         lcdproc_enabled;
  gchar*           lcdproc_hostname;
  guint 	   lcdproc_port;

#endif
#ifdef NOTIFICATION_TRAYICON
  gboolean         trayicon_enabled;
  gboolean         trayicon_hide_at_startup;
  gboolean         trayicon_close_to_tray;
  gboolean         trayicon_hide_when_iconified;
  gboolean         trayicon_folder_specific;
#ifdef HAVE_LIBNOTIFY
  gboolean         trayicon_display_folder_name;
  gboolean         trayicon_popup_enabled;
  gint             trayicon_popup_timeout;
#endif /* HAVE_LIBNOTIFY */
#endif /* Trayicon */
#ifdef NOTIFICATION_INDICATOR
  gboolean indicator_enabled;
  gboolean indicator_hide_minimized;
#endif /* NOTIFICATION_INDICATOR */
#ifdef NOTIFICATION_HOTKEYS
  gboolean hotkeys_enabled;
  gchar* hotkeys_toggle_mainwindow;
#endif /* Hotkeys */
} NotifyPrefs;

extern NotifyPrefs notify_config;
extern PrefParam   notify_param[];

void notify_gtk_init(void);
void notify_gtk_done(void);
void notify_save_config(void);

#endif /* NOTIFICATION_PREFS_H */

--- NEW FILE: notification_prefs.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "pluginconfig.h"

[...1913 lines suppressed...]
    active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hotkeys_page.hotkeys_enabled));
    gtk_widget_set_sensitive(hotkeys_page.hotkeys_cont_enable, active);
}
#endif /* hotkeys */


/* This feels so wrong... */
static gint conv_color_to_int(GdkColor *color)
{
	gint result;
	guint red, green, blue;

	red = (guint) ((gdouble)(color->red) /65535.*255.);
	green = (guint) ((gdouble)(color->green) /65535.*255.);
	blue = (guint) ((gdouble)(color->blue) /65535.*255.);

	result = (gint) (blue | (green<<8)| (red<<16));

	return result;
}

--- NEW FILE: Makefile.am ---
if BUILD_HOTKEYS
hotkey_lib = libcmnpgtkhotkey.la
hotkey_lib_path = $(top_builddir)/src/plugins/notification/gtkhotkey/libcmnpgtkhotkey.la
else
hotkey_lib =
hotkey_lib_path =
endif


EXTRA_DIST = claws.def plugin.def version.rc
CFLAGS += "-Wall"

if OS_WIN32

LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RC) \
     `echo $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) | \
     sed -e 's/-I/--include-dir /g;s/-D/--define /g'`

%.lo : %.rc
	$(LTRCCOMPILE) -i $< -o $@

plugin_res = version.lo
plugin_res_ldflag = -Wl,.libs/version.o

export_symbols = -export-symbols $(srcdir)/plugin.def

plugin_deps = libclaws.a $(plugin_res) plugin.def $(hotkey_lib) 

libclaws.a: claws.def
	$(DLLTOOL) --output-lib $@ --def $<

plugin_ldadd = -L. -lclaws

else
plugin_res =
plugin_res_ldflag =
export_symbols =
plugin_deps =
plugin_ldadd =
endif

if PLATFORM_WIN32
no_undefined = -no-undefined
else
no_undefined =
endif

if CYGWIN
cygwin_export_lib = -L$(top_builddir)/src -lclaws-mail
else
cygwin_export_lib = 
endif

plugindir = $(pkglibdir)/plugins

plugin_LTLIBRARIES = notification_plugin.la

notification_plugin_la_SOURCES = \
	gettext.h \
	notification_plugin.c notification_plugin.h \
	notification_core.c notification_core.h \
	notification_popup.c notification_popup.h \
	notification_banner.c notification_banner.h \
	notification_command.c notification_command.h \
	notification_lcdproc.c notification_lcdproc.h \
	notification_trayicon.c notification_trayicon.h \
	notification_indicator.c notification_indicator.h \
	notification_hotkeys.c notification_hotkeys.h \
	notification_prefs.c notification_prefs.h \
	notification_foldercheck.c notification_foldercheck.h \
	notification_pixbuf.c notification_pixbuf.h \
	raw_claws_mail_logo_64x64.h

notification_plugin_la_LDFLAGS = \
	$(plugin_res_ldflag) $(no_undefined) $(export_symbols) \
	-avoid-version -module

notification_plugin_la_DEPENDENCIES = $(plugin_deps) \
	$(hotkey_lib_path)

INCLUDES = \
	-I$(top_srcdir)/src/plugins/notification/gtkhotkey \
	-I$(top_srcdir)/src \
	-I$(top_srcdir)/src/common \
	-I$(top_srcdir)/src/gtk


notification_plugin_la_LIBADD = $(plugin_ldadd) $(cygwin_export_lib) \
        $(GTK_LIBS)  \
	$(libnotify_LIBS) \
	$(libindicate_LIBS) \
	$(libcanberra_gtk_LIBS) \
	$(hotkey_lib_path)

notification_plugin_la_CPPFLAGS = \
	$(NOTIFY_CFLAGS) \
	$(CLAWS_MAIL_CFLAGS) \
	$(GLIB_CFLAGS) \
	$(GTK_CFLAGS) \
	-DLOCALEDIR=\""$(localedir)"\" \
	$(libnotify_CFLAGS) \
	$(libindicate_CFLAGS) \
	$(libcanberra_gtk_CFLAGS)

clean-local:
	rm -f libclaws.a

--- NEW FILE: notification_plugin.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "pluginconfig.h"

#include "common/claws.h"
#include "common/version.h"
#include "common/utils.h"
#include "common/defs.h"
#include "folder.h"
#include "common/hooks.h"
#include "procmsg.h"
#include "mainwindow.h"
#include "main.h"
#include "gtk/gtkutils.h"

#include "notification_plugin.h"
#include "notification_core.h"
#include "notification_prefs.h"
#include "notification_banner.h"
#include "notification_lcdproc.h"
#include "notification_trayicon.h"
#include "notification_indicator.h"
#include "notification_hotkeys.h"
#include "notification_foldercheck.h"
#include "notification_pixbuf.h"
#include "plugin.h"

#if HAVE_LIBNOTIFY
#  include <libnotify/notify.h>
#endif


static gboolean my_folder_item_update_hook(gpointer, gpointer);
static gboolean my_folder_update_hook(gpointer, gpointer);
static gboolean my_msginfo_update_hook(gpointer, gpointer);
static gboolean my_offline_switch_hook(gpointer, gpointer);
static gboolean my_main_window_close_hook(gpointer, gpointer);
static gboolean my_main_window_got_iconified_hook(gpointer, gpointer);
static gboolean my_account_list_changed_hook(gpointer, gpointer);
static gboolean my_update_theme_hook(gpointer, gpointer);

#ifdef NOTIFICATION_TRAYICON
static gboolean trayicon_startup_idle(gpointer);
#endif

static guint hook_f_item;
static guint hook_f;
static guint hook_m_info;
static guint hook_offline;
static guint hook_mw_close;
static guint hook_got_iconified;
static guint hook_account;
static guint hook_theme_changed;

#ifdef NOTIFICATION_BANNER
static GSList* banner_collected_msgs;
#endif

void notification_update_urgency_hint(void)
{
  MainWindow *mainwin;
  mainwin = mainwindow_get_mainwindow();
  if(mainwin) {
    NotificationMsgCount count;
    gboolean active;
    active = FALSE;
    if(notify_config.urgency_hint_new || notify_config.urgency_hint_unread) {
      notification_core_get_msg_count(NULL, &count);
      if(notify_config.urgency_hint_new)
        active = (active || (count.new_msgs > 0));
      if(notify_config.urgency_hint_unread)
        active = (active || (count.unread_msgs > 0));
    }
    gtk_window_set_urgency_hint(GTK_WINDOW(mainwin->window), active);
  }
}

static gboolean my_account_list_changed_hook(gpointer source,
					     gpointer data)
{
  gboolean retVal = FALSE;

#ifdef NOTIFICATION_TRAYICON
  notification_update_msg_counts(NULL);
  retVal = notification_trayicon_account_list_changed(source, data);

#endif
  return retVal;
}

static gboolean my_update_theme_hook(gpointer source, gpointer data)
{
  notification_pixbuf_free_all();
#ifdef NOTIFICATION_TRAYICON
  notification_update_trayicon();
#endif
  return FALSE;
}

static gboolean my_main_window_got_iconified_hook(gpointer source,
						  gpointer data)
{
  gboolean retVal = FALSE;
#ifdef NOTIFICATION_TRAYICON
  notification_update_msg_counts(NULL);
  retVal = notification_trayicon_main_window_got_iconified(source, data);
#endif
  return retVal;
}

static gboolean my_main_window_close_hook(gpointer source, gpointer data)
{
  gboolean retVal = FALSE;
#ifdef NOTIFICATION_TRAYICON
  notification_update_msg_counts(NULL);
  retVal = notification_trayicon_main_window_close(source, data);
#endif
  return retVal;
}

static gboolean my_offline_switch_hook(gpointer source, gpointer data)
{
#ifdef NOTIFICATION_TRAYICON
  notification_update_msg_counts(NULL);
#endif
  return FALSE;
}

static gboolean my_folder_item_update_hook(gpointer source, gpointer data)
{
  FolderItemUpdateData *update_data = source;
  FolderType ftype;
  gchar *uistr;

  g_return_val_if_fail(source != NULL, FALSE);

#if defined(NOTIFICATION_LCDPROC) || defined(NOTIFICATION_TRAYICON) || defined(NOTIFICATION_INDICATOR)
    notification_update_msg_counts(NULL);
#else
    if(notify_config.urgency_hint)
    	notification_update_msg_counts(NULL);
#endif

  /* Check if the folder types is to be notified about */
  ftype = update_data->item->folder->klass->type;
  uistr = update_data->item->folder->klass->uistr;
  if(!notify_include_folder_type(ftype, uistr))
    return FALSE;

  if(update_data->update_flags & F_ITEM_UPDATE_MSGCNT) {
#ifdef NOTIFICATION_BANNER
    notification_update_banner();
#endif
#if defined(NOTIFICATION_POPUP) || defined(NOTIFICATION_COMMAND)
    notification_new_unnotified_msgs(update_data);
#endif
  }
  return FALSE;
}

static gboolean my_folder_update_hook(gpointer source, gpointer data)
{
  FolderUpdateData *hookdata;

  g_return_val_if_fail(source != NULL, FALSE);
  hookdata = source;

#if defined(NOTIFICATION_LCDPROC) || defined(NOTIFICATION_TRAYICON)
  if(hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM)
    notification_update_msg_counts(hookdata->item);
  else
    notification_update_msg_counts(NULL);
#endif

  return FALSE;

}


static gboolean my_msginfo_update_hook(gpointer source, gpointer data)
{
  return notification_notified_hash_msginfo_update((MsgInfoUpdate*)source);
}

gint plugin_init(gchar **error)
{
  gchar *rcpath;

  /* Version check */
  /* No be able to test against new-contacts */
  if(!check_plugin_version(MAKE_NUMERIC_VERSION(3,8,1,46),
			   VERSION_NUMERIC, _("Notification"), error))
    return -1;

  /* Check if threading is enabled */
  if(!g_thread_supported()) {
    *error = g_strdup(_("The Notification plugin needs threading support."));
    return -1;
  }

  hook_f_item = hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST,
				    my_folder_item_update_hook, NULL);
  if(hook_f_item == (guint) -1) {
    *error = g_strdup(_("Failed to register folder item update hook in the "
			"Notification plugin"));
    return -1;
  }

  hook_f = hooks_register_hook(FOLDER_UPDATE_HOOKLIST,
			       my_folder_update_hook, NULL);
  if(hook_f == (guint) -1) {
    *error = g_strdup(_("Failed to register folder update hook in the "
			"Notification plugin"));
    hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
    return -1;
  }


  hook_m_info = hooks_register_hook(MSGINFO_UPDATE_HOOKLIST,
				    my_msginfo_update_hook, NULL);
  if(hook_m_info == (guint) -1) {
    *error = g_strdup(_("Failed to register msginfo update hook in the "
			"Notification plugin"));
    hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
    hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
    return -1;
  }

  hook_offline = hooks_register_hook(OFFLINE_SWITCH_HOOKLIST,
				     my_offline_switch_hook, NULL);
  if(hook_offline == (guint) -1) {
    *error = g_strdup(_("Failed to register offline switch hook in the "
			"Notification plugin"));
    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);
    return -1;
  }

  hook_mw_close = hooks_register_hook(MAIN_WINDOW_CLOSE,
				      my_main_window_close_hook, NULL);
  if(hook_mw_close == (guint) -1) {
    *error = g_strdup(_("Failed to register main window close hook in the "
			"Notification plugin"));
    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);
    return -1;
  }

  hook_got_iconified = hooks_register_hook(MAIN_WINDOW_GOT_ICONIFIED,
					   my_main_window_got_iconified_hook,
					   NULL);
  if(hook_got_iconified == (guint) -1) {
    *error = g_strdup(_("Failed to register got iconified hook in the "
			"Notification plugin"));
    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);
    return -1;
  }

  hook_account = hooks_register_hook(ACCOUNT_LIST_CHANGED_HOOKLIST,
				     my_account_list_changed_hook, NULL);
  if (hook_account == (guint) -1) {
    *error = g_strdup(_("Failed to register account list changed hook in the "
			"Notification plugin"));
    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);
    return -1;
  }

  hook_theme_changed = hooks_register_hook(THEME_CHANGED_HOOKLIST, my_update_theme_hook, NULL);
  if(hook_theme_changed == (guint)-1) {
    *error = g_strdup(_("Failed to register theme change hook int the "
      "Notification plugin"));
    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);
    return -1;
  }

  /* Configuration */
  prefs_set_default(notify_param);
  rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
  prefs_read_config(notify_param, "NotificationPlugin", rcpath, NULL);
  g_free(rcpath);

  /* Folder specific stuff */
  notification_foldercheck_read_array();

  notification_notified_hash_startup_init();

  notify_gtk_init();

#ifdef NOTIFICATION_BANNER
  notification_update_banner();
#endif
#ifdef NOTIFICATION_LCDPROC
  notification_lcdproc_connect();
#endif
#ifdef NOTIFICATION_TRAYICON
  if(notify_config.trayicon_enabled &&
		 notify_config.trayicon_hide_at_startup && claws_is_starting()) {
    MainWindow *mainwin = mainwindow_get_mainwindow();

		g_idle_add(trayicon_startup_idle,NULL);
    if(mainwin && gtk_widget_get_visible(GTK_WIDGET(mainwin->window)))
      main_window_hide(mainwin);
    main_set_show_at_startup(FALSE);
  }
#endif
  my_account_list_changed_hook(NULL,NULL);

  if(notify_config.urgency_hint_new || notify_config.urgency_hint_unread)
	notification_update_msg_counts(NULL);

#ifdef NOTIFICATION_HOTKEYS
  notification_hotkeys_update_bindings();
#endif

  debug_print("Notification plugin loaded\n");

  return 0;
}

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;
}

const gchar *plugin_name(void)
{
  return _("Notification");
}

const gchar *plugin_desc(void)
{
  return _("This plugin provides various ways "
    "to notify the user of new and unread email.\n"
    "The plugin is extensively configurable in the "
    "plugins section of the preferences dialog.\n\n"
    "Feedback to <berndth at gmx.de> is welcome.");
}

const gchar *plugin_type(void)
{
  return "GTK2";
}

const gchar *plugin_licence(void)
{
  return "GPL3+";
}

const gchar *plugin_version(void)
{
  return VERSION;
}

struct PluginFeature *plugin_provides(void)
{
  static struct PluginFeature features[] =
    { {PLUGIN_NOTIFIER, N_("Various tools")},
      {PLUGIN_NOTHING, NULL}};
  return features;
}

#ifdef NOTIFICATION_BANNER
void notification_update_banner(void)
{
  notification_collected_msgs_free(banner_collected_msgs);
  banner_collected_msgs = NULL;

  if(notify_config.banner_show != NOTIFY_BANNER_SHOW_NEVER) {
    guint id;
    GSList *folder_list = NULL;

    if(notify_config.banner_folder_specific) {
      id = notification_register_folder_specific_list
				(BANNER_SPECIFIC_FOLDER_ID_STR);
      folder_list = notification_foldercheck_get_list(id);
    }

    if(!(notify_config.banner_folder_specific && (folder_list == NULL)))
      banner_collected_msgs =
				notification_collect_msgs(notify_config.banner_include_unread,
																	notify_config.banner_folder_specific ?
																	folder_list : NULL, notify_config.banner_max_msgs);
  }

  notification_banner_show(banner_collected_msgs);
}
#endif

#ifdef NOTIFICATION_TRAYICON
static gboolean trayicon_startup_idle(gpointer data)
{
	/* if the trayicon is not available,
		 simulate click on it to show mainwindow */
	if(!notification_trayicon_is_available())
		notification_trayicon_on_activate(NULL,data);
	return FALSE;
}
#endif

--- NEW FILE: notification_indicator.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2009 Holger Berndt and the Claws Mail Team.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "pluginconfig.h"

#ifdef NOTIFICATION_INDICATOR

#include "notification_indicator.h"
#include "notification_prefs.h"
#include "notification_core.h"

#include "folder.h"
#include "common/utils.h"

#include <libindicate/server.h>
#include <libindicate/indicator.h>
#include <libindicate/indicator-messages.h>

static IndicateServer *server = NULL;
static GHashTable *indicators = NULL;
static gulong mainwin_state_changed_signal_id = 0;

void notification_indicator_destroy(void)
{
  if(indicators) {
    g_hash_table_destroy(indicators);
    indicators = NULL;
  }
  if(server) {
    indicate_server_hide(server);
    g_object_unref(server);
    server = NULL;
  }
  if(mainwin_state_changed_signal_id != 0) {
    MainWindow *mainwin;
    if((mainwin = mainwindow_get_mainwindow()) != NULL)
      g_signal_handler_disconnect(mainwin->window, mainwin_state_changed_signal_id);
    mainwin_state_changed_signal_id = 0;
  }

}

static void show_claws_mail(IndicateIndicator *indicator, guint dummy, gpointer data)
{
  MainWindow *mainwin;

  if((mainwin = mainwindow_get_mainwindow()) == NULL)
    return;

  notification_show_mainwindow(mainwin);
  if(data) {
    Folder *folder = data;
    FolderItem *item = folder->inbox;

    gchar *path = folder_item_get_identifier(item);
    mainwindow_jump_to(path, FALSE);
    g_free(path);
  }
}

static void set_indicator_unread_count(IndicateIndicator *indicator, gint new, gint unread)
{
  gchar *count_str;

  count_str = g_strdup_printf("%d / %d", new, unread);
  indicate_indicator_set_property(indicator, INDICATE_INDICATOR_MESSAGES_PROP_COUNT, count_str);
  g_free(count_str);
}

static void create_indicators(void)
{
  IndicateIndicator *indicator;
  GList *cur_mb;

  indicators = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);

  for(cur_mb = folder_get_list(); cur_mb; cur_mb = cur_mb->next) {
    gchar *name;
    Folder *folder = cur_mb->data;

    if(!folder->name) {
      debug_print("Notification plugin: Warning: Ignoring unnamed mailbox in indicator applet\n");
      continue;
    }
    name = g_strdup(folder->name);

    indicator = indicate_indicator_new();
    indicate_indicator_set_property(indicator, INDICATE_INDICATOR_MESSAGES_PROP_NAME, name);
    set_indicator_unread_count(indicator, 0, 0);
    g_object_set_data(G_OBJECT(indicator), "new_msgs", GINT_TO_POINTER(0));
    g_object_set_data(G_OBJECT(indicator), "unread_msgs", GINT_TO_POINTER(0));
    g_signal_connect(indicator, "user-display", G_CALLBACK (show_claws_mail), folder);
    indicate_indicator_show(indicator);
    g_hash_table_insert(indicators, name, indicator);
  }
}

static gboolean mainwin_state_event(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data)
{
  if(notify_config.indicator_hide_minimized) {
    MainWindow *mainwin;

    if((mainwin = mainwindow_get_mainwindow()) == NULL)
      return FALSE;

    if((event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && (event->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
      gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mainwin->window), TRUE);
    }
    else if((event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && !(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
      gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mainwin->window), FALSE);
    }
  }
  return FALSE;
}

void notification_update_indicator(void)
{
  GHashTableIter iter;
  gpointer key, value;

  if(!mainwin_state_changed_signal_id) {
    MainWindow *mainwin;

    if((mainwin = mainwindow_get_mainwindow()) != NULL)
      mainwin_state_changed_signal_id = g_signal_connect(G_OBJECT(mainwin->window), "window-state-event", G_CALLBACK(mainwin_state_event), NULL);
  }


  if(!notify_config.indicator_enabled)
    return;

  if(!server) {
    server = indicate_server_ref_default();
    indicate_server_set_type (server, "message.mail");
    indicate_server_set_desktop_file(server, get_desktop_file());
    g_signal_connect(server, "server-display", G_CALLBACK(show_claws_mail), NULL);
    indicate_server_show(server);
  }

  if(!indicators)
    create_indicators();

  /* check accounts for new/unread counts */
  g_hash_table_iter_init(&iter, indicators);
  while(g_hash_table_iter_next(&iter, &key, &value)) {
    NotificationMsgCount count;
    gchar *foldername = key;
    IndicateIndicator *indicator = value;

    notification_core_get_msg_count_of_foldername(foldername, &count);

    set_indicator_unread_count(indicator, count.new_msgs, count.unread_msgs);
    indicate_indicator_set_property(indicator, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION,
                                    (count.new_msgs > 0) ? "true" : "false");
    g_object_set_data(G_OBJECT(indicator), "new_msgs", GINT_TO_POINTER(count.new_msgs));
    g_object_set_data(G_OBJECT(indicator), "unread_msgs", GINT_TO_POINTER(count.unread_msgs));
  }
}

#endif /* NOTIFICATION_INDICATOR */

--- NEW FILE: plugin.def ---
EXPORTS
        plugin_desc
        plugin_done
        plugin_init
        plugin_licence
        plugin_name
        plugin_type
	plugin_provides
        plugin_version


--- NEW FILE: notification_plugin.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_PLUGIN_H
#define NOTIFICATION_PLUGIN_H NOTIFICATION_PLUGIN_H

#include "pluginconfig.h"

#ifdef NOTIFICATION_BANNER
void notification_update_banner(void);
#endif

void notification_update_urgency_hint(void);

#endif /* NOTIFICATION_PLUGIN_H */

--- NEW FILE: notification_indicator.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2009 Holger Berndt and the Claws Mail Team.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_INDICATOR_H
#define NOTIFICATION_INDICATOR_H NOTIFICATION_INDICATOR_H

#include "pluginconfig.h"

#ifdef NOTIFICATION_INDICATOR

#include <glib.h>

void notification_update_indicator(void);
void notification_indicator_destroy(void);

#endif /* NOTIFICATION_INDICATOR */
#endif /* NOTIFICATION_INDICATOR_H */

--- NEW FILE: notification_trayicon.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt and the Claws Mail Team.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/* This module is of course inspired by the trayicon plugin which is
 * shipped with Claws-Mail, copyrighted by the Claws-Mail Team. */

#include "pluginconfig.h"

#ifdef NOTIFICATION_TRAYICON

#include "notification_trayicon.h"
#include "notification_prefs.h"
#include "notification_core.h"
#include "notification_hotkeys.h"
#include "notification_pixbuf.h"
#include "notification_foldercheck.h"

#include "main.h"
#include "account.h"
#include "mainwindow.h"
#include "prefs_common.h"
#include "alertpanel.h"
#include "gtk/menu.h"
#ifndef USE_NEW_ADDRBOOK
    #include "addressbook.h"
    #include "addrindex.h"
#else
    #include "addressbook-dbus.h"
#endif

#include "gtk/manage_window.h"
#include "common/utils.h"
#include "gtk/gtkutils.h"

static GdkPixbuf* notification_trayicon_create(void);

static void notification_trayicon_on_popup_menu(GtkStatusIcon*,guint,
						guint,gpointer);
static gboolean notification_trayicon_on_size_changed(GtkStatusIcon*,
						      gint, gpointer);

static void trayicon_get_all_cb(GtkAction*, gpointer);
static void trayicon_compose_cb(GtkAction*, gpointer);
static void trayicon_compose_acc_cb(GtkMenuItem*, gpointer);
static void trayicon_addressbook_cb(GtkAction*, gpointer);
static void trayicon_exit_cb(GtkAction*,gpointer);
static void trayicon_toggle_offline_cb(GtkAction*,gpointer);
#ifdef HAVE_LIBNOTIFY
static void trayicon_toggle_notify_cb(GtkAction*,gpointer);
#endif

#ifdef HAVE_LIBNOTIFY
#include <libnotify/notify.h>

#ifndef NOTIFY_CHECK_VERSION
# define NOTIFY_CHECK_VERSION(a,b,c) 0
#endif

typedef struct {
  gint count;
  gint num_mail;
  gint num_news;
  gint num_calendar;
  gint num_rss;
  gchar *msg_path;
  NotifyNotification *notification;
  GError *error;
} NotificationTrayiconPopup;

static NotificationTrayiconPopup popup;

static gboolean notification_trayicon_popup_add_msg(MsgInfo*,
						    NotificationFolderType);
static gboolean notification_trayicon_popup_create(MsgInfo*,
						   NotificationFolderType);
static void popup_timeout_fun(NotifyNotification*, gpointer);
static void notification_trayicon_popup_free_func(gpointer);
static void notification_trayicon_popup_default_action_cb(NotifyNotification*,
							  const char*,void*);
static gchar* notification_trayicon_popup_assemble_summary(void);
static gchar* notification_trayicon_popup_assemble_body(MsgInfo*);
static void   notification_trayicon_popup_count_msgs(NotificationFolderType);

G_LOCK_DEFINE_STATIC(trayicon_popup);

#endif

static GtkStatusIcon *trayicon;
static gboolean updating_menu = FALSE;
static GtkWidget *traymenu_popup;

static GtkActionEntry trayicon_popup_menu_entries[] = {
	{"SysTrayiconPopup", NULL, "SysTrayiconPopup" },
	{"SysTrayiconPopup/GetMail", NULL, N_("_Get Mail"), NULL, NULL, G_CALLBACK(trayicon_get_all_cb) },
	{"SysTrayiconPopup/---", NULL, "---" },
	{"SysTrayiconPopup/Email", NULL, N_("_Email"), NULL, NULL, G_CALLBACK(trayicon_compose_cb) },
	{"SysTrayiconPopup/EmailAcc", NULL, N_("E_mail from account"), NULL, NULL, NULL },
	{"SysTrayiconPopup/OpenAB", NULL, N_("Open A_ddressbook"), NULL, NULL, G_CALLBACK(trayicon_addressbook_cb) },
	{"SysTrayiconPopup/Exit", NULL, N_("E_xit Claws Mail"), NULL, NULL, G_CALLBACK(trayicon_exit_cb) },
};

static GtkToggleActionEntry trayicon_popup_toggle_menu_entries[] =
{
	{"SysTrayiconPopup/ToggleOffline",		NULL, N_("_Work Offline"), NULL, NULL, G_CALLBACK(trayicon_toggle_offline_cb) },
#ifdef HAVE_LIBNOTIFY
	{"SysTrayiconPopup/ShowBubbles", NULL, N_("Show Trayicon Notifications"), NULL, NULL, G_CALLBACK(trayicon_toggle_notify_cb) },
#endif
};


void notification_trayicon_msg(MsgInfo *msginfo)
{
#ifndef HAVE_LIBNOTIFY
  return;

#else
  FolderType ftype;
  NotificationFolderType nftype;
  gchar *uistr;

  nftype = F_TYPE_MAIL;

  if(!msginfo || !notify_config.trayicon_enabled ||
     !notify_config.trayicon_popup_enabled ||
     !MSG_IS_NEW(msginfo->flags))
    return;

  if(notify_config.trayicon_folder_specific) {
    guint id;
    GSList *list;
    gchar *identifier;
    gboolean found = FALSE;

    if(!(msginfo->folder))
      return;

    identifier = folder_item_get_identifier(msginfo->folder);

    id =
      notification_register_folder_specific_list
      (TRAYICON_SPECIFIC_FOLDER_ID_STR);
    list = notification_foldercheck_get_list(id);
    for(; (list != NULL) && !found; list = g_slist_next(list)) {
      gchar *list_identifier;
      FolderItem *list_item = (FolderItem*) list->data;

      list_identifier = folder_item_get_identifier(list_item);
      if(!strcmp2(list_identifier, identifier))
	found = TRUE;

      g_free(list_identifier);
    }
    g_free(identifier);

    if(!found)
      return;
  } /* folder specific */

  ftype = msginfo->folder->folder->klass->type;

  G_LOCK(trayicon_popup);
  /* Check out which type to notify about */
  switch(ftype) {
  case F_MH:
  case F_MBOX:
  case F_MAILDIR:
  case F_IMAP:
    nftype = F_TYPE_MAIL;
    break;
  case F_NEWS:
    nftype = F_TYPE_NEWS;
    break;
  case F_UNKNOWN:
    if((uistr = msginfo->folder->folder->klass->uistr) == NULL) {
      G_UNLOCK(trayicon_popup);
      return;
    }
    else if(!strcmp(uistr, "vCalendar"))
      nftype = F_TYPE_CALENDAR;
    else if(!strcmp(uistr, "RSSyl"))
      nftype = F_TYPE_RSS;
    else {
      debug_print("Notification Plugin: Unknown folder type %d\n",ftype);
      G_UNLOCK(trayicon_popup);
      return;
    }
    break;
  default:
    debug_print("Notification Plugin: Unknown folder type %d\n",ftype);
    G_UNLOCK(trayicon_popup);
    return;
  }


  notification_trayicon_popup_add_msg(msginfo, nftype);

  G_UNLOCK(trayicon_popup);

#endif /* HAVE_LIBNOTIFY */
}

void notification_trayicon_destroy(void)
{
  if(trayicon) {
    gtk_status_icon_set_visible(trayicon, FALSE);
    g_object_unref(trayicon);
    trayicon = NULL;
  }
}

void notification_update_trayicon()
{
  gchar *buf;
  static GdkPixbuf *old_icon = NULL;
  GdkPixbuf *new_icon;
  gint offset;
  NotificationMsgCount count;
  GSList *list;

  if(!notify_config.trayicon_enabled)
    return;

  if(notify_config.trayicon_folder_specific) {
    guint id;
    id =
      notification_register_folder_specific_list
      (TRAYICON_SPECIFIC_FOLDER_ID_STR);
    list = notification_foldercheck_get_list(id);
  }
  else
    list = NULL;

  notification_core_get_msg_count(list, &count);

  if(!trayicon) {

#ifdef NOTIFICATION_HOTKEYS
    notification_hotkeys_update_bindings();
#endif

    old_icon = notification_trayicon_create();
    if(!trayicon) {
      debug_print("Notification plugin: Could not create trayicon\n");
      return;
    }
  }

  /* Tooltip */
  buf = g_strdup_printf(_("New %d, Unread: %d, Total: %d"),
			count.new_msgs, count.unread_msgs,
			count.total_msgs);
#if GTK_CHECK_VERSION(2,16,0)
  gtk_status_icon_set_tooltip_text(trayicon, buf);
#else
  gtk_status_icon_set_tooltip(trayicon, buf);
#endif
  g_free(buf);

  /* Pixmap */
  (prefs_common_get_prefs()->work_offline) ? (offset = 1) : (offset = 0);

  if((count.new_msgs > 0) && (count.unreadmarked_msgs > 0))
    new_icon =
      notification_pixbuf_get(NOTIFICATION_TRAYICON_NEWMARKEDMAIL+offset);
  else if(count.new_msgs > 0)
    new_icon =
      notification_pixbuf_get(NOTIFICATION_TRAYICON_NEWMAIL+offset);
  else if(count.unreadmarked_msgs > 0)
    new_icon =
      notification_pixbuf_get(NOTIFICATION_TRAYICON_UNREADMARKEDMAIL+offset);
  else if(count.unread_msgs > 0)
    new_icon =
      notification_pixbuf_get(NOTIFICATION_TRAYICON_UNREADMAIL+offset);
  else
    new_icon =
      notification_pixbuf_get(NOTIFICATION_TRAYICON_NOMAIL+offset);

  if(new_icon != old_icon) {
    gtk_status_icon_set_from_pixbuf(trayicon, new_icon);
    old_icon = new_icon;
  }
}

gboolean notification_trayicon_main_window_close(gpointer source, gpointer data)
{
  if(!notify_config.trayicon_enabled)
    return FALSE;

  if(source) {
    gboolean *close_allowed = (gboolean*)source;

    if(notify_config.trayicon_close_to_tray) {
      MainWindow *mainwin = mainwindow_get_mainwindow();

      *close_allowed = FALSE;
      if(mainwin && gtk_widget_get_visible(GTK_WIDGET(mainwin->window)))
	main_window_hide(mainwin);
    }
  }
  return FALSE;
}

gboolean notification_trayicon_main_window_got_iconified(gpointer source,
							 gpointer data)
{
  MainWindow *mainwin = mainwindow_get_mainwindow();

  if(!notify_config.trayicon_enabled)
    return FALSE;

  if(notify_config.trayicon_hide_when_iconified &&
     mainwin && gtk_widget_get_visible(GTK_WIDGET(mainwin->window))
     && !gtk_window_get_skip_taskbar_hint(GTK_WINDOW(mainwin->window))) {
    gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mainwin->window), TRUE);
  }
  return FALSE;
}

gboolean notification_trayicon_account_list_changed(gpointer source,
						    gpointer data)
{
  GList *cur_ac;
	GtkWidget *menu, *submenu;
  GtkWidget *menuitem;
  PrefsAccount *ac_prefs;

  GList *account_list = account_get_list();

  if(!notify_config.trayicon_enabled)
    return FALSE;

	menu = gtk_ui_manager_get_widget(gtkut_ui_manager(), "/Menus/SysTrayiconPopup/EmailAcc");
	gtk_widget_show(menu);

	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu), NULL);
	submenu = gtk_menu_new();

  for(cur_ac = account_list; cur_ac != NULL; cur_ac = cur_ac->next) {
    ac_prefs = (PrefsAccount *)cur_ac->data;

    menuitem = gtk_menu_item_new_with_label
      (ac_prefs->account_name ? ac_prefs->account_name
       : _("Untitled"));
    gtk_widget_show(menuitem);
		gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
    g_signal_connect(G_OBJECT(menuitem), "activate",
		     G_CALLBACK(trayicon_compose_acc_cb),
		     ac_prefs);
  }
	gtk_widget_show(submenu);
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu), submenu);
  return FALSE;
}

static GdkPixbuf* notification_trayicon_create(void)
{
  GdkPixbuf *trayicon_nomail;
	GtkActionGroup *action_group;

  trayicon_nomail = notification_pixbuf_get(NOTIFICATION_TRAYICON_NOMAIL);

  notification_trayicon_destroy();

  trayicon = gtk_status_icon_new_from_pixbuf(trayicon_nomail);

  g_signal_connect(G_OBJECT(trayicon), "activate",
		   G_CALLBACK(notification_trayicon_on_activate), NULL);
  g_signal_connect(G_OBJECT(trayicon), "popup-menu",
		   G_CALLBACK(notification_trayicon_on_popup_menu), NULL);
  g_signal_connect(G_OBJECT(trayicon), "size-changed",
		   G_CALLBACK(notification_trayicon_on_size_changed), NULL);

  /* Popup-Menu */
	action_group = cm_menu_create_action_group("SysTrayiconPopup", trayicon_popup_menu_entries,
																						 G_N_ELEMENTS(trayicon_popup_menu_entries), NULL);
	gtk_action_group_add_toggle_actions(action_group, trayicon_popup_toggle_menu_entries,
																			G_N_ELEMENTS(trayicon_popup_toggle_menu_entries), NULL);

	MENUITEM_ADDUI("/Menus", "SysTrayiconPopup", "SysTrayiconPopup", GTK_UI_MANAGER_MENU)
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "GetMail", "SysTrayiconPopup/GetMail", GTK_UI_MANAGER_MENUITEM)
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Separator1", "SysTrayiconPopup/---", GTK_UI_MANAGER_SEPARATOR)
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Email", "SysTrayiconPopup/Email", GTK_UI_MANAGER_MENUITEM)
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "EmailAcc", "SysTrayiconPopup/EmailAcc", GTK_UI_MANAGER_MENU)
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Separator2", "SysTrayiconPopup/---", GTK_UI_MANAGER_SEPARATOR)
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "OpenAB", "SysTrayiconPopup/OpenAB", GTK_UI_MANAGER_MENUITEM)
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Separator3", "SysTrayiconPopup/---", GTK_UI_MANAGER_SEPARATOR)
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "ToggleOffline", "SysTrayiconPopup/ToggleOffline", GTK_UI_MANAGER_MENUITEM)
#ifdef HAVE_LIBNOTIFY
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "ShowBubbles", "SysTrayiconPopup/ShowBubbles", GTK_UI_MANAGER_MENUITEM)
#endif
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Separator4", "SysTrayiconPopup/---", GTK_UI_MANAGER_SEPARATOR)
	MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Exit", "SysTrayiconPopup/Exit", GTK_UI_MANAGER_MENUITEM)

	traymenu_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
				gtk_ui_manager_get_widget(gtkut_ui_manager(), "/Menus/SysTrayiconPopup")));


  return trayicon_nomail;
}

void notification_trayicon_on_activate(GtkStatusIcon *status_icon, gpointer user_data)
{
  notification_toggle_hide_show_window();
}

static void notification_trayicon_on_popup_menu(GtkStatusIcon *status_icon,
						guint button, guint activate_time,
						gpointer user_data)
{
  MainWindow *mainwin = mainwindow_get_mainwindow();

  if(!mainwin)
    return;

  /* tell callbacks to skip any event */
  updating_menu = TRUE;
  /* initialize checkitems according to current states */
	cm_toggle_menu_set_active("SysTrayiconPopup/ToggleOffline", prefs_common_get_prefs()->work_offline);
#ifdef HAVE_LIBNOTIFY
	cm_toggle_menu_set_active("SysTrayiconPopup/ShowBubbles", notify_config.trayicon_popup_enabled);
#endif
	cm_menu_set_sensitive("SysTrayiconPopup/GetMail", mainwin->lock_count == 0);

  updating_menu = FALSE;

#ifndef G_OS_WIN32
  gtk_menu_popup(GTK_MENU(traymenu_popup), NULL, NULL, NULL, NULL,
		 button, activate_time);
#else
  /* http://bugzilla.gnome.org/show_bug.cgi?id=552642 */
  gtk_menu_popup(GTK_MENU(traymenu_popup), NULL, NULL, NULL, NULL,
		 0, activate_time);
#endif
}

static gboolean notification_trayicon_on_size_changed(GtkStatusIcon *icon,
						      gint size,
						      gpointer user_data)
{
  notification_update_msg_counts(NULL);
  return FALSE;
}

/* popup menu callbacks */
static void trayicon_get_all_cb(GtkAction *action, gpointer data)
{
  MainWindow *mainwin = mainwindow_get_mainwindow();
  inc_all_account_mail_cb(mainwin, 0, NULL);
}

static void trayicon_compose_cb(GtkAction *action, gpointer data)
{
  MainWindow *mainwin = mainwindow_get_mainwindow();
  compose_mail_cb(mainwin, 0, NULL);
}

static void trayicon_compose_acc_cb(GtkMenuItem *menuitem, gpointer data)
{
  compose_new((PrefsAccount *)data, NULL, NULL);
}

static void trayicon_addressbook_cb(GtkAction *action, gpointer data)
{
#ifndef USE_NEW_ADDRBOOK
    addressbook_open(NULL);
#else
    GError* error = NULL;

    addressbook_dbus_open(FALSE, &error);
    if (error) {
	g_warning("%s", error->message);
	g_error_free(error);
    }
#endif
}

static void trayicon_toggle_offline_cb(GtkAction *action, gpointer data)
{
  /* toggle offline mode if menu checkitem has been clicked */
  if(!updating_menu) {
    MainWindow *mainwin = mainwindow_get_mainwindow();
    main_window_toggle_work_offline(mainwin, !prefs_common_get_prefs()->work_offline, TRUE);
  }
}

#ifdef HAVE_LIBNOTIFY
static void trayicon_toggle_notify_cb(GtkAction *action, gpointer data)
{
  if(!updating_menu) {
    notify_config.trayicon_popup_enabled = !notify_config.trayicon_popup_enabled;
  }
}
#endif

static void app_exit_cb(MainWindow *mainwin, guint action, GtkWidget *widget)
{
  if(prefs_common_get_prefs()->confirm_on_exit) {
    if(alertpanel(_("Exit"), _("Exit Claws Mail?"),
		  GTK_STOCK_CANCEL, GTK_STOCK_OK,
		  NULL) != G_ALERTALTERNATE) {
      return;
    }
    manage_window_focus_in(mainwin->window, NULL, NULL);
  }

  if (prefs_common_get_prefs()->clean_on_exit) {
    if (!main_window_empty_trash(mainwin, prefs_common_get_prefs()->ask_on_clean, TRUE))
      return;
  }

  app_will_exit(NULL, mainwin);
}

static void trayicon_exit_cb(GtkAction *action, gpointer data)
{
  MainWindow *mainwin = mainwindow_get_mainwindow();

  if(mainwin->lock_count == 0) {
    app_exit_cb(mainwin, 0, NULL);
  }
}

#ifdef HAVE_LIBNOTIFY
static gboolean notification_trayicon_popup_add_msg(MsgInfo *msginfo,
						    NotificationFolderType nftype)
{
  gchar *summary;
  gchar *utf8_str;
  gboolean retval;
  GdkPixbuf *pixbuf;

  g_return_val_if_fail(msginfo, FALSE);

  if(!popup.notification)
    return notification_trayicon_popup_create(msginfo,nftype);

  /* Count messages */
  notification_trayicon_popup_count_msgs(nftype);

  if(popup.msg_path) {
    g_free(popup.msg_path);
    popup.msg_path = NULL;
  }

  summary  = notification_trayicon_popup_assemble_summary();
  utf8_str = notification_trayicon_popup_assemble_body(msginfo);

  /* make sure we show a logo on many msg arrival */
  pixbuf = notification_pixbuf_get(NOTIFICATION_CM_LOGO_64x64);
  if(pixbuf)
    notify_notification_set_icon_from_pixbuf(popup.notification, pixbuf);

  retval = notify_notification_update(popup.notification, summary,
				      utf8_str, NULL);
  g_free(summary);
  g_free(utf8_str);
  if(!retval) {
    debug_print("Notification Plugin: Failed to update notification.\n");
    return FALSE;
  }
  /* Show the popup */
  notify_notification_set_hint_string(popup.notification, "desktop-entry", "claws-mail");
  if(!notify_notification_show(popup.notification, &(popup.error))) {
    debug_print("Notification Plugin: Failed to send updated notification: "
		"%s\n",	popup.error->message);
    g_clear_error(&(popup.error));
    return FALSE;
  }

  debug_print("Notification Plugin: Popup successfully modified "
	      "with libnotify.\n");

  return TRUE;
}

static gboolean notification_trayicon_popup_create(MsgInfo *msginfo,
						   NotificationFolderType nftype)
{
  gchar *summary = NULL;
  gchar *utf8_str = NULL;
  GdkPixbuf *pixbuf;
  GList *caps = NULL;
  gboolean support_actions = FALSE;

  /* init libnotify if necessary */
  if(!notify_is_initted()) {
    if(!notify_init("claws-mail")) {
      debug_print("Notification Plugin: Failed to initialize libnotify. "
		  "No popups will be shown.\n");
      return FALSE;
    }
  }

  /* Count messages */
  notification_trayicon_popup_count_msgs(nftype);

  summary  = notification_trayicon_popup_assemble_summary();
  utf8_str = notification_trayicon_popup_assemble_body(msginfo);

#if NOTIFY_CHECK_VERSION(0, 7, 0)
  popup.notification = notify_notification_new(summary, utf8_str, NULL);
#else
  popup.notification = notify_notification_new(summary, utf8_str, NULL, NULL);
  notify_notification_attach_to_status_icon(popup.notification, trayicon);
#endif

  g_free(summary);
  g_free(utf8_str);

  caps = notify_get_server_caps();
    if(caps != NULL) {
      GList *c;
      for(c = caps; c != NULL; c = c->next) {
	if(strcmp((char*)c->data, "actions") == 0 ) {
	  support_actions = TRUE;
	  break;
        }
      }

    g_list_foreach(caps, (GFunc)g_free, NULL);
    g_list_free(caps);
  }

  /* Default action */
  if (support_actions)
    notify_notification_add_action(popup.notification,
				   "default", "Present main window",
				   (NotifyActionCallback)
				   notification_trayicon_popup_default_action_cb,
				   GINT_TO_POINTER(nftype),
				   notification_trayicon_popup_free_func);

  if(popup.notification == NULL) {
    debug_print("Notification Plugin: Failed to create a new notification.\n");
    return FALSE;
  }

  /* Icon */
  pixbuf = NULL;
#ifndef USE_NEW_ADDRBOOK
  if(msginfo && msginfo->from) {
    gchar *icon_path;
    icon_path = addrindex_get_picture_file(msginfo->from);
    if(is_file_exist(icon_path)) {
      GError *error = NULL;
      gint w, h;

      gdk_pixbuf_get_file_info(icon_path, &w, &h);
      if((w > 64) || (h > 64))
	pixbuf = gdk_pixbuf_new_from_file_at_scale(icon_path,
						   64, 64, TRUE, &error);
      else
	pixbuf = gdk_pixbuf_new_from_file(icon_path, &error);

      if(!pixbuf) {
	debug_print("Could not load picture file: %s\n",
		    error ? error->message : "no details");
	g_error_free(error);
      }
    }
    else
      debug_print("Picture path does not exist: %s\n",icon_path);
    g_free(icon_path);
  }
#endif
  if(!pixbuf)
    pixbuf = g_object_ref(notification_pixbuf_get(NOTIFICATION_CM_LOGO_64x64));

  if(pixbuf) {
    notify_notification_set_icon_from_pixbuf(popup.notification, pixbuf);
    g_object_unref(pixbuf);
  }
  else /* This is not fatal */
    debug_print("Notification plugin: Icon could not be loaded.\n");

  /* timeout */
  notify_notification_set_timeout(popup.notification, notify_config.trayicon_popup_timeout);

  /* Category */
  notify_notification_set_category(popup.notification, "email.arrived");

  /* get notified on bubble close */
  g_signal_connect(G_OBJECT(popup.notification), "closed", G_CALLBACK(popup_timeout_fun), NULL);

  /* Show the popup */
  notify_notification_set_hint_string(popup.notification, "desktop-entry", "claws-mail");
  if(!notify_notification_show(popup.notification, &(popup.error))) {
    debug_print("Notification Plugin: Failed to send notification: %s\n",
		popup.error->message);
    g_clear_error(&(popup.error));
    g_object_unref(G_OBJECT(popup.notification));
    popup.notification = NULL;
    return FALSE;
  }

  /* Store path to message */
  if(nftype == F_TYPE_MAIL) {
    if(msginfo->folder && msginfo->folder) {
      gchar *ident;
      ident = folder_item_get_identifier(msginfo->folder);
      popup.msg_path = g_strdup_printf("%s%s%u", ident,G_DIR_SEPARATOR_S,
				       msginfo->msgnum);
      g_free(ident);
    }
    else
      popup.msg_path = NULL;
  }

  debug_print("Notification Plugin: Popup created with libnotify.\n");

  return TRUE;
}

static void popup_timeout_fun(NotifyNotification *nn, gpointer data)
{
  G_LOCK(trayicon_popup);

  g_object_unref(G_OBJECT(popup.notification));

  popup.notification = NULL;
  g_clear_error(&(popup.error));

  popup.count = 0;
  popup.num_mail = 0;
  popup.num_news = 0;
  popup.num_calendar = 0;
  popup.num_rss = 0;

  if(popup.msg_path) {
    g_free(popup.msg_path);
    popup.msg_path = NULL;
  }

  G_UNLOCK(trayicon_popup);
}

static void notification_trayicon_popup_free_func(gpointer data)
{
  if(popup.msg_path) {
    g_free(popup.msg_path);
    popup.msg_path = NULL;
  }

  debug_print("Freed notification data\n");
}

static void notification_trayicon_popup_default_action_cb(NotifyNotification
							  *notification,
							  const char *action,
							  void *user_data)
{
  if(strcmp("default", action))
    return;

  MainWindow *mainwin;
  mainwin = mainwindow_get_mainwindow();
  if(mainwin) {
    NotificationFolderType nftype;

    /* Let mainwindow pop up */
    notification_show_mainwindow(mainwin);
    /* If there is only one new mail message, jump to this message */
    nftype = (NotificationFolderType)GPOINTER_TO_INT(user_data);
    if((popup.count == 1) && (nftype == F_TYPE_MAIL)) {
      gchar *select_str;
      G_LOCK(trayicon_popup);
      select_str = g_strdup(popup.msg_path);
      G_UNLOCK(trayicon_popup);
      debug_print("Notification plugin: Select message %s\n", select_str);
      mainwindow_jump_to(select_str, FALSE);
      g_free(select_str);
    }
  }
}

static void notification_trayicon_popup_count_msgs(NotificationFolderType nftype)
{
  switch(nftype) {
  case F_TYPE_MAIL:
    popup.num_mail++;
    break;
  case F_TYPE_NEWS:
    popup.num_news++;
    break;
  case F_TYPE_CALENDAR:
    popup.num_calendar++;
    break;
  case F_TYPE_RSS:
    popup.num_rss++;
    break;
  default:
    debug_print("Notification plugin: Unknown folder type\n");
    return;
  }
  popup.count++;
}

/* The returned value has to be freed by the caller */
static gchar* notification_trayicon_popup_assemble_summary(void)
{
  gchar *summary = NULL;

  if(popup.count == 1) {
    if(popup.num_mail)
      summary = g_strdup(_("New mail message"));
    else if(popup.num_news)
      summary = g_strdup(_("New news post"));
    else if(popup.num_calendar)
      summary = g_strdup(_("New calendar message"));
    else
      summary = g_strdup(_("New article in RSS feed"));
  } /* One new message */
  else {
    summary = g_strdup(_("New messages arrived"));
  } /* Many new messages */

  return summary;
}

/* The returned value has to be freed by the caller */
static gchar* notification_trayicon_popup_assemble_body(MsgInfo *msginfo)
{
  gchar *utf8_str;

  if(popup.count == 1) {
    if(popup.num_mail || popup.num_news) {
      gchar *from;
      gchar *subj;
      gchar *text;
	  gchar *foldname = NULL;

      from = notification_libnotify_sanitize_str(msginfo->from ?
						 msginfo->from :
						 _("(No From)"));
      subj = notification_libnotify_sanitize_str(msginfo->subject ?
						 msginfo->subject :
						 _("(No Subject)"));
  	if (notify_config.trayicon_display_folder_name) {
        foldname = notification_libnotify_sanitize_str(msginfo->folder->path);
        text = g_strconcat(from,"\n\n", subj, "\n\n", foldname, NULL);
	}
    else
        text = g_strconcat(from, "\n\n",subj, NULL);


      /* Make sure text is valid UTF8 */
      utf8_str = notification_validate_utf8_str(text);
      g_free(text);

      if(from) g_free(from);
      if(subj) g_free(subj);
	  if(foldname) g_free(foldname);
    }
    else if(popup.num_calendar) {
      utf8_str = g_strdup(_("A new calendar message arrived"));
    }
    else {
      utf8_str = g_strdup(_("A new article in a RSS feed arrived"));
    }
  } /* One message */

  else {
    gchar *msg;
    gchar *tmp;
    gboolean str_empty = TRUE;

    utf8_str = g_strdup("");

    if(popup.num_mail) {
      msg = g_strdup_printf(ngettext("%d new mail message arrived",
		      		     "%d new mail messages arrived",
		            popup.num_mail),
			    popup.num_mail);
      tmp = g_strdup_printf("%s%s%s",utf8_str,str_empty?"":"\n",msg);
      g_free(msg);
      g_free(utf8_str);
      utf8_str = tmp;
      str_empty = FALSE;
    }
    if(popup.num_news) {
      msg = g_strdup_printf(ngettext("%d new news post arrived",
		      		     "%d new news posts arrived",
		            popup.num_news),
			    popup.num_news);
      tmp = g_strdup_printf("%s%s%s",utf8_str,str_empty?"":"\n",msg);
      g_free(msg);
      g_free(utf8_str);
      utf8_str = tmp;
      str_empty = FALSE;
    }
    if(popup.num_calendar) {
      msg = g_strdup_printf(ngettext("%d new calendar message arrived",
		      		     "%d new calendar messages arrived",
		            popup.num_calendar),
			    popup.num_calendar);
      tmp = g_strdup_printf("%s%s%s",utf8_str,str_empty?"":"\n",msg);
      g_free(msg);
      g_free(utf8_str);
      utf8_str = tmp;
      str_empty = FALSE;
    }
    if(popup.num_rss) {
      msg = g_strdup_printf(ngettext("%d new article in RSS feeds arrived",
		      		     "%d new articles in RSS feeds arrived",
		            popup.num_rss),
			    popup.num_rss);
      tmp = g_strdup_printf("%s%s%s",utf8_str,str_empty?"":"\n",msg);
      g_free(msg);
      g_free(utf8_str);
      utf8_str = tmp;
      str_empty = FALSE;
    }
  } /* Many messages */

  return utf8_str;
}

#endif /* HAVE_LIBNOTIFY */

gboolean notification_trayicon_is_available(void)
{
	gboolean is_available;
	is_available = FALSE;

	if(trayicon) {
		if(gtk_status_icon_is_embedded(trayicon) &&
			 gtk_status_icon_get_visible(trayicon))
			is_available = TRUE;
	}

	return is_available;
}

#endif /* NOTIFICATION_TRAYICON */

--- NEW FILE: raw_claws_mail_logo_64x64.h ---
/* GdkPixbuf RGBA C-Source image dump */

#ifdef __SUNPRO_C
#pragma align 4 (raw_claws_mail_logo_64x64)
#endif
#ifdef __GNUC__
static const guint8 raw_claws_mail_logo_64x64[] __attribute__ ((__aligned__ (4))) = 
#else
static const guint8 raw_claws_mail_logo_64x64[] = 
#endif
{ ""
  /* Pixbuf magic (0x47646b50) */
  "GdkP"
  /* length: header (24) + pixel_data (16384) */
  "\0\0@\30"
  /* pixdata_type (0x1010002) */
  "\1\1\0\2"
  /* rowstride (256) */
  "\0\0\1\0"
  /* width (64) */
  "\0\0\0@"
  /* height (64) */
  "\0\0\0@"
  /* pixel_data: */
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\1\0\0\0\1\0\0\0\3\0\0\0\5\0\0\0\7\0\0\0\10\0\0\0\10\0\0\0\7\0"
  "\0\0\6\0\0\0\4\0\0\0\2\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0"
  "\0\0\1\0\0\0\3\0\0\0\6\0\0\0\15\0\0\0\27\0\0\0(\0\0\0=\15\30\35W\"@M"
  "w-Sc\2073]n\2226`q\2250Ve\214)IW}\26&-_\4\6\7B\0\0\0+\0\0\0\31\0\0\0"
  "\16\0\0\0\6\0\0\0\2\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\1\0\0\0\2\0\0\0\4\0\0\0\14\0\0\0\31\0\0\0""0\24&.c8g{\244T\215\245"
  "\321s\257\310\362\215\304\333\375\243\321\344\377\261\327\350\377\271"
  "\333\352\377\273\335\352\377\265\331\350\377\252\323\346\377\227\311"
  "\337\376\200\267\316\366b\230\260\335Gw\213\263&@Kv\4\4\4""7\0\0\0\31"
  "\0\0\0\12\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\4\0\0\0\14\0\0"
  "\0\40\0\5\13P\25""7P\242Y\225\255\333\211\302\333\375\265\330\350\377"
  "\321\343\355\377\343\354\362\377\346\354\361\377\353\362\365\377\360"
  "\367\372\377\360\367\372\377\360\367\372\377\360\367\372\377\360\367"
  "\372\377\360\366\372\377\353\364\370\377\336\356\364\377\304\340\355"
  "\377\235\315\340\376o\246\275\351Fr\204\254\20\30\34O\0\0\0\37\0\0\0"
  "\12\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\1\0\0\0\3\0\0\0\10\0\0\0\26\0\2\4C\22""4N\250:g\212\361\236"
  "\304\327\377\311\334\346\377\331\341\350\377\336\344\352\377\336\344"
  "\352\377\336\344\352\377\337\346\353\377\346\356\363\377\345\354\361"
  "\377\344\353\357\377\344\353\357\377\346\357\363\377\352\363\370\377"
  "\353\364\370\377\351\363\367\377\346\355\363\377\352\363\366\377\352"
  "\364\370\377\334\354\364\377\265\332\350\377~\264\314\365Jv\212\263\14"
  "\21\24H\0\0\0\30\0\0\0\7\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\1\0\0\0\4\0\0\0\15\0\0\0-\22)6zCz\227\337\220\271\320\377\316"
  "\340\352\377\325\336\346\377\324\334\344\377\324\334\344\377\324\334"
  "\344\377\324\334\344\377\325\334\344\377\325\335\344\377\326\335\345"
  "\377\326\335\345\377\326\336\345\377\327\336\346\377\327\336\346\377"
  "\330\340\346\377\331\342\350\377\330\337\346\377\330\337\346\377\330"
  "\340\347\377\335\345\354\377\340\352\360\377\344\357\365\377\334\355"
  "\364\377\260\326\346\377r\251\300\3555Tb\214\0\0\0*\0\0\0\13\0\0\0\3"
  "\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\5\0\0\0\21\0\0\0""3\40G_\257i\234"
  "\272\376\242\270\313\377\306\321\334\377\312\324\336\377\312\324\336"
  "\377\312\324\336\377\312\324\336\377\312\324\336\377\313\325\336\377"
  "\314\325\337\377\314\326\337\377\315\326\337\377\315\327\340\377\316"
  "\327\340\377\316\327\340\377\317\330\341\377\317\330\341\377\317\330"
  "\341\377\320\331\341\377\320\331\342\377\320\331\342\377\320\331\342"
  "\377\320\331\342\377\320\331\342\377\326\342\351\377\334\352\361\377"
  "\313\342\354\377\220\303\330\375Q\200\223\276\6\11\12@\0\0\0\22\0\0\0"
  "\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\2\0\0\0\6\0\0\0\27\0\5\12N\13/O\303Sz\234\376\262\301\320"
  "\377\277\314\330\377\277\314\330\377\277\314\330\377\277\314\330\377"
  "\277\314\330\377\277\314\330\377\300\315\330\377\301\315\331\377\302"
  "\316\331\377\303\317\332\377\303\317\332\377\276\312\324\377\266\302"
  "\314\377\302\316\327\377\200\207\216\377\277\313\325\377\307\321\334"
  "\377\307\321\335\377\307\322\335\377\310\322\335\377\306\320\333\377"
  "\310\322\335\377\310\322\335\377\310\322\335\377\310\322\334\377\310"
  "\322\334\377\300\315\331\377\227\273\320\377T\204\235\334\25\37$`\0\0"
  "\0\36\0\0\0\6\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\2\0\0\0\6\0\0\0\27\0\7\16W\17""8`\344j\210\244\377\255\275\315"
  "\377\265\304\322\377\265\304\322\377\265\304\322\377\265\304\322\377"
  "\265\304\322\377\265\304\322\377\266\305\322\377\267\305\323\377\270"
  "\306\324\377\271\307\324\377\270\306\323\377\226\240\253\377\201\213"
  "\224\377py\200\377\267\304\320\377\40\"#\377\216\225\233\377\304\317"
  "\331\377\275\310\325\377\275\310\324\377\237\251\264\377\203\213\224"
  "\377\257\272\306\377\300\314\330\377\300\314\327\377\300\314\327\377"
  "\300\314\330\377\300\313\327\377\274\311\325\377\207\236\263\377T\200"
  "\236\372\32-=\206\0\0\0\33\0\0\0\6\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\2\0\0\0\6\0\0\0\26\0\3\10O\13""2Z\334n\213\247\377\251\272"
  "\313\377\252\274\314\377\252\274\314\377\252\274\314\377\252\274\314"
  "\377\252\273\314\377\252\273\314\377\253\275\314\377\254\275\315\377"
  "\255\276\316\377\256\277\316\377\260\300\317\377\252\271\307\377^fn\377"
  "(,/\377ox\202\377\240\256\272\377!$&\377\26\27\30\377\216\223\230\377"
  "\235\247\257\377dkq\377\32\34\36\377r{\203\377lt{\377\237\253\266\377"
  "\271\307\324\377\270\305\323\377\272\310\326\377\270\305\322\377\267"
  "\305\322\377\267\304\322\377\253\304\325\377[\212\246\362\14\26\36d\0"
  "\0\0\26\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0\24\0\4\10"
  "K\12""1X\333_~\236\377\236\260\304\377\240\263\306\377\240\263\306\377"
  "\240\263\306\377\240\263\306\377\240\263\306\377\240\263\306\377\240"
  "\263\306\377\242\264\307\377\243\265\310\377\244\266\310\377\243\265"
  "\305\377\233\253\273\377\240\260\301\377x\204\220\377\24\26\30\377|\210"
  "\225\377\203\215\231\377\34\36\40\377\0\0\0\377\36\37\37\377ORU\377\3"
  "\3\3\377\16\17\21\377\26\30\31\377_in\377\265\304\323\377\277\323\337"
  "\377\267\310\326\377\304\331\344\377\261\277\316\377\262\301\317\377"
  "\300\325\341\377\311\343\355\377\260\325\344\377Q~\232\351\6\11\14J\0"
  "\0\0\17\0\0\0\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\4\0\0\0\15\0\0\0""1\4$D\273Tv\227"
  "\377\223\250\276\377\226\253\300\377\226\253\300\377\226\253\300\377"
  "\226\253\300\377\226\253\300\377\226\253\300\377\226\253\300\377\227"
  "\254\300\377\231\255\301\377\232\256\302\377\234\257\303\377\233\257"
  "\302\377\212\232\253\377q\177\214\3777>D\377\37\"%\377`ir\377mu}\377"
  "\27\31\33\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\21\23"
  "\24\377\207\231\241\377\276\327\342\377\311\344\357\377\311\344\357\377"
  "\260\303\321\377\252\272\312\377\260\302\321\377\310\342\355\377\306"
  "\341\355\377\305\337\353\377\241\314\340\377>f~\311\5\5\5""3\0\0\0\12"
  "\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\2\0\0\0\11\0\0\0\36\0\17\37z&Qz\374\204\234\265\377\214"
  "\242\271\377\214\242\271\377\214\242\271\377\214\242\271\377\214\242"
  "\272\377\214\242\272\377\214\242\272\377\214\242\272\377\216\244\273"
  "\377\220\245\274\377\221\246\275\377\223\250\276\377\210\235\260\377"
  "9BJ\377\2\2\2\377\0\0\0\377\20\22\24\377\40#&\377#&)\377\6\7\5\377)9"
  "\6\377*;\6\377\25\35\3\377\6\11\0\377\0\0\0\377(.1\377s\203\213\377\211"
  "\234\245\377\215\241\251\377\304\341\355\377\263\312\331\377\244\265"
  "\307\377\246\271\312\377\302\340\354\377\300\337\353\377\300\336\353"
  "\377\275\334\352\377\205\267\320\376\35""3D\220\0\0\0\34\0\0\0\5\0\0"
  "\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0"
  "\0\5\0\0\0\22\0\0\1C\12""2Z\336c\202\241\377\201\232\263\377\202\232"
  "\263\377\202\232\263\377\202\232\263\377\202\232\264\377\202\232\264"
  "\377\202\232\264\377\202\232\264\377\202\233\265\377\203\234\265\377"
  "}\230\261\377o\215\251\377[|\235\377Gj\216\3775Y}\377\34""3J\377\2\4"
  "\6\377\0\0\0\377\0\0\0\377\1\2\0\377d\207\21\377\202\262\26\377o\226"
  "\23\377`\202\21\377F`\12\377\24\35\2\377\0\0\0\377\12\14\15\377.46\377"
  "z\214\224\377\255\311\325\377\267\324\340\377\236\261\303\377\256\307"
  "\327\377\276\336\353\377\274\334\351\377\274\334\351\377\273\334\351"
  "\377\256\324\344\377V\206\242\353\7\10\11E\0\0\0\16\0\0\0\3\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\12\0\0\0#\0"
  "\27-\2224]\205\377t\220\254\377w\222\255\377w\222\255\377w\222\255\377"
  "w\222\255\377w\222\255\377w\222\256\377v\222\256\377n\213\250\377Vx\233"
  "\3777`\210\377\37Mz\377\25Ft\377\23Dr\377\27Ft\377\32Ep\377!Kw\377\37"
  "7O\377\6\12\16\377\0\0\0\377;P\16\377\207\267\34\377q\233\24\377k\222"
  "\23\377m\225\24\377k\223\23\377Hc\12\377\23\33\1\377\10\13\6\377h~\207"
  "\377\246\310\327\377\243\304\322\377\270\330\345\377\271\331\347\377"
  "\273\334\352\377\272\334\351\377\271\333\351\377\270\331\351\377\266"
  "\331\347\377\264\327\346\377\221\305\334\377>bp\236\0\0\0\37\0\0\0\6"
  "\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0\21"
  "\0\0\0<\10""0W\333Xz\232\377l\212\246\377l\212\247\377l\212\247\377l"
  "\212\247\377l\212\247\377k\211\247\377[}\236\3775]\204\377\22:_\377\30"
  ";L\377/PA\3776P=\377OhC\377RfA\377o\210C\377f{C\377Xk;\377Uh0\377GQ3"
  "\377La\36\377o\2114\377t\2210\377l\215\"\377h\206&\377h\211\34\377c\204"
  "\31\377Eb\11\3771F\6\377\27!\2\377\25\32\34\377L]d\377 at S\\\377\222\302"
  "\327\377\237\317\343\377\257\326\347\377\265\331\350\377\264\331\350"
  "\377\263\327\347\377\261\327\346\377\260\325\345\377\246\320\342\377"
  "k\243\271\350\4\5\5B\0\0\0\15\0\0\0\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\2\0\0\0\11\0\0\0\34\0\15\32t\40Lx\376`\200\240\377b\202\241"
  "\377b\202\241\377b\202\241\377a\201\240\377Qt\230\377'R{\377\35>F\377"
  "6I/\377y\222C\377\200\231G\377\201\234A\377\200\2378\377}\233;\377{\232"
  "7\377o\2106\377f}3\377e\201%\377\\t&\377e\200+\377s\224'\377y\2320\377"
  "h\210\40\377b\177\33\377c\204\32\377h\210#\377f\210\33\377M_)\377FZ\33"
  "\377$/\24\377k\212\230\3775IR\377#29\377\177\264\313\377\207\303\334"
  "\377\212\303\333\377\230\312\337\377\251\323\344\377\256\325\346\377"
  "\255\324\345\377\254\323\343\377\251\321\343\377\211\301\331\3778Xe\220"
  "\0\0\0\32\0\0\0\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\15"
  "\0\0\0+\2#C\270:b\210\377Xz\232\377Xz\232\377Wy\232\377Nr\226\377*V\200"
  "\377\7""6c\377\20\34(\377q\204G\377\224\271=\377\205\2516\377y\241\""
  "\377y\235%\377t\223/\377k\211'\377O_(\377Ma\40\377IY(\377IZ#\377e}-\377"
  "f\204\"\377k\216\34\377k\213%\377_~\31\377Vn\36\377b\203\32\377l\222"
  "\26\377y\234*\377[o.\377d~*\377c~*\377XmT\377t\244\270\377\211\300\330"
  "\377\213\304\335\377\210\303\334\377\206\302\334\377\204\300\331\377"
  "\206\301\332\377\225\310\336\377\245\320\342\377\246\321\342\377\245"
  "\317\341\377\230\311\335\377[\216\244\324\0\0\0""0\0\0\0\12\0\0\0\2\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\6\0\0\0\23\0\0\0\77\15""8_\342Dj\216"
  "\377Nr\224\377Lp\224\3775^\206\377\16\77p\377\0""1`\377QRJ\377\306\264"
  "\223\3771*%\377Sh#\377j\217\27\377e\206\31\377f\210\30\377Pe\40\377F"
  "U&\377>L#\377N[/\377g~3\377\214\257<\377f\201'\377i\213\32\377g\203("
  "\377a|$\377Ob&\377EX\34\377[w\32\377l\221\26\377\205\2520\377o\205>\377"
  "e\200,\377z\236'\377|\2326\377Nb1\377i\222\250\377\215\306\337\377\212"
  "\304\335\377\210\303\334\377\204\300\332\377\202\277\331\377\177\276"
  "\327\377\205\300\330\377\226\310\335\377\237\314\337\377\234\313\336"
  "\377w\263\315\372\22\30\33X\0\0\0\20\0\0\0\3\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\11\0\0\0\34\1\10\17d\24Dq\374Ag\214\377>d\212\377\36Kx\377"
  "\3""6i\377\0""4g\377)9A\377\362\352\326\377\325\275\214\377pbH\377\77"
  "H/\377Vi*\377Na#\377CP%\377\40'\21\377!,\40\377\27#\35\377`u1\377\227"
  "\265N\377}\230@\377o\2121\377e\201'\377f\205\37\377K^!\377>L\34\377C"
  "T\36\377[|\22\377k\213&\377\210\250<\377u\2179\377e\203\"\377e\201&\377"
  "n\215,\377v\221:\377\\p>\377w\247\271\377\214\305\335\377\210\303\334"
  "\377\206\301\333\377\202\277\331\377\177\276\327\377}\274\326\377|\273"
  "\325\377\210\300\330\377\225\310\334\377\203\276\326\3777Vc\221\0\0\0"
  "\32\0\0\0\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\14\0\0\0%\0\34""6\237\40"
  "Ly\377/Y\202\377\16\77o\377\0""4g\377\0""4h\377\0""1a\377\220\205l\377"
  "\353\341\310\377\316\265\200\377H at 1\377+3\36\377=K\36\3778D\33\377)4"
  "#\377\12(E\377\25*4\377i\200:\377\224\270@\377{\227;\377`s2\377Ym.\377"
  "Pd\40\377I[!\377\77G,\377,5\30\377BT\36\377Xr\36\377s\223*\377\216\256"
  "D\377at6\377Qd'\377Zv\32\377Ti$\377x\220B\377\242\303S\377cxC\377p\235"
  "\261\377\210\303\334\377\206\301\333\377\202\277\331\377\200\276\330"
  "\377}\275\326\377z\272\325\377w\270\323\377~\272\324\377\202\276\326"
  "\377O\177\222\300\0\0\0&\0\0\0\10\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\20"
  "\0\0\0/\1$H\302\30Ft\377\7""9j\377\0""4g\377\0""4g\377\0""5h\377\0/\\"
  "\377\277\260\220\377\335\312\243\377d\\G\377\0\31""2\377\26\35\34\377"
  "#+\22\377*0\35\377\14!.\377#6/\377\203\242>\377}\230@\377w\2253\377p"
  "\220(\377`y#\377Pi\35\377FV#\377*;\32\377\0\1\0\377\32\40\37\377<L\32"
  "\377Tr\22\377s\2204\377\200\231E\377Yo'\377%,\32\377IY&\377Un\37\377"
  "Zs\"\377\220\263\77\377\216\256D\377YqI\377v\252\300\377\205\301\333"
  "\377\202\277\331\377\177\276\330\377}\274\326\377z\272\325\377w\270\323"
  "\377t\266\322\377s\266\322\377[\223\253\337\0\0\0""2\0\0\0\13\0\0\0\2"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\23\0\0\0""7\0(P\327\2""5f\377\0""4f\377\0"
  "4g\377\0""4g\377\0""5h\377\0""1a\377\220\204d\377\326\300\220\377\22"
  "%4\377\0&L\377\0#G\377\7\"=\377\6\33""1\377,;&\377x\222<\377~\2348\377"
  "l\212,\377Ys\34\377]q1\3773@\27\3775>\40\377)3\34\377\16\26\34\377\31"
  "!%\377F]Y\377J]\37\377Wk*\377|\2351\377\211\245G\377r\2138\377\".3\377"
  ".67\377:F#\377Nk\15\377`{#\377x\231-\377\241\310J\377Vh;\377m\236\256"
  "\377\201\277\331\377\177\276\330\377}\274\326\377z\272\325\377v\270\322"
  "\377t\266\322\377p\264\321\377d\242\274\361\3\3\3C\0\0\0\16\0\0\0\3\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\26\0\0\0>\0-V\343\0""4f\377\0""4f\377\0""4g"
  "\377\0""4h\377\0""5h\377\0""3e\3776==\377\330\276\211\377\37-7\377\0"
  "&L\377\0#F\377\25,4\377Xj6\377}\2363\377f\205!\377_|\34\377]x!\377Rf"
  "$\37719!\377\26/D\377\31""8U\377\30""1J\377$D`\377U\200\221\377\77S8"
  "\377I[!\377Ti'\377f\207\36\377\234\301H\377\232\271M\377Ool\377d\213"
  "\235\3773E:\377=H%\377Ql\24\377h\205%\377s\221.\377\206\2515\377Pd5\377"
  "q\246\275\377~\275\330\377{\274\326\377z\271\325\377v\270\322\377t\266"
  "\322\377p\264\321\377j\255\311\373\11\14\15R\0\0\0\21\0\0\0\4\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\30\0\0\0C\22Go\353\2""7i\377\0""4f\377\0""4g\377\0"
  "4h\377\0""5h\377\0""1`\377\0!B\377e^J\377\211z\\\377\3\33.\3776D*\377"
  "x\222>\377t\2158\377o\221\40\377g\206$\377a{(\377J_\37\377IT0\377\32"
  "-3\377\31:Z\377\33;[\377\36=\\\377&Ge\377Z\214\240\377AU\77\377L`!\377"
  "^z\35\377g\210\35\377\214\253C\377{\222C\377Vxy\377e\217\240\377Y\177"
  "\216\377&,$\3773B\17\377Wo#\377_x#\377k\206*\377\227\274@\377UiB\377"
  "f\230\251\377{\273\325\377x\271\325\377u\267\322\377r\265\321\377p\264"
  "\321\377k\257\314\375\25\35\"a\0\0\0\23\0\0\0\4\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\31\0\0\0D\34S{\356\30S\202\377\0""4f\377\0""4g\377\0""4g\377\0""5"
  "h\377\0/]\377\0&K\377\0\"C\377CM,\377gy:\377\214\254A\377y\233-\377c"
  "\200\"\377_u-\377Zn*\377K^\36\377'2\35\377\22'/\377\23""5U\377\27""8"
  "X\377\32:Z\377\35=\\\377Dt\223\377u\265\316\377=UE\377Re#\377`x'\377"
  "e\205\36\377\202\241;\377\211\246D\377Ruz\377c\216\240\377c\216\240\377"
  "Lkx\377484\377La\37\377_y'\377g\207#\377}\2338\377u\215<\377La<\377v"
  "\265\316\377w\270\324\377t\267\322\377r\265\321\377n\263\320\377l\261"
  "\316\376\31'-g\0\0\0\24\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\0\0\0E\6"
  "6c\356P\237\304\377)k\226\377\2""6i\377\0""4g\377\0""5h\377\0""1`\377"
  "\0$E\3770G)\377w\2253\377\200\237=\377f\203%\377Yq\"\377Nb#\377M`!\377"
  "Yp(\377.:!\377\15+I\377\21""3V\377\24""6W\377\27""8X\377\32<\\\377Eu"
  "\223\377z\301\337\377w\272\325\377:M#\377H\\\36\377e\205\33\377p\224"
  "\40\377\233\302C\377]l8\377a\215\232\377f\225\250\377_\213\235\377`\213"
  "\236\377A_f\377FT*\377Tj$\377b\177$\377p\223\"\377}\2372\377z\223A\377"
  "_\221\242\377v\267\324\377s\266\321\377p\264\321\377m\263\320\377i\260"
  "\315\376\26#'d\0\0\0\24\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\31\0\0\0B\1"
  ".Z\350\24O~\377a\265\330\377D\217\270\377\2""7j\377\0""4h\377\0""4f\377"
  "\15';\377Xi2\377;E$\3771<\35\377Mb\35\377J_\34\377ES'\377FT(\377CU\33"
  "\377.=%\377\14""0S\377\17""2T\377\31 at a\377D~\244\377h\254\316\377x\301"
  "\340\377z\303\340\377Eie\377M^)\377Vk(\377c\201\40\377j\217\32\377u\216"
  ";\377z\222\77\377^tx\377\217\236\245\377lop\377[u\200\377>RV\377ET#\377"
  "Na#\377Vp\33\377g\206\"\377r\221.\377m\202=\377V\177\210\377t\267\323"
  "\377r\266\321\377n\263\320\377l\261\320\377h\254\311\374\14\23\25Z\0"
  "\0\0\24\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\30\0\0\0:\7""0X\330*l\230\377"
  "a\265\330\377a\265\331\3771v\240\377\0""4h\377\0""5h\377\2$G\377J@*\377"
  "p\\8\377TE)\377\40\34\37\377 at H0\3779F\36\3774A\27\377=J\37\377\33,(\377"
  "\34Ff\377<o\211\377e\254\313\377t\300\340\377u\300\340\377v\301\337\377"
  "^\230\253\377EU&\377IZ%\377]z\34\377k\221\23\377v\231$\377\204\237H\377"
  "Ra0\377\215\215\214\377\262\262\262\377\276\276\275\377kx}\3778MQ\377"
  "4@\26\377=M\35\377JZ'\377[v\36\377r\2172\377\212\247D\377\\\204\204\377"
  "s\266\323\377p\265\321\377m\263\320\377k\261\317\377d\246\303\370\3\4"
  "\4N\0\0\0\22\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\26\0\0\0""2\20""8X\300"
  "H\224\273\377`\264\330\377a\265\330\377Z\254\321\377\2""6i\377\0""5h"
  "\377\1""5e\377\221\204a\377\376\370\356\377\312\260z\377yg>\377\14\15"
  "\21\3779D\35\3772<\33\377;E%\377\12#7\3772f\205\377c\253\312\377p\277"
  "\337\377q\274\335\377p\271\330\377u\256\306\377K^T\377=K#\377FT'\377"
  "Zv\36\377Zn0\377ay/\377w\212F\377bw0\377\263\263\262\377\263\263\262"
  "\377\375\375\373\377\234\237\240\3777NV\3779F\35\377;K\27\377AN#\377"
  "m\212)\377\201\2453\377\203\235J\377U~\177\377p\265\321\377n\263\320"
  "\377l\262\317\377i\260\316\377Y\226\260\350\0\0\0>\0\0\0\20\0\0\0\4\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\23\0\0\0+\27;S\245D\216\265\377`\264\327\377"
  "a\265\330\377a\265\331\377\32X\206\377\0""4g\377%`\211\377\214\177Z\377"
  "\370\363\347\377\306\256z\377\301\250u\377\26\24\24\3774;%\3775@\37\377"
  "\20\37\35\377\5-S\377\14>m\377]\225\262\377\201\251\271\377\230\254\265"
  "\377\257\263\265\377\300\300\300\377T]@\377IZ(\377[n+\377c}%\377b{)\377"
  "}\232<\377\217\252L\377T\\A\377\235\235\234\377\371\371\367\377\376\376"
  "\374\377\332\332\330\377Ry\213\377!*\37\377 at N$\377K]$\377\40$\23\377"
  "&'\37\377OZ4\377Z\221\243\377n\264\321\377m\262\317\377j\261\317\377"
  "h\257\316\377N\205\234\320\0\0\0""2\0\0\0\16\0\0\0\3\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\20\0\0\0$\26*4wQ\236\303\377_\262\325\377_\262\325\377`\263"
  "\326\377<\204\254\377\0""4f\377\37Sw\377ohI\377\364\354\335\377\305\255"
  "{\377\311\261\177\377\21\40(\377\20\35,\377\25$.\3778I[\377it\177\377"
  "\256\261\263\377\302\302\302\377\310\310\310\377\314\314\314\377\317"
  "\317\317\377\322\322\322\377[\\W\377563\377\24\25\33\377\26\23\23\377"
  "4(\32\377\15\16\13\377h~7\377VXP\377\343\343\342\377\376\376\374\377"
  "\376\376\374\377\372\372\370\377Smy\377Aet\377+<6\377G>+\377\260\242"
  "\213\377\346\331\276\377\221~S\377V\215\244\377l\261\316\377j\260\316"
  "\377h\256\314\377e\255\313\377;ev\251\0\0\0'\0\0\0\14\0\0\0\3\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\15\0\0\0\36\1\2\2N1o\223\361\\\255\317\377\\\255\317"
  "\377]\256\320\377\\\256\317\377\34X\204\377\22Ck\377CSM\377\335\315\250"
  "\377\327\306\241\377\314\265\200\377SVR\377\200\202\204\377\214\214\214"
  "\377\217\217\217\377\264\264\264\377\317\317\317\377\322\322\322\377"
  "\326\326\326\377\331\331\331\377\334\334\334\377\337\337\337\377xxy\377"
  ",-0\377>4\"\377\270\235d\377\350\327\265\377hW5\377##$\377\232\232\231"
  "\377\366\366\364\377\376\376\374\377\376\376\374\377\375\375\373\377"
  "fv{\377Q\200\225\377\77dt\377\235\210]\377\357\346\322\377\332\307\240"
  "\377\230\203T\377W\216\246\377h\254\310\377f\253\310\377d\252\306\377"
  "a\250\305\377\32-6v\0\0\0\35\0\0\0\11\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\12\0\0\0\30\0\0\0""8(Xs\306Z\250\310\377Z\251\312\377Y\247\310\377"
  "X\245\305\377f\240\272\377k\212\233\377\\in\377\213wL\377\360\346\322"
  "\377\313\264\200\377\202tV\377\202\202\202\377\226\226\226\377\233\233"
  "\233\377\322\322\322\377\334\334\334\377\332\332\332\377\340\340\340"
  "\377\217\215\207\377\334\334\334\377\352\352\352\377\264\264\264\377"
  "a[P\377\263\227\\\377\317\271\213\377\360\350\323\377m\\8\377www\377"
  "\274\274\272\377\362\362\360\377\376\376\374\377\374\374\372\377\371"
  "\370\366\377\200\203\205\377Jv\210\377NSI\377\317\271\211\377\363\355"
  "\341\377\310\257x\377a\\C\377\\\232\265\377c\247\303\377`\246\302\377"
  "_\244\301\377R\216\247\352\0\0\1F\0\0\0\26\0\0\0\7\0\0\0\1\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\7\0\0\0\23\0\0\0(\23*7\207P\230\267\377t\244\270\377"
  "\242\264\274\377\275\300\302\377\307\307\306\377\273\273\273\377\222"
  "\222\222\377ca[\377\257\234v\377\335\312\243\377\316\266\203\377~rV\377"
  "mic\377\207\206\204\377\227\224\217\377\215\204p\377i^F\377\310\310\310"
  "\377\203pE\377\253\253\251\377\362\362\362\377usp\377\226}F\377\303\252"
  "t\377\354\341\313\377\244\217f\377\\[X\377\261\261\260\377\237\237\235"
  "\377rdE\377\223\214\177\377\271\271\267\377\324\324\322\377\205\204\204"
  "\377STI\377\305\260\200\377\355\343\316\377\317\270\211\377\234\205S"
  "\3777Wc\377_\241\274\377_\241\275\377\\\240\274\377Z\236\273\3778cu\264"
  "\0\0\0-\0\0\0\20\0\0\0\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\17"
  "\0\0\0\37\0\0\0L7l\204\351\242\265\275\377\330\330\327\377\300\300\300"
  "\377\320\320\320\377\315\315\315\377\235\235\235\377\234\234\234\377"
  "nmj\377\207wW\377\314\264\200\377\324\273\207\377\324\274\207\377\323"
  "\272\207\377\323\271\201\377\220{N\377\255\253\247\377\340\340\340\377"
  "\230~H\377zkJ\377\203|n\377\227\200M\377\304\253u\377\337\316\254\377"
  "\264\243\202\377ROH\377\251\251\251\377\270\267\266\377\364\363\361\377"
  "\211\202u\377\250\213P\377\272\241k\377\253\230l\377\300\253{\377\323"
  "\273\210\377\330\305\233\377\310\256x\377\213uF\3775LR\377Du\211\377"
  "Z\233\267\377Z\234\267\377X\232\266\377S\223\257\372\20\35\"i\0\0\0\37"
  "\0\0\0\15\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\12\0\0\0\30"
  "\0\0\0""2\36""9E\251v\226\244\377\375\375\373\377\354\354\352\377\267"
  "\267\266\377\265\265\265\377\250\250\250\377\247\247\247\377\252\252"
  "\252\377\235\235\235\377\220\216\211\377\225\214x\377\227\213r\377\230"
  "\214u\377\225\220\205\377\326\326\326\377\376\376\376\377\365\365\365"
  "\377~mF\377\300\243f\377\307\256w\377\314\265\201\377\324\277\217\377"
  "\241\217g\377QOI\377\240\240\240\377\264\264\263\377\330\327\326\377"
  "\367\366\364\377\360\357\356\377\243\240\234\377\203uW\377\220zO\377"
  "\237\211Y\377\231\204V\377wlL\377EMC\3771S`\377<fx\377>l\177\377O\213"
  "\245\377O\213\244\377N\212\243\3775_q\313\0\0\0I\0\0\0+\0\0\0!\0\0\0"
  "\23\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0\22\0\0\0$\0\2\2"
  "_Lp\200\357\356\356\354\377\376\376\374\377\376\376\374\377\334\334\332"
  "\377\216\216\215\377~~~\377\241\241\241\377\264\264\264\377\310\310\310"
  "\377\373\373\373\377\374\374\374\377\375\375\375\377\376\376\376\377"
  "\376\376\376\377\374\374\374\377\373\373\373\377\252\251\247\377\201"
  "rS\377\234\206X\377\234\207Y\377ujS\377VVU\377\234\234\232\377\263\263"
  "\261\377\304\303\302\377\363\361\357\377\354\354\352\377\356\354\353"
  "\377\356\354\352\377\350\346\345\377\331\327\325\377\316\313\312\377"
  "\202\202\201\377t{\177\377u}\200\377t|\177\377r{\177\377\205\217\223"
  "\377\236\252\256\377\234\250\255\377\234\247\253\376\236\237\237\344"
  "\245\245\244\327\244\244\244\325\243\243\242\323LLLr\0\0\0\22\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\14\0\0\0\32\0\0\0:\24$*\241\320\324"
  "\325\377\376\376\374\377\376\376\374\377\376\376\374\377\374\374\372"
  "\377\252\252\251\377oon\377www\377\230\230\230\377\304\304\304\377\337"
  "\337\337\377\344\344\344\377\333\333\333\377\310\310\310\377\310\310"
  "\310\377\353\353\353\377\271\271\271\377\362\362\362\377\344\344\344"
  "\377\264\264\264\377kkj\377\233\233\232\377\257\257\255\377\266\266\264"
  "\377\352\351\347\377\362\360\356\377\311\310\307\377\263\262\260\377"
  "\312\310\306\377\331\327\325\377\333\330\327\377\312\307\305\377\206"
  "\204\203\377\233\233\232\377\266\266\264\377\266\266\264\377\273\273"
  "\271\377\364\364\362\377\376\376\374\377\376\376\374\377\361\341\330"
  "\377\362\335\323\377\362\337\325\377\363\341\331\377\374\372\367\377"
  "kkk\246\0\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\7\0\0\0\23"
  "\0\0\0'\0\0\0c\233\244\250\361\376\376\374\377\376\376\374\377\376\376"
  "\374\377\376\376\374\377\374\374\372\377\322\322\322\377\225\225\224"
  "\377vvu\377ssr\377\214\214\214\377\262\262\262\377\266\266\266\377\277"
  "\277\277\377\361\361\361\377\345\345\345\377\266\266\266\377\311\311"
  "\311\377\305\305\305\377jjj\377\231\231\230\377\252\252\250\377\263\263"
  "\262\377\340\337\336\377\360\356\354\377\356\353\352\377\345\343\341"
  "\377\265\262\261\377\244\242\240\377\242\240\237\377\241\236\236\377"
  "\237\234\233\377\230\225\223\377vvu\377\266\266\264\377\274\274\272\377"
  "\354\354\352\377\376\376\374\377\376\376\374\377\376\376\374\377\343"
  "yj\377\340F9\377\3325$\377\315Q=\377\365\363\356\377fff\250\0\0\0\37"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\14\0\0\0\35\0\0\0"
  "Gmmm\267\375\375\373\377\376\376\374\377\376\376\374\377\376\376\374"
  "\377\376\376\374\377\376\376\374\377\362\362\360\377\320\320\316\377"
  "\245\245\243\377\216\216\216\377\177\177\177\377\234\234\234\377\352"
  "\352\352\377\376\376\376\377\361\361\361\377\267\267\267\377\266\266"
  "\266\377nnn\377\223\223\222\377\240\240\237\377\260\257\256\377\336\335"
  "\333\377\356\354\352\377\354\352\350\377\350\346\344\377\346\344\342"
  "\377\340\334\333\377\302\277\275\377\250\246\245\377\236\233\232\377"
  "\233\230\227\377\233\230\226\377oon\377\327\327\325\377\367\367\365\377"
  "\376\376\374\377\376\376\374\377\376\376\374\377\376\376\374\377\337"
  "\236\227\377\312\277\272\377\343\240\231\377\325TD\377\365\362\352\377"
  "ccc\250\0\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\10"
  "\0\0\0\25\0\0\0""8@@@}\353\353\351\377\376\376\374\377\376\376\374\377"
  "\376\376\374\377\376\376\374\377\376\376\374\377\376\376\374\377\376"
  "\376\374\377\376\376\374\377\357\357\356\377\326\326\325\377\313\313"
  "\312\377\241\241\240\377\245\245\245\377\342\342\342\377\340\340\340"
  "\377}}|\377\215\215\214\377\240\237\236\377\274\272\271\377\334\333\332"
  "\377\344\342\340\377\344\342\340\377\346\343\342\377\344\342\340\377"
  "\342\337\335\377\340\334\332\377\334\331\330\377\331\325\323\377\322"
  "\316\315\377\316\312\310\377\315\310\307\377\211\206\205\377\373\373"
  "\371\377\376\376\374\377\376\376\374\377\376\376\374\377\376\376\374"
  "\377\371\371\367\377\312\204x\377\322\310\313\377\323\313\313\377\343"
  "ob\377\366\362\352\377```\250\0\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\1\0\0\0\5\0\0\0\17\0\0\0*\5\5\5V\316\316\315\366\376\376"
  "\374\377\376\376\374\377\376\376\374\377\376\376\374\377\376\376\374"
  "\377\376\376\374\377\376\376\374\377\376\376\374\377\376\376\374\377"
  "\374\374\372\377\350\350\346\377\332\332\331\377\330\330\330\377\251"
  "\251\250\377\220\220\220\377\265\265\263\377\326\325\324\377\340\336"
  "\335\377\344\343\341\377\342\340\336\377\340\335\334\377\334\332\331"
  "\377\332\330\326\377\333\330\326\377\334\330\326\377\334\327\326\377"
  "\330\324\322\377\326\322\320\377\324\316\315\377\320\314\312\377\316"
  "\310\307\377\233\227\226\377\332\332\330\377\376\376\374\377\376\376"
  "\374\377\376\376\374\377\376\376\374\377\356\356\354\377\314pc\377\315"
  "ZP\377\321{v\377\341RB\377\365\361\351\377\\\\\\\250\0\0\0\40\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\13\0\0\0\37\0\0\0"
  "L\250\250\250\316\376\376\374\377\376\376\374\377\376\376\374\377\376"
  "\376\374\377\376\376\374\377\376\376\374\377\376\376\374\377\376\376"
  "\374\377\376\376\374\377\370\370\366\377\365\365\363\377\361\361\357"
  "\377\346\345\344\377\337\336\334\377\336\336\334\377\336\335\334\377"
  "\342\340\337\377\344\341\337\377\340\336\334\377\336\334\332\377\334"
  "\331\330\377\331\326\324\377\326\323\322\377\324\320\317\377\322\316"
  "\314\377\320\314\313\377\322\316\314\377\322\314\313\377\320\312\310"
  "\377\314\307\306\377\312\304\302\377\277\271\270\377\237\237\236\377"
  "\376\376\374\377\376\376\374\377\376\376\374\377\376\376\374\377\375"
  "\375\373\377\306\233\220\377\317\202u\377\332\226\210\377\344\263\243"
  "\377\362\357\353\377YXX\250\0\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\2\0\0\0\11\0\0\0\30\0\0\0Bppp\245\375\375\373\377"
  "\376\376\374\377\376\376\374\377\376\376\374\377\376\376\374\377\376"
  "\376\374\377\376\376\374\377\376\376\374\377\373\373\371\377\364\364"
  "\362\377\362\361\357\377\356\356\354\377\354\353\351\377\350\347\345"
  "\377\342\340\336\377\340\336\335\377\342\337\336\377\336\334\333\377"
  "\334\332\330\377\332\330\326\377\330\324\323\377\326\322\320\377\322"
  "\317\315\377\320\314\312\377\316\311\307\377\312\306\304\377\310\303"
  "\302\377\307\302\301\377\310\303\302\377\310\302\300\377\306\277\276"
  "\377\303\274\273\377\207\205\204\377\375\375\373\377\376\376\374\377"
  "\376\376\374\377\376\375\373\377\375\374\372\377\366\365\364\377\371"
  "\370\366\377\366\366\364\377\367\366\364\377\365\364\362\377UUS\250\0"
  "\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6\0"
  "\0\0\23\0\0\0""8<<<z\350\350\346\377\376\376\374\377\376\376\374\377"
  "\376\376\374\377\376\376\374\377\376\376\374\377\376\376\374\377\375"
  "\375\373\377\363\363\361\377\360\357\355\377\355\354\352\377\352\351"
  "\347\377\350\346\344\377\346\343\342\377\342\340\337\377\340\336\334"
  "\377\336\333\332\377\333\330\327\377\330\326\324\377\326\323\321\377"
  "\324\320\316\377\321\315\313\377\316\312\310\377\314\307\306\377\312"
  "\304\302\377\306\301\300\377\304\277\276\377\302\274\273\377\277\272"
  "\270\377\276\270\266\377\276\270\266\377\276\270\266\377xut\377\372\372"
  "\370\377\374\374\372\377\373\373\371\377\371\371\367\377\370\367\365"
  "\377\366\366\364\377\365\364\362\377\363\362\360\377\362\360\357\377"
  "\360\357\355\377PPP\250\0\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0\16\0\0\0*\6\6\6V\310\310\307\367\376\376"
  "\374\377\376\376\374\377\376\376\374\377\376\376\374\377\376\376\374"
  "\377\374\374\372\377\364\364\362\377\356\356\354\377\354\352\350\377"
  "\350\350\346\377\346\344\343\377\344\342\340\377\341\337\335\377\336"
  "\334\332\377\334\332\330\377\332\327\325\377\330\324\322\377\324\321"
  "\320\377\322\316\314\377\320\313\312\377\314\310\306\377\312\306\304"
  "\377\310\302\301\377\305\300\276\377\302\276\274\377\300\273\271\377"
  "\276\270\266\377\274\264\263\377\271\262\260\377\241\233\231\377wsr\377"
  "jhg\377\362\362\360\377\370\367\365\377\366\365\363\377\365\364\362\377"
  "\363\362\360\377\362\360\356\377\360\357\355\377\357\355\353\377\355"
  "\353\351\377\354\351\350\377LLL\250\0\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\13\0\0\0\40\0\0\0L\240\240"
  "\237\321\376\376\374\377\376\376\374\377\376\376\374\377\375\375\373"
  "\377\372\372\370\377\366\365\364\377\354\354\352\377\352\350\347\377"
  "\350\346\344\377\344\343\341\377\342\340\336\377\340\335\334\377\334"
  "\332\331\377\332\330\326\377\330\325\324\377\326\322\320\377\324\317"
  "\316\377\320\314\312\377\316\312\310\377\314\306\305\377\310\304\302"
  "\377\306\300\300\377\304\276\275\377\300\274\272\377\277\271\270\377"
  "\247\241\240\377~zy\377vtt\377xwv\377\220\220\217\377\267\267\267\377"
  "\271\270\266\377\345\343\342\377\363\362\360\377\362\360\356\377\360"
  "\356\355\377\357\355\353\377\355\353\351\377\353\351\347\377\352\350"
  "\346\377\350\346\344\377\347\344\342\377GGG\250\0\0\0\40\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\11\0\0\0\30\0"
  "\0\0Cfff\247\376\376\374\377\376\376\374\377\374\374\372\377\372\371"
  "\367\377\366\366\364\377\354\353\352\377\350\347\345\377\346\344\342"
  "\377\344\341\337\377\340\336\334\377\336\334\332\377\334\331\330\377"
  "\331\326\324\377\326\323\322\377\324\320\317\377\322\316\314\377\317"
  "\313\311\377\314\310\306\377\312\304\303\377\310\302\300\377\304\277"
  "\276\377\255\250\247\377\204\200\177\377ron\377_^]\377eed\377\214\213"
  "\213\377\232\231\230\377\247\246\245\377\274\273\271\377\302\302\300"
  "\377\350\346\344\377\360\356\355\377\356\355\353\377\355\353\351\377"
  "\353\351\347\377\352\347\346\377\350\346\344\377\347\344\342\377\345"
  "\342\341\377\344\341\337\377\342\337\335\377DCC\250\0\0\0\40\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0\23"
  "\0\0\0""8555}\345\345\343\377\372\372\370\377\370\367\365\377\365\364"
  "\362\377\356\355\353\377\346\345\343\377\344\342\340\377\342\337\336"
  "\377\336\334\333\377\334\332\330\377\332\330\326\377\330\324\323\377"
  "\326\322\320\377\322\317\315\377\320\314\312\377\316\311\307\377\312"
  "\306\304\377\263\257\255\377\213\210\207\377\177~}\377\202\201\200\377"
  "\230\230\230\377\277\277\275\377\313\313\311\377\302\301\300\377\272"
  "\271\270\377\300\277\275\377\320\317\315\377\332\331\327\377\333\332"
  "\330\377\353\351\347\377\355\353\351\377\353\351\347\377\352\347\345"
  "\377\350\346\344\377\347\344\342\377\345\342\341\377\344\340\337\377"
  "\342\337\335\377\340\335\333\377\337\333\332\377\335\332\330\377@\77"
  "\77\250\0\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\1\0\0\0\5\0\0\0\16\0\0\0+\7\7\7W\275\275\274\370\366\365\364\377"
  "\364\362\360\377\357\356\354\377\346\344\342\377\342\340\337\377\340"
  "\336\334\377\336\333\332\377\333\330\327\377\330\326\324\377\326\323"
  "\321\377\324\320\316\377\322\315\314\377\271\266\264\377\224\221\220"
  "\377\212\210\207\377\205\204\203\377\220\220\217\377\233\233\231\377"
  "\225\225\225\377\230\230\226\377\251\250\247\377\302\301\277\377\327"
  "\325\324\377\335\335\333\377\326\325\323\377\316\314\312\377\312\311"
  "\310\377\310\306\304\377\334\332\330\377\352\347\345\377\350\345\344"
  "\377\347\344\342\377\345\342\340\377\343\340\337\377\342\337\335\377"
  "\340\335\333\377\337\333\331\377\335\332\330\377\334\330\326\377\332"
  "\326\325\377\331\324\323\377<;;\250\0\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\13\0\0\0\40\0\0\0"
  "M\223\223\223\323\362\360\356\377\357\356\354\377\346\344\342\377\342"
  "\337\335\377\336\334\332\377\334\332\330\377\332\327\325\377\330\324"
  "\322\377\277\274\273\377\231\227\226\376\221\217\216\377\215\214\213"
  "\377\240\240\237\377\303\303\301\377\316\315\314\377\325\325\324\377"
  "\337\336\334\377\350\347\346\377\357\356\354\377\361\360\356\377\362"
  "\360\356\377\361\357\356\377\357\356\354\377\356\354\352\377\354\352"
  "\351\377\353\351\347\377\351\347\345\377\350\345\343\377\346\344\342"
  "\377\345\342\340\377\343\340\337\377\342\336\335\377\340\335\333\377"
  "\337\333\331\377\335\331\330\377\333\330\326\377\332\326\324\377\330"
  "\324\323\377\327\323\321\377\325\321\317\377\324\317\315\377866\250\0"
  "\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\2\0\0\0\11\0\0\0\31\0\0\0DYYY\253\356\354\352\377\350\345\344\377"
  "\340\335\334\377\334\332\331\377\305\303\302\377\237\235\235\372zyy\327"
  "HGG\254\35\35\35\213www\337\317\317\315\377\327\326\324\377\340\340\336"
  "\377\352\351\347\377\360\357\355\377\362\361\360\377\363\362\360\377"
  "\362\361\357\377\361\357\355\377\357\356\354\377\356\354\352\377\354"
  "\352\351\377\353\351\347\377\351\347\345\377\350\345\343\377\346\343"
  "\342\377\345\342\340\377\343\340\336\377\341\336\335\377\340\335\333"
  "\377\336\333\331\377\335\331\327\377\333\330\326\377\332\326\324\377"
  "\330\324\323\377\327\322\321\377\325\321\317\377\324\317\315\377\322"
  "\315\314\377\321\313\312\377\317\312\310\377322\250\0\0\0\40\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6"
  "\0\0\0\23\0\0\0""8+++~\274\272\271\377\247\245\244\372\202\200\200\326"
  "NNN\254%%%\201\6\6\6X\0\0\0M\0\0\0F\0\0\0K\222\222\221\330\361\361\357"
  "\377\364\363\361\377\364\363\362\377\364\363\361\377\362\361\357\377"
  "\361\357\355\377\357\355\354\377\356\354\352\377\354\352\350\377\353"
  "\350\347\377\351\347\345\377\350\345\343\377\346\343\341\377\345\342"
  "\340\377\343\340\336\377\341\336\335\377\340\334\333\377\336\333\331"
  "\377\335\331\327\377\333\327\326\377\332\326\324\377\330\324\322\377"
  "\327\322\321\377\325\321\317\377\324\317\315\377\322\315\313\377\321"
  "\313\312\377\317\312\310\377\316\310\307\377\314\306\305\377\312\305"
  "\303\377/..\250\0\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0\16\0\0\0)\0\0\0P\"\"\"v\7\7\7"
  "X\0\0\0M\0\0\0D\0\0\0""9\0\0\0-\0\0\0$\0\0\0#\0\0\0""5\227\227\226\326"
  "\364\363\361\377\362\361\357\377\361\357\355\377\357\355\354\377\356"
  "\354\352\377\354\352\350\377\353\350\347\377\351\347\345\377\347\345"
  "\343\377\346\343\341\377\344\341\340\377\343\340\336\377\341\336\334"
  "\377\340\334\333\377\336\333\331\377\335\331\327\377\333\327\325\377"
  "\332\326\324\377\330\324\322\377\327\322\321\377\325\320\317\377\323"
  "\317\315\377\322\315\313\377\320\313\312\377\317\312\310\377\315\310"
  "\306\377\314\306\305\377\312\305\303\377\311\303\301\377\307\301\277"
  "\377\306\277\276\377+**\250\0\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\12\0\0\0\30\0\0\0"
  "0\0\0\0""5\0\0\0,\0\0\0\"\0\0\0\34\0\0\0\26\0\0\0\22\0\0\0\21\0\0\0\27"
  "\0\0\0""1\223\222\222\326\357\355\353\377\355\353\352\377\354\352\350"
  "\377\352\350\346\377\351\347\345\377\347\345\343\377\346\343\341\377"
  "\344\341\340\377\343\340\336\377\341\336\334\377\340\334\333\377\336"
  "\332\331\377\335\331\327\377\333\327\325\377\331\325\324\377\330\324"
  "\322\377\326\322\320\377\325\320\317\377\323\317\315\377\322\315\313"
  "\377\320\313\311\377\317\311\310\377\315\310\306\377\314\306\305\377"
  "\312\304\303\377\311\303\301\377\307\301\277\377\306\277\276\377\304"
  "\276\274\377\302\274\272\377\301\272\271\377'&&\250\0\0\0\40\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1"
  "\0\0\0\5\0\0\0\14\0\0\0\21\0\0\0\23\0\0\0\21\0\0\0\16\0\0\0\13\0\0\0"
  "\10\0\0\0\6\0\0\0\10\0\0\0\22\0\0\0/\216\215\214\325\352\350\346\377"
  "\351\346\345\377\347\345\343\377\346\343\341\377\344\341\337\377\342"
  "\337\336\377\341\336\334\377\337\334\332\377\336\332\331\377\334\331"
  "\327\377\333\327\325\377\331\325\324\377\330\324\322\377\326\322\320"
  "\377\325\320\317\377\323\316\315\377\322\315\313\377\320\313\311\377"
  "\317\311\310\377\315\310\306\377\314\306\304\377\312\304\303\377\311"
  "\303\301\377\307\301\277\377\306\277\276\377\304\275\274\377\302\274"
  "\272\377\301\272\271\377\277\270\267\377\276\267\265\377\274\265\263"
  "\377!\40\40\250\0\0\0\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\4\0\0\0\6\0\0\0\7\0\0"
  "\0\5\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\5\0\0\0\17\0\0\0'777|VUU\252"
  "TTT\252RRR\252QPP\252ONN\252MLL\252LKK\252III\252HHG\252FEE\252DCC\252"
  "CBB\252@@@\252\77>=\252=<<\252<::\252999\252776\252654\252433\252311"
  "\252100\252.--\252-,+\252+**\252*((\252(''\252%%$\252$#\"\252\"!!\252"
  "\37\36\36\251\1\1\1_\0\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1"
  "\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\14\0\0\0\32\0"
  "\0\0&\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,"
  "\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0"
  ",\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0"
  "\0,\0\0\0,\0\0\0*\0\0\0\"\0\0\0\23\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\7\0\0\0"
  "\17\0\0\0\26\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0"
  "\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30"
  "\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0"
  "\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0\0\0\30\0"
  "\0\0\30\0\0\0\27\0\0\0\22\0\0\0\13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  "\0\0\0\0\0\0\0\0\0"};



--- NEW FILE: notification_trayicon.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt and the Claws Mail Team.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_TRAYICON_H
#define NOTIFICATION_TRAYICON_H NOTIFICATION_TRAYICON_H

#include "pluginconfig.h"

#ifdef NOTIFICATION_TRAYICON

#include <glib.h>

#include "procmsg.h"

#define TRAYICON_SPECIFIC_FOLDER_ID_STR "trayicon"

void notification_trayicon_msg(MsgInfo*);

void notification_trayicon_destroy(void);

/* creates it, if necessary */
void notification_update_trayicon(void);

gboolean notification_trayicon_main_window_close(gpointer, gpointer);
gboolean notification_trayicon_main_window_got_iconified(gpointer, gpointer);
gboolean notification_trayicon_account_list_changed(gpointer, gpointer);

gboolean notification_trayicon_is_available(void);
void notification_trayicon_on_activate(GtkStatusIcon*,gpointer);

#endif /* NOTIFICATION_TRAYICON */

#endif /* include guard */

--- NEW FILE: notification_command.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "pluginconfig.h"

#ifdef NOTIFICATION_COMMAND

#include <string.h>
#include <glib.h>
#include "common/utils.h"
#include "folder.h"
#include "notification_command.h"
#include "notification_prefs.h"
#include "notification_foldercheck.h"

typedef struct {
  gboolean blocked;
  guint timeout_id;
} NotificationCommand;

static gboolean command_timeout_fun(gpointer data);

static NotificationCommand command;

G_LOCK_DEFINE_STATIC(command);

void notification_command_msg(MsgInfo *msginfo)
{
  gchar *ret_str, *buf;
  gsize by_read = 0, by_written = 0;
  FolderType ftype;

  if(!msginfo || !notify_config.command_enabled || !MSG_IS_NEW(msginfo->flags))
    return;

  if(!notify_config.command_enabled || !MSG_IS_NEW(msginfo->flags))
    return;

  if(notify_config.command_folder_specific) {
    guint id;
    GSList *list;
    gchar *identifier;
    gboolean found = FALSE;

    if(!(msginfo->folder))
      return;

    identifier = folder_item_get_identifier(msginfo->folder);

    id =
      notification_register_folder_specific_list(COMMAND_SPECIFIC_FOLDER_ID_STR);
    list = notification_foldercheck_get_list(id);
    for(; (list != NULL) && !found; list = g_slist_next(list)) {
      gchar *list_identifier;
      FolderItem *list_item = (FolderItem*) list->data;
      
      list_identifier = folder_item_get_identifier(list_item);
      if(!strcmp2(list_identifier, identifier))
	found = TRUE;

      g_free(list_identifier);
    }
    g_free(identifier);
    
    if(!found)
      return;
  } /* folder specific */

  ftype = msginfo->folder->folder->klass->type;

  buf = g_strdup(notify_config.command_line);

  G_LOCK(command);

  if(!command.blocked) {
    /* execute command */
    command.blocked = TRUE;
    ret_str = g_locale_from_utf8(buf,strlen(buf),&by_read,&by_written,NULL);
    if(ret_str && by_written) {
      g_free(buf);
      buf = ret_str;
    }
    execute_command_line(buf, TRUE);
    g_free(buf);
  }

  /* block further execution for some time,
     no matter if it was blocked or not */
  if(command.timeout_id)
    g_source_remove(command.timeout_id);
  command.timeout_id = g_timeout_add(notify_config.command_timeout,
				     command_timeout_fun, NULL);    
  G_UNLOCK(command);
}

static gboolean command_timeout_fun(gpointer data)
{
  G_LOCK(command);
  command.timeout_id = 0;
  command.blocked = FALSE;
  G_UNLOCK(command);
  return FALSE;
}

#endif /* NOTIFICATION_COMMAND */

--- NEW FILE: notification_core.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "pluginconfig.h"

#include "folder.h"
#include "folderview.h"
#include "codeconv.h"
#include "gtk/gtkutils.h"

#include "notification_core.h"
#include "notification_plugin.h"
#include "notification_prefs.h"
#include "notification_banner.h"
#include "notification_popup.h"
#include "notification_command.h"
#include "notification_lcdproc.h"
#include "notification_trayicon.h"
#include "notification_indicator.h"

#ifdef HAVE_LIBCANBERRA_GTK
# include <canberra-gtk.h>
#endif

typedef struct {
  GSList *collected_msgs;
  GSList *folder_items;
  gboolean unread_also;
  gint max_msgs;
  gint num_msgs;
} TraverseCollect;

static gboolean notification_traverse_collect(GNode*, gpointer);
static void     notification_new_unnotified_do_msg(MsgInfo*);
static gboolean notification_traverse_hash_startup(GNode*, gpointer);

static GHashTable *msg_count_hash;
static NotificationMsgCount msg_count;

#ifdef HAVE_LIBCANBERRA_GTK
static gboolean canberra_new_email_is_playing = FALSE;
#endif

static void msg_count_hash_update_func(FolderItem*, gpointer);
static void msg_count_update_from_hash(gpointer, gpointer, gpointer);
static void msg_count_clear(NotificationMsgCount*);
static void msg_count_add(NotificationMsgCount*,NotificationMsgCount*);
static void msg_count_copy(NotificationMsgCount*,NotificationMsgCount*);

void notification_core_global_includes_changed(void)
{
#ifdef NOTIFICATION_BANNER
  notification_update_banner();
#endif

  if(msg_count_hash) {
    g_hash_table_destroy(msg_count_hash);
    msg_count_hash = NULL;
  }
  notification_update_msg_counts(NULL);
}

/* Hide/show main window */
void notification_toggle_hide_show_window(void)
{
  MainWindow *mainwin;
  if((mainwin = mainwindow_get_mainwindow()) == NULL)
    return;

  if(gtk_widget_get_visible(GTK_WIDGET(mainwin->window))) {
    if((gdk_window_get_state(GTK_WIDGET(mainwin->window)->window)&GDK_WINDOW_STATE_ICONIFIED)
       || mainwindow_is_obscured()) {
      notification_show_mainwindow(mainwin);
    }
    else {
      main_window_hide(mainwin);
    }
  }
  else {
    notification_show_mainwindow(mainwin);
  }
}

void notification_update_msg_counts(FolderItem *removed_item)
{
  if(!msg_count_hash)
    msg_count_hash = g_hash_table_new_full(g_str_hash,g_str_equal,
					   g_free,g_free);

  folder_func_to_all_folders(msg_count_hash_update_func, msg_count_hash);

  if(removed_item) {
    gchar *identifier;
    identifier = folder_item_get_identifier(removed_item);
    if(identifier) {
      g_hash_table_remove(msg_count_hash, identifier);
      g_free(identifier);
    }
  }
  msg_count_clear(&msg_count);
  g_hash_table_foreach(msg_count_hash, msg_count_update_from_hash, NULL);
#ifdef NOTIFICATION_LCDPROC
  notification_update_lcdproc();
#endif
#ifdef NOTIFICATION_TRAYICON
  notification_update_trayicon();
#endif
#ifdef NOTIFICATION_INDICATOR
  notification_update_indicator();
#endif
  notification_update_urgency_hint();
}

static void msg_count_clear(NotificationMsgCount *count)
{
  count->new_msgs          = 0;
  count->unread_msgs       = 0;
  count->unreadmarked_msgs = 0;
  count->marked_msgs       = 0;
  count->total_msgs        = 0;
}

/* c1 += c2 */
static void msg_count_add(NotificationMsgCount *c1,NotificationMsgCount *c2)
{
  c1->new_msgs          += c2->new_msgs;
  c1->unread_msgs       += c2->unread_msgs;
  c1->unreadmarked_msgs += c2->unreadmarked_msgs;
  c1->marked_msgs       += c2->marked_msgs;
  c1->total_msgs        += c2->total_msgs;
}

/* c1 = c2 */
static void msg_count_copy(NotificationMsgCount *c1,NotificationMsgCount *c2)
{
  c1->new_msgs          = c2->new_msgs;
  c1->unread_msgs       = c2->unread_msgs;
  c1->unreadmarked_msgs = c2->unreadmarked_msgs;
  c1->marked_msgs       = c2->marked_msgs;
  c1->total_msgs        = c2->total_msgs;
}

gboolean get_flat_gslist_from_nodes_traverse_func(GNode *node, gpointer data)
{
  if(node->data) {
    GSList **list = data;
    *list = g_slist_prepend(*list, node->data);
  }
  return FALSE;
}

GSList* get_flat_gslist_from_nodes(GNode *node)
{
  GSList *retval = NULL;

  g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, get_flat_gslist_from_nodes_traverse_func, &retval);
  return retval;
}

void notification_core_get_msg_count_of_foldername(gchar *foldername, NotificationMsgCount *count)
{
  GList *list;
  Folder *walk_folder;
  Folder *folder = NULL;

  for(list = folder_get_list(); list != NULL; list = list->next) {
    walk_folder = list->data;
    if(strcmp2(foldername, walk_folder->name) == 0) {
      folder = walk_folder;
      break;
    }
  }
  if(!folder) {
    debug_print("Notification plugin: Error: Could not find folder %s\n", foldername);
    return;
  }

  msg_count_clear(count);
  notification_core_get_msg_count(get_flat_gslist_from_nodes(folder->node), count);
}

void notification_core_get_msg_count(GSList *folder_list,
				     NotificationMsgCount *count)
{
  GSList *walk;

  if(!folder_list)
    msg_count_copy(count,&msg_count);
  else {
    msg_count_clear(count);
    for(walk = folder_list; walk; walk = walk->next) {
      gchar *identifier;
      NotificationMsgCount *item_count;
      FolderItem *item = (FolderItem*) walk->data;
      identifier = folder_item_get_identifier(item);
      if(identifier) {
	item_count = g_hash_table_lookup(msg_count_hash,identifier);
	g_free(identifier);
	if(item_count)
	  msg_count_add(count, item_count);
      }
    }
  }
}

static void msg_count_hash_update_func(FolderItem *item, gpointer data)
{
  gchar *identifier;
  NotificationMsgCount *count;
  GHashTable *hash = data;

  if(!notify_include_folder_type(item->folder->klass->type,
				 item->folder->klass->uistr))
    return;

  identifier = folder_item_get_identifier(item);
  if(!identifier)
    return;

  count = g_hash_table_lookup(hash, identifier);

  if(!count) {
    count = g_new0(NotificationMsgCount,1);
    g_hash_table_insert(hash, identifier, count);
  }
  else
    g_free(identifier);

  count->new_msgs          = item->new_msgs;
  count->unread_msgs       = item->unread_msgs;
  count->unreadmarked_msgs = item->unreadmarked_msgs;
  count->marked_msgs       = item->marked_msgs;
  count->total_msgs        = item->total_msgs;
}

static void msg_count_update_from_hash(gpointer key, gpointer value,
				       gpointer data)
{
  NotificationMsgCount *count = value;
  msg_count_add(&msg_count,count);
}


/* Replacement for the post-filtering hook:
   Pseudocode by Colin:
hook on FOLDER_ITEM_UPDATE_HOOKLIST
 if hook flags & F_ITEM_UPDATE_MSGCOUNT
  scan mails (folder_item_get_msg_list)
   if MSG_IS_NEW(msginfo->flags) and not in hashtable
    notify()
    add to hashtable
   procmsg_msg_list_free

hook on MSGINFO_UPDATE_HOOKLIST
 if hook flags & MSGINFO_UPDATE_FLAGS
  if !MSG_IS_NEW(msginfo->flags)
   remove from hashtable, it's now useless
*/

/* This hash table holds all mails that we already notified about,
   and that still are marked as "new". The keys are the msgid's,
   the values are just 1's stored in a pointer. */
static GHashTable *notified_hash = NULL;


/* Remove message from the notified_hash if
 *  - the message flags changed
 *  - the message is not new
 *  - the message is in the hash
*/
gboolean notification_notified_hash_msginfo_update(MsgInfoUpdate *msg_update)
{
  g_return_val_if_fail(msg_update != NULL, FALSE);

  if((msg_update->flags & MSGINFO_UPDATE_FLAGS) &&
     !MSG_IS_NEW(msg_update->msginfo->flags)) {

    MsgInfo *msg;
    gchar *msgid;

    msg = msg_update->msginfo;
    if(msg->msgid)
      msgid = msg->msgid;
    else {
      debug_print("Notification Plugin: Message has no message ID!\n");
      msgid = "";
    }

    g_return_val_if_fail(msg != NULL, FALSE);

    if(g_hash_table_lookup(notified_hash, msgid) != NULL) {

      debug_print("Notification Plugin: Removing message id %s from hash "
		  "table\n", msgid);
      g_hash_table_remove(notified_hash, msgid);
    }
  }
  return FALSE;
}

/* On startup, mark all new mails as already notified
 * (by including them in the hash) */
void notification_notified_hash_startup_init(void)
{
  GList *folder_list, *walk;
  Folder *folder;

  if(!notified_hash) {
    notified_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
					  g_free, NULL);
    debug_print("Notification Plugin: Hash table created\n");
  }

  folder_list = folder_get_list();
  for(walk = folder_list; walk != NULL; walk = g_list_next(walk)) {
    folder = walk->data;

    g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
		    notification_traverse_hash_startup, NULL);
  }
}

static gboolean notification_traverse_hash_startup(GNode *node, gpointer data)
{
  GSList *walk;
  GSList *msg_list;
  FolderItem *item = (FolderItem*) node->data;
  gint new_msgs_left;

  if(!(item->new_msgs))
    return FALSE;

  new_msgs_left = item->new_msgs;
  msg_list = folder_item_get_msg_list(item);

  for(walk = msg_list; walk; walk = g_slist_next(walk)) {
    MsgInfo *msg = (MsgInfo*) walk->data;
    if(MSG_IS_NEW(msg->flags)) {
      gchar *msgid;

      if(msg->msgid)
	msgid = msg->msgid;
      else {
	debug_print("Notification Plugin: Message has no message ID!\n");
	msgid = "";
      }

      /* If the message id is not yet in the hash, add it */
      g_hash_table_insert(notified_hash, g_strdup(msgid),
			  GINT_TO_POINTER(1));
      debug_print("Notification Plugin: Init: Added msg id %s to the hash\n",
		  msgid);
      /* Decrement left count and check if we're already done */
      new_msgs_left--;
      if(new_msgs_left == 0)
	break;
    }
  }
  procmsg_msg_list_free(msg_list);
  return FALSE;
}

void notification_core_free(void)
{
  if(notified_hash) {
    g_hash_table_destroy(notified_hash);
    notified_hash = NULL;
  }
  if(msg_count_hash) {
    g_hash_table_destroy(msg_count_hash);
    msg_count_hash = NULL;
  }
  debug_print("Notification Plugin: Freed internal data\n");
}

void notification_new_unnotified_msgs(FolderItemUpdateData *update_data)
{
  GSList *msg_list, *walk;

  g_return_if_fail(notified_hash != NULL);

  msg_list = folder_item_get_msg_list(update_data->item);

  for(walk = msg_list; walk; walk = g_slist_next(walk)) {
    MsgInfo *msg;
    msg = (MsgInfo*) walk->data;

    if(MSG_IS_NEW(msg->flags)) {
      gchar *msgid;

      if(msg->msgid)
	msgid = msg->msgid;
      else {
	debug_print("Notification Plugin: Message has not message ID!\n");
	msgid = "";
      }

      debug_print("Notification Plugin: Found msg %s, "
		  "checking if it is in hash...\n", msgid);
      /* Check if message is in hash table */
      if(g_hash_table_lookup(notified_hash, msgid) != NULL)
	debug_print("yes.\n");
      else {
	/* Add to hashtable */
	g_hash_table_insert(notified_hash, g_strdup(msgid),
			    GINT_TO_POINTER(1));
	debug_print("no, added to table.\n");

	/* Do the notification */
	notification_new_unnotified_do_msg(msg);
      }

    } /* msg is 'new' */
  } /* for all messages */
  procmsg_msg_list_free(msg_list);
}

#ifdef HAVE_LIBCANBERRA_GTK
static void canberra_finished_cb(ca_context *c, uint32_t id, int error, void *data)
{
  canberra_new_email_is_playing = FALSE;
}
#endif

static void notification_new_unnotified_do_msg(MsgInfo *msg)
{
#ifdef NOTIFICATION_POPUP
  notification_popup_msg(msg);
#endif
#ifdef NOTIFICATION_COMMAND
  notification_command_msg(msg);
#endif
#ifdef NOTIFICATION_TRAYICON
  notification_trayicon_msg(msg);
#endif

#ifdef HAVE_LIBCANBERRA_GTK
  /* canberra */
  if(notify_config.canberra_play_sounds && !canberra_new_email_is_playing) {
    MainWindow *mainwin;
    ca_proplist *proplist;
    mainwin = mainwindow_get_mainwindow();
    ca_proplist_create(&proplist);
    ca_proplist_sets(proplist,CA_PROP_EVENT_ID ,"message-new-email");
    canberra_new_email_is_playing = TRUE;
    ca_context_play_full(ca_gtk_context_get(), 0, proplist, canberra_finished_cb, NULL);
    ca_proplist_destroy(proplist);
  }
#endif
}

/* If folders is not NULL, then consider only those folder items
 * If max_msgs is not 0, stop after collecting msg_msgs messages
 */
GSList* notification_collect_msgs(gboolean unread_also, GSList *folder_items,
				  gint max_msgs)
{
  GList *folder_list, *walk;
  Folder *folder;
  TraverseCollect collect_data;

  collect_data.unread_also = unread_also;
  collect_data.collected_msgs = NULL;
  collect_data.folder_items = folder_items;
  collect_data.max_msgs = max_msgs;
  collect_data.num_msgs = 0;

  folder_list = folder_get_list();
  for(walk = folder_list; walk != NULL; walk = g_list_next(walk)) {
    folder = walk->data;

    g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
		    notification_traverse_collect, &collect_data);
  }
  return collect_data.collected_msgs;
}

void notification_collected_msgs_free(GSList *collected_msgs)
{
  if(collected_msgs) {
    GSList *walk;
    for(walk = collected_msgs; walk != NULL; walk = g_slist_next(walk)) {
      CollectedMsg *msg = walk->data;
      if(msg->from)
				g_free(msg->from);
      if(msg->subject)
				g_free(msg->subject);
      if(msg->folderitem_name)
				g_free(msg->folderitem_name);
			msg->msginfo = NULL;
      g_free(msg);
    }
    g_slist_free(collected_msgs);
  }
}

static gboolean notification_traverse_collect(GNode *node, gpointer data)
{
  TraverseCollect *cdata = data;
  FolderItem *item = node->data;
  gchar *folder_id_cur;

  /* Obey global folder type limitations */
  if(!notify_include_folder_type(item->folder->klass->type,
				 item->folder->klass->uistr))
    return FALSE;

  /* If a folder_items list was given, check it first */
  if((cdata->folder_items) && (item->path != NULL) &&
     ((folder_id_cur  = folder_item_get_identifier(item)) != NULL)) {
    FolderItem *list_item;
    GSList *walk;
    gchar *folder_id_list;
    gboolean eq;
    gboolean folder_in_list = FALSE;

    for(walk = cdata->folder_items; walk != NULL; walk = g_slist_next(walk)) {
      list_item = walk->data;
      folder_id_list = folder_item_get_identifier(list_item);
      eq = !strcmp2(folder_id_list,folder_id_cur);
      g_free(folder_id_list);
      if(eq) {
	folder_in_list = TRUE;
	break;
      }
    }
    g_free(folder_id_cur);
    if(!folder_in_list)
      return FALSE;
  }

  if(item->new_msgs || (cdata->unread_also && item->unread_msgs)) {
    GSList *msg_list = folder_item_get_msg_list(item);
    GSList *walk;
    for(walk = msg_list; walk != NULL; walk = g_slist_next(walk)) {
      MsgInfo *msg_info = walk->data;
      CollectedMsg *cmsg;

      if((cdata->max_msgs != 0) && (cdata->num_msgs >= cdata->max_msgs))
	return FALSE;

      if(MSG_IS_NEW(msg_info->flags) ||
				 (MSG_IS_UNREAD(msg_info->flags) && cdata->unread_also)) {

				cmsg = g_new(CollectedMsg, 1);
				cmsg->from = g_strdup(msg_info->from ? msg_info->from : "");
				cmsg->subject = g_strdup(msg_info->subject ? msg_info->subject : "");
				if(msg_info->folder && msg_info->folder->name)
					cmsg->folderitem_name = g_strdup(msg_info->folder->path);
				else
					cmsg->folderitem_name = g_strdup("");

				cmsg->msginfo = msg_info;

				cdata->collected_msgs = g_slist_prepend(cdata->collected_msgs, cmsg);
				cdata->num_msgs++;
      }
    }
    procmsg_msg_list_free(msg_list);
  }

  return FALSE;
}

gboolean notify_include_folder_type(FolderType ftype, gchar *uistr)
{
  gboolean retval;

  retval = FALSE;
  switch(ftype) {
  case F_MH:
  case F_MBOX:
  case F_MAILDIR:
  case F_IMAP:
    if(notify_config.include_mail)
      retval = TRUE;
    break;
  case F_NEWS:
    if(notify_config.include_news)
      retval = TRUE;
    break;
  case F_UNKNOWN:
    if(uistr == NULL)
      retval = FALSE;
    else if(!strcmp(uistr, "vCalendar")) {
      if(notify_config.include_calendar)
	retval = TRUE;
    }
    else if(!strcmp(uistr, "RSSyl")) {
      if(notify_config.include_rss)
	retval = TRUE;
    }
    else
      debug_print("Notification Plugin: Unknown folder type %d\n",ftype);
    break;
  default:
    debug_print("Notification Plugin: Unknown folder type %d\n",ftype);
  }

  return retval;
}

static void fix_folderview_scroll(MainWindow *mainwin)
{
	static gboolean fix_done = FALSE;

	if (fix_done)
		return;

	gtk_widget_queue_resize(mainwin->folderview->ctree);

	fix_done = TRUE;
}

void notification_show_mainwindow(MainWindow *mainwin)
{
      gtk_window_deiconify(GTK_WINDOW(mainwin->window));
      gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mainwin->window), FALSE);
      main_window_show(mainwin);
      gtk_window_present(GTK_WINDOW(mainwin->window));
      fix_folderview_scroll(mainwin);
}

#ifdef HAVE_LIBNOTIFY
#define STR_MAX_LEN 511
/* Returns a newly allocated string which needs to be freed */
gchar* notification_libnotify_sanitize_str(gchar *in)
{
  gint i_out;
  gchar tmp_str[STR_MAX_LEN+1];

  if(in == NULL) return NULL;

  i_out = 0;
  while(*in) {
    if(*in == '<') {
      if(i_out+3 >= STR_MAX_LEN) break;
      memcpy(&(tmp_str[i_out]),"<",4);
      in++; i_out += 4;
    }
    else if(*in == '>') {
      if(i_out+3 >= STR_MAX_LEN) break;
      memcpy(&(tmp_str[i_out]),">",4);
      in++; i_out += 4;
    }
    else if(*in == '&') {
      if(i_out+4 >= STR_MAX_LEN) break;
      memcpy(&(tmp_str[i_out]),"&",5);
      in++; i_out += 5;
    }
    else {
      if(i_out >= STR_MAX_LEN) break;
      tmp_str[i_out++] = *in++;
    }
  }
  tmp_str[i_out] = '\0';
  return strdup(tmp_str);
}

gchar* notification_validate_utf8_str(gchar *text)
{
  gchar *utf8_str = NULL;

  if(!g_utf8_validate(text, -1, NULL)) {
    debug_print("Notification plugin: String is not valid utf8, "
		"trying to fix it...\n");
    /* fix it */
    utf8_str = conv_codeset_strdup(text,
				   conv_get_locale_charset_str_no_utf8(),
				   CS_INTERNAL);
    /* check if the fix worked */
    if(utf8_str == NULL || !g_utf8_validate(utf8_str, -1, NULL)) {
      debug_print("Notification plugin: String is still not valid utf8, "
		  "sanitizing...\n");
      utf8_str = g_malloc(strlen(text)*2+1);
      conv_localetodisp(utf8_str, strlen(text)*2+1, text);
    }
  }
  else {
    debug_print("Notification plugin: String is valid utf8\n");
    utf8_str = g_strdup(text);
  }
  return utf8_str;
}
#endif

--- NEW FILE: version.rc ---
1 VERSIONINFO
 FILEVERSION 0, 0, 0, 0
 PRODUCTVERSION 0, 0, 0, 0
 FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
 FILEFLAGS 0x1L
#else
 FILEFLAGS 0x0L
#endif
 FILEOS 0x40004L
 FILETYPE 0x2L
 FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "000004b0"
        BEGIN
            VALUE "FileDescription", "notification Plugin\0"
            VALUE "FileVersion", "0.0.0.0\0"
            VALUE "ProductVersion", "0.0.0.0 Win32\0"
            VALUE "LegalCopyright", "GPL / © 1999-2008 Hiroyuki Yamamoto & The Claws Mail Team\0"
            VALUE "CompanyName", "GNU / Free Software Foundation\0"
            VALUE "ProductName", "Claws Mail\0"
//            VALUE "Comments", "\0"
//            VALUE "InternalName", "\0"
//            VALUE "LegalTrademarks", "\0"
//            VALUE "OriginalFilename", "\0"
//            VALUE "PrivateBuild", "\0"
//            VALUE "SpecialBuild", "\0"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x0, 1200
    END
END

--- NEW FILE: claws.def ---
LIBRARY CLAWS-MAIL.EXE
EXPORTS
get_locale_dir
check_plugin_version
debug_print_real
debug_srcname
hooks_register_hook
hooks_unregister_hook
account_get_list
addressbook_open
alertpanel
app_will_exit
claws_is_exiting
claws_is_starting
compose_mail_cb
compose_new
compose_reply_from_messageview
execute_command_line
file_exist
folder_find_item_from_identifier
folder_func_to_all_folders
folder_get_list
folder_has_parent_of_type
folder_item_get_identifier
folder_item_get_msg_list
folder_item_get_name
get_rc_dir
gtkut_convert_int_to_gdk_color
gtkut_stock_button_set_create
gtkut_window_new
inc_all_account_mail_cb
main_set_show_at_startup
mainwindow_get_mainwindow
main_window_hide
main_window_empty_trash
mainwindow_is_obscured
mainwindow_jump_to
main_window_show
main_window_toggle_work_offline
manage_window_destroy
manage_window_focus_in
manage_window_focus_out
manage_window_set_transient
manage_window_unmap
cm_menu_create_action_group_full
gtkut_ui_manager
cm_menu_create_action_group
cm_toggle_menu_set_active
cm_menu_set_sensitive
prefs_common_get_prefs
prefs_common_translated_header_name
prefs_file_close
prefs_file_close_revert
prefs_gtk_register_page
prefs_gtk_unregister_page
prefs_read_config
prefs_set_block_label
prefs_set_default
prefs_write_open
prefs_write_param
procmsg_get_message_file_path
procmsg_msg_list_free
stock_pixbuf_gdk
stock_pixbuf_gdk follow
strcmp2
xml_attr_new
xml_file_put_xml_decl
xml_free_tree
xml_node_new
xml_parse_file
xml_tag_add_attr
xml_tag_new
xml_write_tree

--- NEW FILE: notification_core.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_CORE_H
#define NOTIFICATION_CORE_H NOTIFICATION_CORE_H

#include "mainwindow.h"
#include "folder.h"
#include "procmsg.h"

typedef struct {
  gchar *from;
  gchar *subject;
  FolderItem *folder_item;
  gchar *folderitem_name;
	MsgInfo *msginfo;
} CollectedMsg;

typedef enum {
  F_TYPE_MAIL=0,
  F_TYPE_NEWS,
  F_TYPE_CALENDAR,
  F_TYPE_RSS,
  F_TYPE_LAST
} NotificationFolderType;

typedef struct 
{
  guint new_msgs;
  guint unread_msgs;
  guint unreadmarked_msgs;
  guint marked_msgs;
  guint total_msgs;
} NotificationMsgCount;

/* Collect new and possibly unread messages in all folders */
GSList*  notification_collect_msgs(gboolean, GSList*, gint);
void     notification_collected_msgs_free(GSList*);

void     notification_core_global_includes_changed(void);
void     notification_core_free(void);
void     notification_update_msg_counts(FolderItem*);
void     notification_core_get_msg_count(GSList*,NotificationMsgCount*);
void     notification_core_get_msg_count_of_foldername(gchar*, NotificationMsgCount*);
void     notification_new_unnotified_msgs(FolderItemUpdateData*);
gboolean notification_notified_hash_msginfo_update(MsgInfoUpdate*);
void     notification_notified_hash_startup_init(void);

void     notification_show_mainwindow(MainWindow *mainwin);
/* folder type specific settings */
gboolean notify_include_folder_type(FolderType, gchar*);

void notification_toggle_hide_show_window(void);

#ifdef HAVE_LIBNOTIFY
/* Sanitize a string to use with libnotify. Returns a freshly
 * allocated string that must be freed by the user. */
gchar* notification_libnotify_sanitize_str(gchar*);
/* Returns a freshly allocated copy of the input string, which
 * is guaranteed to be valid UTF8. The returned string has to
 * be freed. */
gchar* notification_validate_utf8_str(gchar*);
#endif

#endif /* NOTIFICATION_CORE_H */

--- NEW FILE: notification_command.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_COMMAND_H
#define NOTIFICATION_COMMAND_H NOTIFICATION_COMMAND_H 

#include "pluginconfig.h"

#ifdef NOTIFICATION_COMMAND

#include "procmsg.h"

#define COMMAND_SPECIFIC_FOLDER_ID_STR "command"

void notification_command_msg(MsgInfo*);

#endif /* NOTIFICATION_COMMAND */

#endif /* include guard */

--- NEW FILE: notification_hotkeys.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2009 Holger Berndt and the Claws Mail Team.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_HOTKEYS_H
#define NOTIFICATION_HOTKEYS_H NOTIFICATION_HOTKEYS_H

#include "pluginconfig.h"

#ifdef NOTIFICATION_HOTKEYS

#include <glib.h>

void notification_hotkeys_update_bindings();
void notification_hotkeys_unbind_all();

#endif /* NOTIFICATION_HOTKEYS */
#endif /* NOTIFICATION_HOTKEYS_H */

--- NEW FILE: notification_pixbuf.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "notification_pixbuf.h"

/* The following files were created from the respective .png or
 * xpm files with the command 
 * gdk-pixbuf-csource --raw --name=<name> file.png > <name>.h
 */
/* From the Claws-Mail distribution */
#include "raw_claws_mail_logo_64x64.h"

#include "stock_pixmap.h"

static GdkPixbuf* notification_pixbuf[NOTIFICATION_PIXBUF_LAST];

GdkPixbuf* notification_pixbuf_get(NotificationPixbuf wanted)
{
  if(!notification_pixbuf[wanted]) {
    switch(wanted) {
    case NOTIFICATION_CM_LOGO_64x64:
      notification_pixbuf[wanted] =
				gdk_pixbuf_new_from_inline(-1, raw_claws_mail_logo_64x64,
																	 FALSE, NULL);
      break;
    case NOTIFICATION_TRAYICON_NEWMAIL:
			stock_pixbuf_gdk(NULL, STOCK_PIXMAP_TRAY_NEWMAIL, &(notification_pixbuf[wanted]));
      g_object_ref(notification_pixbuf[wanted]);
      break;
    case NOTIFICATION_TRAYICON_NEWMAIL_OFFLINE:
			stock_pixbuf_gdk(NULL, STOCK_PIXMAP_TRAY_NEWMAIL_OFFLINE, &(notification_pixbuf[wanted]));
      g_object_ref(notification_pixbuf[wanted]);
      break;
    case NOTIFICATION_TRAYICON_NEWMARKEDMAIL:
			stock_pixbuf_gdk(NULL, STOCK_PIXMAP_TRAY_NEWMARKEDMAIL, &(notification_pixbuf[wanted]));
      g_object_ref(notification_pixbuf[wanted]);
      break;
    case NOTIFICATION_TRAYICON_NEWMARKEDMAIL_OFFLINE:
			stock_pixbuf_gdk(NULL, STOCK_PIXMAP_TRAY_NEWMARKEDMAIL_OFFLINE, &(notification_pixbuf[wanted]));
      g_object_ref(notification_pixbuf[wanted]);
      break;
    case NOTIFICATION_TRAYICON_NOMAIL:
			stock_pixbuf_gdk(NULL, STOCK_PIXMAP_TRAY_NOMAIL, &(notification_pixbuf[wanted]));
      g_object_ref(notification_pixbuf[wanted]);
      break;
    case NOTIFICATION_TRAYICON_NOMAIL_OFFLINE:
			stock_pixbuf_gdk(NULL, STOCK_PIXMAP_TRAY_NOMAIL_OFFLINE, &(notification_pixbuf[wanted]));
      g_object_ref(notification_pixbuf[wanted]);
      break;
    case NOTIFICATION_TRAYICON_UNREADMAIL:
			stock_pixbuf_gdk(NULL, STOCK_PIXMAP_TRAY_UNREADMAIL, &(notification_pixbuf[wanted]));
      g_object_ref(notification_pixbuf[wanted]);
      break;
    case NOTIFICATION_TRAYICON_UNREADMAIL_OFFLINE:
			stock_pixbuf_gdk(NULL, STOCK_PIXMAP_TRAY_UNREADMAIL_OFFLINE, &(notification_pixbuf[wanted]));
      g_object_ref(notification_pixbuf[wanted]);
      break;
    case NOTIFICATION_TRAYICON_UNREADMARKEDMAIL:
			stock_pixbuf_gdk(NULL, STOCK_PIXMAP_TRAY_UNREADMARKEDMAIL, &(notification_pixbuf[wanted]));
      g_object_ref(notification_pixbuf[wanted]);
      break;
    case NOTIFICATION_TRAYICON_UNREADMARKEDMAIL_OFFLINE:
			stock_pixbuf_gdk(NULL, STOCK_PIXMAP_TRAY_UNREADMARKEDMAIL_OFFLINE, &(notification_pixbuf[wanted]));
      g_object_ref(notification_pixbuf[wanted]);
      break;
    case NOTIFICATION_PIXBUF_LAST:
      break;
    }
  }
  return notification_pixbuf[wanted];
}

void notification_pixbuf_free_all(void)
{
  gint ii;

  for(ii = NOTIFICATION_CM_LOGO_64x64; ii < NOTIFICATION_PIXBUF_LAST; ii++) {
    if(notification_pixbuf[ii]) {
      g_object_unref(notification_pixbuf[ii]);
      notification_pixbuf[ii] = NULL;
    }
  }
}

--- NEW FILE: notification_hotkeys.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2009 Holger Berndt and the Claws Mail Team.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "pluginconfig.h"

#ifdef NOTIFICATION_HOTKEYS

#include "notification_hotkeys.h"
#include "notification_prefs.h"
#include "notification_core.h"

#include "gtkhotkey.h"

#define HOTKEYS_APP_ID "claws-mail"
#define HOTKEY_KEY_ID_TOGGLED "toggle-mainwindow"

static GtkHotkeyInfo *hotkey_toggle_mainwindow = NULL;

static void hotkey_toggle_mainwindow_activated(GtkHotkeyInfo *hotkey, guint event_time, gpointer data)
{
  g_return_if_fail(GTK_HOTKEY_IS_INFO(hotkey));
  debug_print("Notification plugin: Toggled hide/show window due to hotkey %s activation\n", gtk_hotkey_info_get_signature(hotkey));
  notification_toggle_hide_show_window();
}

static void unbind_toggle_mainwindow()
{
  GError *error;
  GtkHotkeyRegistry *registry;

  /* clean up old hotkey */
  if(hotkey_toggle_mainwindow) {
    if(gtk_hotkey_info_is_bound(hotkey_toggle_mainwindow)) {
      error = NULL;
      gtk_hotkey_info_unbind(hotkey_toggle_mainwindow, &error);
      if(error) {
        debug_print("Notification plugin: Failed to unbind toggle hotkey\n");
        g_error_free(error);
        return;
      }
    }
    g_object_unref(hotkey_toggle_mainwindow);
    hotkey_toggle_mainwindow = NULL;
  }
  registry = gtk_hotkey_registry_get_default();
  if(gtk_hotkey_registry_has_hotkey(registry, HOTKEYS_APP_ID, HOTKEY_KEY_ID_TOGGLED)) {
    error = NULL;
    gtk_hotkey_registry_delete_hotkey(registry, HOTKEYS_APP_ID, HOTKEY_KEY_ID_TOGGLED, &error);
    if(error) {
      debug_print("Notification plugin: Failed to unregister toggle hotkey: %s\n", error->message);
      g_error_free(error);
      return;
    }
  }
}

static void update_hotkey_binding_toggle_mainwindow()
{
  GError *error;

  /* don't do anything if no signature is given */
  if(!notify_config.hotkeys_toggle_mainwindow || !strcmp(notify_config.hotkeys_toggle_mainwindow, ""))
    return;

  unbind_toggle_mainwindow();

  /* (re)create hotkey info */
  hotkey_toggle_mainwindow = gtk_hotkey_info_new(HOTKEYS_APP_ID, HOTKEY_KEY_ID_TOGGLED, notify_config.hotkeys_toggle_mainwindow, NULL);
  if(!hotkey_toggle_mainwindow) {
    debug_print("Notification plugin: Failed to create toggle hotkey for '%s'\n", notify_config.hotkeys_toggle_mainwindow);
    return;
  }

  /* try to register hotkey */
  error = NULL;
  gtk_hotkey_info_bind(hotkey_toggle_mainwindow, &error);
  if(error) {
    debug_print("Notification plugin: Failed to bind toggle hotkey to '%s': %s\n", notify_config.hotkeys_toggle_mainwindow, error->message);
    g_error_free(error);
    return;
  }

  g_signal_connect(hotkey_toggle_mainwindow, "activated", G_CALLBACK(hotkey_toggle_mainwindow_activated), NULL);
}

void notification_hotkeys_update_bindings()
{
  debug_print("Notification plugin: Updating keybindings..\n");
  if(notify_config.hotkeys_enabled) {
    update_hotkey_binding_toggle_mainwindow();
  }
  else
    notification_hotkeys_unbind_all();
}

void notification_hotkeys_unbind_all()
{
  debug_print("Notification plugin: Unbinding all keybindings..\n");
  unbind_toggle_mainwindow();
}

#endif /* NOTIFICATION_HOTKEYS */

--- NEW FILE: notification_pixbuf.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_PIXBUF_H
#define NOTIFICATION_PIXBUF_H NOTIFICATION_PIXBUF_H

#include <gdk/gdk.h>

/* By convention, the online icons for the trayicon are 
 * immediately followed by the offline icons, so one can do
 * offline = array[online+1] */
typedef enum {
  NOTIFICATION_CM_LOGO_64x64 = 0,
  NOTIFICATION_TRAYICON_NEWMAIL,
  NOTIFICATION_TRAYICON_NEWMAIL_OFFLINE,
  NOTIFICATION_TRAYICON_NEWMARKEDMAIL,
  NOTIFICATION_TRAYICON_NEWMARKEDMAIL_OFFLINE,
  NOTIFICATION_TRAYICON_NOMAIL,
  NOTIFICATION_TRAYICON_NOMAIL_OFFLINE,
  NOTIFICATION_TRAYICON_UNREADMAIL,
  NOTIFICATION_TRAYICON_UNREADMAIL_OFFLINE,
  NOTIFICATION_TRAYICON_UNREADMARKEDMAIL,
  NOTIFICATION_TRAYICON_UNREADMARKEDMAIL_OFFLINE,
  NOTIFICATION_PIXBUF_LAST
} NotificationPixbuf;

/* The reference to the returned GdkPixbuf's belongs to notification_pixbuf,
 * and shall not be removed outside. */
GdkPixbuf* notification_pixbuf_get(NotificationPixbuf);

void notification_pixbuf_free_all(void);

#endif /* NOTIFICATION_PIXBUF_H */

--- NEW FILE: notification_lcdproc.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_LCDPROC_H
#define NOTIFICATION_LCDPROC_H NOTIFICATION_LCDPROC_H

#include "pluginconfig.h"

#ifdef NOTIFICATION_LCDPROC

#include <glib.h>

void notification_lcdproc_connect(void);
void notification_lcdproc_disconnect(void);

void notification_update_lcdproc(void);

#endif /* NOTIFICATION_LCDPROC */

#endif /* include guard */

--- NEW FILE: notification_lcdproc.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "pluginconfig.h"

#ifdef NOTIFICATION_LCDPROC

#include "notification_lcdproc.h"
#include "notification_prefs.h"
#include "notification_core.h"

#include "common/socket.h"

#include <string.h>
#include <sys/socket.h>

#define NOTIFICATION_LCDPROC_BUFFER_SIZE 8192

void notification_sock_puts(SockInfo*, gchar*);
void notification_lcdproc_send(gchar*);

static SockInfo *sock = NULL;

void notification_lcdproc_connect(void)
{
  gint len, count;
  gchar buf[NOTIFICATION_LCDPROC_BUFFER_SIZE];

  if(!notify_config.lcdproc_enabled)
    return;

  if(sock)
    notification_lcdproc_disconnect();

  sock = sock_connect(notify_config.lcdproc_hostname,
		      notify_config.lcdproc_port);
  /*
   * Quietly return when a connection fails; next attempt
   * will be made when some folder info has been changed.
   */
  if(sock == NULL || sock->state == CONN_FAILED) {
    debug_print("Could not connect to LCDd\n");
    if(sock && sock->state == CONN_FAILED) {
      sock_close(sock);
      sock = NULL;
    }
    return;
  }
  else
    debug_print("Connected to LCDd\n");
  
  sock_set_nonblocking_mode(sock, TRUE);

  /* Friendly people say "hello" first */
  notification_sock_puts(sock, "hello");

  /* FIXME: Ouch. Is this really the way to go? */
  count = 50;
  len = 0;
  while((len <= 0) && (count-- >= 0)) {
    g_usleep(125000);
    len = sock_read(sock, buf, NOTIFICATION_LCDPROC_BUFFER_SIZE);
  }
  
/*
 * This might not be a LCDProc server.
 * FIXME: check LCD size, LCDd version etc
 */
  
  if (len <= 0) {
    debug_print("Notification plugin: Can't communicate with "
		"LCDd server! Are you sure that "
		"there is a LCDd server running on %s:%d?\n",
		notify_config.lcdproc_hostname, notify_config.lcdproc_port);
    notification_lcdproc_disconnect();
    return;
  }
  
  notification_lcdproc_send("client_set -name \"{Claws-Mail}\"");

  notification_lcdproc_send("screen_add msg_counts");
  notification_lcdproc_send("screen_set msg_counts -name {Claws-Mail Message Count}");
  
  notification_lcdproc_send("widget_add msg_counts title title");
  notification_lcdproc_send("widget_set msg_counts title {Claws-Mail}");
  notification_lcdproc_send("widget_add msg_counts line1 string");
  notification_lcdproc_send("widget_add msg_counts line2 string");
  notification_lcdproc_send("widget_add msg_counts line3 string");

  notification_update_msg_counts(NULL);
}

void notification_lcdproc_disconnect(void)
{
  if(sock) {
#ifndef G_OS_WIN32
    shutdown(sock->sock, SHUT_RDWR);
#endif
    sock_close(sock);
    sock = NULL;
  }
}

void notification_update_lcdproc(void)
{
  NotificationMsgCount count;
  gchar *buf;

  if(!notify_config.lcdproc_enabled || !sock)
    return;

  if(!sock || sock->state == CONN_FAILED) {
    notification_lcdproc_connect();
    return;
  }
  
  notification_core_get_msg_count(NULL, &count);

  if((count.new_msgs + count.unread_msgs) > 0) {
    buf =
      g_strdup_printf("widget_set msg_counts line1 1 2 {%s: %d}",_("New"),
		      count.new_msgs);
    notification_lcdproc_send(buf);
    buf =
      g_strdup_printf("widget_set msg_counts line2 1 3 {%s: %d}",_("Unread"),
		      count.unread_msgs);
    notification_lcdproc_send(buf);
    buf =
      g_strdup_printf("widget_set msg_counts line3 1 4 {%s: %d}",_("Total"),
		      count.total_msgs);
    notification_lcdproc_send(buf);
  }
  else {
    buf = g_strdup_printf("widget_set msg_counts line1 1 2 {%s}",
			  _("No new messages"));
    notification_lcdproc_send(buf);
    buf = g_strdup_printf("widget_set msg_counts line2 1 3 {}");
    notification_lcdproc_send(buf);
    buf = g_strdup_printf("widget_set msg_counts line3 1 4 {}");
    notification_lcdproc_send(buf);
  }

  g_free(buf);
}

void notification_sock_puts(SockInfo *socket, gchar *string)
{
  sock_write(socket, string, strlen(string));
  sock_write(socket, "\n", 1);
}

void notification_lcdproc_send(gchar *string)
{
  notification_sock_puts(sock, string);
  /* TODO: Check return message from LCDd */
}

#endif /* NOTIFICATION_LCDPROC */

--- NEW FILE: notification_popup.c ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "pluginconfig.h"

#ifdef NOTIFICATION_POPUP

#include <gtk/gtk.h>

#include "mainwindow.h"
#include "procmsg.h"
#include "folder.h"
#ifndef USE_NEW_ADDRBOOK
    #include "addrindex.h"
#endif
#include "common/utils.h"
#include "gtk/gtkutils.h"

#include "notification_popup.h"
#include "notification_prefs.h"
#include "notification_foldercheck.h"
#include "notification_pixbuf.h"
#include "notification_core.h"

#ifdef HAVE_LIBNOTIFY
#  include <libnotify/notify.h>
#endif

#ifndef NOTIFY_CHECK_VERSION
# define NOTIFY_CHECK_VERSION(a,b,c) 0
#endif

typedef struct {
  gint count;
  gchar *msg_path;
#ifdef HAVE_LIBNOTIFY
  NotifyNotification *notification;
  GError *error;
#else /* !HAVE_LIBNOTIFY */
  guint timeout_id;
  GtkWidget *window;
  GtkWidget *frame;
  GtkWidget *event_box;
  GtkWidget *vbox;
  GtkWidget *label1;
  GtkWidget *label2;
#endif
} NotificationPopup;

G_LOCK_DEFINE_STATIC(popup);

#ifdef HAVE_LIBNOTIFY
static NotificationPopup popup[F_TYPE_LAST];

static void popup_timeout_fun(NotifyNotification*, gpointer data);

static gboolean notification_libnotify_create(MsgInfo*, NotificationFolderType);
static gboolean notification_libnotify_add_msg(MsgInfo*, NotificationFolderType);
static void default_action_cb(NotifyNotification*, const char*,void*);
static void notification_libnotify_free_func(gpointer);

#else
static NotificationPopup popup;

static gboolean popup_timeout_fun(gpointer data);

static gboolean notification_popup_add_msg(MsgInfo*);
static gboolean notification_popup_create(MsgInfo*);
static gboolean notification_popup_button(GtkWidget*, GdkEventButton*, gpointer);
#endif


void notification_popup_msg(MsgInfo *msginfo)
{
  gboolean retval;
  FolderType ftype;
  NotificationPopup *ppopup;
#if HAVE_LIBNOTIFY
  gchar *uistr;
#endif
  NotificationFolderType nftype;

  nftype = F_TYPE_MAIL;

  if(!msginfo || !notify_config.popup_show)
    return;

  if(notify_config.popup_folder_specific) {
    guint id;
    GSList *list;
    gchar *identifier;
    gboolean found = FALSE;

    if(!(msginfo->folder))
      return;

    identifier = folder_item_get_identifier(msginfo->folder);

    id =
      notification_register_folder_specific_list(POPUP_SPECIFIC_FOLDER_ID_STR);
    list = notification_foldercheck_get_list(id);
    for(; (list != NULL) && !found; list = g_slist_next(list)) {
      gchar *list_identifier;
      FolderItem *list_item = (FolderItem*) list->data;

      list_identifier = folder_item_get_identifier(list_item);
      if(!strcmp2(list_identifier, identifier))
	found = TRUE;

      g_free(list_identifier);
    }
    g_free(identifier);

    if(!found)
      return;
  }

  ftype = msginfo->folder->folder->klass->type;

  G_LOCK(popup);
#ifdef HAVE_LIBNOTIFY
  /* Check out which type to notify about */
  switch(ftype) {
  case F_MH:
  case F_MBOX:
  case F_MAILDIR:
  case F_IMAP:
    nftype = F_TYPE_MAIL;
    break;
  case F_NEWS:
    nftype = F_TYPE_NEWS;
    break;
  case F_UNKNOWN:
    if((uistr = msginfo->folder->folder->klass->uistr) == NULL) {
      G_UNLOCK(popup);
      return;
    }
    else if(!strcmp(uistr, "vCalendar"))
      nftype = F_TYPE_CALENDAR;
    else if(!strcmp(uistr, "RSSyl"))
      nftype = F_TYPE_RSS;
    else {
      debug_print("Notification Plugin: Unknown folder type %d\n",ftype);
      G_UNLOCK(popup);
      return;
    }
    break;
  default:
    debug_print("Notification Plugin: Unknown folder type %d\n",ftype);
    G_UNLOCK(popup);
    return;
  }

  ppopup = &(popup[nftype]);
  retval = notification_libnotify_add_msg(msginfo, nftype);
#else /* !HAVE_LIBNOTIFY */
  ppopup = &popup;
  retval = notification_popup_add_msg(msginfo);

  /* Renew timeout only when the above call was successful */
  if(retval) {
    if(ppopup->timeout_id)
      g_source_remove(ppopup->timeout_id);
    ppopup->timeout_id = g_timeout_add(notify_config.popup_timeout,
                       popup_timeout_fun,
                       GINT_TO_POINTER(nftype));
  }

  #endif /* !HAVE_LIBNOTIFY */

  G_UNLOCK(popup);

#ifndef HAVE_LIBNOTIFY
  /* GUI update */
  while(gtk_events_pending())
    gtk_main_iteration();
#endif /* !HAVE_LIBNOTIFY */

}

#ifdef HAVE_LIBNOTIFY
static void popup_timeout_fun(NotifyNotification *nn, gpointer data)
{
  NotificationPopup *ppopup;
  NotificationFolderType nftype;

  nftype = GPOINTER_TO_INT(data);

  G_LOCK(popup);

  ppopup = &(popup[nftype]);

  g_object_unref(G_OBJECT(ppopup->notification));
  ppopup->notification = NULL;
  g_clear_error(&(ppopup->error));

  if(ppopup->msg_path) {
    g_free(ppopup->msg_path);
    ppopup->msg_path = NULL;
  }
  ppopup->count = 0;
  G_UNLOCK(popup);
  debug_print("Notification Plugin: Popup closed due to timeout.\n");
}

#else
static gboolean popup_timeout_fun(gpointer data)
{
  NotificationPopup *ppopup;
  NotificationFolderType nftype;

  nftype = GPOINTER_TO_INT(data);

  G_LOCK(popup);

  ppopup = &popup;
  if(ppopup->window) {
    gtk_widget_destroy(ppopup->window);
    ppopup->window = NULL;
  }
  ppopup->timeout_id = 0;

  if(ppopup->msg_path) {
    g_free(ppopup->msg_path);
    ppopup->msg_path = NULL;
  }
  ppopup->count = 0;
  G_UNLOCK(popup);
  debug_print("Notification Plugin: Popup closed due to timeout.\n");
  return FALSE;
}
#endif

#ifdef HAVE_LIBNOTIFY
static void default_action_cb(NotifyNotification *notification,
			      const char *action,
			      void *user_data)
{
  if(strcmp("default", action))
    return;

  MainWindow *mainwin;
  mainwin = mainwindow_get_mainwindow();
  if(mainwin) {
    NotificationFolderType nftype;

    /* Let mainwindow pop up */
    notification_show_mainwindow(mainwin);
    /* If there is only one new mail message, jump to this message */
    nftype = (NotificationFolderType)GPOINTER_TO_INT(user_data);
    if(nftype == F_TYPE_MAIL) {
      if(popup[F_TYPE_MAIL].count == 1) {
	gchar *select_str;
	G_LOCK(popup);
	select_str = g_strdup(popup[F_TYPE_MAIL].msg_path);
	G_UNLOCK(popup);
	debug_print("Select message %s\n", select_str);
	mainwindow_jump_to(select_str, FALSE);
	g_free(select_str);
      }
    }
  }
}

static gboolean notification_libnotify_create(MsgInfo *msginfo,
					      NotificationFolderType nftype)
{
  GdkPixbuf *pixbuf;
  NotificationPopup *ppopup;
  gchar *summary = NULL;
  gchar *text = NULL;
  gchar *utf8_str = NULL;
  gchar *subj = NULL;
  gchar *from = NULL;
  gchar *foldname = NULL;
  GList *caps = NULL;
  gboolean support_actions = FALSE;

  g_return_val_if_fail(msginfo, FALSE);

  ppopup = &(popup[nftype]);

  /* init libnotify if necessary */
  if(!notify_is_initted()) {
    if(!notify_init("claws-mail")) {
      debug_print("Notification Plugin: Failed to initialize libnotify. "
		  "No popup will be shown.\n");
      return FALSE;
    }
  }

  switch(nftype) {
  case F_TYPE_MAIL:
    summary = _("New Mail message");
    from    = notification_libnotify_sanitize_str(msginfo->from ?
                                                  msginfo->from : _("(No From)"));
    subj    = notification_libnotify_sanitize_str(msginfo->subject ?
                                                  msginfo->subject : _("(No Subject)"));
	if (notify_config.popup_display_folder_name) {
		foldname = notification_libnotify_sanitize_str(msginfo->folder->path);
    	text = g_strconcat(from,"\n\n", subj, "\n\n", foldname, NULL);
	}
	else
		text = g_strconcat(from, "\n\n",subj, NULL);

    /* Make sure text is valid UTF8 */
    utf8_str = notification_validate_utf8_str(text);
    g_free(text);

    if(from) g_free(from);
    if(subj) g_free(subj);
    if(foldname) g_free(foldname);
    break;
  case F_TYPE_NEWS:
    summary = _("New News post");
    utf8_str    = g_strdup(_("A new message arrived"));
    break;
  case F_TYPE_CALENDAR:
    summary = _("New Calendar message");
    utf8_str    = g_strdup(_("A new calendar message arrived"));
    break;
  case F_TYPE_RSS:
    summary = _("New RSS feed article");
    utf8_str = g_strdup(_("A new article in a RSS feed arrived"));
    break;
  default:
    summary = _("New unknown message");
    utf8_str = g_strdup(_("Unknown message type arrived"));
    break;
  }

  ppopup->notification = notify_notification_new(summary, utf8_str, NULL
#if !NOTIFY_CHECK_VERSION(0, 7, 0)
      , NULL
#endif
      );
  g_free(utf8_str);
  if(ppopup->notification == NULL) {
    debug_print("Notification Plugin: Failed to create a new "
		"notification.\n");
    return FALSE;
  }

  caps = notify_get_server_caps();
    if(caps != NULL) {
      GList *c;
      for(c = caps; c != NULL; c = c->next) {
	if(strcmp((char*)c->data, "actions") == 0 ) {
	  support_actions = TRUE;
	  break;
        }
      }

    g_list_foreach(caps, (GFunc)g_free, NULL);
    g_list_free(caps);
  }

  /* Default action */
  if (support_actions)
    notify_notification_add_action(ppopup->notification,
				   "default", "Present main window",
				   (NotifyActionCallback)default_action_cb,
				   GINT_TO_POINTER(nftype),
				   notification_libnotify_free_func);

  /* Icon */
  pixbuf = NULL;
#ifndef USE_NEW_ADDRBOOK
  if(msginfo && msginfo->from) {
    gchar *icon_path;
    icon_path = addrindex_get_picture_file(msginfo->from);
    if(is_file_exist(icon_path)) {
      GError *error = NULL;
      gint w, h;

      gdk_pixbuf_get_file_info(icon_path, &w, &h);
      if((w > 64) || (h > 64))
	pixbuf = gdk_pixbuf_new_from_file_at_scale(icon_path,
						   64, 64, TRUE, &error);
      else
	pixbuf = gdk_pixbuf_new_from_file(icon_path, &error);

      if(!pixbuf) {
	debug_print("Could not load picture file: %s\n",
		    error ? error->message : "no details");
	g_error_free(error);
      }
    }
    else
      debug_print("Picture path does not exist: %s\n",icon_path);
    g_free(icon_path);
  }
#endif
  if(!pixbuf)
   pixbuf = g_object_ref(notification_pixbuf_get(NOTIFICATION_CM_LOGO_64x64));

  if(pixbuf) {
    notify_notification_set_icon_from_pixbuf(ppopup->notification, pixbuf);
    g_object_unref(pixbuf);
  }
  else /* This is not fatal */
    debug_print("Notification plugin: Icon could not be loaded.\n");

  /* timeout */
  notify_notification_set_timeout(ppopup->notification, notify_config.popup_timeout);

  /* Category */
  notify_notification_set_category(ppopup->notification, "email.arrived");

  /* get notified on bubble close */
  g_signal_connect(G_OBJECT(popup->notification), "closed", G_CALLBACK(popup_timeout_fun), NULL);

  /* Show the popup */
  notify_notification_set_hint_string(ppopup->notification, "desktop-entry", "claws-mail");
  if(!notify_notification_show(ppopup->notification, &(ppopup->error))) {
    debug_print("Notification Plugin: Failed to send notification: %s\n",
		ppopup->error->message);
    g_clear_error(&(ppopup->error));
    g_object_unref(G_OBJECT(ppopup->notification));
    ppopup->notification = NULL;
    return FALSE;
  }

  debug_print("Notification Plugin: Popup created with libnotify.\n");
  ppopup->count = 1;

  /* Store path to message */
  if(nftype == F_TYPE_MAIL) {
    if(msginfo->folder && msginfo->folder) {
      gchar *ident;
      ident = folder_item_get_identifier(msginfo->folder);
      ppopup->msg_path = g_strdup_printf("%s%s%u", ident,G_DIR_SEPARATOR_S,
					 msginfo->msgnum);
      g_free(ident);
    }
    else
      ppopup->msg_path = NULL;
  }

  return TRUE;
}

static gboolean notification_libnotify_add_msg(MsgInfo *msginfo,
					       NotificationFolderType nftype)
{
  gchar *summary;
  gchar *text;
  gboolean retval;
  NotificationPopup *ppopup;
  GdkPixbuf *pixbuf;

  ppopup = &(popup[nftype]);

  if(!ppopup->notification)
    return notification_libnotify_create(msginfo,nftype);

  ppopup->count++;

  if(ppopup->msg_path) {
    g_free(ppopup->msg_path);
    ppopup->msg_path = NULL;
  }

  /* make sure we show a logo on many msg arrival */
  pixbuf = notification_pixbuf_get(NOTIFICATION_CM_LOGO_64x64);
  if(pixbuf)
    notify_notification_set_icon_from_pixbuf(ppopup->notification, pixbuf);

  switch(nftype) {
  case F_TYPE_MAIL:
    summary = _("Mail message");
    text = g_strdup_printf(ngettext("%d new message arrived",
				    "%d new messages arrived",
				    ppopup->count), ppopup->count);
    break;
  case F_TYPE_NEWS:
    summary = _("News message");
    text = g_strdup_printf(ngettext("%d new message arrived",
                                     "%d new messages arrived",
				     ppopup->count), ppopup->count);
    break;
  case F_TYPE_CALENDAR:
    summary = _("Calendar message");
    text = g_strdup_printf(ngettext("%d new calendar message arrived",
                                     "%d new calendar messages arrived",
				     ppopup->count), ppopup->count);
    break;
  case F_TYPE_RSS:
    summary = _("RSS news feed");
    text = g_strdup_printf(ngettext("%d new article in a RSS feed arrived",
                                     "%d new articles in a RSS feed arrived",
				     ppopup->count), ppopup->count);
    break;
  default:
    /* Should not happen */
    debug_print("Notification Plugin: Unknown folder type ignored\n");
    return FALSE;
  }

  retval = notify_notification_update(ppopup->notification, summary,
				      text, NULL);
  g_free(text);
  if(!retval) {
    debug_print("Notification Plugin: Failed to update notification.\n");
    return FALSE;
  }

  /* Show the popup */
  notify_notification_set_hint_string(ppopup->notification, "desktop-entry", "claws-mail");
  if(!notify_notification_show(ppopup->notification, &(ppopup->error))) {
    debug_print("Notification Plugin: Failed to send updated notification: "
		"%s\n",	ppopup->error->message);
    g_clear_error(&(ppopup->error));
    return FALSE;
  }

  debug_print("Notification Plugin: Popup successfully modified "
	      "with libnotify.\n");
  return TRUE;
}

void notification_libnotify_free_func(gpointer data)
{
  if(popup[F_TYPE_MAIL].msg_path) {
    g_free(popup[F_TYPE_MAIL].msg_path);
    popup[F_TYPE_MAIL].msg_path = NULL;
  }
  debug_print("Freed notification data\n");
}

#else /* !HAVE_LIBNOTIFY */
static gboolean notification_popup_add_msg(MsgInfo *msginfo)
{
  gchar *message;
  NotificationPopup *ppopup;

  ppopup = &popup;

  if(!ppopup->window)
    return notification_popup_create(msginfo);

  ppopup->count++;

  if(ppopup->msg_path) {
    g_free(ppopup->msg_path);
    ppopup->msg_path = NULL;
  }

  if(ppopup->label2)
    gtk_widget_destroy(ppopup->label2);

  message = g_strdup_printf(ngettext("%d new message",
				     "%d new messages",
				     ppopup->count), ppopup->count);
  gtk_label_set_text(GTK_LABEL(ppopup->label1), message);
  g_free(message);
  return TRUE;
}

static gboolean notification_popup_create(MsgInfo *msginfo)
{
  GdkColor bg;
  GdkColor fg;
  NotificationPopup *ppopup;

  g_return_val_if_fail(msginfo, FALSE);

  ppopup = &popup;

  /* Window */
  ppopup->window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "notification_popup");
  gtk_window_set_decorated(GTK_WINDOW(ppopup->window), FALSE);
  gtk_window_set_keep_above(GTK_WINDOW(ppopup->window), TRUE);
  gtk_window_set_accept_focus(GTK_WINDOW(ppopup->window), FALSE);
  gtk_window_set_skip_taskbar_hint(GTK_WINDOW(ppopup->window), TRUE);
  gtk_window_set_skip_pager_hint(GTK_WINDOW(ppopup->window), TRUE);
  gtk_window_move(GTK_WINDOW(ppopup->window), notify_config.popup_root_x,
		  notify_config.popup_root_y);
  gtk_window_resize(GTK_WINDOW(ppopup->window), notify_config.popup_width, 1);
  if(notify_config.popup_sticky)
    gtk_window_stick(GTK_WINDOW(ppopup->window));
  /* Signals */
  gtk_widget_set_events(ppopup->window,
			GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
  g_signal_connect(ppopup->window, "button_press_event",
		   G_CALLBACK(notification_popup_button), NULL);

  /* Event box */
  ppopup->event_box = gtk_event_box_new();
  gtk_container_add(GTK_CONTAINER(ppopup->window), ppopup->event_box);

  /* Frame */
  ppopup->frame = gtk_frame_new(NULL);
  gtk_frame_set_shadow_type(GTK_FRAME(ppopup->frame), GTK_SHADOW_ETCHED_OUT);
  gtk_container_add(GTK_CONTAINER(ppopup->event_box), ppopup->frame);

  /* Vbox with labels */
  ppopup->vbox = gtk_vbox_new(FALSE, 2);
  gtk_container_set_border_width(GTK_CONTAINER(ppopup->vbox), 5);
  ppopup->label1 = gtk_label_new(msginfo->from ?
                                 msginfo->from : _("(No From)"));
  gtk_box_pack_start(GTK_BOX(ppopup->vbox), ppopup->label1, FALSE, FALSE, 0);

  ppopup->label2 = gtk_label_new(msginfo->subject ?
                                 msginfo->subject : _("(No Subject)"));
  gtk_box_pack_start(GTK_BOX(ppopup->vbox), ppopup->label2, FALSE, FALSE, 0);

  gtk_container_add(GTK_CONTAINER(ppopup->frame), ppopup->vbox);
  gtk_widget_set_size_request(ppopup->vbox, notify_config.popup_width, -1);

  /* Color */
  if(notify_config.popup_enable_colors) {
    gtkut_convert_int_to_gdk_color(notify_config.popup_color_bg,&bg);
    gtkut_convert_int_to_gdk_color(notify_config.popup_color_fg,&fg);
    gtk_widget_modify_bg(ppopup->event_box,GTK_STATE_NORMAL,&bg);
    gtk_widget_modify_fg(ppopup->label1,GTK_STATE_NORMAL,&fg);
    gtk_widget_modify_fg(ppopup->label2,GTK_STATE_NORMAL,&fg);
  }

  gtk_widget_show_all(ppopup->window);

  ppopup->count = 1;

  if(msginfo->folder && msginfo->folder->name) {
      gchar *ident;
      ident = folder_item_get_identifier(msginfo->folder);
      ppopup->msg_path = g_strdup_printf("%s%s%u", ident,G_DIR_SEPARATOR_S,
					 msginfo->msgnum);
      g_free(ident);
  }

  return TRUE;
}

static gboolean notification_popup_button(GtkWidget *widget,
					  GdkEventButton *event,
					  gpointer data)
{
  if(event->type == GDK_BUTTON_PRESS) {
    if(event->button == 1) {
      MainWindow *mainwin;
      /* Let mainwindow pop up */
      mainwin = mainwindow_get_mainwindow();
      if(!mainwin)
	return TRUE;
      notification_show_mainwindow(mainwin);
      /* If there is only one new mail message, jump to this message */
      if(popup.count == 1) {
	gchar *select_str;
	G_LOCK(popup);
	select_str = g_strdup(popup.msg_path);
	G_UNLOCK(popup);
	debug_print("Select message %s\n", select_str);
	mainwindow_jump_to(select_str, FALSE);
	g_free(select_str);
      }
    }
  }
  return TRUE;
}
#endif /* !HAVE_LIBNOTIFY */

#endif /* NOTIFICATION_POPUP */

--- NEW FILE: notification_popup.h ---
/* Notification plugin for Claws-Mail
 * Copyright (C) 2005-2007 Holger Berndt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NOTIFICATION_POPUP_H
#define NOTIFICATION_POPUP_H NOTIFICATION_POPUP_H

#include "pluginconfig.h"

#ifdef NOTIFICATION_POPUP

#include "procmsg.h"

#define POPUP_SPECIFIC_FOLDER_ID_STR "popup"

void notification_popup_msg(MsgInfo*);

#endif /* NOTIFICATION_POPUP */

#endif /* NOTIFICATION_POPUP_H */



More information about the Commits mailing list