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.
This commit is contained in:
Colin Leroy 2013-02-17 21:22:03 +00:00
parent 2c79a205e4
commit abf3a16d40
134 changed files with 42232 additions and 15 deletions

138
ChangeLog
View file

@ -1,3 +1,141 @@
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.
2013-02-16 [colin] 3.9.0cvs74
* po/POTFILES.in

File diff suppressed because one or more lines are too long

View file

@ -12,7 +12,7 @@ MINOR_VERSION=9
MICRO_VERSION=0
INTERFACE_AGE=0
BINARY_AGE=0
EXTRA_VERSION=74
EXTRA_VERSION=75
EXTRA_RELEASE=
EXTRA_GTK2_VERSION=
@ -863,6 +863,9 @@ AC_ARG_ENABLE(acpi_notifier-plugin,
[ac_cv_enable_acpi_notifier_plugin=$enableval], [ac_cv_enable_acpi_notifier_plugin=yes])
if test x"$ac_cv_enable_acpi_notifier_plugin" = xyes; then
PLUGINS="acpi_notifier $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_ACPI_NOTIFIER_PLUGIN, test x"$ac_cv_enable_acpi_notifier_plugin" = xyes)
@ -872,6 +875,9 @@ AC_ARG_ENABLE(address_keeper-plugin,
[ac_cv_enable_address_keeper_plugin=$enableval], [ac_cv_enable_address_keeper_plugin=yes])
if test x"$ac_cv_enable_address_keeper_plugin" = xyes; then
PLUGINS="address_keeper $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_ADDRESS_KEEPER_PLUGIN, test x"$ac_cv_enable_address_keeper_plugin" = xyes)
@ -887,6 +893,9 @@ if test x"$ac_cv_enable_archive_plugin" = xyes; then
exit 1
)
PLUGINS="archive $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_ARCHIVE_PLUGIN, test x"$ac_cv_enable_archive_plugin" = xyes)
@ -896,6 +905,9 @@ AC_ARG_ENABLE(att_remover-plugin,
[ac_cv_enable_att_remover_plugin=$enableval], [ac_cv_enable_att_remover_plugin=yes])
if test x"$ac_cv_enable_att_remover_plugin" = xyes; then
PLUGINS="att_remover $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_ATT_REMOVER_PLUGIN, test x"$ac_cv_enable_att_remover_plugin" = xyes)
@ -905,6 +917,9 @@ AC_ARG_ENABLE(attachwarner-plugin,
[ac_cv_enable_attachwarner_plugin=$enableval], [ac_cv_enable_attachwarner_plugin=yes])
if test x"$ac_cv_enable_attachwarner_plugin" = xyes; then
PLUGINS="attachwarner $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_ATTACHWARNER_PLUGIN, test x"$ac_cv_enable_attachwarner_plugin" = xyes)
@ -929,15 +944,34 @@ AC_ARG_ENABLE(bsfilter-plugin,
[ac_cv_enable_bsfilter_plugin=$enableval], [ac_cv_enable_bsfilter_plugin=yes])
if test x"$ac_cv_enable_bsfilter_plugin" = xyes; then
PLUGINS="bsfilter $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_BSFILTER_PLUGIN, test x"$ac_cv_enable_bsfilter_plugin" = xyes)
dnl --- clamd ---
AC_MSG_CHECKING([whether to build clamd plugin])
AC_ARG_ENABLE(clamd-plugin,
[ --disable-clamd-plugin do not build clamd plugin],
[ac_cv_enable_clamd_plugin=$enableval], [ac_cv_enable_clamd_plugin=yes])
if test x"$ac_cv_enable_clamd_plugin" = xyes; then
PLUGINS="clamd $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_CLAMD_PLUGIN, test x"$ac_cv_enable_clamd_plugin" = xyes)
dnl --- Demo ---
AC_ARG_ENABLE(demo-plugin,
[ --enable-demo-plugin build demo plugin],
[ac_cv_enable_demo_plugin=$enableval], [ac_cv_enable_demo_plugin=no])
if test x"$ac_cv_enable_demo_plugin" = xyes; then
PLUGINS="demo $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_DEMO_PLUGIN, test x"$ac_cv_enable_demo_plugin" = xyes)
@ -993,6 +1027,209 @@ if test x"$ac_cv_enable_fancy_plugin" = xyes; then
fi
AM_CONDITIONAL(BUILD_FANCY_PLUGIN, test x"$ac_cv_enable_fancy_plugin" = xyes)
dnl --- fetchinfo ---
AC_MSG_CHECKING([whether to build fetchinfo plugin])
AC_ARG_ENABLE(fetchinfo-plugin,
[ --disable-fetchinfo-plugin do not build fetchinfo plugin],
[ac_cv_enable_fetchinfo_plugin=$enableval], [ac_cv_enable_fetchinfo_plugin=yes])
if test x"$ac_cv_enable_fetchinfo_plugin" = xyes; then
PLUGINS="fetchinfo $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_FETCHINFO_PLUGIN, test x"$ac_cv_enable_fetchinfo_plugin" = xyes)
dnl --- gdata ---
AC_MSG_CHECKING([whether to build gdata plugin])
AC_ARG_ENABLE(gdata-plugin,
[ --disable-gdata-plugin do not build gdata plugin],
[ac_cv_enable_gdata_plugin=$enableval], [ac_cv_enable_gdata_plugin=yes])
if test x"$ac_cv_enable_gdata_plugin" = xyes; then
PKG_CHECK_MODULES(GDATA, libgdata >= 0.9.1, [ac_cv_enable_gdata_plugin=yes], [ac_cv_enable_gdata_plugin=no])
if test x"$ac_cv_enable_gdata_plugin" = xyes; then
AC_DEFINE(HAVE_GDATA_VERSION_0_9_1, 1, [at least version 0.9.1 of libgdata is available])
AC_DEFINE(HAVE_GDATA_VERSION_0_9, 1, [at least version 0.9.0 of libgdata is available])
else
PKG_CHECK_MODULES(GDATA, libgdata >= 0.6.4, [ac_cv_enable_gdata_plugin=yes], [ac_cv_enable_gdata_plugin=no])
fi
if test x"$ac_cv_enable_gdata_plugin" = xyes; then
AC_SUBST(GDATA_CFLAGS)
AC_SUBST(GDATA_LIBS)
AC_DEFINE(CM_GDATA_CLIENT_ID, ["Claws Mail GData plugin"], [client id])
PLUGINS="gdata $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_ERROR(libgdata is not available)
fi
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_GDATA_PLUGIN, test x"$ac_cv_enable_gdata_plugin" = xyes)
dnl --- mailmbox ---
AC_MSG_CHECKING([whether to build mailmbox plugin])
AC_ARG_ENABLE(mailmbox-plugin,
[ --disable-mailmbox-plugin do not build mailmbox plugin],
[ac_cv_enable_mailmbox_plugin=$enableval], [ac_cv_enable_mailmbox_plugin=yes])
if test x"$ac_cv_enable_mailmbox_plugin" = xyes; then
PLUGINS="mailmbox $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_MAILMBOX_PLUGIN, test x"$ac_cv_enable_mailmbox_plugin" = xyes)
dnl --- newmail ---
AC_MSG_CHECKING([whether to build newmail plugin])
AC_ARG_ENABLE(newmail-plugin,
[ --disable-newmail-plugin do not build newmail plugin],
[ac_cv_enable_newmail_plugin=$enableval], [ac_cv_enable_newmail_plugin=yes])
if test x"$ac_cv_enable_newmail_plugin" = xyes; then
PLUGINS="newmail $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_NEWMAIL_PLUGIN, test x"$ac_cv_enable_newmail_plugin" = xyes)
dnl --- notification - disabled - too many autofoo annoyances for today ---
AC_MSG_CHECKING([whether to build notification plugin])
AC_ARG_ENABLE(notification-plugin,
[ --disable-notification-plugin do not build notification plugin],
[ac_cv_enable_notification_plugin=$enableval], [ac_cv_enable_notification_plugin=no])
if test x"$ac_cv_enable_notification_plugin" = xyes; then
PLUGINS="notification $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_NOTIFICATION_PLUGIN, test x"$ac_cv_enable_notification_plugin" = xyes)
dnl --- pdf_viewer ---
AC_MSG_CHECKING([whether to build pdf_viewer plugin])
AC_ARG_ENABLE(pdf_viewer-plugin,
[ --disable-pdf_viewer-plugin do not build pdf_viewer plugin],
[ac_cv_enable_pdf_viewer_plugin=$enableval], [ac_cv_enable_pdf_viewer_plugin=yes])
if test x"$ac_cv_enable_pdf_viewer_plugin" = xyes; then
PKG_CHECK_MODULES(POPPLER, poppler-glib >= 0.4.2, ,
AC_MSG_ERROR([Can't find Poppler >= 0.4.2 Glib wrapper]))
AC_SUBST(POPPLER_LIBS)
AC_SUBST(POPPLER_CFLAGS)
OLD_CFLAGS=$CFLAGS
CFLAGS="$POPPLER_CFLAGS $GTK_CFLAGS $GLIB_CFLAGS"
AC_CHECK_DECL(POPPLER_DEST_NAMED,
[AC_DEFINE([HAVE_POPPLER_DEST_NAMED], [], [Description])],
,[#include <poppler-action.h>])
AC_CHECK_DECL(POPPLER_DEST_XYZ,
[AC_DEFINE([HAVE_POPPLER_DEST_XYZ], [], [Description])],
,[#include <poppler-action.h>])
CFLAGS=$OLD_CFLAGS
PLUGINS="pdf_viewer $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_PDF_VIEWER_PLUGIN, test x"$ac_cv_enable_pdf_viewer_plugin" = xyes)
dnl --- perl ---
AC_MSG_CHECKING([whether to build perl plugin])
AC_ARG_ENABLE(perl-plugin,
[ --disable-perl-plugin do not build perl plugin],
[ac_cv_enable_perl_plugin=$enableval], [ac_cv_enable_perl_plugin=yes])
if test x"$ac_cv_enable_perl_plugin" = xyes; then
AC_PATH_PROG(sedpath, sed, no)
if test x$sedpath = xno ; then
AC_MSG_ERROR(Test for sed failed.)
fi
dnl Perl
AC_PATH_PROG(PERL_PATH, perl, no)
if test x$PERL_PATH = xno ; then
AC_MSG_ERROR(Test for Perl failed)
fi
AC_MSG_CHECKING(for perl >= 5.8.0)
PERL_VER=`$PERL_PATH -e 'print $] > 5.0079999?"yes":"no"'`
if test "$PERL_VER" = "yes"; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR(Your Perl version is too old.)
fi
AC_MSG_CHECKING(for Perl compile flags)
PERL_CFLAGS=`$PERL_PATH -MExtUtils::Embed -e ccopts`
PERL_CFLAGS=`echo $PERL_CFLAGS | $sedpath 's/-D_FILE_OFFSET_BITS=[[0-9]]*//'`
PERL_LDFLAGS=`$PERL_PATH -MExtUtils::Embed -e ldopts |$sedpath 's/-lgdbm//'`
PERL_LDFLAGS=`echo $PERL_LDFLAGS |$sedpath 's/-ldb//'`
PERL_LDFLAGS=`echo $PERL_LDFLAGS |$sedpath 's/-lndbm//'`
PERL_LDFLAGS=`echo $PERL_LDFLAGS |$sedpath 's/-lc//'`
AC_MSG_RESULT(ok)
AC_SUBST(PERL_CFLAGS)
AC_SUBST(PERL_LDFLAGS)
PLUGINS="perl $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_PERL_PLUGIN, test x"$ac_cv_enable_perl_plugin" = xyes)
dnl --- python ---
AC_MSG_CHECKING([whether to build python plugin])
AC_ARG_ENABLE(python-plugin,
[ --disable-python-plugin do not build python plugin],
[ac_cv_enable_python_plugin=$enableval], [ac_cv_enable_python_plugin=yes])
if test x"$ac_cv_enable_python_plugin" = xyes; then
AM_PATH_PYTHON([2.5], [
AC_PATH_PROG(PYTHON_CONFIG, python$PYTHON_VERSION-config)
if test x"$PYTHON_CONFIG" = x"" ; then
AC_PATH_PROG(PYTHON_CONFIG, python-config)
fi
if test x"$PYTHON_CONFIG" != x""; then
PYTHON_CFLAGS=`$PYTHON_CONFIG --includes`
PYTHON_LIBS=`$PYTHON_CONFIG --libs`
PYTHON_PREFIX=`$PYTHON_CONFIG --prefix`
else
AC_MSG_ERROR(python-config not found. Maybe you need to install development packages for Python.)
fi
# libpython.so
PYTHON_SO_FILE="libpython${PYTHON_VERSION}.so"
found_libpython_so="no"
if test -f "$PYTHON_PREFIX/lib/$PYTHON_SO_FILE"; then
found_libpython_so="yes"
PYTHON_SHARED_LIB=`python -c "import os,sys; print os.path.basename(os.path.realpath(\"$PYTHON_PREFIX/lib/$PYTHON_SO_FILE\"))"`
fi
if test -f "$PYTHON_PREFIX/lib64/$PYTHON_SO_FILE"; then
found_libpython_so="yes"
PYTHON_SHARED_LIB=`python -c "import os,sys; print os.path.basename(os.path.realpath(\"$PYTHON_PREFIX/lib64/$PYTHON_SO_FILE\"))"`
fi
if test x"$found_libpython_so" != x"yes"; then
AC_MSG_ERROR(Could not find Python shared libary: $PYTHON_SO_FILE does not exist. Maybe you need to install development packages for Python.)
fi
# PyGTK
PKG_CHECK_MODULES(PYGTK,
[pygtk-2.0 >= 2.10.3],
[
AC_DEFINE(ENABLE_PYTHON, [1], [Enable Python support])
])
])
AC_SUBST(PYTHON_SHARED_LIB)
AC_SUBST(PYTHON_CFLAGS)
AC_SUBST(PYTHON_LIBS)
AC_SUBST(PYGTK_CFLAGS)
AC_SUBST(PYGTK_LIBS)
PLUGINS="python $PLUGINS"
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_PYTHON_PLUGIN, test x"$ac_cv_enable_python_plugin" = xyes)
dnl --- PGP/CORE ---
AC_MSG_CHECKING([whether to build PGP/CORE plugin])
AC_ARG_ENABLE(pgpcore-plugin,
@ -1214,9 +1451,18 @@ src/plugins/att_remover/Makefile
src/plugins/attachwarner/Makefile
src/plugins/bogofilter/Makefile
src/plugins/bsfilter/Makefile
src/plugins/clamd/Makefile
src/plugins/clamd/libclamd/Makefile
src/plugins/demo/Makefile
src/plugins/dillo_viewer/Makefile
src/plugins/fancy/Makefile
src/plugins/fetchinfo/Makefile
src/plugins/gdata/Makefile
src/plugins/mailmbox/Makefile
src/plugins/newmail/Makefile
src/plugins/pdf_viewer/Makefile
src/plugins/perl/Makefile
src/plugins/python/Makefile
src/plugins/pgpcore/Makefile
src/plugins/pgpmime/Makefile
src/plugins/pgpinline/Makefile

View file

@ -26,6 +26,10 @@ if BUILD_BSFILTER_PLUGIN
bsfilter_dir = bsfilter
endif
if BUILD_CLAMD_PLUGIN
clamd_dir = clamd
endif
if BUILD_DEMO_PLUGIN
demo_dir = demo
endif
@ -38,6 +42,38 @@ if BUILD_FANCY_PLUGIN
fancy_dir = fancy
endif
if BUILD_FETCHINFO_PLUGIN
fetchinfo_dir = fetchinfo
endif
if BUILD_GDATA_PLUGIN
gdata_dir = gdata
endif
if BUILD_MAILMBOX_PLUGIN
mailmbox_dir = mailmbox
endif
if BUILD_NEWMAIL_PLUGIN
newmail_dir = newmail
endif
if BUILD_NOTIFICATION_PLUGIN
notification_dir = notification
endif
if BUILD_PDF_VIEWER_PLUGIN
pdf_viewer_dir = pdf_viewer
endif
if BUILD_PERL_PLUGIN
perl_dir = perl
endif
if BUILD_PYTHON_PLUGIN
python_dir = python
endif
if BUILD_PGPCORE_PLUGIN
pgpcore_dir = pgpcore
if BUILD_PGPMIME_PLUGIN
@ -75,9 +111,18 @@ SUBDIRS = \
$(attachwarner_dir) \
$(bogofilter_dir) \
$(bsfilter_dir) \
$(clamd_dir) \
$(demo_dir) \
$(dillo_viewer_dir) \
$(fancy_dir) \
$(fetchinfo_dir) \
$(gdata_dir) \
$(mailmbox_dir) \
$(newmail_dir) \
$(notification_dir) \
$(pdf_viewer_dir) \
$(perl_dir) \
$(python_dir) \
$(pgpcore_dir) \
$(pgpmime_dir) \
$(pgpinline_dir) \

View file

@ -1,8 +1,5 @@
plugindir = $(pkglibdir)/plugins
INCLUDES = @GLIB_CFLAGS@ \
-I$(top_srcdir) -I$(top_builddir)
plugin_LTLIBRARIES = archive.la
archive_la_SOURCES = \

View file

@ -0,0 +1,30 @@
SUBDIRS = libclamd
plugindir = $(pkglibdir)/plugins
plugin_LTLIBRARIES = clamd.la
clamd_la_SOURCES = \
clamav_plugin.c \
clamav_plugin_gtk.c \
clamav_plugin.h
clamd_la_LDFLAGS = \
-avoid-version -module \
$(GTK_LIBS) \
-L$(top_builddir)/src/plugins/clamd/libclamd
clamd_la_LIBADD = \
-lclamd-plugin
INCLUDES = \
-I$(top_srcdir)/src/plugins/clamd/libclamd \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/common \
-I$(top_srcdir)/src/gtk
AM_CPPFLAGS = \
-Wall \
$(CLAWS_MAIL_CFLAGS) \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS) \
-DLOCALEDIR=\""$(localedir)"\"

View file

@ -0,0 +1,344 @@
/*
* Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 2003-2010 Michael Rasmussen 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/>.
*
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "claws-features.h"
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include "defs.h"
#include "common/claws.h"
#include "common/version.h"
#include "plugin.h"
#include "utils.h"
#include "hooks.h"
#include "inc.h"
#include "mimeview.h"
#include "folder.h"
#include "prefs.h"
#include "prefs_gtk.h"
#include "alertpanel.h"
#include "clamav_plugin.h"
#include "clamd-plugin.h"
#define PLUGIN_NAME (_("Clam AntiVirus"))
static guint hook_id;
static MessageCallback message_callback;
static ClamAvConfig config;
static PrefParam param[] = {
{"clamav_enable", "FALSE", &config.clamav_enable, P_BOOL,
NULL, NULL, NULL},
/* {"clamav_enable_arc", "FALSE", &config.clamav_enable_arc, P_BOOL,
NULL, NULL, NULL},*/
{"clamav_max_size", "1", &config.clamav_max_size, P_USHORT,
NULL, NULL, NULL},
{"clamav_recv_infected", "TRUE", &config.clamav_recv_infected, P_BOOL,
NULL, NULL, NULL},
{"clamav_save_folder", NULL, &config.clamav_save_folder, P_STRING,
NULL, NULL, NULL},
{"clamad_config_type", "TRUE", &config.clamd_config_type, P_BOOL,
NULL, NULL, NULL},
{"clamd_config_folder", NULL, &config.clamd_config_folder, P_STRING,
NULL, NULL, NULL},
{"clamd_host", NULL, &config.clamd_host, P_STRING,
NULL, NULL, NULL},
{"clamd_port", NULL, &config.clamd_port, P_INT,
NULL, NULL, NULL},
{NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
};
struct clamd_result {
Clamd_Stat status;
};
static gboolean scan_func(GNode *node, gpointer data)
{
struct clamd_result *result = (struct clamd_result *) data;
MimeInfo *mimeinfo = (MimeInfo *) node->data;
gchar *outfile;
response buf;
int max;
struct stat info;
outfile = procmime_get_tmp_file_name(mimeinfo);
if (procmime_get_part(outfile, mimeinfo) < 0)
g_warning("Can't get the part of multipart message.");
else {
max = config.clamav_max_size * 1048576; /* maximum file size */
if (stat(outfile, &info) == -1)
g_warning("Can't determine file size");
else {
if (info.st_size <= max) {
debug_print("Scanning %s\n", outfile);
result->status = clamd_verify_email(outfile, &buf);
debug_print("status: %d\n", result->status);
switch (result->status) {
case NO_SOCKET:
g_warning("[scanning] No socket information");
alertpanel_error(_("Scanning\nNo socket information.\nAntivirus disabled."));
break;
case NO_CONNECTION:
g_warning("[scanning] Clamd does not respond to ping");
alertpanel_warning(_("Scanning\nClamd does not respond to ping.\nIs clamd running?"));
break;
case VIRUS:
g_warning("Detected %s virus.\n", clamd_get_virus_name(buf.msg));
alertpanel_warning(_("Detected %s virus."), clamd_get_virus_name(buf.msg));
break;
case SCAN_ERROR:
debug_print("Error: %s\n", buf.msg);
alertpanel_error(_("Scanning error:\n%s"), buf.msg);
break;
case OK:
debug_print("No virus detected.\n");
break;
}
}
else {
debug_print("File: %s. Size (%d) greater than limit (%d)\n",
outfile, (int) info.st_size, max);
}
}
g_unlink(outfile);
}
return (result->status == OK) ? FALSE : TRUE;
}
static gboolean mail_filtering_hook(gpointer source, gpointer data)
{
MailFilteringData *mail_filtering_data = (MailFilteringData *) source;
MsgInfo *msginfo = mail_filtering_data->msginfo;
MimeInfo *mimeinfo;
struct clamd_result result;
if (!config.clamav_enable)
return FALSE;
mimeinfo = procmime_scan_message(msginfo);
if (!mimeinfo) return FALSE;
debug_print("Scanning message %d for viruses\n", msginfo->msgnum);
if (message_callback != NULL)
message_callback(_("ClamAV: scanning message..."));
debug_print("status: %d\n", result.status);
g_node_traverse(mimeinfo->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, scan_func, &result);
if (result.status == VIRUS) {
if (config.clamav_recv_infected) {
FolderItem *clamav_save_folder;
if ((!config.clamav_save_folder) ||
(config.clamav_save_folder[0] == '\0') ||
((clamav_save_folder = folder_find_item_from_identifier(config.clamav_save_folder)) == NULL))
clamav_save_folder = folder_get_default_trash();
procmsg_msginfo_unset_flags(msginfo, ~0, 0);
msginfo->filter_op = IS_MOVE;
msginfo->to_filter_folder = clamav_save_folder;
} else {
folder_item_remove_msg(msginfo->folder, msginfo->msgnum);
}
}
procmime_mimeinfo_free_all(mimeinfo);
return (result.status == OK) ? FALSE : TRUE;
}
Clamd_Stat clamd_prepare(void) {
debug_print("Creating socket\n");
if (!config.clamd_config_type || (config.clamd_host != NULL && config.clamd_port > 0)) {
if (config.clamd_host == NULL || config.clamd_port < 1) {
/* error */
return NO_SOCKET;
}
/* Manual configuration has highest priority */
debug_print("Using user input: %s:%d\n",
config.clamd_host, config.clamd_port);
clamd_create_config_manual(config.clamd_host, config.clamd_port);
}
else if (config.clamd_config_type || config.clamd_config_folder != NULL) {
if (config.clamd_config_folder == NULL) {
/* error */
return NO_SOCKET;
}
debug_print("Using clamd.conf: %s\n", config.clamd_config_folder);
clamd_create_config_automatic(config.clamd_config_folder);
}
else {
/* Fall back. Try enable anyway */
if (! clamd_find_socket())
return NO_SOCKET;
}
return clamd_init(NULL);
}
ClamAvConfig *clamav_get_config(void)
{
return &config;
}
void clamav_save_config(void)
{
PrefFile *pfile;
gchar *rcpath;
debug_print("Saving Clamd Page\n");
rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
pfile = prefs_write_open(rcpath);
g_free(rcpath);
if (!pfile || (prefs_set_block_label(pfile, "ClamAV") < 0))
return;
if (prefs_write_param(param, pfile->fp) < 0) {
g_warning("failed to write Clamd configuration to file\n");
prefs_file_close_revert(pfile);
return;
}
if (fprintf(pfile->fp, "\n") < 0) {
FILE_OP_ERROR(rcpath, "fprintf");
prefs_file_close_revert(pfile);
} else
prefs_file_close(pfile);
}
void clamav_set_message_callback(MessageCallback callback)
{
message_callback = callback;
}
gint plugin_init(gchar **error)
{
gchar *rcpath;
if (!check_plugin_version(MAKE_NUMERIC_VERSION(2,9,2,72),
VERSION_NUMERIC, PLUGIN_NAME, error))
return -1;
hook_id = hooks_register_hook(MAIL_FILTERING_HOOKLIST, mail_filtering_hook, NULL);
if (hook_id == -1) {
*error = g_strdup(_("Failed to register mail filtering hook"));
return -1;
}
prefs_set_default(param);
rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
prefs_read_config(param, "ClamAV", rcpath, NULL);
g_free(rcpath);
clamav_gtk_init();
if (config.clamav_enable) {
debug_print("Creating socket\n");
Clamd_Stat status = clamd_prepare();
switch (status) {
case NO_SOCKET:
g_warning("[init] No socket information");
alertpanel_error(_("Init\nNo socket information.\nAntivirus disabled."));
break;
case NO_CONNECTION:
g_warning("[init] Clamd does not respond to ping");
alertpanel_warning(_("Init\nClamd does not respond to ping.\nIs clamd running?"));
break;
default:
break;
}
}
debug_print("Clamd plugin loaded\n");
return 0;
}
gboolean plugin_done(void)
{
hooks_unregister_hook(MAIL_FILTERING_HOOKLIST, hook_id);
g_free(config.clamav_save_folder);
clamav_gtk_done();
clamd_free();
debug_print("Clamd plugin unloaded\n");
return TRUE;
}
const gchar *plugin_name(void)
{
return PLUGIN_NAME;
}
const gchar *plugin_desc(void)
{
return _("This plugin uses Clam AntiVirus to scan all messages that are "
"received from an IMAP, LOCAL or POP account.\n"
"\n"
"When a message attachment is found to contain a virus it can be "
"deleted or saved in a specially designated folder.\n"
"\n"
"Because this plugin communicates with clamd via a\n"
"socket then there are some minimum requirements to\n"
"the permissions for your home folder and the\n"
".claws-mail folder provided the clamav-daemon is\n"
"configured to communicate via a unix socket. All\n"
"users at least need to be given execute permissions\n"
"on these folders.\n"
"\n"
"To avoid changing permissions you could configure\n"
"the clamav-daemon to communicate via a TCP socket\n"
"and choose manual configuration for clamd.\n"
"\n"
"Options can be found in /Configuration/Preferences/Plugins/Clam AntiVirus");
}
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_FILTERING, N_("Virus detection")},
{PLUGIN_NOTHING, NULL}};
return features;
}

View file

@ -0,0 +1,50 @@
/*
* Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 2003-2010 Michael Rasmussen 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 CLAMAV_PLUGIN_H
#define CLAMAV_PLUGIN_H 1
#include <glib.h>
#include "clamd-plugin.h"
typedef struct _ClamAvConfig ClamAvConfig;
typedef void (*MessageCallback) (gchar *);
struct _ClamAvConfig
{
gboolean clamav_enable;
/* gboolean clamav_enable_arc;*/
guint clamav_max_size;
gboolean clamav_recv_infected;
gchar *clamav_save_folder;
gboolean clamd_config_type;
gchar *clamd_host;
int clamd_port;
gchar *clamd_config_folder;
};
ClamAvConfig *clamav_get_config (void);
void clamav_save_config (void);
void clamav_set_message_callback (MessageCallback callback);
Clamd_Stat clamd_prepare(void);
gint clamav_gtk_init(void);
void clamav_gtk_done(void);
#endif

View file

@ -0,0 +1,569 @@
/*
* Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 2003-2010 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/>.
*
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "claws-features.h"
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include "defs.h"
#include <gtk/gtk.h>
#include <gtk/gtkutils.h>
#include "common/claws.h"
#include "common/version.h"
#include "plugin.h"
#include "utils.h"
#include "prefs.h"
#include "folder.h"
#include "prefs_gtk.h"
#include "foldersel.h"
#include "clamav_plugin.h"
#include "statusbar.h"
#include "alertpanel.h"
#include "clamd-plugin.h"
struct ClamAvPage
{
PrefsPage page;
GtkWidget *enable_clamav;
/* GtkWidget *enable_arc;*/
GtkWidget *max_size;
GtkWidget *recv_infected;
GtkWidget *save_folder;
GtkWidget *config_type;
GtkWidget *config_folder;
GtkWidget *config_host;
GtkWidget *config_port;
};
static GtkWidget *hbox_auto1, *hbox_auto2, *hbox_manual1, *hbox_manual2;
static void foldersel_cb(GtkWidget *widget, gpointer data)
{
struct ClamAvPage *page = (struct ClamAvPage *) data;
FolderItem *item;
gchar *item_id;
gint newpos = 0;
item = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, FALSE);
if (item && (item_id = folder_item_get_identifier(item)) != NULL) {
gtk_editable_delete_text(GTK_EDITABLE(page->save_folder), 0, -1);
gtk_editable_insert_text(GTK_EDITABLE(page->save_folder), item_id, strlen(item_id), &newpos);
g_free(item_id);
}
}
static void clamd_folder_cb(GtkWidget *widget, gpointer data)
{
GtkWidget *dialog;
gchar* file;
gint newpos = 0;
struct ClamAvPage *page = (struct ClamAvPage *) data;
dialog = gtk_file_chooser_dialog_new(
"Select file with clamd configuration [clamd.conf]",
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
NULL);
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), "/etc");
if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY) {
file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
debug_print("New clamd.conf: %s\n", file);
if (file) {
gtk_editable_delete_text(GTK_EDITABLE(page->config_folder), 0, -1);
gtk_editable_insert_text(GTK_EDITABLE(page->config_folder), file, strlen(file), &newpos);
g_free(file);
}
}
gtk_widget_destroy(dialog);
}
static void check_permission(gchar* folder) {
struct stat info;
g_stat(folder, &info);
mode_t perm = info.st_mode & ~(S_IFMT);
debug_print("%s: Old file permission: %05o\n", folder, perm);
if ((perm & S_IXOTH) != S_IXOTH) {
perm = perm | S_IXOTH;
g_chmod(folder, perm);
}
debug_print("%s: New file permission: %05o\n", folder, perm);
}
static void folder_permission_cb(GtkWidget *widget, gpointer data) {
static gchar* folders[] = {
".claws-mail",
".claws-mail/mimetmp",
".claws-mail/tmp",
NULL};
const gchar* home = g_get_home_dir();
int i;
check_permission((gchar *) home);
for (i = 0; folders[i]; i++) {
gchar* file = g_strdup_printf("%s/%s", home, folders[i]);
check_permission(file);
g_free(file);
}
}
static void clamav_show_config(Config* config) {
if (config) {
if (config->ConfigType == MANUAL) {
gtk_widget_hide(hbox_auto1);
gtk_widget_hide(hbox_auto2);
gtk_widget_show(hbox_manual1);
gtk_widget_show(hbox_manual2);
}
else {
gtk_widget_hide(hbox_manual1);
gtk_widget_hide(hbox_manual2);
gtk_widget_show(hbox_auto1);
gtk_widget_show(hbox_auto2);
}
}
}
static void setting_type_cb(GtkWidget *widget, gpointer data) {
gboolean state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
struct ClamAvPage *page = (struct ClamAvPage *) data;
Config* c;
gint newpos = 0;
gboolean tmp_conf = FALSE;
if (page && page->page.widget) {
/* Reset configuration */
debug_print("Resetting configuration\n");
gtk_editable_delete_text(GTK_EDITABLE(page->config_folder), 0, -1);
gtk_editable_delete_text(GTK_EDITABLE(page->config_host), 0, -1);
gtk_editable_delete_text(GTK_EDITABLE(page->config_port), 0, -1);
clamav_save_config();
c = clamd_get_config();
if (!c) {
c = clamd_config_new();
tmp_conf = TRUE;
}
if (state) {
/* Automatic configuration */
debug_print("Setting clamd to automatic configuration\n");
if (clamd_find_socket()) {
if (tmp_conf) {
Config* clamd_conf = clamd_get_config();
if (clamd_conf->automatic.folder)
c->automatic.folder = g_strdup(clamd_conf->automatic.folder);
else
c->automatic.folder = g_strdup("");
}
if (c->ConfigType == AUTOMATIC) {
gtk_editable_insert_text(GTK_EDITABLE(page->config_folder),
c->automatic.folder, strlen(c->automatic.folder), &newpos);
clamav_save_config();
}
}
c->ConfigType = AUTOMATIC;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->config_type), TRUE);
}
else {
/* Manual configuration */
debug_print("Setting clamd to manual configuration\n");
c->ConfigType = MANUAL;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->config_type), FALSE);
}
clamav_show_config(c);
if (tmp_conf)
clamd_config_free(c);
}
}
static void clamav_create_widget_func(PrefsPage * _page, GtkWindow *window, gpointer data)
{
struct ClamAvPage *page = (struct ClamAvPage *) _page;
ClamAvConfig *config;
Config *clamd_config;
GtkWidget *vbox1, *vbox2;
GtkWidget *enable_clamav;
GtkWidget *label1;
/* GtkWidget *enable_arc;*/
GtkWidget *label2;
GtkObject *max_size_adj;
GtkWidget *max_size;
GtkWidget *hbox1;
GtkWidget *recv_infected;
GtkWidget *save_folder;
GtkWidget *save_folder_select;
GtkWidget *clamd_conf_label;
GtkWidget *config_folder;
GtkWidget *config_host;
GtkWidget *config_port;
GtkWidget *config_folder_select;
GtkWidget *blank;
GtkWidget *permission_label;
GtkWidget *permission_select;
GtkWidget *host_label;
GtkWidget *port_label;
GtkWidget *setting_type;
GtkTooltips *tooltips;
tooltips = gtk_tooltips_new();
enable_clamav = page->enable_clamav;
vbox1 = gtk_vbox_new (FALSE, VSPACING);
gtk_widget_show (vbox1);
gtk_container_set_border_width (GTK_CONTAINER (vbox1), VBOX_BORDER);
vbox2 = gtk_vbox_new (FALSE, 4);
gtk_widget_show (vbox2);
gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, FALSE, 0);
PACK_CHECK_BUTTON (vbox2, enable_clamav, _("Enable virus scanning"));
/* PACK_CHECK_BUTTON (vbox2, enable_arc, _("Scan archive contents"));
SET_TOGGLE_SENSITIVITY (enable_clamav, enable_arc);*/
hbox1 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox1);
gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 0);
/* SET_TOGGLE_SENSITIVITY (enable_arc, hbox1);*/
label1 = gtk_label_new(_("Maximum attachment size"));
gtk_widget_show (label1);
gtk_box_pack_start (GTK_BOX (hbox1), label1, FALSE, FALSE, 0);
SET_TOGGLE_SENSITIVITY (enable_clamav, label1);
max_size_adj = gtk_adjustment_new (1, 1, 1024, 1, 10, 0);
max_size = gtk_spin_button_new (GTK_ADJUSTMENT (max_size_adj), 1, 0);
gtk_widget_show (max_size);
gtk_box_pack_start (GTK_BOX (hbox1), max_size, FALSE, FALSE, 0);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (max_size), TRUE);
gtk_tooltips_set_tip(tooltips, max_size,
_("Message attachments larger than this will not be scanned"),
NULL);
SET_TOGGLE_SENSITIVITY (enable_clamav, max_size);
label2 = gtk_label_new(_("MB"));
gtk_widget_show (label2);
gtk_box_pack_start (GTK_BOX (hbox1), label2, FALSE, FALSE, 0);
SET_TOGGLE_SENSITIVITY (enable_clamav, label2);
hbox1 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox1);
gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 0);
recv_infected = gtk_check_button_new_with_label(_("Save infected mail in"));
gtk_widget_show (recv_infected);
gtk_box_pack_start (GTK_BOX (hbox1), recv_infected, FALSE, FALSE, 0);
gtk_tooltips_set_tip(tooltips, recv_infected,
_("Save mail that contains viruses"),
NULL);
SET_TOGGLE_SENSITIVITY (enable_clamav, recv_infected);
save_folder = gtk_entry_new ();
gtk_widget_show (save_folder);
gtk_box_pack_start (GTK_BOX (hbox1), save_folder, TRUE, TRUE, 0);
gtk_tooltips_set_tip(tooltips, save_folder,
_("Folder for storing infected mail. Leave empty to use the default trash folder"),
NULL);
SET_TOGGLE_SENSITIVITY (enable_clamav, save_folder);
save_folder_select = gtkut_get_browse_directory_btn(_("_Browse"));
gtk_widget_show (save_folder_select);
gtk_box_pack_start (GTK_BOX (hbox1), save_folder_select, FALSE, FALSE, 0);
gtk_tooltips_set_tip(tooltips, save_folder_select,
_("Click this button to select a folder for storing infected mail"),
NULL);
SET_TOGGLE_SENSITIVITY (enable_clamav, save_folder_select);
hbox1 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox1);
gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 0);
setting_type = gtk_check_button_new_with_label(_("Automatic configuration"));
/*gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(setting_type), TRUE);*/
gtk_widget_show (setting_type);
gtk_box_pack_start (GTK_BOX (hbox1), setting_type, FALSE, FALSE, 0);
gtk_tooltips_set_tip(tooltips, setting_type,
_("Should configuration be done automatic or manual"),
NULL);
SET_TOGGLE_SENSITIVITY (enable_clamav, setting_type);
hbox_auto1 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox_auto1);
gtk_box_pack_start (GTK_BOX (vbox2), hbox_auto1, FALSE, FALSE, 0);
clamd_conf_label = gtk_label_new(_("Where is clamd.conf"));
gtk_widget_show (clamd_conf_label);
gtk_box_pack_start (GTK_BOX (hbox_auto1), clamd_conf_label, FALSE, FALSE, 0);
config_folder = gtk_entry_new ();
gtk_widget_show (config_folder);
gtk_box_pack_start (GTK_BOX (hbox_auto1), config_folder, TRUE, TRUE, 0);
gtk_tooltips_set_tip(tooltips, config_folder,
_("Full path to clamd.conf. If this field is not empty then the plugin has been able to locate the file automatically"),
NULL);
SET_TOGGLE_SENSITIVITY (enable_clamav, config_folder);
config_folder_select = gtkut_get_browse_directory_btn(_("Br_owse"));
gtk_widget_show (config_folder_select);
gtk_box_pack_start (GTK_BOX (hbox_auto1), config_folder_select, FALSE, FALSE, 0);
gtk_tooltips_set_tip(tooltips, config_folder_select,
_("Click this button to select full path to clamd.conf"),
NULL);
SET_TOGGLE_SENSITIVITY (enable_clamav, config_folder_select);
hbox_auto2 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox_auto2);
gtk_box_pack_start (GTK_BOX (vbox2), hbox_auto2, FALSE, FALSE, 0);
permission_label = gtk_label_new(_("Check permission for folders and adjust if necessary"));
gtk_widget_show (permission_label);
gtk_box_pack_start (GTK_BOX (hbox_auto2), permission_label, FALSE, FALSE, 0);
blank = gtk_label_new("");
gtk_widget_show (blank);
gtk_box_pack_start (GTK_BOX (hbox_auto2), blank, TRUE, TRUE, 0);
permission_select = gtk_button_new_from_stock(GTK_STOCK_FIND_AND_REPLACE);
/*gtk_button_new_with_mnemonic(_("_Check Permission"));*/
gtk_widget_show (permission_select);
gtk_box_pack_start (GTK_BOX (hbox_auto2), permission_select, FALSE, FALSE, 0);
gtk_tooltips_set_tip(tooltips, permission_select,
_("Click this button to check and adjust folder permissions"),
NULL);
SET_TOGGLE_SENSITIVITY (enable_clamav, permission_select);
hbox_manual1 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox_manual1);
gtk_box_pack_start (GTK_BOX (vbox2), hbox_manual1, FALSE, FALSE, 0);
host_label = gtk_label_new(_("Remote Host"));
gtk_widget_show (host_label);
gtk_box_pack_start (GTK_BOX (hbox_manual1), host_label, FALSE, FALSE, 0);
config_host = gtk_entry_new ();
gtk_widget_show (config_host);
gtk_box_pack_start (GTK_BOX (hbox_manual1), config_host, FALSE, FALSE, 0);
gtk_tooltips_set_tip(tooltips, config_host,
_("Hostname or IP for remote host running clamav daemon"),
NULL);
SET_TOGGLE_SENSITIVITY (enable_clamav, config_host);
blank = gtk_label_new("");
gtk_widget_show (blank);
gtk_box_pack_start (GTK_BOX (hbox_manual1), blank, TRUE, TRUE, 0);
hbox_manual2 = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox_manual2);
gtk_box_pack_start (GTK_BOX (vbox2), hbox_manual2, FALSE, FALSE, 0);
port_label = gtk_label_new(_("Port"));
gtk_widget_show (port_label);
gtk_box_pack_start (GTK_BOX (hbox_manual2), port_label, FALSE, FALSE, 0);
config_port = gtk_entry_new ();
gtk_entry_set_width_chars(GTK_ENTRY(config_port), 5);
gtk_entry_set_max_length(GTK_ENTRY(config_port), 5);
gtk_widget_show (config_port);
gtk_box_pack_start (GTK_BOX (hbox_manual2), config_port, FALSE, FALSE, 0);
gtk_tooltips_set_tip(tooltips, config_port,
_("Port number where clamav daemon is listening"),
NULL);
blank = gtk_label_new("");
gtk_widget_show (blank);
gtk_box_pack_start (GTK_BOX (hbox_manual2), blank, TRUE, TRUE, 0);
SET_TOGGLE_SENSITIVITY (enable_clamav, config_port);
g_signal_connect(G_OBJECT(save_folder_select), "clicked",
G_CALLBACK(foldersel_cb), page);
g_signal_connect(G_OBJECT(config_folder_select), "clicked",
G_CALLBACK(clamd_folder_cb), page);
g_signal_connect(G_OBJECT(permission_select), "clicked",
G_CALLBACK(folder_permission_cb), page);
g_signal_connect(G_OBJECT(setting_type), "clicked",
G_CALLBACK(setting_type_cb), page);
config = clamav_get_config();
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_clamav), config->clamav_enable);
/* gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_arc), config->clamav_enable_arc);*/
gtk_spin_button_set_value(GTK_SPIN_BUTTON(max_size), (float) config->clamav_max_size);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(recv_infected), config->clamav_recv_infected);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(setting_type), config->clamd_config_type);
clamd_config = clamd_get_config();
if (config->clamav_save_folder != NULL)
gtk_entry_set_text(GTK_ENTRY(save_folder), config->clamav_save_folder);
if (!config->clamd_config_type) {
/*if (config->clamd_host && strlen(config->clamd_host) > 0 && config->clamd_port > 0) {*/
gtk_entry_set_text(GTK_ENTRY(config_host), config->clamd_host);
gchar* s = int2char(config->clamd_port);
gtk_entry_set_text(GTK_ENTRY(config_port), s);
g_free(s);
/* activate manual checkbox and blind folder */
debug_print("Showing manual configuration and hiding automatic configuration\n");
if (! clamd_config) {
clamd_config = clamd_config_new();
clamd_config->ConfigType = MANUAL;
clamav_show_config(clamd_config);
clamd_config_free(clamd_config);
}
else
clamav_show_config(clamd_config);
}
else {
//else if (config->clamd_config_folder == NULL || strlen(config->clamd_config_folder) == 0) {
if (clamd_find_socket()) {
Config* c = clamd_get_config();
if (c && c->ConfigType == AUTOMATIC) {
config->clamd_config_folder = g_strdup(c->automatic.folder);
/* deactivate manual checkbox and blind host and port */
debug_print("Showing automatic configuration and hiding manual configuration\n");
clamav_show_config(c);
gint newpos = 0;
gtk_editable_delete_text(GTK_EDITABLE(config_folder), 0, -1);
gtk_editable_insert_text(GTK_EDITABLE(config_folder),
config->clamd_config_folder, strlen(config->clamd_config_folder), &newpos);
}
else if (c && c->ConfigType == MANUAL) {
/* deactivate automatic automatic configuration */
debug_print("Showing manual configuration and hiding automatic configuration\n");
clamav_show_config(c);
}
}
}
/* else {
gtk_entry_set_text(GTK_ENTRY(config_folder), config->clamd_config_folder);
// deactivate manual checkbox and blind host and port
debug_print("Showing automatic configuration and hiding manual configuration\n");
if (! clamd_config) {
clamd_config = clamd_config_new();
clamd_config->ConfigType = AUTOMATIC;
clamav_show_config(clamd_config);
clamd_config_free(clamd_config);
}
else
clamav_show_config(clamd_config);
}*/
page->enable_clamav = enable_clamav;
/* page->enable_arc = enable_arc;*/
page->max_size = max_size;
page->recv_infected = recv_infected;
page->save_folder = save_folder;
page->config_type = setting_type;
page->config_folder = config_folder;
page->config_host = config_host;
page->config_port = config_port;
page->page.widget = vbox1;
clamav_save_config();
}
static void clamav_destroy_widget_func(PrefsPage *_page)
{
debug_print("Destroying Clamd widget\n");
}
static void clamav_save_func(PrefsPage *_page)
{
struct ClamAvPage *page = (struct ClamAvPage *) _page;
ClamAvConfig *config;
debug_print("Saving Clamd Page\n");
config = clamav_get_config();
config->clamav_enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->enable_clamav));
/* config->clamav_enable_arc = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->enable_arc));*/
config->clamav_max_size = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(page->max_size));
config->clamav_recv_infected = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->recv_infected));
g_free(config->clamav_save_folder);
config->clamav_save_folder = gtk_editable_get_chars(GTK_EDITABLE(page->save_folder), 0, -1);
config->clamd_config_type = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->config_type));
g_free(config->clamd_config_folder);
config->clamd_config_folder = gtk_editable_get_chars(GTK_EDITABLE(page->config_folder), 0, -1);
g_free(config->clamd_host);
config->clamd_host = gtk_editable_get_chars(GTK_EDITABLE(page->config_host), 0, -1);
config->clamd_port = atoi(gtk_entry_get_text(GTK_ENTRY(page->config_port)));
if (config->clamav_enable) {
Clamd_Stat status = clamd_prepare();
switch (status) {
case NO_SOCKET:
g_warning("[New config] No socket information");
alertpanel_error(_("New config\nNo socket information.\nAntivirus disabled."));
break;
case NO_CONNECTION:
g_warning("[New config] Clamd does not respond to ping");
alertpanel_warning(_("New config\nClamd does not respond to ping.\nIs clamd running?"));
break;
default:
break;
}
}
clamav_save_config();
}
static struct ClamAvPage clamav_page;
static void gtk_message_callback(gchar *message)
{
statusbar_print_all("%s", message);
}
gint clamav_gtk_init(void)
{
static gchar *path[3];
path[0] = _("Plugins");
path[1] = _("Clam AntiVirus");
path[2] = NULL;
clamav_page.page.path = path;
clamav_page.page.create_widget = clamav_create_widget_func;
clamav_page.page.destroy_widget = clamav_destroy_widget_func;
clamav_page.page.save_page = clamav_save_func;
clamav_page.page.weight = 35.0;
prefs_gtk_register_page((PrefsPage *) &clamav_page);
clamav_set_message_callback(gtk_message_callback);
debug_print("Clamd GTK plugin loaded\n");
return 0;
}
void clamav_gtk_done(void)
{
prefs_gtk_unregister_page((PrefsPage *) &clamav_page);
}

View file

@ -0,0 +1,20 @@
INCLUDES = @GLIB_CFLAGS@ \
@GTK_CFLAGS@ \
-I$(top_srcdir) \
-I$(top_builddir) \
$(CLAWS_MAIL_CFLAGS) \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/common \
-I$(top_srcdir)/src/gtk
noinst_LTLIBRARIES = libclamd-plugin.la
libclamd_plugin_la_SOURCES = \
clamd-plugin.h \
clamd-plugin.c
noinst_HEADERS = clamd-plugin.h
libclamd_plugin_la_LIBADD = \
@GLIB_LIBS@ \
@GTK_LIBS@

View file

@ -0,0 +1,689 @@
/* vim: set textwidth=80 tabstop=4: */
/*
* Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2008 Michael Rasmussen 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/>.
*
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "defs.h"
#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <gtk/gtkutils.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "common/claws.h"
#include "common/version.h"
#include "plugin.h"
#include "utils.h"
#include "prefs.h"
#include "folder.h"
#include "prefs_gtk.h"
#include "foldersel.h"
#include "statusbar.h"
#include "alertpanel.h"
#include "clamd-plugin.h"
/* needs to be generic */
static const gchar* config_dirs[] = {
"/etc",
"/usr/local/etc",
"/etc/clamav",
"/usr/local/etc/clamav",
NULL };
static const gchar* clamd_tokens[] = {
"LocalSocket",
"TCPSocket",
"TCPAddr",
NULL };
static Clamd_Socket* Socket = NULL;
static int sock;
static Config* config = NULL;
/**
* clamd commands used
* prefixing with either z or n is recommended
* z <=> null terminated command
* n <=> newline terminated command
*/
static const gchar ping[] = "nPING\n";
static const gchar version[] = "nVERSION\n";
static const gchar scan[] = "nSCAN";
static const gchar contscan[] = "nCONTSCAN";
static const gchar instream[10] = "zINSTREAM\0";
void clamd_create_config_automatic(const gchar* path) {
FILE* conf;
char buf[1024];
gchar* key = NULL;
gchar* value = NULL;
/*debug_set_mode(TRUE);*/
/*debug_print("%s : %s\n", folder, path);*/
if (! path) {
g_warning("Missing path");
return;
}
if (config && config->ConfigType == AUTOMATIC &&
config->automatic.folder &&
strcmp(config->automatic.folder, path) == 0) {
debug_print("%s : %s - Identical. No need to read again\n",
config->automatic.folder, path);
return;
}
if (config)
clamd_config_free(config);
config = clamd_config_new();
config->ConfigType = AUTOMATIC;
config->automatic.folder = g_strdup(path);
debug_print("Opening %s to parse config file\n", path);
conf = fopen(path, "r");
if (!conf) {
/*g_error("%s: Unable to open", path);*/
alertpanel_error(_("%s: Unable to open\nclamd will be disabled"), path);
return;
}
while (fgets(buf, sizeof(buf), conf)) {
g_strstrip(buf);
if (buf[0] == '#')
continue;
const gchar** tokens = clamd_tokens;
while (*tokens) {
const gchar* token = *tokens++;
if ((key = g_strstr_len(buf, strlen(buf), token)) != NULL) {
gchar* tmp = &(*(key + strlen(token)));
tmp = g_strchug(tmp);
gchar* end = index(tmp, '#');
if (end)
value = g_strndup(tmp, end - tmp);
else
value = g_strdup(g_strchomp(tmp));
if (strcmp(clamd_tokens[0], token) == 0) {
/* UNIX socket */
Socket = (Clamd_Socket *) malloc(sizeof(Clamd_Socket *));
if (Socket) {
Socket->socket.path = NULL;
Socket->socket.host = NULL;
Socket->socket.port = -1;
Socket->type = UNIX_SOCKET;
Socket->socket.path = g_strdup(value);
g_free(value);
value = NULL;
fclose(conf);
debug_print("clamctl: %s\n", Socket->socket.path);
return;
}
}
else if (strcmp(clamd_tokens[1], token) == 0) {
/* INET socket */
if (! Socket) {
Socket = (Clamd_Socket *) malloc(sizeof(Clamd_Socket *));
if (Socket) {
Socket->socket.path = NULL;
Socket->socket.host = NULL;
Socket->socket.port = -1;
Socket->type = INET_SOCKET;
Socket->socket.port = atoi(value);
Socket->socket.host = g_strdup("localhost");
g_free(value);
value = NULL;
debug_print("clamctl: %s:%d\n",
Socket->socket.host, Socket->socket.port);
}
}
else {
Socket->type = INET_SOCKET;
Socket->socket.port = atoi(value);
g_free(value);
value = NULL;
if (! Socket->socket.host)
Socket->socket.host = g_strdup("localhost");
debug_print("clamctl: %s:%d\n",
Socket->socket.host, Socket->socket.port);
}
/* We must continue since TCPAddr could also be configured */
}
else if (strcmp(clamd_tokens[2], token) == 0) {
if (! Socket) {
Socket = (Clamd_Socket *) malloc(sizeof(Clamd_Socket *));
if (Socket) {
Socket->socket.path = NULL;
Socket->socket.host = NULL;
Socket->socket.port = 3310; /* default port */
Socket->type = INET_SOCKET;
Socket->socket.host = g_strdup(value);
g_free(value);
value = NULL;
debug_print("clamctl: %s:%d\n",
Socket->socket.host, Socket->socket.port);
}
}
else {
Socket->type = INET_SOCKET;
if (Socket->socket.host)
g_free(Socket->socket.host);
Socket->socket.host = g_strdup(value);
g_free(value);
value = NULL;
if (Socket->socket.port == -1)
Socket->socket.port = 3310;
debug_print("clamctl: %s:%d\n",
Socket->socket.host, Socket->socket.port);
}
/* We must continue since TCPSocket could also be configured */
}
}
}
}
fclose(conf);
if (! (Socket && (Socket->socket.port || Socket->socket.path))) {
/*g_error("%s: Not able to find required information", path);*/
alertpanel_error(_("%s: Not able to find required information\nclamd will be disabled"), path);
}
/*debug_set_mode(FALSE);*/
}
void clamd_create_config_manual(const gchar* host, int port) {
if (! host || port < 1) {
g_warning("Missing host or port < 1");
return;
}
if (config && config->ConfigType == MANUAL &&
config->manual.host && config->manual.port == port &&
strcmp(config->manual.host, host) == 0) {
debug_print("%s : %s and %d : %d - Identical. No need to read again\n",
config->manual.host, host, config->manual.port, port);
return;
}
if (config)
clamd_config_free(config);
config = clamd_config_new();
config->ConfigType = MANUAL;
config->manual.host = g_strdup(host);
config->manual.port = port;
/* INET socket */
Socket = (Clamd_Socket *) malloc(sizeof(Clamd_Socket *));
if (Socket) {
Socket->type = INET_SOCKET;
Socket->socket.port = port;
Socket->socket.host = g_strdup(host);
}
else {
/*g_error("%s: Not able to find required information", path);*/
alertpanel_error(_("Could not create socket"));
}
}
gboolean clamd_find_socket() {
const gchar** config_dir = config_dirs;
gchar *clamd_conf = NULL;
while (*config_dir) {
clamd_conf = g_strdup_printf("%s/clamd.conf", *config_dir++);
debug_print("Looking for %s\n", clamd_conf);
if (g_file_test(clamd_conf, G_FILE_TEST_EXISTS))
break;
g_free(clamd_conf);
clamd_conf = NULL;
}
if (! clamd_conf)
return FALSE;
debug_print("Using %s to find configuration\n", clamd_conf);
clamd_create_config_automatic(clamd_conf);
g_free(clamd_conf);
return TRUE;
}
Config* clamd_get_config() {
return config;
}
Clamd_Socket* clamd_get_socket() {
return Socket;
}
static void close_socket() {
debug_print("Closing socket: %d\n", sock);
close(sock);
}
static void create_socket() {
struct sockaddr_un addr_u;
struct sockaddr_in addr_i;
struct hostent *hp;
/*debug_set_mode(TRUE);*/
if (! Socket) {
sock = -1;
return;
}
memset(&addr_u, 0, sizeof(addr_u));
memset(&addr_i, 0, sizeof(addr_i));
debug_print("socket->type: %d\n", Socket->type);
switch (Socket->type) {
case UNIX_SOCKET:
debug_print("socket path: %s\n", Socket->socket.path);
sock = socket(PF_UNIX, SOCK_STREAM, 0);
debug_print("socket file (create): %d\n", sock);
if (sock < 0)
return;
addr_u.sun_family = AF_UNIX;
memcpy(addr_u.sun_path, Socket->socket.path,
strlen(Socket->socket.path));
if (connect(sock, (struct sockaddr *) &addr_u, sizeof(addr_u)) < 0) {
perror("connect socket");
close_socket();
sock = -2;
}
debug_print("socket file (connect): %d\n", sock);
break;
case INET_SOCKET:
addr_i.sin_family = AF_INET;
addr_i.sin_port = htons(Socket->socket.port);
hp = gethostbyname(Socket->socket.host);
bcopy((void *)hp->h_addr, (void *)&addr_i.sin_addr, hp->h_length);
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock < 0)
return;
if (connect(sock, (struct sockaddr *)&addr_i, sizeof(addr_i)) < 0) {
perror("connect socket");
close_socket();
sock = -2;
}
break;
}
/*debug_set_mode(FALSE);*/
}
static void copy_socket(Clamd_Socket* sock) {
Socket = (Clamd_Socket *) malloc(sizeof(Clamd_Socket *));
Socket->socket.path = NULL;
Socket->socket.host = NULL;
Socket->type = sock->type;
if (Socket->type == UNIX_SOCKET) {
Socket->socket.path = g_strdup(sock->socket.path);
}
else {
Socket->socket.host = g_strdup(sock->socket.host);
Socket->socket.port = sock->socket.port;
}
}
Clamd_Stat clamd_init(Clamd_Socket* config) {
gchar buf[BUFSIZ];
int n_read;
gboolean connect = FALSE;
/*debug_set_mode(TRUE);*/
if (config != NULL && Socket != NULL)
return NO_SOCKET;
if (config) {
debug_print("socket: %s\n", config->socket.path);
copy_socket(config);
}
create_socket();
if (sock < 0) {
debug_print("no connection\n");
return NO_CONNECTION;
}
if (write(sock, ping, strlen(ping)) == -1) {
debug_print("no connection\n");
return NO_CONNECTION;
}
memset(buf, '\0', sizeof(buf));
while ((n_read = read(sock, buf, BUFSIZ)) > 0) {
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
debug_print("Ping result: %s\n", buf);
if (strcmp("PONG", buf) == 0)
connect = TRUE;
}
close_socket();
create_socket();
if (sock < 0) {
debug_print("no connection\n");
return NO_CONNECTION;
}
if (write(sock, version, strlen(version)) == -1) {
debug_print("no connection\n");
return NO_CONNECTION;
}
memset(buf, '\0', sizeof(buf));
while ((n_read = read(sock, buf, BUFSIZ)) > 0) {
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
debug_print("Version: %s\n", buf);
}
close_socket();
/*debug_set_mode(FALSE);*/
return (connect) ? OK : NO_CONNECTION;
}
static Clamd_Stat clamd_stream_scan(
const gchar* path, gchar** res, ssize_t size) {
int fd;
ssize_t count;
gchar buf[BUFSIZ];
int n_read;
int32_t chunk;
debug_print("Scanning: %s\n", path);
memset(buf, '\0', sizeof(buf));
if (! res || size < 1) {
return SCAN_ERROR;
}
if (! *res)
*res = g_new(gchar, size);
memset(*res, '\0', size);
if (! g_file_test(path, G_FILE_TEST_EXISTS)) {
*res = g_strconcat("ERROR -> ", path, _(": File does not exist"), NULL);
debug_print("res: %s\n", *res);
return SCAN_ERROR;
}
#ifdef _LARGE_FILES
fd = open(path, O_RDONLY, O_LARGEFILE);
#else
fd = open(path, O_RDONLY);
#endif
if (fd < 0) {
/*g_error("%s: Unable to open", path);*/
*res = g_strconcat("ERROR -> ", path, _(": Unable to open"), NULL);
return SCAN_ERROR;
}
debug_print("command: %s\n", instream);
if (write(sock, instream, strlen(instream) + 1) == -1) {
close(fd);
return NO_CONNECTION;
}
while ((count = read(fd, (void *) buf, sizeof(buf))) > 0) {
if (count == -1) {
close(fd);
*res = g_strconcat("ERROR -> ", path, _("%s: Error reading"), NULL);
return SCAN_ERROR;
}
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
debug_print("read: %ld bytes\n", count);
debug_print("chunk size: %ld\n", count);
chunk = htonl(count);
if (write(sock, &chunk, 4) == -1) {
close(fd);
*res = g_strconcat("ERROR -> ", _("Socket write error"), NULL);
return SCAN_ERROR;
}
if (write(sock, buf, count) == -1) {
close(fd);
*res = g_strconcat("ERROR -> ", _("Socket write error"), NULL);
return SCAN_ERROR;
}
memset(buf, '\0', sizeof(buf));
}
close(fd);
chunk = htonl(0);
if (write(sock, &chunk, 4) == -1) {
*res = g_strconcat("ERROR -> ", _("Socket write error"), NULL);
return SCAN_ERROR;
}
debug_print("reading from socket\n");
n_read = read(sock, *res, size);
if (n_read < 0) {
*res = g_strconcat("ERROR -> ", _("Socket read error"), NULL);
return SCAN_ERROR;
}
debug_print("received: %s\n", *res);
return OK;
}
Clamd_Stat clamd_verify_email(const gchar* path, response* result) {
gchar buf[BUFSIZ];
int n_read;
gchar* command;
Clamd_Stat stat;
/*debug_set_mode(TRUE);*/
if (!result) {
result = malloc(sizeof(response *));
memset(result, '\0', sizeof(response *));
}
create_socket();
if (sock < 0) {
debug_print("no connection\n");
return NO_CONNECTION;
}
memset(buf, '\0', sizeof(buf));
if (Socket->type == INET_SOCKET) {
gchar* tmp = g_new0(gchar, BUFSIZ);
stat = clamd_stream_scan(path, &tmp, BUFSIZ);
if (stat != OK) {
close_socket();
result->msg = g_strdup(tmp);
g_free(tmp);
debug_print("result: %s\n", result->msg);
/*debug_set_mode(FALSE);*/
return stat;
}
debug_print("copy to buf: %s\n", tmp);
memcpy(&buf, tmp, BUFSIZ);
g_free(tmp);
}
else {
command = g_strconcat(scan, " ", path, "\n", NULL);
debug_print("command: %s\n", command);
if (write(sock, command, strlen(command)) == -1) {
debug_print("no connection\n");
stat = NO_CONNECTION;
}
g_free(command);
memset(buf, '\0', sizeof(buf));
while ((n_read = read(sock, buf, BUFSIZ)) > 0) {
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
}
}
debug_print("response: %s\n", buf);
if (strstr(buf, "ERROR")) {
stat = SCAN_ERROR;
result->msg = g_strdup(buf);
}
else if (strstr(buf, "FOUND")) {
stat = VIRUS;
result->msg = g_strdup(buf);
}
else {
stat = OK;
result->msg = NULL;
}
close_socket();
/*debug_set_mode(FALSE);*/
return stat;
}
GSList* clamd_verify_dir(const gchar* path) {
gchar buf[BUFSIZ];
int n_read;
gchar* command;
GSList *list = NULL;
if (Socket->type == INET_SOCKET)
return list;
create_socket();
if (sock < 0) {
debug_print("No socket\n");
return list;
}
command = g_strconcat(contscan, path, "\n", NULL);
debug_print("command: %s\n", command);
if (write(sock, command, strlen(command)) == -1) {
debug_print("No socket\n");
return list;
}
g_free(command);
memset(buf, '\0', sizeof(buf));
while ((n_read = read(sock, buf, BUFSIZ)) > 0) {
gchar** tmp = g_strsplit(buf, "\n", 0);
gchar** head = tmp;
while (*tmp) {
gchar* file = *tmp++;
debug_print("%s\n", file);
if (strstr(file, "ERROR")) {
g_warning("%s", file);
/* dont report files with errors */
}
else if (strstr(file, "FOUND")) {
list = g_slist_append(list, g_strdup(file));
}
}
g_strfreev(head);
}
close_socket();
return list;
}
void clamd_free_gslist(GSList* list) {
GSList* tmp = list;
while(tmp) {
g_free(tmp->data);
tmp = g_slist_next(tmp);
}
g_slist_free(list);
}
gchar* clamd_get_virus_name(gchar* msg) {
gchar *head, *tail, *name;
tail = g_strrstr_len(msg, strlen(msg), "FOUND");
if (! tail)
return NULL;
head = g_strstr_len(msg, strlen(msg), ":");
++head;
name = g_strndup(head, tail - head);
g_strstrip(name);
return name;
}
void clamd_free() {
/*
* struct _Clamd_Socket {
* Type type;
* union {
* struct {
* gchar* path;
* };
* struct {
* gchar* host;
* int port;
* };
* } socket;
* };
*/
if (sock > 0) {
close_socket();
sock = 0;
}
if (Socket) {
switch (Socket->type) {
case UNIX_SOCKET:
if (Socket->socket.path) {
g_free(Socket->socket.path);
Socket->socket.path = NULL;
}
break;
case INET_SOCKET:
if (Socket->socket.host) {
g_free(Socket->socket.host);
Socket->socket.host = NULL;
}
break;
}
g_free(Socket);
Socket = NULL;
}
if (config) {
clamd_config_free(config);
config = NULL;
}
}
Config* clamd_config_new() {
return g_new0(Config, 1);
}
void clamd_config_free(Config* c) {
if (c->ConfigType == AUTOMATIC) {
g_free(c->automatic.folder);
c->automatic.folder = NULL;
}
else {
g_free(c->manual.host);
c->manual.host = NULL;
}
g_free(c);
}
gchar* int2char(int i) {
gchar* s = g_new0(gchar, 5);
sprintf(s, "%d", i);
return s;
}
gchar* long2char(long l) {
gchar* s = g_new0(gchar, 5);
debug_print("l: %ld\n", l);
sprintf(s, "%ld", l);
debug_print("s: %s\n", s);
return s;
}

View file

@ -0,0 +1,144 @@
/* vim: set textwidth=80 tabstop=4: */
/*
* Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2008 Michael Rasmussen 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 __CLAMD_PLUGIN_H__
#define __CLAMD_PLUGIN_H__
#include <glib.h>
typedef enum _Type Type;
enum _Type { UNIX_SOCKET, INET_SOCKET };
typedef enum _Clamd_Stat Clamd_Stat;
enum _Clamd_Stat { OK, VIRUS, NO_SOCKET, NO_CONNECTION, SCAN_ERROR };
typedef struct _Clamd_Socket Clamd_Socket;
struct _Clamd_Socket {
Type type;
union {
struct {
gchar* path;
};
struct {
gchar* host;
int port;
};
} socket;
};
typedef struct {
enum { AUTOMATIC, MANUAL } ConfigType;
union {
struct {
gchar* folder;
} automatic;
struct {
gchar* host;
int port;
} manual;
};
} Config;
typedef struct _response response;
struct _response {
gchar* msg;
};
void clamd_create_config_automatic(const gchar* path);
void clamd_create_config_manual(const gchar* host, int port);
gchar* int2char(int i);
gchar* long2char(long l);
/**
* Function which looks for clamd.conf the default places
* and configures the plugin according to the information
* found.
* @return <b>TRUE</b> if clamd.conf found which means all
* information need to make a connection has been found.
* <b>FALSE</b> otherwise.
*/
gboolean clamd_find_socket();
/**
* Function to get current configuration
* @return the current configuration for clamd or <b>NULL</b>
*/
Config* clamd_get_config();
/**
* Function to retrieve virus name from msg
* @param msg Message returned from clamd
* @return virus name or <b>NULL</b> if no virus name found
*/
gchar* clamd_get_virus_name(gchar* msg);
/**
* Function to initialize the connection to clamd.
* @param config A pointer to a struct _Clamd_Socket having
* the required information. If clamd_find_socket returned
* TRUE config should be <b>NULL</b> because all the needed
* information is already present @see clamd_find_socket.
* @return Clamd_Stat. @see _Clamd_Stat.
*/
Clamd_Stat clamd_init(Clamd_Socket* config);
/**
* Function returning the current socket information.
* @return reference to the current Clamd_Socket. @see _Clamd_Socket.
*/
Clamd_Socket* clamd_get_socket();
/**
* Function which is checks a specific email for known viruses
* @param path Absolut path to email to check.
* @param msg String to which result of scan will be copied. Will be
* <b>NULL</b> if no virus was found.
* @return Clamd_Stat. @see _Clamd_Stat.
*/
Clamd_Stat clamd_verify_email(const gchar* path, response* result);
/**
* Function which is checks files in a specific directory for
* known viruses. Dont stop when a virus is found but keeps going
* @param path Absolut path to directory to check.
* @return list of list with virus or <b>NULL</b>.
*/
GSList* clamd_verify_dir(const gchar* path);
/**
* Function to free all memory assigned to a GSList
* @param list The GSList to free
*/
void clamd_free_gslist(GSList* list);
/**
* Function which frees all memory assigned to clamd_plugin
*/
void clamd_free();
Config* clamd_config_new();
void clamd_config_free(Config* c);
#endif

View file

@ -1 +0,0 @@
Placeholder

View file

@ -0,0 +1,23 @@
plugindir = $(pkglibdir)/plugins
plugin_LTLIBRARIES = fetchinfo_plugin.la
fetchinfo_plugin_la_SOURCES = \
fetchinfo_plugin.c fetchinfo_plugin.h \
fetchinfo_plugin_gtk.c
fetchinfo_plugin_la_LDFLAGS = \
-avoid-version -module \
$(GTK_LIBS)
AM_CPPFLAGS = \
$(CLAWS_MAIL_CFLAGS) \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS)
INCLUDES = \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/common \
-I$(top_srcdir)/src/gtk
EXTRA_DIST=

View file

@ -0,0 +1,239 @@
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2003 Hiroyuki Yamamoto 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "claws-features.h"
#endif
#include "defs.h"
#include <glib.h>
#include <glib/gi18n.h>
/* common */
#include "version.h"
#include "claws.h"
#include "plugin.h"
#include "utils.h"
#include "hooks.h"
#include "inc.h"
#include "prefs.h"
#include "prefs_gtk.h"
#include "fetchinfo_plugin.h"
/* add headers */
#include "pop.h"
#include "quoted-printable.h"
/* parse headers */
#include "procheader.h"
#include "plugin.h"
static guint mail_receive_hook_id;
static FetchinfoConfig config;
static PrefParam param[] = {
{"fetchinfo_enable", "FALSE", &config.fetchinfo_enable,
P_BOOL, NULL, NULL, NULL},
{"fetchinfo_uidl", "TRUE", &config.fetchinfo_uidl,
P_BOOL, NULL, NULL, NULL},
{"fetchinfo_account", "TRUE", &config.fetchinfo_account,
P_BOOL, NULL, NULL, NULL},
{"fetchinfo_server", "TRUE", &config.fetchinfo_server,
P_BOOL, NULL, NULL, NULL},
{"fetchinfo_userid", "TRUE", &config.fetchinfo_userid,
P_BOOL, NULL, NULL, NULL},
{"fetchinfo_time", "TRUE", &config.fetchinfo_time,
P_BOOL, NULL, NULL, NULL},
{NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
};
gchar *fetchinfo_add_header(gchar **data, const gchar *header,const gchar *value)
{
gchar *line;
gchar *qpline;
gchar *newdata;
line = g_strdup_printf("%s: %s", header, value);
qpline = g_malloc(strlen(line)*4);
qp_encode_line(qpline, line);
newdata = g_strconcat(*data, qpline, NULL);
g_free(line);
g_free(qpline);
g_free(*data);
*data = newdata;
return newdata;
}
static gboolean mail_receive_hook(gpointer source, gpointer data)
{
MailReceiveData *mail_receive_data = (MailReceiveData *) source;
Pop3Session *session;
gchar *newheaders;
gchar *newdata;
gchar date[PREFSBUFSIZE];
if (!config.fetchinfo_enable) {
return FALSE;
}
g_return_val_if_fail(
mail_receive_data
&& mail_receive_data->session
&& mail_receive_data->data,
FALSE );
session = mail_receive_data->session;
get_rfc822_date(date, PREFSBUFSIZE);
newheaders = g_strdup("");
if (config.fetchinfo_uidl)
fetchinfo_add_header(&newheaders, "X-FETCH-UIDL",
session->msg[session->cur_msg].uidl);
if (config.fetchinfo_account)
fetchinfo_add_header(&newheaders, "X-FETCH-ACCOUNT",
session->ac_prefs->account_name);
if (config.fetchinfo_server)
fetchinfo_add_header(&newheaders, "X-FETCH-SERVER",
session->ac_prefs->recv_server);
if (config.fetchinfo_userid)
fetchinfo_add_header(&newheaders, "X-FETCH-USERID",
session->ac_prefs->userid);
if (config.fetchinfo_time)
fetchinfo_add_header(&newheaders, "X-FETCH-TIME",
date);
newdata = g_strconcat(newheaders, mail_receive_data->data, NULL);
g_free(newheaders);
g_free(mail_receive_data->data);
mail_receive_data->data = newdata;
mail_receive_data->data_len = strlen(newdata);
return FALSE;
}
FetchinfoConfig *fetchinfo_get_config(void)
{
return &config;
}
void fetchinfo_save_config(void)
{
PrefFile *pfile;
gchar *rcpath;
debug_print("Saving Fetchinfo Page\n");
rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
pfile = prefs_write_open(rcpath);
g_free(rcpath);
if (!pfile || (prefs_set_block_label(pfile, "Fetchinfo") < 0))
return;
if (prefs_write_param(param, pfile->fp) < 0) {
/* i18n: Possible error message during plugin load */
g_warning(_("failed to write Fetchinfo configuration to file\n"));
prefs_file_close_revert(pfile);
return;
}
if (fprintf(pfile->fp, "\n") < 0) {
FILE_OP_ERROR(rcpath, "fprintf");
prefs_file_close_revert(pfile);
} else
prefs_file_close(pfile);
}
gint plugin_init(gchar **error)
{
gchar *rcpath;
if (!check_plugin_version(MAKE_NUMERIC_VERSION(2,9,2,72),
VERSION_NUMERIC, _("Fetchinfo"), error))
return -1;
mail_receive_hook_id = hooks_register_hook(MAIL_RECEIVE_HOOKLIST, mail_receive_hook, NULL);
if (mail_receive_hook_id == (guint)-1) {
/* i18n: Possible error message during plugin load */
*error = g_strdup(_("Failed to register mail receive hook"));
return -1;
}
prefs_set_default(param);
rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
prefs_read_config(param, "Fetchinfo", rcpath, NULL);
g_free(rcpath);
fetchinfo_gtk_init();
debug_print("Fetchinfo plugin loaded\n");
return 0;
}
gboolean plugin_done(void)
{
hooks_unregister_hook(MAIL_RECEIVE_HOOKLIST, mail_receive_hook_id);
fetchinfo_gtk_done();
debug_print("Fetchinfo plugin unloaded\n");
return TRUE;
}
const gchar *plugin_name(void)
{
return _("Fetchinfo");
}
const gchar *plugin_desc(void)
{
/* i18n: Description seen in plugins dialog.
* Translation of "Plugins" part of preferences path should to be
* the same as translation of "Plugins" string in Claws Mail message
* catalog. */
return _("This plugin modifies the downloaded messages. "
"It inserts headers containing some download "
"information: UIDL, Claws Mail account name, "
"POP server, user ID and retrieval time.\n"
"\n"
"Options can be found in /Configuration/Preferences/Plugins/Fetchinfo");
}
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[] =
/* i18n: Description of functionality added by this plugin */
{ {PLUGIN_UTILITY, N_("Mail marking")},
{PLUGIN_NOTHING, NULL}};
return features;
}

View file

@ -0,0 +1,42 @@
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2003 Hiroyuki Yamamoto 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef FETCHINFO_PLUGIN_H
#define FETCHINFO_PLUGIN_H 1
#include <glib.h>
typedef struct _FetchinfoConfig FetchinfoConfig;
struct _FetchinfoConfig
{
gboolean fetchinfo_enable;
gboolean fetchinfo_uidl;
gboolean fetchinfo_account;
gboolean fetchinfo_server;
gboolean fetchinfo_userid;
gboolean fetchinfo_time;
};
FetchinfoConfig *fetchinfo_get_config (void);
void fetchinfo_save_config (void);
gint fetchinfo_gtk_init(void);
void fetchinfo_gtk_done(void);
#endif

View file

@ -0,0 +1,198 @@
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2003 Hiroyuki Yamamoto 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "claws-features.h"
#endif
#include "defs.h"
#include "version.h"
#include "claws.h"
#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "plugin.h"
#include "utils.h"
#include "prefs.h"
#include "prefs_gtk.h"
#include "fetchinfo_plugin.h"
struct FetchinfoPage
{
PrefsPage page;
GtkWidget *fetchinfo_enable;
GtkWidget *fetchinfo_uidl;
GtkWidget *fetchinfo_account;
GtkWidget *fetchinfo_server;
GtkWidget *fetchinfo_userid;
GtkWidget *fetchinfo_time;
};
static void fetchinfo_set_sensitive(struct FetchinfoPage *page, gboolean enable)
{
gtk_widget_set_sensitive(GTK_WIDGET(page->fetchinfo_uidl), enable);
gtk_widget_set_sensitive(GTK_WIDGET(page->fetchinfo_account), enable);
gtk_widget_set_sensitive(GTK_WIDGET(page->fetchinfo_server), enable);
gtk_widget_set_sensitive(GTK_WIDGET(page->fetchinfo_userid), enable);
gtk_widget_set_sensitive(GTK_WIDGET(page->fetchinfo_time), enable);
}
static void fetchinfo_enable_cb(GtkWidget *widget, gpointer data)
{
struct FetchinfoPage *page = (struct FetchinfoPage *) data;
fetchinfo_set_sensitive(page, gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(page->fetchinfo_enable)));
}
#define ADD_NEW_CHECKBOX(line, button, text) \
button = gtk_check_button_new_with_label (text); \
gtk_widget_show (button); \
gtk_table_attach (GTK_TABLE (table), button, 1, 2, line, line+1, \
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL), \
(GtkAttachOptions) (0), 0, 0);
static void fetchinfo_create_widget_func(PrefsPage * _page, GtkWindow *window, gpointer data)
{
struct FetchinfoPage *page = (struct FetchinfoPage *) _page;
FetchinfoConfig *config;
GtkWidget *table;
GtkWidget *fetchinfo_enable;
GtkWidget *fetchinfo_uidl;
GtkWidget *fetchinfo_account;
GtkWidget *fetchinfo_server;
GtkWidget *fetchinfo_userid;
GtkWidget *fetchinfo_time;
table = gtk_table_new (6, 3, FALSE);
gtk_widget_show(table);
gtk_table_set_row_spacings(GTK_TABLE(table), 4);
gtk_table_set_col_spacings(GTK_TABLE(table), 8);
/* i18n: Heading of a preferences section determining which headers to add */
fetchinfo_enable = gtk_check_button_new_with_label (_("Add fetchinfo headers"));
gtk_widget_show (fetchinfo_enable);
gtk_table_attach (GTK_TABLE (table), fetchinfo_enable, 0, 2, 0, 1,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
/* i18n: Description of a header to be added */
ADD_NEW_CHECKBOX(1, fetchinfo_uidl, _("UIDL"));
/* i18n: Description of a header to be added */
ADD_NEW_CHECKBOX(2, fetchinfo_account, _("Account name"));
/* i18n: Description of a header to be added */
ADD_NEW_CHECKBOX(3, fetchinfo_server, _("Receive server"));
/* i18n: Description of a header to be added */
ADD_NEW_CHECKBOX(4, fetchinfo_userid, _("UserID"));
/* i18n: Description of a header to be added */
ADD_NEW_CHECKBOX(5, fetchinfo_time, _("Fetch time"));
config = fetchinfo_get_config();
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fetchinfo_enable),
config->fetchinfo_enable);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fetchinfo_uidl),
config->fetchinfo_uidl);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fetchinfo_account),
config->fetchinfo_account);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fetchinfo_server),
config->fetchinfo_server);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fetchinfo_userid),
config->fetchinfo_userid);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fetchinfo_time),
config->fetchinfo_time);
g_signal_connect(G_OBJECT(fetchinfo_enable), "released",
G_CALLBACK(fetchinfo_enable_cb), page);
page->fetchinfo_enable = fetchinfo_enable;
page->fetchinfo_uidl = fetchinfo_uidl;
page->fetchinfo_account = fetchinfo_account;
page->fetchinfo_server = fetchinfo_server;
page->fetchinfo_userid = fetchinfo_userid;
page->fetchinfo_time = fetchinfo_time;
page->page.widget = table;
fetchinfo_set_sensitive(page, config->fetchinfo_enable);
}
#undef ADD_NEW_CHECKBOX
static void fetchinfo_destroy_widget_func(PrefsPage *_page)
{
debug_print("Destroying Fetchinfo widget\n");
}
static void fetchinfo_save_func(PrefsPage *_page)
{
struct FetchinfoPage *page = (struct FetchinfoPage *) _page;
FetchinfoConfig *config;
debug_print("Saving Fetchinfo Page\n");
config = fetchinfo_get_config();
config->fetchinfo_enable = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(page->fetchinfo_enable) );
config->fetchinfo_uidl = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(page->fetchinfo_uidl) );
config->fetchinfo_account = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(page->fetchinfo_account));
config->fetchinfo_server = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(page->fetchinfo_server) );
config->fetchinfo_userid = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(page->fetchinfo_userid) );
config->fetchinfo_time = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(page->fetchinfo_time) );
fetchinfo_save_config();
}
static struct FetchinfoPage fetchinfo_page;
gint fetchinfo_gtk_init(void)
{
static gchar *path[3];
path[0] = _("Plugins");
path[1] = _("Fetchinfo");
path[2] = NULL;
fetchinfo_page.page.path = path;
fetchinfo_page.page.create_widget = fetchinfo_create_widget_func;
fetchinfo_page.page.destroy_widget = fetchinfo_destroy_widget_func;
fetchinfo_page.page.save_page = fetchinfo_save_func;
prefs_gtk_register_page((PrefsPage *) &fetchinfo_page);
debug_print("Fetchinfo GTK plugin loaded\n");
return 0;
}
void fetchinfo_gtk_done(void)
{
prefs_gtk_unregister_page((PrefsPage *) &fetchinfo_page);
debug_print("Fetchinfo GTK plugin unloaded\n");
}

View file

@ -1 +0,0 @@
Placeholder

View file

@ -0,0 +1,30 @@
plugindir = $(pkglibdir)/plugins
plugin_LTLIBRARIES = gdata_plugin.la
gdata_plugin_la_SOURCES = \
gdata_plugin.c \
gdata_plugin.h \
cm_gdata_contacts.c \
cm_gdata_contacts.h \
cm_gdata_prefs.c \
cm_gdata_prefs.h
gdata_plugin_la_LDFLAGS = \
-avoid-version -module \
$(GTK_LIBS) \
$(GDATA_LIBS)
INCLUDES = \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/common \
-I$(top_srcdir)/src/gtk
AM_CPPFLAGS = \
-Wall \
$(CLAWS_MAIL_CFLAGS) \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS) \
$(GDATA_CFLAGS) \
-DLOCALEDIR=\""$(localedir)"\"

View file

@ -0,0 +1,508 @@
/* GData plugin for Claws-Mail
* Copyright (C) 2011 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/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "claws-features.h"
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include "cm_gdata_contacts.h"
#include "cm_gdata_prefs.h"
#include <gtk/gtk.h>
#include "addr_compl.h"
#include "main.h"
#include "prefs_common.h"
#include "common/log.h"
#include "common/xml.h"
#include <gdata/gdata.h>
#define GDATA_CONTACTS_FILENAME "gdata_cache.xml"
typedef struct
{
const gchar *family_name;
const gchar *given_name;
const gchar *full_name;
const gchar *address;
} Contact;
typedef struct
{
GSList *contacts;
} CmGDataContactsCache;
CmGDataContactsCache contacts_cache;
gboolean cm_gdata_contacts_query_running = FALSE;
gchar *contacts_group_id = NULL;
static void write_cache_to_file(void)
{
gchar *path;
PrefFile *pfile;
XMLTag *tag;
XMLNode *xmlnode;
GNode *rootnode;
GNode *contactsnode;
GSList *walk;
path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, GDATA_CONTACTS_FILENAME, NULL);
pfile = prefs_write_open(path);
g_free(path);
if(pfile == NULL) {
debug_print("GData plugin error: Cannot open file " GDATA_CONTACTS_FILENAME " for writing\n");
return;
}
/* XML declarations */
xml_file_put_xml_decl(pfile->fp);
/* Build up XML tree */
/* root node */
tag = xml_tag_new("gdata");
xmlnode = xml_node_new(tag, NULL);
rootnode = g_node_new(xmlnode);
/* contacts node */
tag = xml_tag_new("contacts");
xmlnode = xml_node_new(tag, NULL);
contactsnode = g_node_new(xmlnode);
g_node_append(rootnode, contactsnode);
/* walk contacts cache */
for(walk = contacts_cache.contacts; walk; walk = walk->next)
{
GNode *contactnode;
Contact *contact = walk->data;
tag = xml_tag_new("contact");
xml_tag_add_attr(tag, xml_attr_new("family_name",contact->family_name));
xml_tag_add_attr(tag, xml_attr_new("given_name",contact->given_name));
xml_tag_add_attr(tag, xml_attr_new("full_name",contact->full_name));
xml_tag_add_attr(tag, xml_attr_new("address",contact->address));
xmlnode = xml_node_new(tag, NULL);
contactnode = g_node_new(xmlnode);
g_node_append(contactsnode, contactnode);
}
/* Actual writing and cleanup */
xml_write_tree(rootnode, pfile->fp);
if(prefs_file_close(pfile) < 0)
debug_print("GData plugin error: Failed to write file " GDATA_CONTACTS_FILENAME "\n");
debug_print("GData plugin error: Wrote cache to file " GDATA_CONTACTS_FILENAME "\n");
/* Free XML tree */
xml_free_tree(rootnode);
}
static int add_gdata_contact_to_cache(GDataContactsContact *contact)
{
GList *walk;
int retval;
retval = 0;
for(walk = gdata_contacts_contact_get_email_addresses(contact); walk; walk = walk->next) {
const gchar *email_address;
GDataGDEmailAddress *address = GDATA_GD_EMAIL_ADDRESS(walk->data);
email_address = gdata_gd_email_address_get_address(address);
if(email_address && (*email_address != '\0')) {
GDataGDName *name;
Contact *cached_contact;
name = gdata_contacts_contact_get_name(contact);
cached_contact = g_new0(Contact, 1);
cached_contact->full_name = g_strdup(gdata_gd_name_get_full_name(name));
cached_contact->given_name = g_strdup(gdata_gd_name_get_given_name(name));
cached_contact->family_name = g_strdup(gdata_gd_name_get_family_name(name));
cached_contact->address = g_strdup(email_address);
contacts_cache.contacts = g_slist_prepend(contacts_cache.contacts, cached_contact);
debug_print("GData plugin: Added %s <%s>\n", cached_contact->full_name, cached_contact->address);
retval = 1;
}
}
if(retval == 0)
{
debug_print("GData plugin: Skipped received contact \"%s\" because it doesn't have an email address\n",
gdata_gd_name_get_full_name(gdata_contacts_contact_get_name(contact)));
}
return retval;
}
static void free_contact(Contact *contact)
{
g_free((gpointer)contact->full_name);
g_free((gpointer)contact->family_name);
g_free((gpointer)contact->given_name);
g_free((gpointer)contact->address);
g_free(contact);
}
static void clear_contacts_cache(void)
{
GSList *walk;
for(walk = contacts_cache.contacts; walk; walk = walk->next)
free_contact(walk->data);
g_slist_free(contacts_cache.contacts);
contacts_cache.contacts = NULL;
}
static void cm_gdata_query_contacts_ready(GDataContactsService *service, GAsyncResult *res, gpointer data)
{
GDataFeed *feed;
GList *walk;
GError *error = NULL;
guint num_contacts = 0;
guint num_contacts_added = 0;
gchar *tmpstr1, *tmpstr2;
feed = gdata_service_query_finish(GDATA_SERVICE(service), res, &error);
cm_gdata_contacts_query_running = FALSE;
if(error)
{
g_object_unref(feed);
log_error(LOG_PROTOCOL, _("GData plugin: Error querying for contacts: %s\n"), error->message);
g_error_free(error);
return;
}
/* clear cache */
clear_contacts_cache();
/* Iterate through the returned contacts and fill the cache */
for(walk = gdata_feed_get_entries(feed); walk; walk = walk->next) {
num_contacts_added += add_gdata_contact_to_cache(GDATA_CONTACTS_CONTACT(walk->data));
num_contacts++;
}
g_object_unref(feed);
contacts_cache.contacts = g_slist_reverse(contacts_cache.contacts);
/* i18n: First part of "Added X of Y contacts to cache" */
tmpstr1 = g_strdup_printf(ngettext("Added %d of", "Added %d of", num_contacts_added), num_contacts_added);
/* i18n: Second part of "Added X of Y contacts to cache" */
tmpstr2 = g_strdup_printf(ngettext("1 contact to the cache", "%d contacts to the cache", num_contacts), num_contacts);
log_message(LOG_PROTOCOL, "%s %s\n", tmpstr1, tmpstr2);
g_free(tmpstr1);
g_free(tmpstr2);
}
static void query_after_auth(GDataContactsService *service)
{
GDataContactsQuery *query;
log_message(LOG_PROTOCOL, _("GData plugin: Starting async contacts query\n"));
query = gdata_contacts_query_new(NULL);
gdata_contacts_query_set_group(query, contacts_group_id);
gdata_query_set_max_results(GDATA_QUERY(query), cm_gdata_config.max_num_results);
gdata_contacts_service_query_contacts_async(service, GDATA_QUERY(query), NULL, NULL, NULL,
#ifdef HAVE_GDATA_VERSION_0_9_1
NULL,
#endif
(GAsyncReadyCallback)cm_gdata_query_contacts_ready, NULL);
g_object_unref(query);
}
#ifdef HAVE_GDATA_VERSION_0_9_1
static void cm_gdata_query_groups_ready(GDataContactsService *service, GAsyncResult *res, gpointer data)
{
GDataFeed *feed;
GList *walk;
GError *error = NULL;
feed = gdata_service_query_finish(GDATA_SERVICE(service), res, &error);
if(error)
{
g_object_unref(feed);
log_error(LOG_PROTOCOL, _("GData plugin: Error querying for groups: %s\n"), error->message);
g_error_free(error);
return;
}
/* Iterate through the returned groups and search for Contacts group id */
for(walk = gdata_feed_get_entries(feed); walk; walk = walk->next) {
const gchar *system_group_id;
GDataContactsGroup *group = GDATA_CONTACTS_GROUP(walk->data);
system_group_id = gdata_contacts_group_get_system_group_id(group);
if(system_group_id && !strcmp(system_group_id, GDATA_CONTACTS_GROUP_CONTACTS)) {
gchar *pos;
const gchar *id;
id = gdata_entry_get_id(GDATA_ENTRY(group));
/* possibly replace projection "full" by "base" */
pos = g_strrstr(id, "/full/");
if(pos) {
GString *str = g_string_new("\0");
int off = pos-id;
g_string_append_len(str, id, off);
g_string_append(str, "/base/");
g_string_append(str, id+off+strlen("/full/"));
g_string_append_c(str, '\0');
contacts_group_id = str->str;
g_string_free(str, FALSE);
}
else
contacts_group_id = g_strdup(id);
break;
}
}
g_object_unref(feed);
log_message(LOG_PROTOCOL, _("GData plugin: Groups received\n"));
query_after_auth(service);
}
#endif
#ifdef HAVE_GDATA_VERSION_0_9
static void query_for_contacts_group_id(GDataClientLoginAuthorizer *authorizer)
{
GDataContactsService *service;
#ifdef HAVE_GDATA_VERSION_0_9_1
log_message(LOG_PROTOCOL, _("GData plugin: Starting async groups query\n"));
service = gdata_contacts_service_new(GDATA_AUTHORIZER(authorizer));
gdata_contacts_service_query_groups_async(service, NULL, NULL, NULL, NULL, NULL,
(GAsyncReadyCallback)cm_gdata_query_groups_ready, NULL);
#else
service = gdata_contacts_service_new(GDATA_AUTHORIZER(authorizer));
query_after_auth(service);
#endif
g_object_unref(service);
}
static void cm_gdata_auth_ready(GDataClientLoginAuthorizer *authorizer, GAsyncResult *res, gpointer data)
{
GError *error = NULL;
if(gdata_client_login_authorizer_authenticate_finish(authorizer, res, &error) == FALSE)
{
log_error(LOG_PROTOCOL, _("GData plugin: Authentication error: %s\n"), error->message);
g_error_free(error);
cm_gdata_contacts_query_running = FALSE;
return;
}
log_message(LOG_PROTOCOL, _("GData plugin: Authenticated\n"));
if(!contacts_group_id)
{
query_for_contacts_group_id(authorizer);
}
else {
GDataContactsService *service;
service = gdata_contacts_service_new(GDATA_AUTHORIZER(authorizer));
query_after_auth(service);
g_object_unref(service);
}
}
#else
static void cm_gdata_auth_ready(GDataContactsService *service, GAsyncResult *res, gpointer data)
{
GError *error = NULL;
if(!gdata_service_authenticate_finish(GDATA_SERVICE(service), res, &error))
{
log_error(LOG_PROTOCOL, _("GData plugin: Authentication error: %s\n"), error->message);
g_error_free(error);
cm_gdata_contacts_query_running = FALSE;
return;
}
log_message(LOG_PROTOCOL, _("GData plugin: Authenticated\n"));
query_after_auth(service);
}
#endif
static void query()
{
#ifdef HAVE_GDATA_VERSION_0_9
GDataClientLoginAuthorizer *authorizer;
#else
GDataContactsService *service;
#endif
if(cm_gdata_contacts_query_running)
{
debug_print("GData plugin: Network query already in progress");
return;
}
log_message(LOG_PROTOCOL, _("GData plugin: Starting async authentication\n"));
#ifdef HAVE_GDATA_VERSION_0_9
authorizer = gdata_client_login_authorizer_new(CM_GDATA_CLIENT_ID, GDATA_TYPE_CONTACTS_SERVICE);
gdata_client_login_authorizer_authenticate_async(authorizer, cm_gdata_config.username, cm_gdata_config.password, NULL, (GAsyncReadyCallback)cm_gdata_auth_ready, NULL);
cm_gdata_contacts_query_running = TRUE;
#else
service = gdata_contacts_service_new(CM_GDATA_CLIENT_ID);
cm_gdata_contacts_query_running = TRUE;
gdata_service_authenticate_async(GDATA_SERVICE(service), cm_gdata_config.username, cm_gdata_config.password, NULL,
(GAsyncReadyCallback)cm_gdata_auth_ready, NULL);
#endif
#ifdef HAVE_GDATA_VERSION_0_9
g_object_unref(authorizer);
#else
g_object_unref(service);
#endif
}
static void add_contacts_to_list(GList **address_list, GSList *contacts)
{
GSList *walk;
for(walk = contacts; walk; walk = walk->next)
{
address_entry *ae;
Contact *contact = walk->data;
ae = g_new0(address_entry, 1);
ae->name = g_strdup(contact->full_name);
ae->address = g_strdup(contact->address);
ae->grp_emails = NULL;
*address_list = g_list_prepend(*address_list, ae);
addr_compl_add_address1(ae->address, ae);
if(contact->given_name && *(contact->given_name) != '\0')
addr_compl_add_address1(contact->given_name, ae);
if(contact->family_name && *(contact->family_name) != '\0')
addr_compl_add_address1(contact->family_name, ae);
}
}
void cm_gdata_add_contacts(GList **address_list)
{
add_contacts_to_list(address_list, contacts_cache.contacts);
}
gboolean cm_gdata_update_contacts_cache(void)
{
if(prefs_common.work_offline)
{
debug_print("GData plugin: Offline mode\n");
}
else if(!cm_gdata_config.username || *(cm_gdata_config.username) == '\0' || !cm_gdata_config.password)
{
/* noop if no credentials are given */
debug_print("GData plugin: Empty username or password\n");
}
else
{
debug_print("GData plugin: Querying contacts");
query();
}
return TRUE;
}
void cm_gdata_contacts_done(void)
{
g_free(contacts_group_id);
contacts_group_id = NULL;
write_cache_to_file();
if(contacts_cache.contacts && !claws_is_exiting())
clear_contacts_cache();
}
void cm_gdata_load_contacts_cache_from_file(void)
{
gchar *path;
GNode *rootnode, *childnode, *contactnode;
XMLNode *xmlnode;
path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, GDATA_CONTACTS_FILENAME, NULL);
if(!is_file_exist(path)) {
g_free(path);
return;
}
/* no merging; make sure the cache is empty (this should be a noop, but just to be safe...) */
clear_contacts_cache();
rootnode = xml_parse_file(path);
g_free(path);
if(!rootnode)
return;
xmlnode = rootnode->data;
/* Check that root entry is "gdata" */
if(strcmp2(xmlnode->tag->tag, "gdata") != 0) {
g_warning("wrong gdata cache file\n");
xml_free_tree(rootnode);
return;
}
for(childnode = rootnode->children; childnode; childnode = childnode->next) {
GList *attributes;
xmlnode = childnode->data;
if(strcmp2(xmlnode->tag->tag, "contacts") != 0)
continue;
for(contactnode = childnode->children; contactnode; contactnode = contactnode->next)
{
Contact *cached_contact;
xmlnode = contactnode->data;
cached_contact = g_new0(Contact, 1);
/* Attributes of the branch nodes */
for(attributes = xmlnode->tag->attr; attributes; attributes = attributes->next) {
XMLAttr *attr = attributes->data;
if(attr && attr->name && attr->value) {
if(!strcmp2(attr->name, "full_name"))
cached_contact->full_name = g_strdup(attr->value);
else if(!strcmp2(attr->name, "given_name"))
cached_contact->given_name = g_strdup(attr->value);
else if(!strcmp2(attr->name, "family_name"))
cached_contact->family_name = g_strdup(attr->value);
else if(!strcmp2(attr->name, "address"))
cached_contact->address = g_strdup(attr->value);
}
}
contacts_cache.contacts = g_slist_prepend(contacts_cache.contacts, cached_contact);
debug_print("Read contact from cache: %s\n", cached_contact->full_name);
}
}
/* Free XML tree */
xml_free_tree(rootnode);
contacts_cache.contacts = g_slist_reverse(contacts_cache.contacts);
}

View file

@ -0,0 +1,28 @@
/* GData plugin for Claws-Mail
* Copyright (C) 2011 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 CM_GDATA_CONTACTS_H
#define CM_GDATA_CONTACTS_H
#include <glib.h>
void cm_gdata_add_contacts(GList **address_list);
void cm_gdata_contacts_done(void);
gboolean cm_gdata_update_contacts_cache(void);
void cm_gdata_load_contacts_cache_from_file(void);
#endif /* CM_GDATA_CONTACTS_H */

View file

@ -0,0 +1,161 @@
/* GData plugin for Claws-Mail
* Copyright (C) 2011 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/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "claws-features.h"
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include "cm_gdata_prefs.h"
#include "gdata_plugin.h"
#include "cm_gdata_contacts.h"
#include "prefs_gtk.h"
#include "main.h"
#include <gtk/gtk.h>
typedef struct
{
PrefsPage page;
GtkWidget *entry_username;
GtkWidget *entry_password;
GtkWidget *spin_max_num_results;
GtkWidget *spin_max_cache_age;
} CmGDataPage;
CmGDataPrefs cm_gdata_config;
CmGDataPage gdata_page;
PrefParam cm_gdata_param[] =
{
{"username", NULL, &cm_gdata_config.username, P_STRING,
&gdata_page.entry_username, prefs_set_data_from_entry, prefs_set_entry},
{"password", NULL, &cm_gdata_config.password, P_PASSWORD,
&gdata_page.entry_password, prefs_set_data_from_entry, prefs_set_entry},
{ "max_num_results", "1000", &cm_gdata_config.max_num_results, P_INT,
&gdata_page.spin_max_num_results, prefs_set_data_from_spinbtn, prefs_set_spinbtn},
{ "max_cache_age", "300", &cm_gdata_config.max_cache_age, P_INT,
&gdata_page.spin_max_cache_age, prefs_set_data_from_spinbtn, prefs_set_spinbtn},
{NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL }
};
static void gdata_create_prefs_page(PrefsPage *page, GtkWindow *window, gpointer data)
{
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *spinner;
GtkWidget *table;
GtkWidget *label;
GtkWidget *entry;
vbox = gtk_vbox_new(FALSE, 0);
/* auth frame */
frame = gtk_frame_new(_("Authentication"));
gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
/* username */
table = gtk_table_new(2, 2, FALSE);
label = gtk_label_new(_("Username:"));
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 4, 4);
entry = gtk_entry_new();
gtk_widget_set_size_request(entry, 250, -1);
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 4, 4);
gdata_page.entry_username = entry;
label = gtk_label_new(_("Password:"));
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 4, 4);
entry = gtk_entry_new();
gtk_widget_set_size_request(entry, 250, -1);
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
gdata_page.entry_password = entry;
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 4, 4);
gtk_container_add(GTK_CONTAINER(frame), table);
table = gtk_table_new(2, 2, FALSE);
gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
label = gtk_label_new(_("Polling interval (seconds):"));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 4, 4);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
spinner = gtk_spin_button_new_with_range(10, 10000, 10);
gtk_table_attach(GTK_TABLE(table), spinner, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 4, 4);
gdata_page.spin_max_cache_age = spinner;
label = gtk_label_new(_("Maximum number of results:"));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 4, 4);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
spinner = gtk_spin_button_new_with_range(0, G_MAXINT, 50);
gtk_table_attach(GTK_TABLE(table), spinner, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 4, 4);
gdata_page.spin_max_num_results = spinner;
gtk_widget_show_all(vbox);
page->widget = vbox;
prefs_set_dialog(cm_gdata_param);
}
static void gdata_destroy_prefs_page(PrefsPage *page)
{
}
static void gdata_save_prefs(PrefsPage *page)
{
int old_max_cache_age = cm_gdata_config.max_cache_age;
if (!page->page_open)
return;
prefs_set_data_from_dialog(cm_gdata_param);
cm_gdata_update_contacts_cache();
if(old_max_cache_age != cm_gdata_config.max_cache_age)
cm_gdata_update_contacts_update_timer();
}
void cm_gdata_prefs_init(void)
{
static gchar *path[3];
path[0] = _("Plugins");
path[1] = _("GData");
path[2] = NULL;
gdata_page.page.path = path;
gdata_page.page.create_widget = gdata_create_prefs_page;
gdata_page.page.destroy_widget = gdata_destroy_prefs_page;
gdata_page.page.save_page = gdata_save_prefs;
prefs_gtk_register_page((PrefsPage*) &gdata_page);
}
void cm_gdata_prefs_done(void)
{
if(!claws_is_exiting()) {
prefs_gtk_unregister_page((PrefsPage*) &gdata_page);
}
}

View file

@ -0,0 +1,36 @@
/* GData plugin for Claws-Mail
* Copyright (C) 2011 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 CM_GDATA_PREFS_H_
#define CM_GDATA_PREFS_H_
#include "prefs_gtk.h"
typedef struct {
char *username;
char *password;
int max_num_results;
int max_cache_age;
} CmGDataPrefs;
extern CmGDataPrefs cm_gdata_config;
extern PrefParam cm_gdata_param[];
void cm_gdata_prefs_init(void);
void cm_gdata_prefs_done(void);
#endif /* CM_GDATA_PREFS_H_ */

View file

@ -0,0 +1,190 @@
/* GData plugin for Claws-Mail
* Copyright (C) 2011 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/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "claws-features.h"
#endif
#include <glib.h>
#include <glib/gi18n.h>
#ifdef G_OS_UNIX
# include <libintl.h>
#endif
#include "common/plugin.h"
#include "common/version.h"
#include "common/utils.h"
#include "common/hooks.h"
#include "common/defs.h"
#include "common/prefs.h"
#include "main.h"
#include "mainwindow.h"
#include "addr_compl.h"
#include "cm_gdata_contacts.h"
#include "cm_gdata_prefs.h"
static guint hook_address_completion;
static guint hook_offline_switch;
static guint timer_query_contacts = 0;
static gboolean my_address_completion_build_list_hook(gpointer source, gpointer data)
{
cm_gdata_add_contacts(source);
return FALSE;
}
static gboolean my_offline_switch_hook(gpointer source, gpointer data)
{
cm_gdata_update_contacts_cache();
return FALSE;
}
static void cm_gdata_save_config(void)
{
PrefFile *pfile;
gchar *rcpath;
debug_print("Saving GData plugin configuration...\n");
rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
pfile = prefs_write_open(rcpath);
g_free(rcpath);
if (!pfile || (prefs_set_block_label(pfile, "GDataPlugin") < 0))
return;
if (prefs_write_param(cm_gdata_param, pfile->fp) < 0) {
debug_print("failed!\n");
g_warning(_("\nGData Plugin: Failed to write plugin configuration to file\n"));
prefs_file_close_revert(pfile);
return;
}
if (fprintf(pfile->fp, "\n") < 0) {
FILE_OP_ERROR(rcpath, "fprintf");
prefs_file_close_revert(pfile);
}
else
prefs_file_close(pfile);
debug_print("done.\n");
}
void cm_gdata_update_contacts_update_timer(void)
{
if(timer_query_contacts != 0)
g_source_remove(timer_query_contacts);
timer_query_contacts = g_timeout_add_seconds(cm_gdata_config.max_cache_age, (GSourceFunc)cm_gdata_update_contacts_cache, NULL);
}
gint plugin_init(gchar **error)
{
gchar *rcpath;
/* Version check */
if(!check_plugin_version(MAKE_NUMERIC_VERSION(3,7,1,55),
VERSION_NUMERIC, _("GData"), error))
return -1;
hook_address_completion = hooks_register_hook(ADDDRESS_COMPLETION_BUILD_ADDRESS_LIST_HOOKLIST,
my_address_completion_build_list_hook, NULL);
if(hook_address_completion == (guint) -1) {
*error = g_strdup(_("Failed to register address completion hook in the GData plugin"));
return -1;
}
hook_offline_switch = hooks_register_hook(OFFLINE_SWITCH_HOOKLIST, my_offline_switch_hook, NULL);
if(hook_offline_switch == (guint) -1) {
hooks_unregister_hook(ADDDRESS_COMPLETION_BUILD_ADDRESS_LIST_HOOKLIST, hook_address_completion);
*error = g_strdup(_("Failed to register offline switch hook in the GData plugin"));
return -1;
}
/* Configuration */
prefs_set_default(cm_gdata_param);
rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
prefs_read_config(cm_gdata_param, "GDataPlugin", rcpath, NULL);
g_free(rcpath);
cm_gdata_prefs_init();
/* contacts cache */
cm_gdata_load_contacts_cache_from_file();
cm_gdata_update_contacts_update_timer();
cm_gdata_update_contacts_cache();
debug_print("GData plugin loaded\n");
return 0;
}
gboolean plugin_done(void)
{
if(!claws_is_exiting()) {
hooks_unregister_hook(ADDDRESS_COMPLETION_BUILD_ADDRESS_LIST_HOOKLIST, hook_address_completion);
hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline_switch);
g_source_remove(timer_query_contacts);
}
cm_gdata_prefs_done();
cm_gdata_contacts_done();
cm_gdata_save_config();
debug_print("GData plugin unloaded\n");
/* returning FALSE because dependant libraries may not be unload-safe. */
return FALSE;
}
const gchar *plugin_name(void)
{
return _("GData");
}
const gchar *plugin_desc(void)
{
return _("This plugin provides access to the GData protocol "
"for Claws Mail.\n\n"
"The GData protocol is an interface to Google services.\n"
"Currently, the only implemented functionality is to include "
"Google Contacts into the Tab-address completion.\n"
"\nFeedback to <berndth@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_UTILITY, N_("GData integration")},
{PLUGIN_NOTHING, NULL}};
return features;
}

View file

@ -0,0 +1,23 @@
/* GData plugin for Claws-Mail
* Copyright (C) 2011 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 GDATA_PLUGIN_H_
#define GDATA_PLUGIN_H_
void cm_gdata_update_contacts_update_timer(void);
#endif /* GDATA_PLUGIN_H_ */

View file

@ -1 +0,0 @@
Placeholder

View file

@ -1 +0,0 @@
Placeholder

View file

@ -1 +0,0 @@
Placeholder

View file

@ -0,0 +1,42 @@
plugindir = $(pkglibdir)/plugins
plugin_LTLIBRARIES = mailmbox.la
## Mailmbox folder plugin
mailmbox_la_SOURCES = \
plugin.c plugin_gtk.c \
carray.c carray.h \
chash.c chash.h \
clist.c clist.h \
mailimf.c mailimf.h \
mailimf_types.c mailimf_types.h \
mailimf_types_helper.c mailimf_types_helper.h \
mailimf_write.c mailimf_write.h \
maillock.c maillock.h \
mailmbox.c mailmbox.h \
mailmbox_folder.c mailmbox_folder.h \
mailmbox_parse.c mailmbox_parse.h \
mailmbox_types.c mailmbox_types.h \
mmapstring.c mmapstring.h \
plugin_gtk.h
mailmbox_la_LDFLAGS = \
-avoid-version -module
mailmbox_la_LIBADD = \
$(GTK_LIBS)
mailmbox_la_CPPFLAGS = \
$(CLAWS_MAIL_CFLAGS) \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS)
AM_CPPFLAGS = \
$(CLAWS_MAIL_CFLAGS) \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS)
INCLUDES = \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/common \
-I$(top_srcdir)/src/gtk

View file

@ -0,0 +1,143 @@
/*
* libEtPan! -- a mail stuff library
*
* carray - Implements simple dynamic pointer arrays
*
* Copyright (c) 1999-2000, Gaël Roualland <gael.roualland@iname.com>
* interface changes - 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#include <stdlib.h>
#include <string.h>
#include "carray.h"
carray * carray_new(unsigned int initsize) {
carray * array;
array = (carray *) malloc(sizeof(carray));
if (!array) return NULL;
array->len = 0;
array->max = initsize;
array->array = (void **) malloc(sizeof(void *) * initsize);
if (!array->array) {
free(array);
return NULL;
}
return array;
}
int carray_add(carray * array, void * data, unsigned int * index) {
int r;
r = carray_set_size(array, array->len + 1);
if (r < 0)
return r;
array->array[array->len - 1] = data;
if (index != NULL)
* index = array->len - 1;
return 0;
}
int carray_set_size(carray * array, unsigned int new_size)
{
if (new_size > array->max) {
unsigned int n = array->max * 2;
void * new;
while (n <= new_size)
n *= 2;
new = (void **) realloc(array->array, sizeof(void *) * n);
if (!new)
return -1;
array->array = new;
array->max = n;
}
array->len = new_size;
return 0;
}
int carray_delete_fast(carray * array, unsigned int indx) {
if (indx >= array->len)
return -1;
array->array[indx] = NULL;
return 0;
}
int carray_delete(carray * array, unsigned int indx) {
if (indx >= array->len)
return -1;
if (indx != --array->len)
array->array[indx] = array->array[array->len];
return 0;
}
int carray_delete_slow(carray * array, unsigned int indx) {
if (indx >= array->len)
return -1;
if (indx != --array->len)
memmove(array->array + indx, array->array + indx + 1,
(array->len - indx) * sizeof(void *));
return 0;
}
#ifdef NO_MACROS
void ** carray_data(carray * array) {
return array->array;
}
unsigned int carray_count(carray * array) {
return array->len;
}
void * carray_get(carray * array, unsigned int indx) {
return array->array[indx];
}
void carray_set(carray * array, unsigned int indx, void * value) {
array->array[indx] = value;
}
#endif
void carray_free(carray * array) {
free(array->array);
free(array);
}

View file

@ -0,0 +1,126 @@
/*
* libEtPan! -- a mail stuff library
*
* carray - Implements simple dynamic pointer arrays
*
* Copyright (c) 1999-2000, Gaël Roualland <gael.roualland@iname.com>
* interface changes - 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef CARRAY_H
#define CARRAY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
struct carray_s {
void ** array;
unsigned int len;
unsigned int max;
};
typedef struct carray_s carray;
/* Creates a new array of pointers, with initsize preallocated cells */
carray * carray_new(unsigned int initsize);
/* Adds the pointer to data in the array.
Returns the index of the pointer in the array or -1 on error */
int carray_add(carray * array, void * data, unsigned int * index);
int carray_set_size(carray * array, unsigned int new_size);
/* Removes the cell at this index position. Returns TRUE on success.
Order of elements in the array IS changed. */
int carray_delete(carray * array, unsigned int indx);
/* Removes the cell at this index position. Returns TRUE on success.
Order of elements in the array IS not changed. */
int carray_delete_slow(carray * array, unsigned int indx);
/* remove without decreasing the size of the array */
int carray_delete_fast(carray * array, unsigned int indx);
/* Some of the following routines can be implemented as macros to
be faster. If you don't want it, define NO_MACROS */
#ifdef NO_MACROS
/* Returns the array itself */
void ** carray_data(carray);
/* Returns the number of elements in the array */
int carray_count(carray);
/* Returns the contents of one cell */
void * carray_get(carray array, unsigned int indx);
/* Sets the contents of one cell */
void carray_set(carray array, unsigned int indx, void * value);
#else
#if 0
#define carray_data(a) (a->array)
#define carray_count(a) (a->len)
#define carray_get(a, indx) (a->array[indx])
#define carray_set(a, indx, v) do { a->array[indx]=v; } while(0)
#endif
static inline void ** carray_data(carray * array) {
return array->array;
}
static inline unsigned int carray_count(carray * array) {
return array->len;
}
static inline void * carray_get(carray * array, unsigned int indx) {
return array->array[indx];
}
static inline void carray_set(carray * array,
unsigned int indx, void * value) {
array->array[indx] = value;
}
#endif
void carray_free(carray * array);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,395 @@
/*
* libEtPan! -- a mail stuff library
*
* chash - Implements generic hash tables.
*
* Copyright (c) 1999-2000, Gaël Roualland <gael.roualland@iname.com>
* interface changes - 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#include <stdlib.h>
#include <string.h>
#include "chash.h"
/* This defines the maximum (average) number of entries per bucket.
The hash is resized everytime inserting an entry makes the
average go over that value. */
#define CHASH_MAXDEPTH 3
static inline unsigned int chash_func(const char * key, unsigned int len) {
#if 0
register unsigned int c = 0, t;
register const char * k = key;
while (len--) {
c += (c << 4) + *k++;
if ((t = c & 0xF0000000)) {
c ^= t >> 24;
c ^= t;
}
}
return c;
#endif
register unsigned int c = 5381;
register const char * k = key;
while (len--) {
c = ((c << 5) + c) + *k++;
}
return c;
}
static inline char * chash_dup(const void * data, unsigned int len)
{
void * r;
r = (char *) malloc(len);
if (!r)
return NULL;
memcpy(r, data, len);
return r;
}
chash * chash_new(unsigned int size, int flags)
{
chash * h;
h = (chash *) malloc(sizeof(chash));
if (h == NULL)
return NULL;
h->count = 0;
h->cells = (struct chashcell **) calloc(size, sizeof(struct chashcell *));
if (h->cells == NULL) {
free(h);
return NULL;
}
h->size = size;
h->copykey = flags & CHASH_COPYKEY;
h->copyvalue = flags & CHASH_COPYVALUE;
return h;
}
int chash_get(chash * hash,
chashdatum * key, chashdatum * result)
{
unsigned int func;
chashiter * iter;
func = chash_func(key->data, key->len);
/* look for the key in existing cells */
iter = hash->cells[func % hash->size];
while (iter) {
if (iter->key.len == key->len && iter->func == func
&& !memcmp(iter->key.data, key->data, key->len)) {
* result = iter->value; /* found */
return 0;
}
iter = iter->next;
}
return -1;
}
int chash_set(chash * hash,
chashdatum * key,
chashdatum * value,
chashdatum * oldvalue)
{
unsigned int func, indx;
chashiter * iter, * cell;
int r;
if (hash->count > hash->size * CHASH_MAXDEPTH) {
r = chash_resize(hash, (hash->count / CHASH_MAXDEPTH) * 2 + 1);
if (r < 0)
goto err;
}
func = chash_func(key->data, key->len);
indx = func % hash->size;
/* look for the key in existing cells */
iter = hash->cells[indx];
while (iter) {
if (iter->key.len == key->len && iter->func == func
&& !memcmp(iter->key.data, key->data, key->len)) {
/* found, replacing entry */
if (hash->copyvalue) {
char * data;
data = chash_dup(value->data, value->len);
if (data == NULL)
goto err;
free(iter->value.data);
iter->value.data = data;
iter->value.len = value->len;
} else {
if (oldvalue != NULL) {
oldvalue->data = iter->value.data;
oldvalue->len = iter->value.len;
}
iter->value.data = value->data;
iter->value.len = value->len;
}
if (!hash->copykey)
iter->key.data = key->data;
if (oldvalue != NULL) {
oldvalue->data = value->data;
oldvalue->len = value->len;
}
return 0;
}
iter = iter->next;
}
if (oldvalue != NULL) {
oldvalue->data = NULL;
oldvalue->len = 0;
}
/* not found, adding entry */
cell = (struct chashcell *) malloc(sizeof(struct chashcell));
if (cell == NULL)
goto err;
if (hash->copykey) {
cell->key.data = chash_dup(key->data, key->len);
if (cell->key.data == NULL)
goto free;
}
else
cell->key.data = key->data;
cell->key.len = key->len;
if (hash->copyvalue) {
cell->value.data = chash_dup(value->data, value->len);
if (cell->value.data == NULL)
goto free_key_data;
}
else
cell->value.data = value->data;
cell->value.len = value->len;
cell->func = func;
cell->next = hash->cells[indx];
hash->cells[indx] = cell;
hash->count++;
return 0;
free_key_data:
if (hash->copykey)
free(cell->key.data);
free:
free(cell);
err:
return -1;
}
int chash_delete(chash * hash, chashdatum * key, chashdatum * oldvalue)
{
/* chashdatum result = { NULL, TRUE }; */
unsigned int func, indx;
chashiter * iter, * old;
/*
if (!keylen)
keylen = strlen(key) + 1;
*/
func = chash_func(key->data, key->len);
indx = func % hash->size;
/* look for the key in existing cells */
old = NULL;
iter = hash->cells[indx];
while (iter) {
if (iter->key.len == key->len && iter->func == func
&& !memcmp(iter->key.data, key->data, key->len)) {
/* found, deleting */
if (old)
old->next = iter->next;
else
hash->cells[indx] = iter->next;
if (hash->copykey)
free(iter->key.data);
if (hash->copyvalue)
free(iter->value.data);
else {
if (oldvalue != NULL) {
oldvalue->data = iter->value.data;
oldvalue->len = iter->value.len;
}
}
free(iter);
hash->count--;
return 0;
}
old = iter;
iter = iter->next;
}
return -1; /* not found */
}
void chash_free(chash * hash) {
unsigned int indx;
chashiter * iter, * next;
/* browse the hash table */
for(indx = 0; indx < hash->size; indx++) {
iter = hash->cells[indx];
while (iter) {
next = iter->next;
if (hash->copykey)
free(iter->key.data);
if (hash->copyvalue)
free(iter->value.data);
free(iter);
iter = next;
}
}
free(hash->cells);
free(hash);
}
void chash_clear(chash * hash) {
unsigned int indx;
chashiter * iter, * next;
/* browse the hash table */
for(indx = 0; indx < hash->size; indx++) {
iter = hash->cells[indx];
while (iter) {
next = iter->next;
if (hash->copykey)
free(iter->key.data);
if (hash->copyvalue)
free(iter->value.data);
free(iter);
iter = next;
}
}
memset(hash->cells, 0, hash->size * sizeof(* hash->cells));
hash->count = 0;
}
chashiter * chash_begin(chash * hash) {
chashiter * iter;
unsigned int indx = 0;
iter = hash->cells[0];
while(!iter) {
indx++;
if (indx >= hash->size)
return NULL;
iter = hash->cells[indx];
}
return iter;
}
chashiter * chash_next(chash * hash, chashiter * iter) {
unsigned int indx;
if (!iter)
return NULL;
indx = iter->func % hash->size;
iter = iter->next;
while(!iter) {
indx++;
if (indx >= hash->size)
return NULL;
iter = hash->cells[indx];
}
return iter;
}
int chash_resize(chash * hash, unsigned int size)
{
struct chashcell ** cells;
unsigned int indx, nindx;
chashiter * iter, * next;
if (hash->size == size)
return 0;
cells = (struct chashcell **) calloc(size, sizeof(struct chashcell *));
if (!cells)
return -1;
/* browse initial hash and copy items in second hash */
for(indx = 0; indx < hash->size; indx++) {
iter = hash->cells[indx];
while (iter) {
next = iter->next;
nindx = iter->func % size;
iter->next = cells[nindx];
cells[nindx] = iter;
iter = next;
}
}
free(hash->cells);
hash->size = size;
hash->cells = cells;
return 0;
}
#ifdef NO_MACROS
int chash_count(chash * hash) {
return hash->count;
}
int chash_size(chash * hash) {
return hash->size;
}
void chash_value(chashiter * iter, chashdatum * result) {
* result = iter->value;
}
void chash_key(chashiter * iter, chashdatum * result) {
* result = iter->key;
}
#endif

View file

@ -0,0 +1,166 @@
/*
* libEtPan! -- a mail stuff library
*
* chash - Implements generic hash tables.
*
* Copyright (c) 1999-2000, Gaël Roualland <gael.roualland@iname.com>
* interface changes - 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef CHASH_H
#define CHASH_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
void * data;
unsigned int len;
} chashdatum;
struct chash {
unsigned int size;
unsigned int count;
int copyvalue;
int copykey;
struct chashcell ** cells;
};
typedef struct chash chash;
struct chashcell {
unsigned int func;
chashdatum key;
chashdatum value;
struct chashcell * next;
};
typedef struct chashcell chashiter;
#define CHASH_COPYNONE 0
#define CHASH_COPYKEY 1
#define CHASH_COPYVALUE 2
#define CHASH_COPYALL (CHASH_COPYKEY | CHASH_COPYVALUE)
#define CHASH_DEFAULTSIZE 13
/* Allocates a new (empty) hash using this initial size and the given flags,
specifying which data should be copied in the hash.
CHASH_COPYNONE : Keys/Values are not copied.
CHASH_COPYKEY : Keys are dupped and freed as needed in the hash.
CHASH_COPYVALUE : Values are dupped and freed as needed in the hash.
CHASH_COPYALL : Both keys and values are dupped in the hash.
*/
chash * chash_new(unsigned int size, int flags);
/* Frees a hash */
void chash_free(chash * hash);
/* Removes all elements from a hash */
void chash_clear(chash * hash);
/* Adds an entry in the hash table.
Length can be 0 if key/value are strings.
If an entry already exists for this key, it is replaced, and its value
is returned. Otherwise, the data pointer will be NULL and the length
field be set to TRUE or FALSe to indicate success or failure. */
int chash_set(chash * hash,
chashdatum * key,
chashdatum * value,
chashdatum * oldvalue);
/* Retrieves the data associated to the key if it is found in the hash table.
The data pointer and the length will be NULL if not found*/
int chash_get(chash * hash,
chashdatum * key, chashdatum * result);
/* Removes the entry associated to this key if it is found in the hash table,
and returns its contents if not dupped (otherwise, pointer will be NULL
and len TRUE). If entry is not found both pointer and len will be NULL. */
int chash_delete(chash * hash,
chashdatum * key,
chashdatum * oldvalue);
/* Resizes the hash table to the passed size. */
int chash_resize(chash * hash, unsigned int size);
/* Returns an iterator to the first non-empty entry of the hash table */
chashiter * chash_begin(chash * hash);
/* Returns the next non-empty entry of the hash table */
chashiter * chash_next(chash * hash, chashiter * iter);
/* Some of the following routines can be implemented as macros to
be faster. If you don't want it, define NO_MACROS */
#ifdef NO_MACROS
/* Returns the size of the hash table */
unsigned int chash_size(chash * hash);
/* Returns the number of entries in the hash table */
unsigned int chash_count(chash * hash);
/* Returns the key part of the entry pointed by the iterator */
void chash_key(chashiter * iter, chashdatum * result);
/* Returns the value part of the entry pointed by the iterator */
void chash_value(chashiter * iter, chashdatum * result);
#else
static inline unsigned int chash_size(chash * hash)
{
return hash->size;
}
static inline unsigned int chash_count(chash * hash)
{
return hash->count;
}
static inline void chash_key(chashiter * iter, chashdatum * result)
{
* result = iter->key;
}
static inline void chash_value(chashiter * iter, chashdatum * result)
{
* result = iter->value;
}
#endif
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,266 @@
/*
* libEtPan! -- a mail stuff library
*
* clist - Implements simple generic double-linked pointer lists
*
* Copyright (c) 1999-2000, Gaël Roualland <gael.roualland@iname.com>
* interface changes - 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#include <stdlib.h>
#include "clist.h"
clist * clist_new() {
clist * lst;
lst = (clist *) malloc(sizeof(clist));
if (!lst) return NULL;
lst->first = lst->last = NULL;
lst->count = 0;
return lst;
}
void clist_free(clist * lst) {
clistcell * l1, * l2;
l1 = lst->first;
while (l1) {
l2 = l1->next;
free(l1);
l1 = l2;
}
free(lst);
}
#ifdef NO_MACROS
int clist_isempty(clist * lst) {
return ((lst->first==lst->last) && (lst->last==NULL));
}
clistiter * clist_begin(clist * lst) {
return lst->first;
}
clistiter * clist_end(clist * lst) {
return lst->last;
}
clistiter * clist_next(clistiter * iter) {
if (iter)
return iter->next;
else
return NULL;
}
clistiter * clist_previous(clistiter * iter) {
if (iter)
return iter->previous;
else
return NULL;
}
void * clist_content(clistiter * iter) {
if (iter)
return iter->data;
else
return NULL;
}
int clist_count(clist * lst) {
return lst->count;
}
int clist_prepend(clist * lst, void * data) {
return clist_insert_before(lst, lst->first, data);
}
int clist_append(clist * lst, void * data) {
return clist_insert_after(lst, lst->last, data);
}
#endif
int clist_insert_before(clist * lst, clistiter * iter, void * data) {
clistcell * c;
c = (clistcell *) malloc(sizeof(clistcell));
if (!c) return -1;
c->data = data;
lst->count++;
if (clist_isempty(lst)) {
c->previous = c->next = NULL;
lst->first = lst->last = c;
return 0;
}
if (!iter) {
c->previous = lst->last;
c->previous->next = c;
c->next = NULL;
lst->last = c;
return 0;
}
c->previous = iter->previous;
c->next = iter;
c->next->previous = c;
if (c->previous)
c->previous->next = c;
else
lst->first = c;
return 0;
}
int clist_insert_after(clist * lst, clistiter * iter, void * data) {
clistcell * c;
c = (clistcell *) malloc(sizeof(clistcell));
if (!c) return -1;
c->data = data;
lst->count++;
if (clist_isempty(lst)) {
c->previous = c->next = NULL;
lst->first = lst->last = c;
return 0;
}
if (!iter) {
c->previous = lst->last;
c->previous->next = c;
c->next = NULL;
lst->last = c;
return 0;
}
c->previous = iter;
c->next = iter->next;
if (c->next)
c->next->previous = c;
else
lst->last = c;
c->previous->next = c;
return 0;
}
clistiter * clist_delete(clist * lst, clistiter * iter) {
clistiter * ret;
if (!iter) return NULL;
if (iter->previous)
iter->previous->next = iter->next;
else
lst->first = iter->next;
if (iter->next) {
iter->next->previous = iter->previous;
ret = iter->next;
} else {
lst->last = iter->previous;
ret = NULL;
}
free(iter);
lst->count--;
return ret;
}
void clist_foreach(clist * lst, clist_func func, void * data)
{
clistiter * cur;
for(cur = clist_begin(lst) ; cur != NULL ; cur = cur->next)
func(cur->data, data);
}
void clist_concat(clist * dest, clist * src)
{
if (src->first == NULL) {
/* do nothing */
}
else if (dest->last == NULL) {
dest->first = src->first;
dest->last = src->last;
}
else {
dest->last->next = src->first;
src->first->previous = dest->last;
dest->last = src->last;
}
dest->count += src->count;
src->last = src->first = NULL;
}
static inline clistiter * internal_clist_nth(clist * lst, int index)
{
clistiter * cur;
cur = clist_begin(lst);
while ((index > 0) && (cur != NULL)) {
cur = cur->next;
index --;
}
if (cur == NULL)
return NULL;
return cur;
}
void * clist_nth_data(clist * lst, int index)
{
clistiter * cur;
cur = internal_clist_nth(lst, index);
if (cur == NULL)
return NULL;
return cur->data;
}
clistiter * clist_nth(clist * lst, int index)
{
return internal_clist_nth(lst, index);
}

View file

@ -0,0 +1,134 @@
/*
* libEtPan! -- a mail stuff library
*
* clist - Implements simple generic double-linked pointer lists
*
* Copyright (c) 1999-2000, Gaël Roualland <gael.roualland@iname.com>
* interface changes - 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef CLIST_H
#define CLIST_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct clistcell_s {
void * data;
struct clistcell_s * previous;
struct clistcell_s * next;
} clistcell;
struct clist_s {
clistcell * first;
clistcell * last;
int count;
};
typedef struct clist_s clist;
typedef clistcell clistiter;
/* Allocate a new pointer list */
clist * clist_new();
/* Destroys a list. Data pointed by data pointers is NOT freed. */
void clist_free(clist *);
/* Some of the following routines can be implemented as macros to
be faster. If you don't want it, define NO_MACROS */
#ifdef NO_MACROS
/* Returns TRUE if list is empty */
int clist_isempty(clist *);
/* Returns the number of elements in the list */
int clist_count(clist *);
/* Returns an iterator to the first element of the list */
clistiter * clist_begin(clist *);
/* Returns an iterator to the last element of the list */
clistiter * clist_end(clist *);
/* Returns an iterator to the next element of the list */
clistiter * clist_next(clistiter *);
/* Returns an iterator to the previous element of the list */
clistiter * clist_previous(clistiter *);
/* Returns the data pointer of this element of the list */
void* clist_content(clistiter *);
/* Inserts this data pointer at the beginning of the list */
int clist_prepend(clist *, void *);
/* Inserts this data pointer at the end of the list */
int clist_append(clist *, void *);
#else
#define clist_isempty(lst) ((lst->first==lst->last) && (lst->last==NULL))
#define clist_count(lst) (lst->count)
#define clist_begin(lst) (lst->first)
#define clist_end(lst) (lst->last)
#define clist_next(iter) (iter ? iter->next : NULL)
#define clist_previous(iter) (iter ? iter->previous : NULL)
#define clist_content(iter) (iter ? iter->data : NULL)
#define clist_prepend(lst, data) (clist_insert_before(lst, lst->first, data))
#define clist_append(lst, data) (clist_insert_after(lst, lst->last, data))
#endif
/* Inserts this data pointer before the element pointed by the iterator */
int clist_insert_before(clist *, clistiter *, void *);
/* Inserts this data pointer after the element pointed by the iterator */
int clist_insert_after(clist *, clistiter *, void *);
/* Deletes the element pointed by the iterator.
Returns an iterator to the next element. */
clistiter * clist_delete(clist *, clistiter *);
typedef void (* clist_func)(void *, void *);
void clist_foreach(clist * lst, clist_func func, void * data);
void clist_concat(clist * dest, clist * src);
void * clist_nth_data(clist * lst, int index);
clistiter * clist_nth(clist * lst, int index);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,345 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef MAILIMF_H
#define MAILIMF_H
#ifdef __cplusplus
extern "C" {
#endif
#include "mailimf_types.h"
#include "mailimf_write.h"
#include "mailimf_types_helper.h"
#include <inttypes.h>
#include <sys/types.h>
/*
mailimf_message_parse will parse the given message
@param message this is a string containing the message content
@param length this is the size of the given string
@param index this is a pointer to the start of the message in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int mailimf_message_parse(const char * message, size_t length,
size_t * index,
struct mailimf_message ** result);
/*
mailimf_body_parse will parse the given text part of a message
@param message this is a string containing the message text part
@param length this is the size of the given string
@param index this is a pointer to the start of the message text part in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int mailimf_body_parse(const char * message, size_t length,
size_t * index,
struct mailimf_body ** result);
/*
mailimf_fields_parse will parse the given header fields
@param message this is a string containing the header fields
@param length this is the size of the given string
@param index this is a pointer to the start of the header fields in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int mailimf_fields_parse(const char * message, size_t length,
size_t * index,
struct mailimf_fields ** result);
/*
mailimf_mailbox_list_parse will parse the given mailbox list
@param message this is a string containing the mailbox list
@param length this is the size of the given string
@param index this is a pointer to the start of the mailbox list in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int
mailimf_mailbox_list_parse(const char * message, size_t length,
size_t * index,
struct mailimf_mailbox_list ** result);
/*
mailimf_address_list_parse will parse the given address list
@param message this is a string containing the address list
@param length this is the size of the given string
@param index this is a pointer to the start of the address list in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int
mailimf_address_list_parse(const char * message, size_t length,
size_t * index,
struct mailimf_address_list ** result);
/*
mailimf_address_parse will parse the given address
@param message this is a string containing the address
@param length this is the size of the given string
@param index this is a pointer to the start of the address in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int mailimf_address_parse(const char * message, size_t length,
size_t * index,
struct mailimf_address ** result);
/*
mailimf_mailbox_parse will parse the given address
@param message this is a string containing the mailbox
@param length this is the size of the given string
@param index this is a pointer to the start of the mailbox in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int mailimf_mailbox_parse(const char * message, size_t length,
size_t * index,
struct mailimf_mailbox ** result);
/*
mailimf_date_time_parse will parse the given RFC 2822 date
@param message this is a string containing the date
@param length this is the size of the given string
@param index this is a pointer to the start of the date in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int mailimf_date_time_parse(const char * message, size_t length,
size_t * index,
struct mailimf_date_time ** result);
/*
mailimf_envelope_fields_parse will parse the given fields (Date,
From, Sender, Reply-To, To, Cc, Bcc, Message-ID, In-Reply-To,
References and Subject)
@param message this is a string containing the header fields
@param length this is the size of the given string
@param index this is a pointer to the start of the header fields in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int mailimf_envelope_fields_parse(const char * message, size_t length,
size_t * index,
struct mailimf_fields ** result);
/*
mailimf_ignore_field_parse will skip the given field
@param message this is a string containing the header field
@param length this is the size of the given string
@param index this is a pointer to the start of the header field in
the given string, (* index) is modified to point at the end
of the parsed data
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int mailimf_ignore_field_parse(const char * message, size_t length,
size_t * index);
/*
mailimf_envelope_fields will parse the given fields (Date,
From, Sender, Reply-To, To, Cc, Bcc, Message-ID, In-Reply-To,
References and Subject), other fields will be added as optional
fields.
@param message this is a string containing the header fields
@param length this is the size of the given string
@param index this is a pointer to the start of the header fields in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int
mailimf_envelope_and_optional_fields_parse(const char * message, size_t length,
size_t * index,
struct mailimf_fields ** result);
/*
mailimf_envelope_fields will parse the given fields as optional
fields.
@param message this is a string containing the header fields
@param length this is the size of the given string
@param index this is a pointer to the start of the header fields in
the given string, (* index) is modified to point at the end
of the parsed data
@param result the result of the parse operation is stored in
(* result)
@return MAILIMF_NO_ERROR on success, MAILIMF_ERROR_XXX on error
*/
int
mailimf_optional_fields_parse(const char * message, size_t length,
size_t * index,
struct mailimf_fields ** result);
/* internal use, exported for MIME */
int mailimf_fws_parse(const char * message, size_t length, size_t * index);
int mailimf_cfws_parse(const char * message, size_t length,
size_t * index);
int mailimf_char_parse(const char * message, size_t length,
size_t * index, char token);
int mailimf_unstrict_char_parse(const char * message, size_t length,
size_t * index, char token);
int mailimf_crlf_parse(const char * message, size_t length, size_t * index);
int
mailimf_custom_string_parse(const char * message, size_t length,
size_t * index, char ** result,
int (* is_custom_char)(char));
int
mailimf_token_case_insensitive_len_parse(const char * message, size_t length,
size_t * index, char * token,
size_t token_length);
#define mailimf_token_case_insensitive_parse(message, length, index, token) \
mailimf_token_case_insensitive_len_parse(message, length, index, token, \
sizeof(token) - 1)
int mailimf_quoted_string_parse(const char * message, size_t length,
size_t * index, char ** result);
int
mailimf_number_parse(const char * message, size_t length,
size_t * index, uint32_t * result);
int mailimf_msg_id_parse(const char * message, size_t length,
size_t * index,
char ** result);
int mailimf_msg_id_list_parse(const char * message, size_t length,
size_t * index, clist ** result);
int mailimf_word_parse(const char * message, size_t length,
size_t * index, char ** result);
int mailimf_atom_parse(const char * message, size_t length,
size_t * index, char ** result);
int mailimf_fws_atom_parse(const char * message, size_t length,
size_t * index, char ** result);
int mailimf_fws_word_parse(const char * message, size_t length,
size_t * index, char ** result);
int mailimf_fws_quoted_string_parse(const char * message, size_t length,
size_t * index, char ** result);
/* exported for IMAP */
int mailimf_references_parse(const char * message, size_t length,
size_t * index,
struct mailimf_references ** result);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,868 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#include "mailimf_types.h"
#include "mmapstring.h"
#include <stdlib.h>
void mailimf_atom_free(char * atom)
{
free(atom);
}
void mailimf_dot_atom_free(char * dot_atom)
{
free(dot_atom);
}
void mailimf_dot_atom_text_free(char * dot_atom)
{
free(dot_atom);
}
void mailimf_quoted_string_free(char * quoted_string)
{
free(quoted_string);
}
void mailimf_word_free(char * word)
{
free(word);
}
void mailimf_phrase_free(char * phrase)
{
free(phrase);
}
void mailimf_unstructured_free(char * unstructured)
{
free(unstructured);
}
struct mailimf_date_time *
mailimf_date_time_new(int dt_day, int dt_month, int dt_year,
int dt_hour, int dt_min, int dt_sec, int dt_zone)
{
struct mailimf_date_time * date_time;
date_time = malloc(sizeof(* date_time));
if (date_time == NULL)
return NULL;
date_time->dt_day = dt_day;
date_time->dt_month = dt_month;
date_time->dt_year = dt_year;
date_time->dt_hour = dt_hour;
date_time->dt_min = dt_min;
date_time->dt_sec = dt_sec;
date_time->dt_zone = dt_zone;
return date_time;
}
void mailimf_date_time_free(struct mailimf_date_time * date_time)
{
free(date_time);
}
struct mailimf_address *
mailimf_address_new(int ad_type, struct mailimf_mailbox * ad_mailbox,
struct mailimf_group * ad_group)
{
struct mailimf_address * address;
address = malloc(sizeof(* address));
if (address == NULL)
return NULL;
address->ad_type = ad_type;
switch (ad_type) {
case MAILIMF_ADDRESS_MAILBOX:
address->ad_data.ad_mailbox = ad_mailbox;
break;
case MAILIMF_ADDRESS_GROUP:
address->ad_data.ad_group = ad_group;
break;
}
return address;
}
void mailimf_address_free(struct mailimf_address * address)
{
switch (address->ad_type) {
case MAILIMF_ADDRESS_MAILBOX:
mailimf_mailbox_free(address->ad_data.ad_mailbox);
break;
case MAILIMF_ADDRESS_GROUP:
mailimf_group_free(address->ad_data.ad_group);
}
free(address);
}
struct mailimf_mailbox *
mailimf_mailbox_new(char * mb_display_name, char * mb_addr_spec)
{
struct mailimf_mailbox * mb;
mb = malloc(sizeof(* mb));
if (mb == NULL)
return NULL;
mb->mb_display_name = mb_display_name;
mb->mb_addr_spec = mb_addr_spec;
return mb;
}
void mailimf_mailbox_free(struct mailimf_mailbox * mailbox)
{
if (mailbox->mb_display_name != NULL)
mailimf_display_name_free(mailbox->mb_display_name);
mailimf_addr_spec_free(mailbox->mb_addr_spec);
free(mailbox);
}
void mailimf_angle_addr_free(char * angle_addr)
{
free(angle_addr);
}
struct mailimf_group *
mailimf_group_new(char * grp_display_name,
struct mailimf_mailbox_list * grp_mb_list)
{
struct mailimf_group * group;
group = malloc(sizeof(* group));
if (group == NULL)
return NULL;
group->grp_display_name = grp_display_name;
group->grp_mb_list = grp_mb_list;
return group;
}
void mailimf_group_free(struct mailimf_group * group)
{
if (group->grp_mb_list)
mailimf_mailbox_list_free(group->grp_mb_list);
mailimf_display_name_free(group->grp_display_name);
free(group);
}
void mailimf_display_name_free(char * display_name)
{
mailimf_phrase_free(display_name);
}
struct mailimf_mailbox_list *
mailimf_mailbox_list_new(clist * mb_list)
{
struct mailimf_mailbox_list * mbl;
mbl = malloc(sizeof(* mbl));
if (mbl == NULL)
return NULL;
mbl->mb_list = mb_list;
return mbl;
}
void mailimf_mailbox_list_free(struct mailimf_mailbox_list * mb_list)
{
clist_foreach(mb_list->mb_list, (clist_func) mailimf_mailbox_free, NULL);
clist_free(mb_list->mb_list);
free(mb_list);
}
struct mailimf_address_list *
mailimf_address_list_new(clist * ad_list)
{
struct mailimf_address_list * addr_list;
addr_list = malloc(sizeof(* addr_list));
if (addr_list == NULL)
return NULL;
addr_list->ad_list = ad_list;
return addr_list;
}
void mailimf_address_list_free(struct mailimf_address_list * addr_list)
{
clist_foreach(addr_list->ad_list, (clist_func) mailimf_address_free, NULL);
clist_free(addr_list->ad_list);
free(addr_list);
}
void mailimf_addr_spec_free(char * addr_spec)
{
free(addr_spec);
}
void mailimf_local_part_free(char * local_part)
{
free(local_part);
}
void mailimf_domain_free(char * domain)
{
free(domain);
}
void mailimf_domain_literal_free(char * domain_literal)
{
free(domain_literal);
}
struct mailimf_message *
mailimf_message_new(struct mailimf_fields * msg_fields,
struct mailimf_body * msg_body)
{
struct mailimf_message * message;
message = malloc(sizeof(* message));
if (message == NULL)
return NULL;
message->msg_fields = msg_fields;
message->msg_body = msg_body;
return message;
}
void mailimf_message_free(struct mailimf_message * message)
{
mailimf_body_free(message->msg_body);
mailimf_fields_free(message->msg_fields);
free(message);
}
struct mailimf_body * mailimf_body_new(const char * bd_text, size_t bd_size)
{
struct mailimf_body * body;
body = malloc(sizeof(* body));
if (body == NULL)
return NULL;
body->bd_text = bd_text;
body->bd_size = bd_size;
return body;
}
void mailimf_body_free(struct mailimf_body * body)
{
free(body);
}
struct mailimf_field *
mailimf_field_new(int fld_type,
struct mailimf_return * fld_return_path,
struct mailimf_orig_date * fld_resent_date,
struct mailimf_from * fld_resent_from,
struct mailimf_sender * fld_resent_sender,
struct mailimf_to * fld_resent_to,
struct mailimf_cc * fld_resent_cc,
struct mailimf_bcc * fld_resent_bcc,
struct mailimf_message_id * fld_resent_msg_id,
struct mailimf_orig_date * fld_orig_date,
struct mailimf_from * fld_from,
struct mailimf_sender * fld_sender,
struct mailimf_reply_to * fld_reply_to,
struct mailimf_to * fld_to,
struct mailimf_cc * fld_cc,
struct mailimf_bcc * fld_bcc,
struct mailimf_message_id * fld_message_id,
struct mailimf_in_reply_to * fld_in_reply_to,
struct mailimf_references * fld_references,
struct mailimf_subject * fld_subject,
struct mailimf_comments * fld_comments,
struct mailimf_keywords * fld_keywords,
struct mailimf_optional_field * fld_optional_field)
{
struct mailimf_field * field;
field = malloc(sizeof(* field));
if (field == NULL)
return NULL;
field->fld_type = fld_type;
switch (fld_type) {
case MAILIMF_FIELD_RETURN_PATH:
field->fld_data.fld_return_path = fld_return_path;
break;
case MAILIMF_FIELD_RESENT_DATE:
field->fld_data.fld_resent_date = fld_resent_date;
break;
case MAILIMF_FIELD_RESENT_FROM:
field->fld_data.fld_resent_from = fld_resent_from;
break;
case MAILIMF_FIELD_RESENT_SENDER:
field->fld_data.fld_resent_sender = fld_resent_sender;
break;
case MAILIMF_FIELD_RESENT_TO:
field->fld_data.fld_resent_to = fld_resent_to;
break;
case MAILIMF_FIELD_RESENT_CC:
field->fld_data.fld_resent_cc = fld_resent_cc;
break;
case MAILIMF_FIELD_RESENT_BCC:
field->fld_data.fld_resent_bcc = fld_resent_bcc;
break;
case MAILIMF_FIELD_RESENT_MSG_ID:
field->fld_data.fld_resent_msg_id = fld_resent_msg_id;
break;
case MAILIMF_FIELD_ORIG_DATE:
field->fld_data.fld_orig_date = fld_orig_date;
break;
case MAILIMF_FIELD_FROM:
field->fld_data.fld_from = fld_from;
break;
case MAILIMF_FIELD_SENDER:
field->fld_data.fld_sender = fld_sender;
break;
case MAILIMF_FIELD_REPLY_TO:
field->fld_data.fld_reply_to = fld_reply_to;
break;
case MAILIMF_FIELD_TO:
field->fld_data.fld_to = fld_to;
break;
case MAILIMF_FIELD_CC:
field->fld_data.fld_cc = fld_cc;
break;
case MAILIMF_FIELD_BCC:
field->fld_data.fld_bcc = fld_bcc;
break;
case MAILIMF_FIELD_MESSAGE_ID:
field->fld_data.fld_message_id = fld_message_id;
break;
case MAILIMF_FIELD_IN_REPLY_TO:
field->fld_data.fld_in_reply_to = fld_in_reply_to;
break;
case MAILIMF_FIELD_REFERENCES:
field->fld_data.fld_references = fld_references;
break;
case MAILIMF_FIELD_SUBJECT:
field->fld_data.fld_subject = fld_subject;
break;
case MAILIMF_FIELD_COMMENTS:
field->fld_data.fld_comments = fld_comments;
break;
case MAILIMF_FIELD_KEYWORDS:
field->fld_data.fld_keywords = fld_keywords;
break;
case MAILIMF_FIELD_OPTIONAL_FIELD:
field->fld_data.fld_optional_field = fld_optional_field;
break;
}
return field;
}
void mailimf_field_free(struct mailimf_field * field)
{
switch (field->fld_type) {
case MAILIMF_FIELD_RETURN_PATH:
mailimf_return_free(field->fld_data.fld_return_path);
break;
case MAILIMF_FIELD_RESENT_DATE:
mailimf_orig_date_free(field->fld_data.fld_resent_date);
break;
case MAILIMF_FIELD_RESENT_FROM:
mailimf_from_free(field->fld_data.fld_resent_from);
break;
case MAILIMF_FIELD_RESENT_SENDER:
mailimf_sender_free(field->fld_data.fld_resent_sender);
break;
case MAILIMF_FIELD_RESENT_TO:
mailimf_to_free(field->fld_data.fld_resent_to);
break;
case MAILIMF_FIELD_RESENT_CC:
mailimf_cc_free(field->fld_data.fld_resent_cc);
break;
case MAILIMF_FIELD_RESENT_BCC:
mailimf_bcc_free(field->fld_data.fld_resent_bcc);
break;
case MAILIMF_FIELD_RESENT_MSG_ID:
mailimf_message_id_free(field->fld_data.fld_resent_msg_id);
break;
case MAILIMF_FIELD_ORIG_DATE:
mailimf_orig_date_free(field->fld_data.fld_orig_date);
break;
case MAILIMF_FIELD_FROM:
mailimf_from_free(field->fld_data.fld_from);
break;
case MAILIMF_FIELD_SENDER:
mailimf_sender_free(field->fld_data.fld_sender);
break;
case MAILIMF_FIELD_REPLY_TO:
mailimf_reply_to_free(field->fld_data.fld_reply_to);
break;
case MAILIMF_FIELD_TO:
mailimf_to_free(field->fld_data.fld_to);
break;
case MAILIMF_FIELD_CC:
mailimf_cc_free(field->fld_data.fld_cc);
break;
case MAILIMF_FIELD_BCC:
mailimf_bcc_free(field->fld_data.fld_bcc);
break;
case MAILIMF_FIELD_MESSAGE_ID:
mailimf_message_id_free(field->fld_data.fld_message_id);
break;
case MAILIMF_FIELD_IN_REPLY_TO:
mailimf_in_reply_to_free(field->fld_data.fld_in_reply_to);
break;
case MAILIMF_FIELD_REFERENCES:
mailimf_references_free(field->fld_data.fld_references);
break;
case MAILIMF_FIELD_SUBJECT:
mailimf_subject_free(field->fld_data.fld_subject);
break;
case MAILIMF_FIELD_COMMENTS:
mailimf_comments_free(field->fld_data.fld_comments);
break;
case MAILIMF_FIELD_KEYWORDS:
mailimf_keywords_free(field->fld_data.fld_keywords);
break;
case MAILIMF_FIELD_OPTIONAL_FIELD:
mailimf_optional_field_free(field->fld_data.fld_optional_field);
break;
}
free(field);
}
struct mailimf_fields * mailimf_fields_new(clist * fld_list)
{
struct mailimf_fields * fields;
fields = malloc(sizeof(* fields));
if (fields == NULL)
return NULL;
fields->fld_list = fld_list;
return fields;
}
void mailimf_fields_free(struct mailimf_fields * fields)
{
if (fields->fld_list != NULL) {
clist_foreach(fields->fld_list, (clist_func) mailimf_field_free, NULL);
clist_free(fields->fld_list);
}
free(fields);
}
struct mailimf_orig_date * mailimf_orig_date_new(struct mailimf_date_time *
dt_date_time)
{
struct mailimf_orig_date * orig_date;
orig_date = malloc(sizeof(* orig_date));
if (orig_date == NULL)
return NULL;
orig_date->dt_date_time = dt_date_time;
return orig_date;
}
void mailimf_orig_date_free(struct mailimf_orig_date * orig_date)
{
if (orig_date->dt_date_time != NULL)
mailimf_date_time_free(orig_date->dt_date_time);
free(orig_date);
}
struct mailimf_from *
mailimf_from_new(struct mailimf_mailbox_list * frm_mb_list)
{
struct mailimf_from * from;
from = malloc(sizeof(* from));
if (from == NULL)
return NULL;
from->frm_mb_list = frm_mb_list;
return from;
}
void mailimf_from_free(struct mailimf_from * from)
{
if (from->frm_mb_list != NULL)
mailimf_mailbox_list_free(from->frm_mb_list);
free(from);
}
struct mailimf_sender * mailimf_sender_new(struct mailimf_mailbox * snd_mb)
{
struct mailimf_sender * sender;
sender = malloc(sizeof(* sender));
if (sender == NULL)
return NULL;
sender->snd_mb = snd_mb;
return sender;
}
void mailimf_sender_free(struct mailimf_sender * sender)
{
if (sender->snd_mb != NULL)
mailimf_mailbox_free(sender->snd_mb);
free(sender);
}
struct mailimf_reply_to *
mailimf_reply_to_new(struct mailimf_address_list * rt_addr_list)
{
struct mailimf_reply_to * reply_to;
reply_to = malloc(sizeof(* reply_to));
if (reply_to == NULL)
return NULL;
reply_to->rt_addr_list = rt_addr_list;
return reply_to;
}
void mailimf_reply_to_free(struct mailimf_reply_to * reply_to)
{
if (reply_to->rt_addr_list != NULL)
mailimf_address_list_free(reply_to->rt_addr_list);
free(reply_to);
}
struct mailimf_to * mailimf_to_new(struct mailimf_address_list * to_addr_list)
{
struct mailimf_to * to;
to = malloc(sizeof(* to));
if (to == NULL)
return NULL;
to->to_addr_list = to_addr_list;
return to;
}
void mailimf_to_free(struct mailimf_to * to)
{
if (to->to_addr_list != NULL)
mailimf_address_list_free(to->to_addr_list);
free(to);
}
struct mailimf_cc * mailimf_cc_new(struct mailimf_address_list * cc_addr_list)
{
struct mailimf_cc * cc;
cc = malloc(sizeof(* cc));
if (cc == NULL)
return NULL;
cc->cc_addr_list = cc_addr_list;
return cc;
}
void mailimf_cc_free(struct mailimf_cc * cc)
{
if (cc->cc_addr_list != NULL)
mailimf_address_list_free(cc->cc_addr_list);
free(cc);
}
struct mailimf_bcc *
mailimf_bcc_new(struct mailimf_address_list * bcc_addr_list)
{
struct mailimf_bcc * bcc;
bcc = malloc(sizeof(* bcc));
if (bcc == NULL)
return NULL;
bcc->bcc_addr_list = bcc_addr_list;
return bcc;
}
void mailimf_bcc_free(struct mailimf_bcc * bcc)
{
if (bcc->bcc_addr_list != NULL)
mailimf_address_list_free(bcc->bcc_addr_list);
free(bcc);
}
struct mailimf_message_id * mailimf_message_id_new(char * mid_value)
{
struct mailimf_message_id * message_id;
message_id = malloc(sizeof(* message_id));
if (message_id == NULL)
return NULL;
message_id->mid_value = mid_value;
return message_id;
}
void mailimf_message_id_free(struct mailimf_message_id * message_id)
{
if (message_id->mid_value != NULL)
mailimf_msg_id_free(message_id->mid_value);
free(message_id);
}
struct mailimf_in_reply_to * mailimf_in_reply_to_new(clist * mid_list)
{
struct mailimf_in_reply_to * in_reply_to;
in_reply_to = malloc(sizeof(* in_reply_to));
if (in_reply_to == NULL)
return NULL;
in_reply_to->mid_list = mid_list;
return in_reply_to;
}
void mailimf_in_reply_to_free(struct mailimf_in_reply_to * in_reply_to)
{
clist_foreach(in_reply_to->mid_list,
(clist_func) mailimf_msg_id_free, NULL);
clist_free(in_reply_to->mid_list);
free(in_reply_to);
}
struct mailimf_references * mailimf_references_new(clist * mid_list)
{
struct mailimf_references * ref;
ref = malloc(sizeof(* ref));
if (ref == NULL)
return NULL;
ref->mid_list = mid_list;
return ref;
}
void mailimf_references_free(struct mailimf_references * references)
{
clist_foreach(references->mid_list,
(clist_func) mailimf_msg_id_free, NULL);
clist_free(references->mid_list);
free(references);
}
void mailimf_msg_id_free(char * msg_id)
{
free(msg_id);
}
void mailimf_id_left_free(char * id_left)
{
free(id_left);
}
void mailimf_id_right_free(char * id_right)
{
free(id_right);
}
void mailimf_no_fold_quote_free(char * nfq)
{
free(nfq);
}
void mailimf_no_fold_literal_free(char * nfl)
{
free(nfl);
}
struct mailimf_subject * mailimf_subject_new(char * sbj_value)
{
struct mailimf_subject * subject;
subject = malloc(sizeof(* subject));
if (subject == NULL)
return NULL;
subject->sbj_value = sbj_value;
return subject;
}
void mailimf_subject_free(struct mailimf_subject * subject)
{
mailimf_unstructured_free(subject->sbj_value);
free(subject);
}
struct mailimf_comments * mailimf_comments_new(char * cm_value)
{
struct mailimf_comments * comments;
comments = malloc(sizeof(* comments));
if (comments == NULL)
return NULL;
comments->cm_value = cm_value;
return comments;
}
void mailimf_comments_free(struct mailimf_comments * comments)
{
mailimf_unstructured_free(comments->cm_value);
free(comments);
}
struct mailimf_keywords * mailimf_keywords_new(clist * kw_list)
{
struct mailimf_keywords * keywords;
keywords = malloc(sizeof(* keywords));
if (keywords == NULL)
return NULL;
keywords->kw_list = kw_list;
return keywords;
}
void mailimf_keywords_free(struct mailimf_keywords * keywords)
{
clist_foreach(keywords->kw_list, (clist_func) mailimf_phrase_free, NULL);
clist_free(keywords->kw_list);
free(keywords);
}
struct mailimf_return *
mailimf_return_new(struct mailimf_path * ret_path)
{
struct mailimf_return * return_path;
return_path = malloc(sizeof(* return_path));
if (return_path == NULL)
return NULL;
return_path->ret_path = ret_path;
return return_path;
}
void mailimf_return_free(struct mailimf_return * return_path)
{
mailimf_path_free(return_path->ret_path);
free(return_path);
}
struct mailimf_path * mailimf_path_new(char * pt_addr_spec)
{
struct mailimf_path * path;
path = malloc(sizeof(* path));
if (path == NULL)
return NULL;
path->pt_addr_spec = pt_addr_spec;
return path;
}
void mailimf_path_free(struct mailimf_path * path)
{
if (path->pt_addr_spec != NULL)
mailimf_addr_spec_free(path->pt_addr_spec);
free(path);
}
struct mailimf_optional_field *
mailimf_optional_field_new(char * fld_name, char * fld_value)
{
struct mailimf_optional_field * opt_field;
opt_field = malloc(sizeof(* opt_field));
if (opt_field == NULL)
return NULL;
opt_field->fld_name = fld_name;
opt_field->fld_value = fld_value;
return opt_field;
}
void mailimf_optional_field_free(struct mailimf_optional_field * opt_field)
{
mailimf_field_name_free(opt_field->fld_name);
mailimf_unstructured_free(opt_field->fld_value);
free(opt_field);
}
void mailimf_field_name_free(char * field_name)
{
free(field_name);
}

View file

@ -0,0 +1,797 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001 - 2003 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef MAILIMF_TYPES_H
#define MAILIMF_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
#include "clist.h"
#include <sys/types.h>
/*
IMPORTANT NOTE:
All allocation functions will take as argument allocated data
and will store these data in the structure they will allocate.
Data should be persistant during all the use of the structure
and will be freed by the free function of the structure
allocation functions will return NULL on failure
*/
/*
mailimf_date_time is a date
- day is the day of month (1 to 31)
- month (1 to 12)
- year (4 digits)
- hour (0 to 23)
- min (0 to 59)
- sec (0 to 59)
- zone (this is the decimal value that we can read, for example:
for "-0200", the value is -200)
*/
struct mailimf_date_time {
int dt_day;
int dt_month;
int dt_year;
int dt_hour;
int dt_min;
int dt_sec;
int dt_zone;
};
struct mailimf_date_time *
mailimf_date_time_new(int dt_day, int dt_month, int dt_year,
int dt_hour, int dt_min, int dt_sec, int dt_zone);
void mailimf_date_time_free(struct mailimf_date_time * date_time);
/* this is the type of address */
enum {
MAILIMF_ADDRESS_ERROR, /* on parse error */
MAILIMF_ADDRESS_MAILBOX, /* if this is a mailbox (mailbox@domain) */
MAILIMF_ADDRESS_GROUP, /* if this is a group
(group_name: address1@domain1,
address2@domain2; ) */
};
/*
mailimf_address is an address
- type can be MAILIMF_ADDRESS_MAILBOX or MAILIMF_ADDRESS_GROUP
- mailbox is a mailbox if type is MAILIMF_ADDRESS_MAILBOX
- group is a group if type is MAILIMF_ADDRESS_GROUP
*/
struct mailimf_address {
int ad_type;
union {
struct mailimf_mailbox * ad_mailbox; /* can be NULL */
struct mailimf_group * ad_group; /* can be NULL */
} ad_data;
};
struct mailimf_address *
mailimf_address_new(int ad_type, struct mailimf_mailbox * ad_mailbox,
struct mailimf_group * ad_group);
void mailimf_address_free(struct mailimf_address * address);
/*
mailimf_mailbox is a mailbox
- display_name is the name that will be displayed for this mailbox,
for example 'name' in '"name" <mailbox@domain>,
should be allocated with malloc()
- addr_spec is the mailbox, for example 'mailbox@domain'
in '"name" <mailbox@domain>, should be allocated with malloc()
*/
struct mailimf_mailbox {
char * mb_display_name; /* can be NULL */
char * mb_addr_spec; /* != NULL */
};
struct mailimf_mailbox *
mailimf_mailbox_new(char * mb_display_name, char * mb_addr_spec);
void mailimf_mailbox_free(struct mailimf_mailbox * mailbox);
/*
mailimf_group is a group
- display_name is the name that will be displayed for this group,
for example 'group_name' in
'group_name: address1@domain1, address2@domain2;', should be allocated
with malloc()
- mb_list is a list of mailboxes
*/
struct mailimf_group {
char * grp_display_name; /* != NULL */
struct mailimf_mailbox_list * grp_mb_list; /* can be NULL */
};
struct mailimf_group *
mailimf_group_new(char * grp_display_name,
struct mailimf_mailbox_list * grp_mb_list);
void mailimf_group_free(struct mailimf_group * group);
/*
mailimf_mailbox_list is a list of mailboxes
- list is a list of mailboxes
*/
struct mailimf_mailbox_list {
clist * mb_list; /* list of (struct mailimf_mailbox *) */
/* != NULL */
};
struct mailimf_mailbox_list *
mailimf_mailbox_list_new(clist * mb_list);
void mailimf_mailbox_list_free(struct mailimf_mailbox_list * mb_list);
/*
mailimf_address_list is a list of addresses
- list is a list of addresses
*/
struct mailimf_address_list {
clist * ad_list; /* list of (struct mailimf_address *) */
/* != NULL */
};
struct mailimf_address_list *
mailimf_address_list_new(clist * ad_list);
void mailimf_address_list_free(struct mailimf_address_list * addr_list);
/*
mailimf_body is the text part of a message
- text is the beginning of the text part, it is a substring
of an other string
- size is the size of the text part
*/
struct mailimf_body {
const char * bd_text; /* != NULL */
size_t bd_size;
};
struct mailimf_body * mailimf_body_new(const char * bd_text, size_t bd_size);
void mailimf_body_free(struct mailimf_body * body);
/*
mailimf_message is the content of the message
- fields is the header fields of the message
- body is the text part of the message
*/
struct mailimf_message {
struct mailimf_fields * msg_fields; /* != NULL */
struct mailimf_body * msg_body; /* != NULL */
};
struct mailimf_message *
mailimf_message_new(struct mailimf_fields * msg_fields,
struct mailimf_body * msg_body);
void mailimf_message_free(struct mailimf_message * message);
/*
mailimf_fields is a list of header fields
- list is a list of header fields
*/
struct mailimf_fields {
clist * fld_list; /* list of (struct mailimf_field *) */
/* != NULL */
};
struct mailimf_fields * mailimf_fields_new(clist * fld_list);
void mailimf_fields_free(struct mailimf_fields * fields);
/* this is a type of field */
enum {
MAILIMF_FIELD_NONE, /* on parse error */
MAILIMF_FIELD_RETURN_PATH, /* Return-Path */
MAILIMF_FIELD_RESENT_DATE, /* Resent-Date */
MAILIMF_FIELD_RESENT_FROM, /* Resent-From */
MAILIMF_FIELD_RESENT_SENDER, /* Resent-Sender */
MAILIMF_FIELD_RESENT_TO, /* Resent-To */
MAILIMF_FIELD_RESENT_CC, /* Resent-Cc */
MAILIMF_FIELD_RESENT_BCC, /* Resent-Bcc */
MAILIMF_FIELD_RESENT_MSG_ID, /* Resent-Message-ID */
MAILIMF_FIELD_ORIG_DATE, /* Date */
MAILIMF_FIELD_FROM, /* From */
MAILIMF_FIELD_SENDER, /* Sender */
MAILIMF_FIELD_REPLY_TO, /* Reply-To */
MAILIMF_FIELD_TO, /* To */
MAILIMF_FIELD_CC, /* Cc */
MAILIMF_FIELD_BCC, /* Bcc */
MAILIMF_FIELD_MESSAGE_ID, /* Message-ID */
MAILIMF_FIELD_IN_REPLY_TO, /* In-Reply-To */
MAILIMF_FIELD_REFERENCES, /* References */
MAILIMF_FIELD_SUBJECT, /* Subject */
MAILIMF_FIELD_COMMENTS, /* Comments */
MAILIMF_FIELD_KEYWORDS, /* Keywords */
MAILIMF_FIELD_OPTIONAL_FIELD, /* other field */
};
/*
mailimf_field is a field
- type is the type of the field
- return_path is the parsed content of the Return-Path field if type is
MAILIMF_FIELD_RETURN_PATH
- resent_date is the parsed content of the Resent-Date field if type is
MAILIMF_FIELD_RESENT_DATE
- resent_from is the parsed content of the Resent-From field
- resent_sender is the parsed content of the Resent-Sender field
- resent_to is the parsed content of the Resent-To field
- resent_cc is the parsed content of the Resent-Cc field
- resent_bcc is the parsed content of the Resent-Bcc field
- resent_msg_id is the parsed content of the Resent-Message-ID field
- orig_date is the parsed content of the Date field
- from is the parsed content of the From field
- sender is the parsed content of the Sender field
- reply_to is the parsed content of the Reply-To field
- to is the parsed content of the To field
- cc is the parsed content of the Cc field
- bcc is the parsed content of the Bcc field
- message_id is the parsed content of the Message-ID field
- in_reply_to is the parsed content of the In-Reply-To field
- references is the parsed content of the References field
- subject is the content of the Subject field
- comments is the content of the Comments field
- keywords is the parsed content of the Keywords field
- optional_field is an other field and is not parsed
*/
#define LIBETPAN_MAILIMF_FIELD_UNION
struct mailimf_field {
int fld_type;
union {
struct mailimf_return * fld_return_path; /* can be NULL */
struct mailimf_orig_date * fld_resent_date; /* can be NULL */
struct mailimf_from * fld_resent_from; /* can be NULL */
struct mailimf_sender * fld_resent_sender; /* can be NULL */
struct mailimf_to * fld_resent_to; /* can be NULL */
struct mailimf_cc * fld_resent_cc; /* can be NULL */
struct mailimf_bcc * fld_resent_bcc; /* can be NULL */
struct mailimf_message_id * fld_resent_msg_id; /* can be NULL */
struct mailimf_orig_date * fld_orig_date; /* can be NULL */
struct mailimf_from * fld_from; /* can be NULL */
struct mailimf_sender * fld_sender; /* can be NULL */
struct mailimf_reply_to * fld_reply_to; /* can be NULL */
struct mailimf_to * fld_to; /* can be NULL */
struct mailimf_cc * fld_cc; /* can be NULL */
struct mailimf_bcc * fld_bcc; /* can be NULL */
struct mailimf_message_id * fld_message_id; /* can be NULL */
struct mailimf_in_reply_to * fld_in_reply_to; /* can be NULL */
struct mailimf_references * fld_references; /* can be NULL */
struct mailimf_subject * fld_subject; /* can be NULL */
struct mailimf_comments * fld_comments; /* can be NULL */
struct mailimf_keywords * fld_keywords; /* can be NULL */
struct mailimf_optional_field * fld_optional_field; /* can be NULL */
} fld_data;
};
struct mailimf_field *
mailimf_field_new(int fld_type,
struct mailimf_return * fld_return_path,
struct mailimf_orig_date * fld_resent_date,
struct mailimf_from * fld_resent_from,
struct mailimf_sender * fld_resent_sender,
struct mailimf_to * fld_resent_to,
struct mailimf_cc * fld_resent_cc,
struct mailimf_bcc * fld_resent_bcc,
struct mailimf_message_id * fld_resent_msg_id,
struct mailimf_orig_date * fld_orig_date,
struct mailimf_from * fld_from,
struct mailimf_sender * fld_sender,
struct mailimf_reply_to * fld_reply_to,
struct mailimf_to * fld_to,
struct mailimf_cc * fld_cc,
struct mailimf_bcc * fld_bcc,
struct mailimf_message_id * fld_message_id,
struct mailimf_in_reply_to * fld_in_reply_to,
struct mailimf_references * fld_references,
struct mailimf_subject * fld_subject,
struct mailimf_comments * fld_comments,
struct mailimf_keywords * fld_keywords,
struct mailimf_optional_field * fld_optional_field);
void mailimf_field_free(struct mailimf_field * field);
/*
mailimf_orig_date is the parsed Date field
- date_time is the parsed date
*/
struct mailimf_orig_date {
struct mailimf_date_time * dt_date_time; /* != NULL */
};
struct mailimf_orig_date * mailimf_orig_date_new(struct mailimf_date_time *
dt_date_time);
void mailimf_orig_date_free(struct mailimf_orig_date * orig_date);
/*
mailimf_from is the parsed From field
- mb_list is the parsed mailbox list
*/
struct mailimf_from {
struct mailimf_mailbox_list * frm_mb_list; /* != NULL */
};
struct mailimf_from *
mailimf_from_new(struct mailimf_mailbox_list * frm_mb_list);
void mailimf_from_free(struct mailimf_from * from);
/*
mailimf_sender is the parsed Sender field
- mb is the parsed mailbox
*/
struct mailimf_sender {
struct mailimf_mailbox * snd_mb; /* != NULL */
};
struct mailimf_sender * mailimf_sender_new(struct mailimf_mailbox * snd_mb);
void mailimf_sender_free(struct mailimf_sender * sender);
/*
mailimf_reply_to is the parsed Reply-To field
- addr_list is the parsed address list
*/
struct mailimf_reply_to {
struct mailimf_address_list * rt_addr_list; /* != NULL */
};
struct mailimf_reply_to *
mailimf_reply_to_new(struct mailimf_address_list * rt_addr_list);
void mailimf_reply_to_free(struct mailimf_reply_to * reply_to);
/*
mailimf_to is the parsed To field
- addr_list is the parsed address list
*/
struct mailimf_to {
struct mailimf_address_list * to_addr_list; /* != NULL */
};
struct mailimf_to * mailimf_to_new(struct mailimf_address_list * to_addr_list);
void mailimf_to_free(struct mailimf_to * to);
/*
mailimf_cc is the parsed Cc field
- addr_list is the parsed addres list
*/
struct mailimf_cc {
struct mailimf_address_list * cc_addr_list; /* != NULL */
};
struct mailimf_cc * mailimf_cc_new(struct mailimf_address_list * cc_addr_list);
void mailimf_cc_free(struct mailimf_cc * cc);
/*
mailimf_bcc is the parsed Bcc field
- addr_list is the parsed addres list
*/
struct mailimf_bcc {
struct mailimf_address_list * bcc_addr_list; /* can be NULL */
};
struct mailimf_bcc *
mailimf_bcc_new(struct mailimf_address_list * bcc_addr_list);
void mailimf_bcc_free(struct mailimf_bcc * bcc);
/*
mailimf_message_id is the parsed Message-ID field
- value is the message identifier
*/
struct mailimf_message_id {
char * mid_value; /* != NULL */
};
struct mailimf_message_id * mailimf_message_id_new(char * mid_value);
void mailimf_message_id_free(struct mailimf_message_id * message_id);
/*
mailimf_in_reply_to is the parsed In-Reply-To field
- msg_id_list is the list of message identifers
*/
struct mailimf_in_reply_to {
clist * mid_list; /* list of (char *) */
/* != NULL */
};
struct mailimf_in_reply_to * mailimf_in_reply_to_new(clist * mid_list);
void mailimf_in_reply_to_free(struct mailimf_in_reply_to * in_reply_to);
/*
mailimf_references is the parsed References field
- msg_id_list is the list of message identifiers
*/
struct mailimf_references {
clist * mid_list; /* list of (char *) */
/* != NULL */
};
struct mailimf_references * mailimf_references_new(clist * mid_list);
void mailimf_references_free(struct mailimf_references * references);
/*
mailimf_subject is the parsed Subject field
- value is the value of the field
*/
struct mailimf_subject {
char * sbj_value; /* != NULL */
};
struct mailimf_subject * mailimf_subject_new(char * sbj_value);
void mailimf_subject_free(struct mailimf_subject * subject);
/*
mailimf_comments is the parsed Comments field
- value is the value of the field
*/
struct mailimf_comments {
char * cm_value; /* != NULL */
};
struct mailimf_comments * mailimf_comments_new(char * cm_value);
void mailimf_comments_free(struct mailimf_comments * comments);
/*
mailimf_keywords is the parsed Keywords field
- list is the list of keywords
*/
struct mailimf_keywords {
clist * kw_list; /* list of (char *) */
/* != NULL */
};
struct mailimf_keywords * mailimf_keywords_new(clist * kw_list);
void mailimf_keywords_free(struct mailimf_keywords * keywords);
/*
mailimf_return is the parsed Return-Path field
- path is the parsed value of Return-Path
*/
struct mailimf_return {
struct mailimf_path * ret_path; /* != NULL */
};
struct mailimf_return *
mailimf_return_new(struct mailimf_path * ret_path);
void mailimf_return_free(struct mailimf_return * return_path);
/*
mailimf_path is the parsed value of Return-Path
- addr_spec is a mailbox
*/
struct mailimf_path {
char * pt_addr_spec; /* can be NULL */
};
struct mailimf_path * mailimf_path_new(char * pt_addr_spec);
void mailimf_path_free(struct mailimf_path * path);
/*
mailimf_optional_field is a non-parsed field
- name is the name of the field
- value is the value of the field
*/
struct mailimf_optional_field {
char * fld_name; /* != NULL */
char * fld_value; /* != NULL */
};
struct mailimf_optional_field *
mailimf_optional_field_new(char * fld_name, char * fld_value);
void mailimf_optional_field_free(struct mailimf_optional_field * opt_field);
/*
mailimf_fields is the native structure that IMF module will use,
this module will provide an easier structure to use when parsing fields.
mailimf_single_fields is an easier structure to get parsed fields,
rather than iteration over the list of fields
- orig_date is the parsed "Date" field
- from is the parsed "From" field
- sender is the parsed "Sender "field
- reply_to is the parsed "Reply-To" field
- to is the parsed "To" field
- cc is the parsed "Cc" field
- bcc is the parsed "Bcc" field
- message_id is the parsed "Message-ID" field
- in_reply_to is the parsed "In-Reply-To" field
- references is the parsed "References" field
- subject is the parsed "Subject" field
- comments is the parsed "Comments" field
- keywords is the parsed "Keywords" field
*/
struct mailimf_single_fields {
struct mailimf_orig_date * fld_orig_date; /* can be NULL */
struct mailimf_from * fld_from; /* can be NULL */
struct mailimf_sender * fld_sender; /* can be NULL */
struct mailimf_reply_to * fld_reply_to; /* can be NULL */
struct mailimf_to * fld_to; /* can be NULL */
struct mailimf_cc * fld_cc; /* can be NULL */
struct mailimf_bcc * fld_bcc; /* can be NULL */
struct mailimf_message_id * fld_message_id; /* can be NULL */
struct mailimf_in_reply_to * fld_in_reply_to; /* can be NULL */
struct mailimf_references * fld_references; /* can be NULL */
struct mailimf_subject * fld_subject; /* can be NULL */
struct mailimf_comments * fld_comments; /* can be NULL */
struct mailimf_keywords * fld_keywords; /* can be NULL */
};
/* internal use */
void mailimf_atom_free(char * atom);
void mailimf_dot_atom_free(char * dot_atom);
void mailimf_dot_atom_text_free(char * dot_atom);
void mailimf_quoted_string_free(char * quoted_string);
void mailimf_word_free(char * word);
void mailimf_phrase_free(char * phrase);
void mailimf_unstructured_free(char * unstructured);
void mailimf_angle_addr_free(char * angle_addr);
void mailimf_display_name_free(char * display_name);
void mailimf_addr_spec_free(char * addr_spec);
void mailimf_local_part_free(char * local_part);
void mailimf_domain_free(char * domain);
void mailimf_domain_literal_free(char * domain);
void mailimf_msg_id_free(char * msg_id);
void mailimf_id_left_free(char * id_left);
void mailimf_id_right_free(char * id_right);
void mailimf_no_fold_quote_free(char * nfq);
void mailimf_no_fold_literal_free(char * nfl);
void mailimf_field_name_free(char * field_name);
/* these are the possible returned error codes */
enum {
MAILIMF_NO_ERROR = 0,
MAILIMF_ERROR_PARSE,
MAILIMF_ERROR_MEMORY,
MAILIMF_ERROR_INVAL,
MAILIMF_ERROR_FILE,
};
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,370 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef MAILIMF_TYPES_HELPER
#define MAILIMF_TYPES_HELPER
#ifdef __cplusplus
extern "C" {
#endif
#include "mailimf_types.h"
/*
IMPORTANT NOTE:
All allocation functions will take as argument allocated data
and will store these data in the structure they will allocate.
Data should be persistant during all the use of the structure
and will be freed by the free function of the structure
allocation functions will return NULL on failure
*/
/*
mailimf_mailbox_list_new_empty creates an empty list of mailboxes
*/
struct mailimf_mailbox_list *
mailimf_mailbox_list_new_empty();
/*
mailimf_mailbox_list_add adds a mailbox to the list of mailboxes
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
int mailimf_mailbox_list_add(struct mailimf_mailbox_list * mailbox_list,
struct mailimf_mailbox * mb);
/*
mailimf_mailbox_list_add_parse parse the given string
into a mailimf_mailbox structure and adds it to the list of mailboxes
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
int mailimf_mailbox_list_add_parse(struct mailimf_mailbox_list * mailbox_list,
char * mb_str);
/*
mailimf_mailbox creates a mailimf_mailbox structure with the given
arguments and adds it to the list of mailboxes
- display_name is the name that will be displayed for this mailbox,
for example 'name' in '"name" <mailbox@domain>,
should be allocated with malloc()
- address is the mailbox, for example 'mailbox@domain'
in '"name" <mailbox@domain>, should be allocated with malloc()
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
int mailimf_mailbox_list_add_mb(struct mailimf_mailbox_list * mailbox_list,
char * display_name, char * address);
/*
mailimf_address_list_new_empty creates an empty list of addresses
*/
struct mailimf_address_list *
mailimf_address_list_new_empty();
/*
mailimf_address_list_add adds a mailbox to the list of addresses
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
int mailimf_address_list_add(struct mailimf_address_list * address_list,
struct mailimf_address * addr);
/*
mailimf_address_list_add_parse parse the given string
into a mailimf_address structure and adds it to the list of addresses
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
int mailimf_address_list_add_parse(struct mailimf_address_list * address_list,
char * addr_str);
/*
mailimf_address_list_add_mb creates a mailbox mailimf_address
with the given arguments and adds it to the list of addresses
- display_name is the name that will be displayed for this mailbox,
for example 'name' in '"name" <mailbox@domain>,
should be allocated with malloc()
- address is the mailbox, for example 'mailbox@domain'
in '"name" <mailbox@domain>, should be allocated with malloc()
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
int mailimf_address_list_add_mb(struct mailimf_address_list * address_list,
char * display_name, char * address);
/*
mailimf_resent_fields_add_data adds a set of resent fields in the
given mailimf_fields structure.
if you don't want a given field in the set to be added in the list
of fields, you can give NULL as argument
@param resent_msg_id sould be allocated with malloc()
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
int
mailimf_resent_fields_add_data(struct mailimf_fields * fields,
struct mailimf_date_time * resent_date,
struct mailimf_mailbox_list * resent_from,
struct mailimf_mailbox * resent_sender,
struct mailimf_address_list * resent_to,
struct mailimf_address_list * resent_cc,
struct mailimf_address_list * resent_bcc,
char * resent_msg_id);
/*
mailimf_resent_fields_new_with_data_all creates a new mailimf_fields
structure with a set of resent fields
if you don't want a given field in the set to be added in the list
of fields, you can give NULL as argument
@param resent_msg_id sould be allocated with malloc()
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
struct mailimf_fields *
mailimf_resent_fields_new_with_data_all(struct mailimf_date_time *
resent_date, struct mailimf_mailbox_list * resent_from,
struct mailimf_mailbox * resent_sender,
struct mailimf_address_list * resent_to,
struct mailimf_address_list * resent_cc,
struct mailimf_address_list * resent_bcc,
char * resent_msg_id);
/*
mailimf_resent_fields_new_with_data_all creates a new mailimf_fields
structure with a set of resent fields.
Resent-Date and Resent-Message-ID fields will be generated for you.
if you don't want a given field in the set to be added in the list
of fields, you can give NULL as argument
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
struct mailimf_fields *
mailimf_resent_fields_new_with_data(struct mailimf_mailbox_list * from,
struct mailimf_mailbox * sender,
struct mailimf_address_list * to,
struct mailimf_address_list * cc,
struct mailimf_address_list * bcc);
/*
this function creates a new mailimf_fields structure with no fields
*/
struct mailimf_fields *
mailimf_fields_new_empty(void);
/*
this function adds a field to the mailimf_fields structure
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
int mailimf_fields_add(struct mailimf_fields * fields,
struct mailimf_field * field);
/*
mailimf_fields_add_data adds a set of fields in the
given mailimf_fields structure.
if you don't want a given field in the set to be added in the list
of fields, you can give NULL as argument
@param msg_id sould be allocated with malloc()
@param subject should be allocated with malloc()
@param in_reply_to each elements of this list should be allocated
with malloc()
@param references each elements of this list should be allocated
with malloc()
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
int mailimf_fields_add_data(struct mailimf_fields * fields,
struct mailimf_date_time * date,
struct mailimf_mailbox_list * from,
struct mailimf_mailbox * sender,
struct mailimf_address_list * reply_to,
struct mailimf_address_list * to,
struct mailimf_address_list * cc,
struct mailimf_address_list * bcc,
char * msg_id,
clist * in_reply_to,
clist * references,
char * subject);
/*
mailimf_fields_new_with_data_all creates a new mailimf_fields
structure with a set of fields
if you don't want a given field in the set to be added in the list
of fields, you can give NULL as argument
@param message_id sould be allocated with malloc()
@param subject should be allocated with malloc()
@param in_reply_to each elements of this list should be allocated
with malloc()
@param references each elements of this list should be allocated
with malloc()
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
struct mailimf_fields *
mailimf_fields_new_with_data_all(struct mailimf_date_time * date,
struct mailimf_mailbox_list * from,
struct mailimf_mailbox * sender,
struct mailimf_address_list * reply_to,
struct mailimf_address_list * to,
struct mailimf_address_list * cc,
struct mailimf_address_list * bcc,
char * message_id,
clist * in_reply_to,
clist * references,
char * subject);
/*
mailimf_fields_new_with_data creates a new mailimf_fields
structure with a set of fields
Date and Message-ID fields will be generated for you.
if you don't want a given field in the set to be added in the list
of fields, you can give NULL as argument
@param subject should be allocated with malloc()
@param in_reply_to each elements of this list should be allocated
with malloc()
@param references each elements of this list should be allocated
with malloc()
@return MAILIMF_NO_ERROR will be returned on success,
other code will be returned otherwise
*/
struct mailimf_fields *
mailimf_fields_new_with_data(struct mailimf_mailbox_list * from,
struct mailimf_mailbox * sender,
struct mailimf_address_list * reply_to,
struct mailimf_address_list * to,
struct mailimf_address_list * cc,
struct mailimf_address_list * bcc,
clist * in_reply_to,
clist * references,
char * subject);
/*
this function returns an allocated message identifier to
use in a Message-ID or Resent-Message-ID field
*/
char * mailimf_get_message_id(void);
/*
this function returns a mailimf_date_time structure to
use in a Date or Resent-Date field
*/
struct mailimf_date_time * mailimf_get_current_date(void);
/*
mailimf_single_fields_init fills a mailimf_single_fields structure
with the content of a mailimf_fields structure
*/
void mailimf_single_fields_init(struct mailimf_single_fields * single_fields,
struct mailimf_fields * fields);
/*
mailimf_single_fields_new creates a new mailimf_single_fields and
fills the structure with mailimf_fields
*/
struct mailimf_single_fields *
mailimf_single_fields_new(struct mailimf_fields * fields);
void mailimf_single_fields_free(struct mailimf_single_fields *
single_fields);
/*
mailimf_field_new_custom creates a new field of type optional
@param name should be allocated with malloc()
@param value should be allocated with malloc()
*/
struct mailimf_field * mailimf_field_new_custom(char * name, char * value);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,134 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef MAILIMF_WRITE_H
#define MAILIMF_WRITE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "mailimf_types.h"
/*
mailimf_string_write writes a string to a given stream
@param f is the stream
@param col (* col) is the column number where we will start to
write the text, the ending column will be stored in (* col)
@param str is the string to write
*/
int mailimf_string_write(FILE * f, int * col,
const char * str, size_t length);
/*
mailimf_fields_write writes the fields to a given stream
@param f is the stream
@param col (* col) is the column number where we will start to
write the text, the ending column will be stored in (* col)
@param fields is the fields to write
*/
int mailimf_fields_write(FILE * f, int * col,
struct mailimf_fields * fields);
/*
mailimf_envelope_fields_write writes only some fields to a given stream
@param f is the stream
@param col (* col) is the column number where we will start to
write the text, the ending column will be stored in (* col)
@param fields is the fields to write
*/
int mailimf_envelope_fields_write(FILE * f, int * col,
struct mailimf_fields * fields);
/*
mailimf_field_write writes a field to a given stream
@param f is the stream
@param col (* col) is the column number where we will start to
write the text, the ending column will be stored in (* col)
@param field is the field to write
*/
int mailimf_field_write(FILE * f, int * col,
struct mailimf_field * field);
/*
mailimf_quoted_string_write writes a string that is quoted
to a given stream
@param f is the stream
@param col (* col) is the column number where we will start to
write the text, the ending column will be stored in (* col)
@param string is the string to quote and write
*/
int mailimf_quoted_string_write(FILE * f, int * col,
const char * string, size_t len);
int mailimf_address_list_write(FILE * f, int * col,
struct mailimf_address_list * addr_list);
int mailimf_mailbox_list_write(FILE * f, int * col,
struct mailimf_mailbox_list * mb_list);
/*
mailimf_header_string_write writes a header value and fold the header
if needed.
@param f is the stream
@param col (* col) is the column number where we will start to
write the text, the ending column will be stored in (* col)
@param str is the string to write
*/
int mailimf_header_string_write(FILE * f, int * col,
const char * str, size_t length);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,284 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id $
*/
#include "maillock.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
/* ********************************************************************** */
/* lock primitives */
/* the lock code is modified from the dot lock file code from mail.local.c */
/*
SENDMAIL LICENSE
The following license terms and conditions apply, unless a different
license is obtained from Sendmail, Inc., 6425 Christie Ave, Fourth Floor,
Emeryville, CA 94608, or by electronic mail at license@sendmail.com.
License Terms:
Use, Modification and Redistribution (including distribution of any
modified or derived work) in source and binary forms is permitted only if
each of the following conditions is met:
1. Redistributions qualify as "freeware" or "Open Source Software" under
one of the following terms:
(a) Redistributions are made at no charge beyond the reasonable cost of
materials and delivery.
(b) Redistributions are accompanied by a copy of the Source Code or by an
irrevocable offer to provide a copy of the Source Code for up to three
years at the cost of materials and delivery. Such redistributions
must allow further use, modification, and redistribution of the Source
Code under substantially the same terms as this license. For the
purposes of redistribution "Source Code" means the complete compilable
and linkable source code of sendmail including all modifications.
2. Redistributions of source code must retain the copyright notices as they
appear in each source code file, these license terms, and the
disclaimer/limitation of liability set forth as paragraph 6 below.
3. Redistributions in binary form must reproduce the Copyright Notice,
these license terms, and the disclaimer/limitation of liability set
forth as paragraph 6 below, in the documentation and/or other materials
provided with the distribution. For the purposes of binary distribution
the "Copyright Notice" refers to the following language:
"Copyright (c) 1998-2002 Sendmail, Inc. All rights reserved."
4. Neither the name of Sendmail, Inc. nor the University of California nor
the names of their contributors may be used to endorse or promote
products derived from this software without specific prior written
permission. The name "sendmail" is a trademark of Sendmail, Inc.
5. All redistributions must comply with the conditions imposed by the
University of California on certain embedded code, whose copyright
notice and conditions for redistribution are as follows:
(a) Copyright (c) 1988, 1993 The Regents of the University of
California. All rights reserved.
(b) Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
(i) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(ii) Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
(iii) Neither the name of the University nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
6. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY
SENDMAIL, INC. AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
NO EVENT SHALL SENDMAIL, INC., THE REGENTS OF THE UNIVERSITY OF
CALIFORNIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/*
TODO : lock, prefer fcntl() over flock()
AND use dotlock code above
*/
#define LOCKTO_RM 300 /* timeout for stale lockfile removal */
#define LOCKTO_GLOB 400 /* global timeout for lockfile creation */
static int lock_common(const char * filename, int fd, short locktype)
{
char lockfilename[PATH_MAX];
struct flock lock;
/* dot lock file */
int statfailed = 0;
time_t start;
int r;
int res;
lock.l_start = 0;
lock.l_len = 0;
lock.l_pid = getpid();
lock.l_type = locktype;
lock.l_whence = SEEK_SET;
r = fcntl(fd, F_SETLKW, &lock);
if (r < 0) {
/* WARNING POSIX lock could not be applied */
}
/* dot lock file */
if (strlen(filename) + 6 > PATH_MAX) {
res = -1;
goto unlock;
}
snprintf(lockfilename, PATH_MAX, "%s.lock", filename);
time(&start);
while (1) {
int fd;
struct stat st;
time_t now;
/* global timeout */
time(&now);
if (now > start + LOCKTO_GLOB) {
res = -1;
goto unlock;
}
fd = open(lockfilename, O_WRONLY|O_EXCL|O_CREAT, 0);
if (fd >= 0) {
/* defeat lock checking programs which test pid */
write(fd, "0", 2);
close(fd);
break;
}
/* libEtPan! - adds a delay of 5 seconds between each tries */
sleep(5);
if (stat(lockfilename, &st) < 0) {
if (statfailed++ > 5) {
res = -1;
goto unlock;
}
continue;
}
statfailed = 0;
time(&now);
if (now < st.st_ctime + LOCKTO_RM)
continue;
/* try to remove stale lockfile */
if (unlink(lockfilename) < 0) {
res = -1;
goto unlock;
}
/*
libEtPan! - removes this delay of 5 seconds,
maybe it was misplaced ?
*/
#if 0
sleep(5);
#endif
}
return 0;
unlock:
lock.l_start = 0;
lock.l_len = 0;
lock.l_pid = getpid();
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
r = fcntl(fd, F_SETLK, &lock);
if (r < 0) {
/* WARNING POSIX lock could not be applied */
}
return res;
}
static int unlock_common(const char * filename, int fd)
{
char lockfilename[PATH_MAX];
struct flock lock;
int r;
if (strlen(filename) + 6 > PATH_MAX)
return -1;
snprintf(lockfilename, PATH_MAX, "%s.lock", filename);
unlink(lockfilename);
lock.l_start = 0;
lock.l_len = 0;
lock.l_pid = getpid();
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
r = fcntl(fd, F_SETLK, &lock);
if (r < 0) {
/* WARNING POSIX lock could not be applied */
}
return 0;
}
int maillock_read_lock(const char * filename, int fd)
{
return lock_common(filename, fd, F_RDLCK);
}
int maillock_read_unlock(const char * filename, int fd)
{
return unlock_common(filename, fd);
}
int maillock_write_lock(const char * filename, int fd)
{
return lock_common(filename, fd, F_WRLCK);
}
int maillock_write_unlock(const char * filename, int fd)
{
return unlock_common(filename, fd);
}

View file

@ -0,0 +1,53 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef MAILLOCK_H
#define MAILLOCK_H
#ifdef __cplusplus
extern "C" {
#endif
int maillock_read_lock(const char * filename, int fd);
int maillock_read_unlock(const char * filename, int fd);
int maillock_write_lock(const char * filename, int fd);
int maillock_write_unlock(const char * filename, int fd);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,140 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef MAILMBOX_H
#define MAILMBOX_H
#ifdef __cplusplus
extern "C" {
#endif
#include "mailmbox_types.h"
int
claws_mailmbox_append_message_list(struct claws_mailmbox_folder * folder,
carray * append_tab);
int
claws_mailmbox_append_message(struct claws_mailmbox_folder * folder,
const char * data, size_t len);
int claws_mailmbox_fetch_msg(struct claws_mailmbox_folder * folder,
uint32_t num, const char ** result,
size_t * result_len);
int claws_mailmbox_fetch_msg_headers(struct claws_mailmbox_folder * folder,
uint32_t num, const char ** result,
size_t * result_len);
void claws_mailmbox_fetch_result_free(char * msg);
int claws_mailmbox_copy_msg_list(struct claws_mailmbox_folder * dest_folder,
struct claws_mailmbox_folder * src_folder,
carray * tab);
int claws_mailmbox_copy_msg(struct claws_mailmbox_folder * dest_folder,
struct claws_mailmbox_folder * src_folder,
uint32_t uid);
int claws_mailmbox_expunge(struct claws_mailmbox_folder * folder);
int claws_mailmbox_delete_msg(struct claws_mailmbox_folder * folder, uint32_t uid);
int claws_mailmbox_init(const char * filename,
int force_readonly,
int force_no_uid,
uint32_t default_written_uid,
struct claws_mailmbox_folder ** result_folder);
void claws_mailmbox_done(struct claws_mailmbox_folder * folder);
/* low-level access primitives */
int claws_mailmbox_write_lock(struct claws_mailmbox_folder * folder);
int claws_mailmbox_write_unlock(struct claws_mailmbox_folder * folder);
int claws_mailmbox_read_lock(struct claws_mailmbox_folder * folder);
int claws_mailmbox_read_unlock(struct claws_mailmbox_folder * folder);
/* memory map */
int claws_mailmbox_map(struct claws_mailmbox_folder * folder);
void claws_mailmbox_unmap(struct claws_mailmbox_folder * folder);
void claws_mailmbox_sync(struct claws_mailmbox_folder * folder);
/* open & close file */
int claws_mailmbox_open(struct claws_mailmbox_folder * folder);
void claws_mailmbox_close(struct claws_mailmbox_folder * folder);
/* validate cache */
int claws_mailmbox_validate_write_lock(struct claws_mailmbox_folder * folder);
int claws_mailmbox_validate_read_lock(struct claws_mailmbox_folder * folder);
/* fetch message */
int claws_mailmbox_fetch_msg_no_lock(struct claws_mailmbox_folder * folder,
uint32_t num, const char ** result,
size_t * result_len);
int claws_mailmbox_fetch_msg_headers_no_lock(struct claws_mailmbox_folder * folder,
uint32_t num, const char ** result,
size_t * result_len);
/* append message */
int
claws_mailmbox_append_message_list_no_lock(struct claws_mailmbox_folder * folder,
carray * append_tab);
int claws_mailmbox_expunge_no_lock(struct claws_mailmbox_folder * folder);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2003 Hiroyuki Yamamoto
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __MAILMBOX_FOLDER_H__
#define __MAILMBOX_FOLDER_H__
#include <glib.h>
#include "folder.h"
#include "localfolder.h"
typedef struct _MAILMBOXFolder MAILMBOXFolder;
#define MAILMBOX_FOLDER(obj) ((MAILMBOXFolder *)obj)
struct _MAILMBOXFolder
{
LocalFolder lfolder;
};
FolderClass *claws_mailmbox_get_class (void);
#endif /* __MH_H__ */

View file

@ -0,0 +1 @@
mailmbox

View file

@ -0,0 +1,624 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#include "mailmbox_parse.h"
#include "mailmbox.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#define UID_HEADER "X-LibEtPan-UID:"
#include "utils.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
enum {
UNSTRUCTURED_START,
UNSTRUCTURED_CR,
UNSTRUCTURED_LF,
UNSTRUCTURED_WSP,
UNSTRUCTURED_OUT
};
static inline int
claws_mailmbox_fields_parse(char * str, size_t length,
size_t * index,
uint32_t * puid,
size_t * phlen)
{
size_t cur_token;
int r;
size_t hlen;
size_t uid;
int end;
cur_token = * index;
end = FALSE;
uid = 0;
while (!end) {
size_t begin;
begin = cur_token;
r = mailimf_ignore_field_parse(str, length, &cur_token);
switch (r) {
case MAILIMF_NO_ERROR:
if (str[begin] == 'X') {
if (strncasecmp(str + begin, UID_HEADER, strlen(UID_HEADER)) == 0) {
begin += strlen(UID_HEADER);
while (str[begin] == ' ')
begin ++;
uid = strtoul(str + begin, NULL, 10);
}
}
break;
case MAILIMF_ERROR_PARSE:
default:
end = TRUE;
break;
}
}
hlen = cur_token - * index;
* phlen = hlen;
* puid = uid;
* index = cur_token;
return MAILMBOX_NO_ERROR;
}
enum {
IN_MAIL,
FIRST_CR,
FIRST_LF,
SECOND_CR,
SECOND_LF,
PARSING_F,
PARSING_R,
PARSING_O,
PARSING_M,
OUT_MAIL
};
static inline int
claws_mailmbox_single_parse(char * str, size_t length,
size_t * index,
size_t * pstart,
size_t * pstart_len,
size_t * pheaders,
size_t * pheaders_len,
size_t * pbody,
size_t * pbody_len,
size_t * psize,
size_t * ppadding,
uint32_t * puid)
{
size_t cur_token;
size_t start;
size_t start_len;
size_t headers;
size_t headers_len;
size_t body;
size_t end;
size_t next;
size_t message_length;
uint32_t uid;
int r;
#if 0
int in_mail_data;
#endif
#if 0
size_t begin;
#endif
int state;
cur_token = * index;
if (cur_token >= length)
return MAILMBOX_ERROR_PARSE;
start = cur_token;
start_len = 0;
headers = cur_token;
if (cur_token + 5 < length) {
if (strncmp(str + cur_token, "From ", 5) == 0) {
cur_token += 5;
while (str[cur_token] != '\n') {
cur_token ++;
if (cur_token >= length)
break;
}
if (cur_token < length) {
cur_token ++;
headers = cur_token;
start_len = headers - start;
}
}
}
next = length;
r = claws_mailmbox_fields_parse(str, length, &cur_token,
&uid, &headers_len);
if (r != MAILMBOX_NO_ERROR)
return r;
/* save position */
#if 0
begin = cur_token;
#endif
mailimf_crlf_parse(str, length, &cur_token);
#if 0
if (str[cur_token] == 'F') {
printf("start !\n");
printf("%50.50s\n", str + cur_token);
getchar();
}
#endif
body = cur_token;
/* restore position */
/* cur_token = begin; */
state = FIRST_LF;
end = length;
#if 0
in_mail_data = 0;
#endif
while (state != OUT_MAIL) {
if (cur_token >= length) {
if (state == IN_MAIL)
end = length;
next = length;
break;
}
switch(state) {
case IN_MAIL:
switch(str[cur_token]) {
case '\r':
state = FIRST_CR;
break;
case '\n':
state = FIRST_LF;
break;
case 'F':
if (cur_token == body) {
end = cur_token;
next = cur_token;
state = PARSING_F;
}
break;
#if 0
default:
in_mail_data = 1;
break;
#endif
}
break;
case FIRST_CR:
end = cur_token;
switch(str[cur_token]) {
case '\r':
state = SECOND_CR;
break;
case '\n':
state = FIRST_LF;
break;
default:
state = IN_MAIL;
#if 0
in_mail_data = 1;
#endif
break;
}
break;
case FIRST_LF:
end = cur_token;
switch(str[cur_token]) {
case '\r':
state = SECOND_CR;
break;
case '\n':
state = SECOND_LF;
break;
default:
state = IN_MAIL;
#if 0
in_mail_data = 1;
#endif
break;
}
break;
case SECOND_CR:
switch(str[cur_token]) {
case '\r':
end = cur_token;
break;
case '\n':
state = SECOND_LF;
break;
case 'F':
next = cur_token;
state = PARSING_F;
break;
default:
state = IN_MAIL;
#if 0
in_mail_data = 1;
#endif
break;
}
break;
case SECOND_LF:
switch(str[cur_token]) {
case '\r':
state = SECOND_CR;
break;
case '\n':
end = cur_token;
break;
case 'F':
next = cur_token;
state = PARSING_F;
break;
default:
state = IN_MAIL;
#if 0
in_mail_data = 1;
#endif
break;
}
break;
case PARSING_F:
switch(str[cur_token]) {
case 'r':
state = PARSING_R;
break;
default:
state = IN_MAIL;
#if 0
in_mail_data = 1;
#endif
break;
}
break;
case PARSING_R:
switch(str[cur_token]) {
case 'o':
state = PARSING_O;
break;
default:
state = IN_MAIL;
#if 0
in_mail_data = 1;
#endif
break;
}
break;
case PARSING_O:
switch(str[cur_token]) {
case 'm':
state = PARSING_M;
break;
default:
state = IN_MAIL;
#if 0
in_mail_data = 1;
#endif
break;
}
break;
case PARSING_M:
switch(str[cur_token]) {
case ' ':
state = OUT_MAIL;
break;
default:
state = IN_MAIL;
break;
}
break;
}
cur_token ++;
}
message_length = end - start;
* pstart = start;
* pstart_len = start_len;
* pheaders = headers;
* pheaders_len = headers_len;
* pbody = body;
* pbody_len = end - body;
* psize = message_length;
* ppadding = next - end;
* puid = uid;
* index = next;
return MAILMBOX_NO_ERROR;
}
int
claws_mailmbox_parse_additionnal(struct claws_mailmbox_folder * folder,
size_t * index)
{
size_t cur_token;
size_t start;
size_t start_len;
size_t headers;
size_t headers_len;
size_t body;
size_t body_len;
size_t size;
size_t padding;
uint32_t uid;
int r;
int res;
uint32_t max_uid;
uint32_t first_index;
unsigned int i;
unsigned int j;
cur_token = * index;
/* remove temporary UID that we will parse */
first_index = carray_count(folder->mb_tab);
for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) {
struct claws_mailmbox_msg_info * info;
info = carray_get(folder->mb_tab, i);
if (info->msg_start < cur_token) {
continue;
}
if (!info->msg_written_uid) {
chashdatum key;
key.data = &info->msg_uid;
key.len = sizeof(info->msg_uid);
chash_delete(folder->mb_hash, &key, NULL);
carray_delete_fast(folder->mb_tab, i);
claws_mailmbox_msg_info_free(info);
if (i < first_index)
first_index = i;
}
}
/* make a sequence in the table */
max_uid = folder->mb_written_uid;
i = 0;
j = 0;
while (i < carray_count(folder->mb_tab)) {
struct claws_mailmbox_msg_info * info;
info = carray_get(folder->mb_tab, i);
if (info != NULL) {
carray_set(folder->mb_tab, j, info);
if (info->msg_uid > max_uid)
max_uid = info->msg_uid;
info->msg_index = j;
j ++;
}
i ++;
}
carray_set_size(folder->mb_tab, j);
/* parse content */
first_index = j;
while (1) {
struct claws_mailmbox_msg_info * info;
chashdatum key;
chashdatum data;
r = claws_mailmbox_single_parse(folder->mb_mapping, folder->mb_mapping_size,
&cur_token,
&start, &start_len,
&headers, &headers_len,
&body, &body_len,
&size, &padding, &uid);
if (r == MAILMBOX_NO_ERROR) {
/* do nothing */
}
else if (r == MAILMBOX_ERROR_PARSE) {
break;
} else {
res = r;
goto err;
}
key.data = &uid;
key.len = sizeof(uid);
r = chash_get(folder->mb_hash, &key, &data);
if (r == 0) {
info = data.data;
if (!info->msg_written_uid) {
/* some new mail has been written and override an
existing temporary UID */
chash_delete(folder->mb_hash, &key, NULL);
info->msg_uid = 0;
if (info->msg_index < first_index)
first_index = info->msg_index;
}
else
uid = 0;
}
if (uid > max_uid)
max_uid = uid;
r = claws_mailmbox_msg_info_update(folder,
start, start_len, headers, headers_len,
body, body_len, size, padding, uid);
if (r != MAILMBOX_NO_ERROR) {
debug_print("claws_mailmbox_msg_info_update failed with %d\n", r);
res = r;
goto err;
}
}
* index = cur_token;
folder->mb_written_uid = max_uid;
/* attribute uid */
for(i = first_index ; i < carray_count(folder->mb_tab) ; i ++) {
struct claws_mailmbox_msg_info * info;
chashdatum key;
chashdatum data;
info = carray_get(folder->mb_tab, i);
if (info->msg_uid != 0) {
continue;
}
max_uid ++;
info->msg_uid = max_uid;
key.data = &info->msg_uid;
key.len = sizeof(info->msg_uid);
data.data = info;
data.len = 0;
r = chash_set(folder->mb_hash, &key, &data, NULL);
if (r < 0) {
debug_print("chash_set failed with %d\n", r);
res = MAILMBOX_ERROR_MEMORY;
goto err;
}
}
folder->mb_max_uid = max_uid;
return MAILMBOX_NO_ERROR;
err:
return res;
}
static void flush_uid(struct claws_mailmbox_folder * folder)
{
unsigned int i;
for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) {
struct claws_mailmbox_msg_info * info;
info = carray_get(folder->mb_tab, i);
if (info != NULL)
claws_mailmbox_msg_info_free(info);
}
chash_clear(folder->mb_hash);
carray_set_size(folder->mb_tab, 0);
}
int claws_mailmbox_parse(struct claws_mailmbox_folder * folder)
{
int r;
int res;
size_t cur_token;
flush_uid(folder);
cur_token = 0;
r = claws_mailmbox_parse_additionnal(folder, &cur_token);
if (r != MAILMBOX_NO_ERROR) {
res = r;
goto err;
}
return MAILMBOX_NO_ERROR;
err:
return res;
}

View file

@ -0,0 +1,56 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef MAILMBOX_PARSE_H
#define MAILMBOX_PARSE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "mailmbox_types.h"
int claws_mailmbox_parse(struct claws_mailmbox_folder * folder);
int
claws_mailmbox_parse_additionnal(struct claws_mailmbox_folder * folder,
size_t * index);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,250 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#include "mailmbox_types.h"
#include <string.h>
#include <stdlib.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* *********************************************************************** */
int claws_mailmbox_msg_info_update(struct claws_mailmbox_folder * folder,
size_t msg_start, size_t msg_start_len,
size_t msg_headers, size_t msg_headers_len,
size_t msg_body, size_t msg_body_len,
size_t msg_size, size_t msg_padding,
uint32_t msg_uid)
{
struct claws_mailmbox_msg_info * info;
int res;
chashdatum key;
chashdatum data;
int r;
key.data = &msg_uid;
key.len = sizeof(msg_uid);
r = chash_get(folder->mb_hash, &key, &data);
if (r < 0) {
unsigned int index;
info = claws_mailmbox_msg_info_new(msg_start, msg_start_len,
msg_headers, msg_headers_len,
msg_body, msg_body_len, msg_size, msg_padding, msg_uid);
if (info == NULL) {
res = MAILMBOX_ERROR_MEMORY;
goto err;
}
r = carray_add(folder->mb_tab, info, &index);
if (r < 0) {
claws_mailmbox_msg_info_free(info);
res = MAILMBOX_ERROR_MEMORY;
goto err;
}
if (msg_uid != 0) {
chashdatum key;
chashdatum data;
key.data = &msg_uid;
key.len = sizeof(msg_uid);
data.data = info;
data.len = 0;
r = chash_set(folder->mb_hash, &key, &data, NULL);
if (r < 0) {
claws_mailmbox_msg_info_free(info);
carray_delete(folder->mb_tab, index);
res = MAILMBOX_ERROR_MEMORY;
goto err;
}
}
info->msg_index = index;
}
else {
info = data.data;
info->msg_start = msg_start;
info->msg_start_len = msg_start_len;
info->msg_headers = msg_headers;
info->msg_headers_len = msg_headers_len;
info->msg_body = msg_body;
info->msg_body_len = msg_body_len;
info->msg_size = msg_size;
info->msg_padding = msg_padding;
}
return MAILMBOX_NO_ERROR;
err:
return res;
}
struct claws_mailmbox_msg_info *
claws_mailmbox_msg_info_new(size_t msg_start, size_t msg_start_len,
size_t msg_headers, size_t msg_headers_len,
size_t msg_body, size_t msg_body_len,
size_t msg_size, size_t msg_padding,
uint32_t msg_uid)
{
struct claws_mailmbox_msg_info * info;
info = malloc(sizeof(* info));
if (info == NULL)
return NULL;
info->msg_index = 0;
info->msg_uid = msg_uid;
if (msg_uid != 0)
info->msg_written_uid = TRUE;
else
info->msg_written_uid = FALSE;
info->msg_deleted = FALSE;
info->msg_start = msg_start;
info->msg_start_len = msg_start_len;
info->msg_headers = msg_headers;
info->msg_headers_len = msg_headers_len;
info->msg_body = msg_body;
info->msg_body_len = msg_body_len;
info->msg_size = msg_size;
info->msg_padding = msg_padding;
return info;
}
void claws_mailmbox_msg_info_free(struct claws_mailmbox_msg_info * info)
{
free(info);
}
/* append info */
struct claws_mailmbox_append_info *
claws_mailmbox_append_info_new(const char * ai_message, size_t ai_size)
{
struct claws_mailmbox_append_info * info;
info = malloc(sizeof(* info));
if (info == NULL)
return NULL;
info->ai_message = ai_message;
info->ai_size = ai_size;
return info;
}
void claws_mailmbox_append_info_free(struct claws_mailmbox_append_info * info)
{
free(info);
}
struct claws_mailmbox_folder * claws_mailmbox_folder_new(const char * mb_filename)
{
struct claws_mailmbox_folder * folder;
folder = malloc(sizeof(* folder));
if (folder == NULL)
goto err;
strncpy(folder->mb_filename, mb_filename, PATH_MAX);
folder->mb_mtime = (time_t) -1;
folder->mb_fd = -1;
folder->mb_read_only = TRUE;
folder->mb_no_uid = TRUE;
folder->mb_changed = FALSE;
folder->mb_deleted_count = 0;
folder->mb_mapping = NULL;
folder->mb_mapping_size = 0;
folder->mb_written_uid = 0;
folder->mb_max_uid = 0;
folder->mb_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
if (folder->mb_hash == NULL)
goto free;
folder->mb_tab = carray_new(128);
if (folder->mb_tab == NULL)
goto free_hash;
return folder;
free_hash:
chash_free(folder->mb_hash);
free:
free(folder);
err:
return NULL;
}
void claws_mailmbox_folder_free(struct claws_mailmbox_folder * folder)
{
unsigned int i;
for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) {
struct claws_mailmbox_msg_info * info;
info = carray_get(folder->mb_tab, i);
if (info != NULL)
claws_mailmbox_msg_info_free(info);
}
carray_free(folder->mb_tab);
chash_free(folder->mb_hash);
free(folder);
}

View file

@ -0,0 +1,141 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef MAILMBOX_TYPES_H
#define MAILMBOX_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
#include <limits.h>
#include "mailimf.h"
#include "carray.h"
#include "chash.h"
enum {
MAILMBOX_NO_ERROR = 0,
MAILMBOX_ERROR_PARSE,
MAILMBOX_ERROR_INVAL,
MAILMBOX_ERROR_FILE_NOT_FOUND,
MAILMBOX_ERROR_MEMORY,
MAILMBOX_ERROR_TEMPORARY_FILE,
MAILMBOX_ERROR_FILE,
MAILMBOX_ERROR_MSG_NOT_FOUND,
MAILMBOX_ERROR_READONLY,
};
struct claws_mailmbox_folder {
char mb_filename[PATH_MAX];
time_t mb_mtime;
int mb_fd;
int mb_read_only;
int mb_no_uid;
int mb_changed;
unsigned int mb_deleted_count;
char * mb_mapping;
size_t mb_mapping_size;
uint32_t mb_written_uid;
uint32_t mb_max_uid;
chash * mb_hash;
carray * mb_tab;
};
struct claws_mailmbox_folder * claws_mailmbox_folder_new(const char * mb_filename);
void claws_mailmbox_folder_free(struct claws_mailmbox_folder * folder);
struct claws_mailmbox_msg_info {
unsigned int msg_index;
uint32_t msg_uid;
int msg_written_uid;
int msg_deleted;
size_t msg_start;
size_t msg_start_len;
size_t msg_headers;
size_t msg_headers_len;
size_t msg_body;
size_t msg_body_len;
size_t msg_size;
size_t msg_padding;
};
int claws_mailmbox_msg_info_update(struct claws_mailmbox_folder * folder,
size_t msg_start, size_t msg_start_len,
size_t msg_headers, size_t msg_headers_len,
size_t msg_body, size_t msg_body_len,
size_t msg_size, size_t msg_padding,
uint32_t msg_uid);
struct claws_mailmbox_msg_info *
claws_mailmbox_msg_info_new(size_t msg_start, size_t msg_start_len,
size_t msg_headers, size_t msg_headers_len,
size_t msg_body, size_t msg_body_len,
size_t msg_size, size_t msg_padding,
uint32_t msg_uid);
void claws_mailmbox_msg_info_free(struct claws_mailmbox_msg_info * info);
struct claws_mailmbox_append_info {
const char * ai_message;
size_t ai_size;
};
struct claws_mailmbox_append_info *
claws_mailmbox_append_info_new(const char * ai_message, size_t ai_size);
void claws_mailmbox_append_info_free(struct claws_mailmbox_append_info * info);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,525 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#include "mmapstring.h"
#include "chash.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <pthread.h>
#include <limits.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MMAP_STRING_DEFAULT_CEIL (8 * 1024 * 1024)
#define DEFAULT_TMP_PATH "/tmp"
static char tmpdir[PATH_MAX] = DEFAULT_TMP_PATH;
static size_t mmap_string_ceil = MMAP_STRING_DEFAULT_CEIL;
/* MMAPString references */
static pthread_mutex_t mmapstring_lock = PTHREAD_MUTEX_INITIALIZER;
static chash * mmapstring_hashtable = NULL;
static void mmapstring_hashtable_init()
{
mmapstring_hashtable = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
}
void mmap_string_set_tmpdir(char * directory)
{
strncpy(tmpdir, directory, PATH_MAX);
tmpdir[PATH_MAX - 1] = 0;
}
int mmap_string_ref(MMAPString * string)
{
chash * ht;
int r;
chashdatum key;
chashdatum data;
pthread_mutex_lock(&mmapstring_lock);
if (mmapstring_hashtable == NULL) {
mmapstring_hashtable_init();
}
ht = mmapstring_hashtable;
if (ht == NULL) {
pthread_mutex_unlock(&mmapstring_lock);
return -1;
}
key.data = &string->str;
key.len = sizeof(string->str);
data.data = string;
data.len = 0;
r = chash_set(mmapstring_hashtable, &key, &data, NULL);
pthread_mutex_unlock(&mmapstring_lock);
if (r < 0)
return r;
return 0;
}
int mmap_string_unref(char * str)
{
MMAPString * string;
chash * ht;
chashdatum key;
chashdatum data;
int r;
pthread_mutex_lock(&mmapstring_lock);
ht = mmapstring_hashtable;
if (ht == NULL) {
pthread_mutex_unlock(&mmapstring_lock);
return -1;
}
key.data = &str;
key.len = sizeof(str);
r = chash_get(ht, &key, &data);
if (r < 0)
string = NULL;
else
string = data.data;
if (string != NULL) {
chash_delete(ht, &key, NULL);
if (chash_count(ht) == 0) {
chash_free(ht);
mmapstring_hashtable = NULL;
}
}
pthread_mutex_unlock(&mmapstring_lock);
if (string != NULL) {
mmap_string_free(string);
return 0;
}
else
return -1;
}
/* MMAPString */
#define MY_MAXSIZE ((size_t) -1)
static inline size_t
nearest_power (size_t base, size_t num)
{
if (num > MY_MAXSIZE / 2) {
return MY_MAXSIZE;
}
else {
size_t n = base;
while (n < num)
n <<= 1;
return n;
}
}
void mmap_string_set_ceil(size_t ceil)
{
mmap_string_ceil = ceil;
}
/* Strings.
*/
static MMAPString * mmap_string_realloc_file(MMAPString * string)
{
char * data;
if (string->fd == -1) {
char tmpfilename[PATH_MAX];
int fd;
* tmpfilename = 0;
strcat(tmpfilename, tmpdir);
strcat(tmpfilename, "/libetpan-mmapstring-XXXXXX");
fd = mkstemp(tmpfilename);
if (fd == -1)
return NULL;
if (unlink(tmpfilename) == -1) {
close(fd);
return NULL;
}
if (ftruncate(fd, string->allocated_len) == -1) {
close(fd);
return NULL;
}
data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ,
MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
close(fd);
return NULL;
}
if (string->str != NULL)
memcpy(data, string->str, string->len + 1);
string->fd = fd;
string->mmapped_size = string->allocated_len;
free(string->str);
string->str = data;
}
else {
if (munmap(string->str, string->mmapped_size) == -1)
return NULL;
if (ftruncate(string->fd, string->allocated_len) == -1)
return NULL;
data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ,
MAP_SHARED, string->fd, 0);
if (data == MAP_FAILED)
return NULL;
string->mmapped_size = string->allocated_len;
string->str = data;
}
return string;
}
static MMAPString * mmap_string_realloc_memory(MMAPString * string)
{
char * tmp;
tmp = realloc (string->str, string->allocated_len);
if (tmp == NULL)
string = NULL;
else
string->str = tmp;
return string;
}
static MMAPString *
mmap_string_maybe_expand (MMAPString* string,
size_t len)
{
if (string->len + len >= string->allocated_len)
{
size_t old_size;
MMAPString * newstring;
old_size = string->allocated_len;
string->allocated_len = nearest_power (1, string->len + len + 1);
#ifndef MMAP_UNAVAILABLE
if (string->allocated_len > mmap_string_ceil)
newstring = mmap_string_realloc_file(string);
else {
#endif
newstring = mmap_string_realloc_memory(string);
#ifndef MMAP_UNAVAILABLE
if (newstring == NULL)
newstring = mmap_string_realloc_file(string);
}
#endif
if (newstring == NULL)
string->allocated_len = old_size;
}
return string;
}
MMAPString*
mmap_string_sized_new (size_t dfl_size)
{
MMAPString *string;
string = malloc(sizeof(* string));
if (string == NULL)
return NULL;
string->allocated_len = 0;
string->len = 0;
string->str = NULL;
string->fd = -1;
string->mmapped_size = 0;
if (mmap_string_maybe_expand (string, MAX (dfl_size, 2)) == NULL)
return NULL;
string->str[0] = 0;
return string;
}
MMAPString*
mmap_string_new (const char *init)
{
MMAPString *string;
string = mmap_string_sized_new (init ? strlen (init) + 2 : 2);
if (string == NULL)
return NULL;
if (init)
mmap_string_append (string, init);
return string;
}
MMAPString*
mmap_string_new_len (const char *init,
size_t len)
{
MMAPString *string;
if (len <= 0)
return mmap_string_new (init);
else
{
string = mmap_string_sized_new (len);
if (init)
mmap_string_append_len (string, init, len);
return string;
}
}
void
mmap_string_free (MMAPString *string)
{
if (string == NULL)
return;
if (string->fd != -1) {
munmap(string->str, string->mmapped_size);
close(string->fd);
}
else {
free (string->str);
}
free(string);
}
MMAPString*
mmap_string_assign (MMAPString *string,
const char *rval)
{
mmap_string_truncate (string, 0);
if (mmap_string_append (string, rval) == NULL)
return NULL;
return string;
}
MMAPString*
mmap_string_truncate (MMAPString *string,
size_t len)
{
string->len = MIN (len, string->len);
string->str[string->len] = 0;
return string;
}
/**
* mmap_string_set_size:
* @string: a #MMAPString
* @len: the new length
*
* Sets the length of a #MMAPString. If the length is less than
* the current length, the string will be truncated. If the
* length is greater than the current length, the contents
* of the newly added area are undefined. (However, as
* always, string->str[string->len] will be a nul byte.)
*
* Return value: @string
**/
MMAPString*
mmap_string_set_size (MMAPString *string,
size_t len)
{
if (len >= string->allocated_len)
if (mmap_string_maybe_expand (string, len - string->len) == NULL)
return NULL;
string->len = len;
string->str[len] = 0;
return string;
}
/*
static int in_mapped_zone(MMAPString * string, char * val)
{
return (val >= string->str) && (val < string->str + string->mmapped_size);
}
*/
MMAPString*
mmap_string_insert_len (MMAPString *string,
size_t pos,
const char *val,
size_t len)
{
if (mmap_string_maybe_expand (string, len) == NULL)
return NULL;
if (pos < string->len)
memmove (string->str + pos + len, string->str + pos, string->len - pos);
/* insert the new string */
memmove (string->str + pos, val, len);
string->len += len;
string->str[string->len] = 0;
return string;
}
MMAPString*
mmap_string_append (MMAPString *string,
const char *val)
{
return mmap_string_insert_len (string, string->len, val, strlen(val));
}
MMAPString*
mmap_string_append_len (MMAPString *string,
const char *val,
size_t len)
{
return mmap_string_insert_len (string, string->len, val, len);
}
MMAPString*
mmap_string_append_c (MMAPString *string,
char c)
{
return mmap_string_insert_c (string, string->len, c);
}
MMAPString*
mmap_string_prepend (MMAPString *string,
const char *val)
{
return mmap_string_insert_len (string, 0, val, strlen(val));
}
MMAPString*
mmap_string_prepend_len (MMAPString *string,
const char *val,
size_t len)
{
return mmap_string_insert_len (string, 0, val, len);
}
MMAPString*
mmap_string_prepend_c (MMAPString *string,
char c)
{
return mmap_string_insert_c (string, 0, c);
}
MMAPString*
mmap_string_insert (MMAPString *string,
size_t pos,
const char *val)
{
return mmap_string_insert_len (string, pos, val, strlen(val));
}
MMAPString*
mmap_string_insert_c (MMAPString *string,
size_t pos,
char c)
{
if (mmap_string_maybe_expand (string, 1) == NULL)
return NULL;
/* If not just an append, move the old stuff */
if (pos < string->len)
memmove (string->str + pos + 1, string->str + pos, string->len - pos);
string->str[pos] = c;
string->len += 1;
string->str[string->len] = 0;
return string;
}
MMAPString*
mmap_string_erase (MMAPString *string,
size_t pos,
size_t len)
{
if ((pos + len) < string->len)
memmove (string->str + pos, string->str + pos + len,
string->len - (pos + len));
string->len -= len;
string->str[string->len] = 0;
return string;
}

View file

@ -0,0 +1,136 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - DINH Viet Hoa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the libEtPan! project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id$
*/
#ifndef __MMAP_STRING_H__
#define __MMAP_STRING_H__
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
#define TMPDIR "/tmp"
*/
typedef struct _MMAPString MMAPString;
struct _MMAPString
{
char * str;
size_t len;
size_t allocated_len;
int fd;
size_t mmapped_size;
/*
char * old_non_mmapped_str;
*/
};
/* configure location of mmaped files */
void mmap_string_set_tmpdir(char * directory);
/* Strings
*/
MMAPString * mmap_string_new (const char * init);
MMAPString * mmap_string_new_len (const char * init,
size_t len);
MMAPString * mmap_string_sized_new (size_t dfl_size);
void mmap_string_free (MMAPString * string);
MMAPString * mmap_string_assign (MMAPString * string,
const char * rval);
MMAPString * mmap_string_truncate (MMAPString *string,
size_t len);
MMAPString * mmap_string_set_size (MMAPString * string,
size_t len);
MMAPString * mmap_string_insert_len (MMAPString * string,
size_t pos,
const char * val,
size_t len);
MMAPString * mmap_string_append (MMAPString * string,
const char * val);
MMAPString * mmap_string_append_len (MMAPString * string,
const char * val,
size_t len);
MMAPString * mmap_string_append_c (MMAPString * string,
char c);
MMAPString * mmap_string_prepend (MMAPString * string,
const char * val);
MMAPString * mmap_string_prepend_c (MMAPString * string,
char c);
MMAPString * mmap_string_prepend_len (MMAPString * string,
const char * val,
size_t len);
MMAPString * mmap_string_insert (MMAPString * string,
size_t pos,
const char * val);
MMAPString * mmap_string_insert_c (MMAPString *string,
size_t pos,
char c);
MMAPString * mmap_string_erase(MMAPString * string,
size_t pos,
size_t len);
void mmap_string_set_ceil(size_t ceil);
int mmap_string_ref(MMAPString * string);
int mmap_string_unref(char * str);
#ifdef __cplusplus
}
#endif
#endif /* __MMAP_STRING_H__ */

View file

@ -1 +0,0 @@
Placeholder

View file

@ -0,0 +1,87 @@
/*
* mailmbox Plugin -- mbox support for Sylpheed
* Copyright (C) 2003 Christoph Hohmann
* Copyright (C) 2003-2005 Hoa v. Dinh, Alfons Hoogervorst
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "claws-features.h"
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include "plugin.h"
#include "folder.h"
#include "mailmbox_folder.h"
#include "common/version.h"
#include "plugin_gtk.h"
#include "plugin.h"
#include "main.h"
gint plugin_init(gchar **error)
{
if (!check_plugin_version(MAKE_NUMERIC_VERSION(3,8,1,46),
VERSION_NUMERIC, "Mailmbox", error))
return -1;
folder_register_class(claws_mailmbox_get_class());
plugin_gtk_init(error);
return 0;
}
gboolean plugin_done(void)
{
plugin_gtk_done();
if (!claws_is_exiting())
folder_unregister_class(claws_mailmbox_get_class());
return TRUE;
}
const gchar *plugin_name(void)
{
return _("mailmbox folder (etPan!)");
}
const gchar *plugin_desc(void)
{
return _("This is a plugin to handle mailboxes in mbox format.");
}
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_FOLDERCLASS, N_("MBOX")},
{PLUGIN_NOTHING, NULL}};
return features;
}

View file

@ -0,0 +1,455 @@
/*
* mailmbox Plugin -- mbox support for Sylpheed
* Copyright (C) 2003-2005 Christoph Hohmann,
* Hoa v. Dinh,
* Alfons Hoogervorst
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include "claws-features.h"
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "plugin.h"
#include "folder.h"
#include "mailmbox_folder.h"
#include "mainwindow.h"
#include "folderview.h"
#include "inputdialog.h"
#include "foldersel.h"
#include "alertpanel.h"
#include "main.h"
#include "menu.h"
#include "account.h"
#include "prefs_actions.h"
#include "summaryview.h"
#include "folder_item_prefs.h"
static void add_mailbox(GtkAction *action, gpointer callback_data);
static void new_folder_cb(GtkAction *action, gpointer data);
static void delete_folder_cb(GtkAction *action, gpointer data);
static void rename_folder_cb(GtkAction *action, gpointer data);
static void move_folder_cb(GtkAction *action, gpointer data);
static void copy_folder_cb(GtkAction *action, gpointer data);
static void update_tree_cb(GtkAction *action, gpointer data);
static void remove_mailbox_cb(GtkAction *action, gpointer data);
static GtkActionEntry claws_mailmbox_popup_entries[] =
{
{"FolderViewPopup/CreateNewFolder", NULL, N_("Create _new folder..."), NULL, NULL, G_CALLBACK(new_folder_cb) },
{"FolderViewPopup/RenameFolder", NULL, N_("_Rename folder..."), NULL, NULL, G_CALLBACK(rename_folder_cb) },
{"FolderViewPopup/MoveFolder", NULL, N_("M_ove folder..."), NULL, NULL, G_CALLBACK(move_folder_cb) },
{"FolderViewPopup/CopyFolder", NULL, N_("Cop_y folder..."), NULL, NULL, G_CALLBACK(copy_folder_cb) },
{"FolderViewPopup/DeleteFolder", NULL, N_("_Delete folder..."), NULL, NULL, G_CALLBACK(delete_folder_cb) },
{"FolderViewPopup/CheckNewMessages", NULL, N_("_Check for new messages"), NULL, NULL, G_CALLBACK(update_tree_cb) }, /*0*/
{"FolderViewPopup/CheckNewFolders", NULL, N_("C_heck for new folders"), NULL, NULL, G_CALLBACK(update_tree_cb) }, /*1*/
{"FolderViewPopup/RebuildTree", NULL, N_("R_ebuild folder tree"), NULL, NULL, G_CALLBACK(update_tree_cb) }, /*2*/
{"FolderViewPopup/RemoveMailbox", NULL, N_("Remove _mailbox..."), NULL, NULL, G_CALLBACK(remove_mailbox_cb) },
};
static void set_sensitivity(GtkUIManager *ui_manager, FolderItem *item);
static void add_menuitems(GtkUIManager *ui_manager, FolderItem *item);
static FolderViewPopup claws_mailmbox_popup =
{
"mailmbox",
"<MailmboxFolder>",
claws_mailmbox_popup_entries,
G_N_ELEMENTS(claws_mailmbox_popup_entries),
NULL, 0,
NULL, 0, 0, NULL,
add_menuitems,
set_sensitivity
};
static GtkActionEntry mainwindow_add_mailbox[] = {{
"File/AddMailbox/Mbox",
NULL, N_("mbox (etPan!)..."), NULL, NULL, G_CALLBACK(add_mailbox)
}};
static guint main_menu_id = 0;
gint plugin_gtk_init(gchar **error)
{
MainWindow *mainwin = mainwindow_get_mainwindow();
folderview_register_popup(&claws_mailmbox_popup);
gtk_action_group_add_actions(mainwin->action_group, mainwindow_add_mailbox,
1, (gpointer)mainwin);
MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menu/File/AddMailbox", "Mbox",
"File/AddMailbox/Mbox", GTK_UI_MANAGER_MENUITEM,
main_menu_id)
return 0;
}
void plugin_gtk_done(void)
{
MainWindow *mainwin = mainwindow_get_mainwindow();
if (mainwin == NULL || claws_is_exiting())
return;
folderview_unregister_popup(&claws_mailmbox_popup);
MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "File/AddMailbox/RSSyl", main_menu_id);
main_menu_id = 0;
}
static void add_menuitems(GtkUIManager *ui_manager, FolderItem *item)
{
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "CreateNewFolder", "FolderViewPopup/CreateNewFolder", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorMbox1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RenameFolder", "FolderViewPopup/RenameFolder", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MoveFolder", "FolderViewPopup/MoveFolder", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "CopyFolder", "FolderViewPopup/CopyFolder", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorMbox2", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "DeleteFolder", "FolderViewPopup/DeleteFolder", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorMbox3", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "CheckNewMessages", "FolderViewPopup/CheckNewMessages", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "CheckNewFolders", "FolderViewPopup/CheckNewFolders", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RebuildTree", "FolderViewPopup/RebuildTree", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorMbox4", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RemoveMailbox", "FolderViewPopup/RemoveMailbox", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorMbox5", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
}
static void set_sensitivity(GtkUIManager *ui_manager, FolderItem *item)
{
gboolean folder_is_normal =
item != NULL &&
item->stype == F_NORMAL &&
!folder_has_parent_of_type(item, F_OUTBOX) &&
!folder_has_parent_of_type(item, F_DRAFT) &&
!folder_has_parent_of_type(item, F_QUEUE) &&
!folder_has_parent_of_type(item, F_TRASH);
#define SET_SENS(name, sens) \
cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
SET_SENS("FolderViewPopup/CreateNewFolder", item->stype != F_INBOX);
SET_SENS("FolderViewPopup/RenameFolder", item->stype == F_NORMAL && folder_item_parent(item) != NULL);
SET_SENS("FolderViewPopup/MoveFolder", folder_is_normal && folder_item_parent(item) != NULL);
SET_SENS("FolderViewPopup/DeleteFolder", item->stype == F_NORMAL && folder_item_parent(item) != NULL);
SET_SENS("FolderViewPopup/CheckNewMessages", folder_item_parent(item) == NULL);
SET_SENS("FolderViewPopup/CheckNewFolders", folder_item_parent(item) == NULL);
SET_SENS("FolderViewPopup/RebuildTree", folder_item_parent(item) == NULL);
SET_SENS("FolderViewPopup/RemoveMailbox", folder_item_parent(item) == NULL);
#undef SET_SENS
}
#define DO_ACTION(name, act) { if (!strcmp(a_name, name)) act; }
static void update_tree_cb(GtkAction *action, gpointer data)
{
FolderView *folderview = (FolderView *)data;
FolderItem *item;
const gchar *a_name = gtk_action_get_name(action);
item = folderview_get_selected_item(folderview);
g_return_if_fail(item != NULL);
summary_show(folderview->summaryview, NULL);
g_return_if_fail(item->folder != NULL);
DO_ACTION("FolderViewPopup/CheckNewMessages", folderview_check_new(item->folder));
DO_ACTION("FolderViewPopup/CheckNewFolders", folderview_rescan_tree(item->folder, FALSE));
DO_ACTION("FolderViewPopup/RebuildTree", folderview_rescan_tree(item->folder, TRUE));
}
static void add_mailbox(GtkAction *action, gpointer callback_data)
{
MainWindow *mainwin = (MainWindow *) callback_data;
gchar *path, *basename;
Folder *folder;
path = input_dialog(_("Add mailbox"),
_("Input the location of mailbox.\n"
"If the existing mailbox is specified, it will be\n"
"scanned automatically."),
"Mail");
if (!path) return;
if (folder_find_from_path(path)) {
alertpanel_error(_("The mailbox `%s' already exists."), path);
g_free(path);
return;
}
basename = g_path_get_basename(path);
folder = folder_new(folder_get_class_from_string("mailmbox"),
!strcmp(path, "Mail") ? _("Mailbox") : basename,
path);
g_free(basename);
g_free(path);
if (folder->klass->create_tree(folder) < 0) {
alertpanel_error(_("Creation of the mailbox failed.\n"
"Maybe some files already exist, or you don't have the permission to write there."));
folder_destroy(folder);
return;
}
folder_add(folder);
folder_scan_tree(folder, TRUE);
folderview_set(mainwin->folderview);
return;
}
static void new_folder_cb(GtkAction *action, gpointer data)
{
FolderView *folderview = (FolderView *)data;
GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
FolderItem *item;
FolderItem *new_item;
gchar *new_folder;
gchar *name;
gchar *p;
if (!folderview->selected) return;
item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
g_return_if_fail(item != NULL);
g_return_if_fail(item->folder != NULL);
new_folder = input_dialog(_("New folder"),
_("Input the name of new folder:"),
_("NewFolder"));
if (!new_folder) return;
AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
p = strchr(new_folder, G_DIR_SEPARATOR);
if (p == NULL)
p = strchr(new_folder, '.');
if (p) {
alertpanel_error(_("`%c' can't be included in folder name."),
p[0]);
return;
}
name = trim_string(new_folder, 32);
AUTORELEASE_STR(name, {g_free(name); return;});
/* find whether the directory already exists */
p = g_strconcat(item->path ? item->path : "", ".", new_folder, NULL);
if (folder_find_child_item_by_name(item, p)) {
g_free(p);
alertpanel_error(_("The folder `%s' already exists."), name);
return;
}
g_free(p);
new_item = folder_create_folder(item, new_folder);
if (!new_item) {
alertpanel_error(_("Can't create the folder `%s'."), name);
return;
}
folder_write_list();
}
static void remove_mailbox_cb(GtkAction *action, gpointer data)
{
FolderView *folderview = (FolderView *)data;
FolderItem *item;
gchar *name;
gchar *message;
AlertValue avalue;
item = folderview_get_selected_item(folderview);
g_return_if_fail(item != NULL);
g_return_if_fail(item->folder != NULL);
if (folder_item_parent(item)) return;
name = trim_string(item->folder->name, 32);
message = g_strdup_printf
(_("Really remove the mailbox `%s' ?\n"
"(The messages are NOT deleted from the disk)"), name);
avalue = alertpanel_full(_("Remove mailbox"), message,
GTK_STOCK_CANCEL, _("_Remove"), NULL, FALSE,
NULL, ALERT_WARNING, G_ALERTDEFAULT);
g_free(message);
g_free(name);
if (avalue != G_ALERTALTERNATE) return;
folderview_unselect(folderview);
summary_clear_all(folderview->summaryview);
folder_destroy(item->folder);
}
static void delete_folder_cb(GtkAction *action, gpointer data)
{
FolderView *folderview = (FolderView *)data;
GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
FolderItem *item;
gchar *message, *name;
AlertValue avalue;
gchar *old_path;
gchar *old_id;
item = folderview_get_selected_item(folderview);
g_return_if_fail(item != NULL);
g_return_if_fail(item->path != NULL);
g_return_if_fail(item->folder != NULL);
name = trim_string(item->name, 32);
AUTORELEASE_STR(name, {g_free(name); return;});
message = g_strdup_printf
(_("All folder(s) and message(s) under `%s' will be deleted.\n"
"Do you really want to delete?"), name);
avalue = alertpanel_full(_("Delete folder"), message,
GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, FALSE,
NULL, ALERT_NOTICE, G_ALERTDEFAULT);
g_free(message);
if (avalue != G_ALERTALTERNATE) return;
Xstrdup_a(old_path, item->path, return);
old_id = folder_item_get_identifier(item);
if (folderview->opened == folderview->selected ||
gtk_cmctree_is_ancestor(ctree,
folderview->selected,
folderview->opened)) {
summary_clear_all(folderview->summaryview);
folderview->opened = NULL;
}
if (item->folder->klass->remove_folder(item->folder, item) < 0) {
alertpanel_error(_("Can't remove the folder `%s'."), name);
if (folderview->opened == folderview->selected)
summary_show(folderview->summaryview,
folderview->summaryview->folder_item);
g_free(old_id);
return;
}
folder_write_list();
prefs_filtering_delete_path(old_id);
g_free(old_id);
}
static void move_folder_cb(GtkAction *action, gpointer data)
{
FolderView *folderview = (FolderView *)data;
FolderItem *from_folder = NULL, *to_folder = NULL;
from_folder = folderview_get_selected_item(folderview);
if (!from_folder || from_folder->folder->klass != claws_mailmbox_get_class())
return;
to_folder = foldersel_folder_sel(from_folder->folder, FOLDER_SEL_MOVE, NULL, FALSE);
if (!to_folder)
return;
folderview_move_folder(folderview, from_folder, to_folder, 0);
}
static void copy_folder_cb(GtkAction *action, gpointer data)
{
FolderView *folderview = (FolderView *)data;
FolderItem *from_folder = NULL, *to_folder = NULL;
from_folder = folderview_get_selected_item(folderview);
if (!from_folder || from_folder->folder->klass != claws_mailmbox_get_class())
return;
to_folder = foldersel_folder_sel(from_folder->folder, FOLDER_SEL_MOVE, NULL, FALSE);
if (!to_folder)
return;
folderview_move_folder(folderview, from_folder, to_folder, 1);
}
static void rename_folder_cb(GtkAction *action, gpointer data)
{
FolderView *folderview = (FolderView *)data;
FolderItem *item, *parent;
gchar *new_folder;
gchar *name;
gchar *message;
gchar *old_path;
gchar *old_id;
gchar *new_id;
gchar *p;
item = folderview_get_selected_item(folderview);
g_return_if_fail(item != NULL);
g_return_if_fail(item->path != NULL);
g_return_if_fail(item->folder != NULL);
name = trim_string(item->name, 32);
message = g_strdup_printf(_("Input new name for `%s':"), name);
new_folder = input_dialog(_("Rename folder"), message, item->name);
g_free(message);
g_free(name);
if (!new_folder) return;
AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
p = strchr(new_folder, G_DIR_SEPARATOR);
if (p == NULL)
p = strchr(new_folder, '.');
if (p) {
alertpanel_error(_("`%c' can't be included in folder name."),
p[0]);
return;
}
parent = folder_item_parent(item);
p = g_strconcat(parent->path ? parent->path : "", ".", new_folder, NULL);
if (folder_find_child_item_by_name(parent, p)) {
name = trim_string(new_folder, 32);
alertpanel_error(_("The folder `%s' already exists."), name);
g_free(name);
return;
}
Xstrdup_a(old_path, item->path, {g_free(new_folder); return;});
old_id = folder_item_get_identifier(item);
if (folder_item_rename(item, new_folder) < 0) {
alertpanel_error(_("The folder could not be renamed.\n"
"The new folder name is not allowed."));
g_free(old_id);
return;
}
new_id = folder_item_get_identifier(item);
prefs_filtering_rename_path(old_id, new_id);
account_rename_path(old_id, new_id);
prefs_actions_rename_path(old_id, new_id);
g_free(old_id);
g_free(new_id);
folder_item_prefs_save_config_recursive(item);
folder_write_list();
}

View file

@ -0,0 +1,30 @@
/*
* mailmbox Plugin -- mbox support for Sylpheed
* Copyright (C) 2003-2005 Christoph Hohmann,
* Hoa v. Dinh,
* Alfons Hoogervorst
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __PLUGIN_GTK_H__
#define __PLUGIN_GTK_H__
#include <glib.h>
gint plugin_gtk_init(gchar **error);
void plugin_gtk_done(void);
#endif

View file

@ -0,0 +1,19 @@
plugindir = $(pkglibdir)/plugins
plugin_LTLIBRARIES = newmail.la
newmail_la_SOURCES = \
newmail.c
newmail_la_LDFLAGS = \
-avoid-version -module
AM_CPPFLAGS = \
$(CLAWS_MAIL_CFLAGS) \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS)
INCLUDES = \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/common \
-I$(top_srcdir)/src/gtk

View file

@ -0,0 +1,168 @@
/*
* newmail - A plugin for Claws Mail
*
* Copyright (C) 2005-2005 H.Merijn Brand and the Claws Mail Team
*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999-2012 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <errno.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "version.h"
#include "claws.h"
#include "plugin.h"
#include "utils.h"
#include "hooks.h"
#include "procmsg.h"
#include <inttypes.h>
#include "plugin.h"
static guint hook_id;
static FILE *NewLog = NULL;
static char *LogName = NULL;
static int truncLog = 1;
static gchar *defstr (gchar *s)
{
return s ? s : "(null)";
} /* defstr */
gboolean newmail_hook (gpointer source, gpointer data)
{
auto MsgInfo *msginfo = (MsgInfo *)source;
auto FolderItem *tof;
if (!msginfo) return (FALSE);
tof = msginfo->folder;
(void)fprintf (NewLog, "---\n"
"Date:\t%s\n"
"Subject:\t%s\n"
"From:\t%s\n"
"To:\t%s\n"
"Cc:\t%s\n"
"Size:\t%jd\n"
"Path:\t%s\n"
"Message:\t%d\n"
"Folder:\t%s\n",
defstr (msginfo->date),
defstr (msginfo->subject),
defstr (msginfo->from),
defstr (msginfo->to),
defstr (msginfo->cc),
(intmax_t) msginfo->size,
defstr (procmsg_get_message_file_path (msginfo)),
msginfo->msgnum,
tof ? defstr (tof->name) : "(null)");
return (FALSE);
} /* newmail_hook */
gboolean plugin_done (void)
{
if (NewLog) {
(void)fclose (NewLog);
NewLog = NULL;
LogName = NULL;
}
hooks_unregister_hook (MAIL_POSTFILTERING_HOOKLIST, hook_id);
printf (_("Newmail plugin unloaded\n"));
return TRUE;
} /* plugin_done */
gint plugin_init (gchar **error)
{
if (!check_plugin_version(MAKE_NUMERIC_VERSION(2,9,2,72),
VERSION_NUMERIC, _("NewMail"), error))
return -1;
hook_id = hooks_register_hook (MAIL_POSTFILTERING_HOOKLIST, newmail_hook, NULL);
if (hook_id == -1) {
*error = g_strdup (_("Failed to register newmail hook"));
return (-1);
}
if (!NewLog) {
auto char *mode = truncLog ? "w" : "a";
if (!LogName) {
auto size_t l;
auto char name[260];
(void)snprintf (name, 256, "%s/Mail/NewLog", getenv ("HOME"));
l = strlen (name);
if (l > 255 || !(LogName = (char *)malloc (l + 1))) {
*error = g_strdup (_("Cannot load plugin NewMail\n"
"$HOME is too long\n"));
plugin_done ();
return (-1);
}
(void)strcpy (LogName, name);
}
if (!(NewLog = fopen (LogName, mode))) {
*error = g_strdup (sys_errlist[errno]);
plugin_done ();
return (-1);
}
setbuf (NewLog, NULL);
}
printf (_("Newmail plugin loaded\n"
"Message header summaries written to %s\n"), LogName);
return (0);
} /* plugin_init */
const gchar *plugin_name (void)
{
return _("NewMail");
} /* plugin_name */
const gchar *plugin_desc (void)
{
return _("This Plugin writes a header summary to a log file for each "
"mail received after sorting.\n\n"
"Default is ~/Mail/NewLog");
} /* plugin_desc */
const gchar *plugin_type (void)
{
return ("Common");
} /* plugin_type */
const gchar *plugin_licence (void)
{
return ("GPL3+");
} /* plugin_licence */
const gchar *plugin_version (void)
{
return (VERSION);
} /* plugin_version */
struct PluginFeature *plugin_provides(void)
{
static struct PluginFeature features[] =
{ {PLUGIN_NOTIFIER, N_("Log file")},
{PLUGIN_NOTHING, NULL}};
return features;
}

View file

@ -1 +0,0 @@
Placeholder

View file

@ -0,0 +1,106 @@
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

View file

@ -0,0 +1,73 @@
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

View file

@ -0,0 +1,503 @@
/* 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 */

View file

@ -0,0 +1,32 @@
/* 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 */

View file

@ -0,0 +1,119 @@
/* 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 */

View file

@ -0,0 +1,33 @@
/* 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 */

View file

@ -0,0 +1,699 @@
/* 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]),"&lt;",4);
in++; i_out += 4;
}
else if(*in == '>') {
if(i_out+3 >= STR_MAX_LEN) break;
memcpy(&(tmp_str[i_out]),"&gt;",4);
in++; i_out += 4;
}
else if(*in == '&') {
if(i_out+4 >= STR_MAX_LEN) break;
memcpy(&(tmp_str[i_out]),"&amp;",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

View file

@ -0,0 +1,79 @@
/* 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 */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,32 @@
/* 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 */

View file

@ -0,0 +1,116 @@
/* 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 */

View file

@ -0,0 +1,31 @@
/* 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 */

View file

@ -0,0 +1,174 @@
/* 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 */

View file

@ -0,0 +1,31 @@
/* 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 */

View file

@ -0,0 +1,172 @@
/* 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 */

View file

@ -0,0 +1,34 @@
/* 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 */

View file

@ -0,0 +1,97 @@
/* 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;
}
}
}

View file

@ -0,0 +1,47 @@
/* 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 */

View file

@ -0,0 +1,479 @@
/* 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@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

View file

@ -0,0 +1,29 @@
/* 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 */

View file

@ -0,0 +1,677 @@
/* 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 */

View file

@ -0,0 +1,33 @@
/* 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 */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,118 @@
/* 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 */

View file

@ -0,0 +1,948 @@
/* 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 */

View file

@ -0,0 +1,47 @@
/* 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 */

View file

@ -1 +0,0 @@
Placeholder

View file

@ -0,0 +1,10 @@
EXPORTS
plugin_desc
plugin_done
plugin_init
plugin_licence
plugin_name
plugin_type
plugin_provides
plugin_version

View file

@ -0,0 +1,684 @@
/* 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@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@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@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@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@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"};

View file

@ -0,0 +1,36 @@
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

View file

@ -0,0 +1,26 @@
plugindir = $(pkglibdir)/plugins
plugin_LTLIBRARIES = pdf_viewer.la
pdf_viewer_la_SOURCES = \
poppler_viewer.c \
poppler_viewer.h \
gettext.h
pdf_viewer_la_LDFLAGS = \
-avoid-version -module \
$(GTK_LIBS) \
$(POPPLER_LIBS)
INCLUDES = \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/common \
-I$(top_srcdir)/src/gtk
AM_CPPFLAGS = \
-Wall \
$(CLAWS_MAIL_CFLAGS) \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS) \
$(POPPLER_CFLAGS) \
-DLOCALEDIR=\""$(localedir)"\"

View file

@ -0,0 +1,21 @@
/* XPM */
static char * doc_index_xpm[] = {
"14 14 4 1",
" c None",
". c #1F0000",
"+ c #4D0202",
"@ c #000000",
"........ ",
".++++++. ",
".+@@@@@@ ",
".+@ @ ",
".+@ @ ",
".+@ @ ",
"...@@@@@ ",
" @@ @@@",
" @@@@@@@@@@",
" @@ @@@",
" @@ ",
" @@ @@@",
" @@@@@@@@@@",
" @@@"};

View file

@ -0,0 +1,19 @@
/* XPM */
static char * doc_index_close_xpm[] = {
"14 14 2 1",
" c None",
". c #000000",
" ",
" ",
" ... ... ",
" .... .... ",
" ... ... ",
" ..... ",
" ..... ",
" ... ",
" ..... ",
" ..... ",
" ... ... ",
" ... ... ",
" ... ... ",
" "};

View file

@ -0,0 +1,104 @@
/* XPM */
static char * doc_info_xpm[] = {
"14 14 87 1",
" c None",
". c #000000",
"+ c #030303",
"@ c #4F4F4F",
"# c #ABABAB",
"$ c #D3D3D3",
"% c #ADADAD",
"& c #515151",
"* c #040404",
"= c #121212",
"- c #B1B1B1",
"; c #EFEFEF",
"> c #8F8F8F",
", c #4C4C4C",
"' c #939393",
") c #E7E7E7",
"! c #B4B4B4",
"~ c #141414",
"{ c #D4D4D4",
"] c #373737",
"^ c #8E8E8E",
"/ c #929292",
"( c #0C0C0C",
"_ c #323232",
": c #CECECE",
"< c #B6B6B6",
"[ c #505050",
"} c #EBEBEB",
"| c #424242",
"1 c #010101",
"2 c #737373",
"3 c #747474",
"4 c #090909",
"5 c #0B0B0B",
"6 c #484848",
"7 c #F6F6F6",
"8 c #555555",
"9 c #919191",
"0 c #0A0A0A",
"a c #060606",
"b c #2A2A2A",
"c c #252525",
"d c #0E0E0E",
"e c #161616",
"f c #B3B3B3",
"g c #D5D5D5",
"h c #050505",
"i c #ACACAC",
"j c #E0E0E0",
"k c #080808",
"l c #7B7B7B",
"m c #DADADA",
"n c #D6D6D6",
"o c #020202",
"p c #979797",
"q c #070707",
"r c #6A6A6A",
"s c #DBDBDB",
"t c #B0B0B0",
"u c #898989",
"v c #969696",
"w c #DEDEDE",
"x c #0F0F0F",
"y c #B5B5B5",
"z c #1B1B1B",
"A c #111111",
"B c #191919",
"C c #E4E4E4",
"D c #5A5A5A",
"E c #B9B9B9",
"F c #C0C0C0",
"G c #262626",
"H c #181818",
"I c #BEBEBE",
"J c #BDBDBD",
"K c #BABABA",
"L c #E8E8E8",
"M c #A5A5A5",
"N c #4B4B4B",
"O c #828282",
"P c #E3E3E3",
"Q c #171717",
"R c #595959",
"S c #DCDCDC",
"T c #DDDDDD",
"U c #B7B7B7",
"V c #5B5B5B",
" .++. ",
" +@#$$%&* ",
" =-;>,,')!~ ",
" +-{].^/(_:<* ",
" [}|1.2345678.",
".%90.abcade<f.",
"*g8h*4ij+kdlma",
"*n80*opj1qdrsa",
".tuah.vw15xuy.",
".8)zaA%$xoBCD.",
" *EFGao..HIJh ",
" eKLMNNOPJQ ",
" hR<STUVa ",
" ..qq.. "};

View file

@ -0,0 +1,49 @@
/* XPM */
static char * first_arrow_xpm[] = {
"16 16 30 1",
" c None",
". c #1D2F3F",
"+ c #1D2F40",
"@ c #1C2C3C",
"# c #3F6588",
"$ c #000000",
"% c #1C2E3E",
"& c #5B88B2",
"* c #5080AD",
"= c #9EB8D1",
"- c #192937",
"; c #080D11",
"> c #9CB7D1",
", c #A4BDD5",
"' c #B6CADD",
") c #B2C7DB",
"! c #AFC5DA",
"~ c #B5C9DC",
"{ c #5F8BB4",
"] c #97B3CE",
"^ c #A0BAD3",
"/ c #9AB5CF",
"( c #9BB6D0",
"_ c #4C79A3",
": c #95B2CE",
"< c #91B0CC",
"[ c #2A435B",
"} c #49749C",
"| c #375978",
"1 c #456F96",
" ",
".+ ",
"@# $ ",
"%# $$ ",
"@# $&$ ",
"@# $*=$$$$$$$ ",
"-# ;*>,''')!~$ ",
"%#${]>^/(>>^($ ",
"@$_:^>>>(//=<$ ",
"@#$[########}$ ",
"@# $[##|||||1$ ",
"@# $[#$$$$$$$ ",
"@# $[$ ",
"%# $$ ",
"@% $ ",
" "};

View file

@ -0,0 +1,49 @@
/* XPM */
static char * last_arrow_xpm[] = {
"16 16 30 1",
" c None",
". c #1D2F40",
"+ c #1D2F3F",
"@ c #000000",
"# c #3F6588",
"$ c #1C2C3C",
"% c #1C2E3E",
"& c #5B88B2",
"* c #9EB8D1",
"= c #5080AD",
"- c #B5C9DC",
"; c #AFC5DA",
"> c #B2C7DB",
", c #B6CADD",
"' c #A4BDD5",
") c #9CB7D1",
"! c #080D11",
"~ c #192937",
"{ c #9BB6D0",
"] c #A0BAD3",
"^ c #9AB5CF",
"/ c #97B3CE",
"( c #5F8BB4",
"_ c #91B0CC",
": c #95B2CE",
"< c #4C79A3",
"[ c #49749C",
"} c #2A435B",
"| c #456F96",
"1 c #375978",
" ",
" .+",
" @ #$",
" @@ #%",
" @&@ #$",
" @@@@@@@*=@ #$",
" @-;>,,,')=! #~",
" @{])){^])/(@#%",
" @_*^^{)))]:<@$",
" @[########}@#$",
" @|11111##}@ #$",
" @@@@@@@#}@ #$",
" @}@ #$",
" @@ #%",
" @ %$",
" "};

View file

@ -0,0 +1,44 @@
/* XPM */
static char * left_arrow_xpm[] = {
"16 16 25 1",
" c None",
". c #000000",
"+ c #5B88B2",
"@ c #5080AD",
"# c #9EB8D1",
"$ c #080D11",
"% c #9CB7D1",
"& c #A4BDD5",
"* c #B6CADD",
"= c #B2C7DB",
"- c #AFC5DA",
"; c #B5C9DC",
"> c #5F8BB4",
", c #97B3CE",
"' c #A0BAD3",
") c #9AB5CF",
"! c #9BB6D0",
"~ c #4C79A3",
"{ c #95B2CE",
"] c #91B0CC",
"^ c #2A435B",
"/ c #3F6588",
"( c #49749C",
"_ c #375978",
": c #456F96",
" ",
" ",
" . ",
" .. ",
" .+. ",
" .@#....... ",
" $@%&***=-;. ",
" .>,%')!%%'!. ",
" .~{'%%%!))#]. ",
" .^////////(. ",
" .^//_____:. ",
" .^/....... ",
" .^. ",
" .. ",
" . ",
" "};

Some files were not shown because too many files have changed in this diff Show more