aboutsummaryrefslogtreecommitdiffstats
path: root/devel/p5-Algorithm-MarkovChain
diff options
context:
space:
mode:
Diffstat (limited to 'devel/p5-Algorithm-MarkovChain')
0 files changed, 0 insertions, 0 deletions
EVOLUTION_2_6_2&id=0fb08f3ff81575a4749d851404233f34252dd2f2'>libical/src/libical/icalyacc.y417
-rw-r--r--libical/src/libicalcap/Makefile.am2
-rw-r--r--libical/src/libicalss/Makefile.am2
-rw-r--r--libical/src/libicalss/icalgauge.h2
-rw-r--r--libical/src/libicalss/icalsslexer.c1746
-rw-r--r--libical/src/libicalss/icalsslexer.l2
-rw-r--r--libical/src/libicalss/icalssyacc.c1397
-rw-r--r--libical/src/libicalss/icalssyacc.y4
-rw-r--r--mail/ChangeLog362
-rw-r--r--mail/GNOME_Evolution_Mail.server.in.in26
-rw-r--r--mail/Makefile.am269
-rw-r--r--mail/component-factory.c153
-rw-r--r--mail/component-factory.h3
-rw-r--r--mail/em-composer-utils.c24
-rw-r--r--mail/em-folder-browser.c3
-rw-r--r--mail/em-folder-selection-button.c242
-rw-r--r--mail/em-folder-selection-button.h59
-rw-r--r--mail/em-folder-selection.c170
-rw-r--r--mail/em-folder-selection.h41
-rw-r--r--mail/em-folder-selector.c349
-rw-r--r--mail/em-folder-selector.h96
-rw-r--r--mail/em-folder-view.c40
-rw-r--r--mail/em-format-html.c8
-rw-r--r--mail/em-marshal.list1
-rw-r--r--mail/em-popup.c3
-rw-r--r--mail/em-popup.h11
-rw-r--r--mail/em-utils.c25
-rw-r--r--mail/em-utils.h1
-rw-r--r--mail/folder-browser-factory.c5
-rw-r--r--mail/folder-browser-factory.h3
-rw-r--r--mail/folder-browser-ui.c816
-rw-r--r--mail/folder-browser-ui.h36
-rw-r--r--mail/folder-browser.c2679
-rw-r--r--mail/folder-browser.h192
-rw-r--r--mail/mail-account-gui.c53
-rw-r--r--mail/mail-accounts.c20
-rw-r--r--mail/mail-accounts.etspec12
-rw-r--r--mail/mail-autofilter.c8
-rw-r--r--mail/mail-callbacks.c3228
-rw-r--r--mail/mail-callbacks.h144
-rw-r--r--mail/mail-component-factory.c104
-rw-r--r--mail/mail-component.c1625
-rw-r--r--mail/mail-component.h99
-rw-r--r--mail/mail-config-factory.c2
-rw-r--r--mail/mail-config.c32
-rw-r--r--mail/mail-display-stream.c104
-rw-r--r--mail/mail-display-stream.h62
-rw-r--r--mail/mail-display.c2995
-rw-r--r--mail/mail-display.h137
-rw-r--r--mail/mail-folder-cache.c66
-rw-r--r--mail/mail-folder-cache.h9
-rw-r--r--mail/mail-font-prefs.c130
-rw-r--r--mail/mail-font-prefs.h66
-rw-r--r--mail/mail-format.c2131
-rw-r--r--mail/mail-format.h71
-rw-r--r--mail/mail-identify.c130
-rw-r--r--mail/mail-importer.c5
-rw-r--r--mail/mail-local.c3
-rw-r--r--mail/mail-mt.c7
-rw-r--r--mail/mail-offline-handler.c14
-rw-r--r--mail/mail-ops.c8
-rw-r--r--mail/mail-search.c403
-rw-r--r--mail/mail-search.h75
-rw-r--r--mail/mail-send-recv.c25
-rw-r--r--mail/mail-session.c11
-rw-r--r--mail/mail-session.h2
-rw-r--r--mail/mail-signature-editor.c4
-rw-r--r--mail/mail-summary.c3
-rw-r--r--mail/mail-tools.c15
-rw-r--r--mail/mail-vfolder.c38
-rw-r--r--mail/mail-vfolder.h2
-rw-r--r--mail/mail.h16
-rw-r--r--mail/main.c161
-rw-r--r--mail/message-browser.c402
-rw-r--r--mail/message-browser.h63
-rw-r--r--mail/subscribe-dialog.c1669
-rw-r--r--mail/subscribe-dialog.etspec9
-rw-r--r--mail/subscribe-dialog.h62
-rw-r--r--mail/upgrade-mailer.c1169
-rw-r--r--po/POTFILES.in13
-rw-r--r--po/POTFILES.skip1
-rw-r--r--po/am.po6107
-rw-r--r--po/az.po7085
-rw-r--r--po/be.po6852
-rw-r--r--po/bg.po6508
-rw-r--r--po/ca.po7175
-rw-r--r--po/cs.po6847
-rw-r--r--po/da.po6854
-rw-r--r--po/de.po6279
-rw-r--r--po/el.po8470
-rw-r--r--po/en_AU.po6005
-rw-r--r--po/en_GB.po6027
-rw-r--r--po/es.po6777
-rw-r--r--po/et.po6877
-rw-r--r--po/eu.po7136
-rw-r--r--po/fi.po6673
-rw-r--r--po/fr.po6272
-rwxr-xr-xpo/ga.po5931
-rw-r--r--po/gl.po6570
-rw-r--r--po/hu.po6958
-rw-r--r--po/it.po7072
-rw-r--r--po/ja.po6915
-rw-r--r--po/ko.po6723
-rw-r--r--po/lt.po6572
-rw-r--r--po/lv.po6977
-rw-r--r--po/ms.po5778
-rw-r--r--po/nl.po6870
-rw-r--r--po/nn.po1059
-rw-r--r--po/no.po6851
-rw-r--r--po/pl.po7006
-rw-r--r--shell/ChangeLog324
-rw-r--r--shell/Evolution-Component.idl37
-rw-r--r--shell/Evolution-Shell.idl82
-rw-r--r--shell/Evolution-ShellComponent.idl2
-rw-r--r--shell/Evolution.idl1
-rw-r--r--shell/Makefile.am95
-rw-r--r--shell/e-activity-handler.c588
-rw-r--r--shell/e-activity-handler.h72
-rw-r--r--shell/e-component-registry.c1
-rw-r--r--shell/e-folder-selection-dialog.c479
-rw-r--r--shell/e-folder-selection-dialog.h82
-rw-r--r--shell/e-folder.c1
-rw-r--r--shell/e-setup.c1
-rw-r--r--shell/e-shell-importer.c4
-rw-r--r--shell/e-shell-importer.h10
-rw-r--r--shell/e-shell-marshal.list1
-rw-r--r--shell/e-shell-offline-handler.c15
-rw-r--r--shell/e-shell-offline-handler.h5
-rw-r--r--shell/e-shell-window-commands.c353
-rw-r--r--shell/e-shell-window-commands.h30
-rw-r--r--shell/e-shell-window.c481
-rw-r--r--shell/e-shell-window.h63
-rw-r--r--shell/e-shell.c1389
-rw-r--r--shell/e-shell.h72
-rw-r--r--shell/e-storage-browser.c331
-rw-r--r--shell/e-storage-browser.h83
-rw-r--r--shell/e-storage.c27
-rw-r--r--shell/e-storage.h15
-rw-r--r--shell/evolution-shell-client.c595
-rw-r--r--shell/evolution-shell-client.h4
-rw-r--r--shell/main.c45
-rw-r--r--tools/Makefile.am29
-rwxr-xr-xtools/csv2vcard236
-rw-r--r--tools/evolution-addressbook-abuse.c137
-rw-r--r--tools/evolution-addressbook-clean.in24
-rw-r--r--tools/evolution-addressbook-import.c90
-rw-r--r--ui/ChangeLog15
-rw-r--r--ui/evolution-calendar.xml22
-rw-r--r--ui/evolution.xml233
-rw-r--r--widgets/misc/ChangeLog50
-rw-r--r--widgets/misc/Makefile.am14
-rw-r--r--widgets/misc/e-source-selector.c682
-rw-r--r--widgets/misc/e-source-selector.h80
-rw-r--r--widgets/misc/test-source-selector.c131
-rw-r--r--wombat/ChangeLog15
-rw-r--r--wombat/GNOME_Evolution_WombatLDAP.server.in.in3
-rw-r--r--wombat/wombat.c11
166 files changed, 116953 insertions, 104111 deletions
diff --git a/libical/src/Net-ICal-Libical/netical_wrap.c b/libical/src/Net-ICal-Libical/netical_wrap.c
index 233c2dc7f7..32eee6f80b 100644
--- a/libical/src/Net-ICal-Libical/netical_wrap.c
+++ b/libical/src/Net-ICal-Libical/netical_wrap.c
@@ -96,6 +96,12 @@ extern "C" {
* SWIGSTATIC.
*
* $Log$
+ * Revision 1.2 2003/10/21 18:28:33 ettore
+ * Merge new-ui-branch to the trunk.
+ *
+ * Revision 1.1.2.1 2003/09/23 19:43:57 ettore
+ * Sync with trunk, and fixicate a bit so it still works.
+ *
* Revision 1.1 2003/09/11 22:04:08 hansp
* Import new libical from mainline HEAD and make appropriate changes to
* Evolution.
diff --git a/libical/src/libical/Makefile.am b/libical/src/libical/Makefile.am
index 4416f28289..302c32a6a0 100644
--- a/libical/src/libical/Makefile.am
+++ b/libical/src/libical/Makefile.am
@@ -2,7 +2,7 @@
# FILE: Makefile.am
# CREATOR: eric
#
-# $Id: Makefile.am,v 1.40 2003/10/09 21:02:23 fejj Exp $
+# $Id: Makefile.am,v 1.41 2003/10/21 18:28:29 ettore Exp $
#
#
# (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
diff --git a/libical/src/libical/icalderivedparameter.c.in b/libical/src/libical/icalderivedparameter.c.in
index b41587e0de..250cf188ee 100644
--- a/libical/src/libical/icalderivedparameter.c.in
+++ b/libical/src/libical/icalderivedparameter.c.in
@@ -3,7 +3,7 @@
FILE: icalderivedparameters.{c,h}
CREATOR: eric 09 May 1999
- $Id: icalderivedparameter.c.in,v 1.2 2003/09/11 22:04:19 hansp Exp $
+ $Id: icalderivedparameter.c.in,v 1.3 2003/10/21 18:28:29 ettore Exp $
$Locker: $
diff --git a/libical/src/libical/icalderivedparameter.h.in b/libical/src/libical/icalderivedparameter.h.in
index a8f3a36085..0e7c29fa65 100644
--- a/libical/src/libical/icalderivedparameter.h.in
+++ b/libical/src/libical/icalderivedparameter.h.in
@@ -4,7 +4,7 @@
CREATOR: eric 20 March 1999
- $Id: icalderivedparameter.h.in,v 1.2 2003/09/11 22:04:19 hansp Exp $
+ $Id: icalderivedparameter.h.in,v 1.3 2003/10/21 18:28:29 ettore Exp $
$Locker: $
diff --git a/libical/src/libical/icalderivedproperty.c.in b/libical/src/libical/icalderivedproperty.c.in
index 36ddc846ae..30b86b0f8c 100644
--- a/libical/src/libical/icalderivedproperty.c.in
+++ b/libical/src/libical/icalderivedproperty.c.in
@@ -4,7 +4,7 @@
FILE: icalderivedproperty.c
CREATOR: eric 15 Feb 2001
- $Id: icalderivedproperty.c.in,v 1.2 2003/09/11 22:04:19 hansp Exp $
+ $Id: icalderivedproperty.c.in,v 1.3 2003/10/21 18:28:29 ettore Exp $
(C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
diff --git a/libical/src/libical/icalderivedproperty.h.in b/libical/src/libical/icalderivedproperty.h.in
index eda95ee031..515034742d 100644
--- a/libical/src/libical/icalderivedproperty.h.in
+++ b/libical/src/libical/icalderivedproperty.h.in
@@ -3,7 +3,7 @@
FILE: icalderivedproperties.{c,h}
CREATOR: eric 09 May 1999
- $Id: icalderivedproperty.h.in,v 1.2 2003/09/11 22:04:19 hansp Exp $
+ $Id: icalderivedproperty.h.in,v 1.3 2003/10/21 18:28:29 ettore Exp $
(C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
======================================================================*/
diff --git a/libical/src/libical/icalderivedvalue.c.in b/libical/src/libical/icalderivedvalue.c.in
index d96461e2b7..33f5083589 100644
--- a/libical/src/libical/icalderivedvalue.c.in
+++ b/libical/src/libical/icalderivedvalue.c.in
@@ -3,7 +3,7 @@
FILE: icalvalue.c
CREATOR: eric 02 May 1999
- $Id: icalderivedvalue.c.in,v 1.4 2003/09/11 22:04:19 hansp Exp $
+ $Id: icalderivedvalue.c.in,v 1.5 2003/10/21 18:28:29 ettore Exp $
(C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
diff --git a/libical/src/libical/icalderivedvalue.h.in b/libical/src/libical/icalderivedvalue.h.in
index 1df5e5126e..ab52499aa8 100644
--- a/libical/src/libical/icalderivedvalue.h.in
+++ b/libical/src/libical/icalderivedvalue.h.in
@@ -4,7 +4,7 @@
CREATOR: eric 20 March 1999
- $Id: icalderivedvalue.h.in,v 1.3 2003/09/11 22:04:19 hansp Exp $
+ $Id: icalderivedvalue.h.in,v 1.4 2003/10/21 18:28:29 ettore Exp $
$Locker: $
diff --git a/libical/src/libical/icallexer.l b/libical/src/libical/icallexer.l
new file mode 100644
index 0000000000..fe292c8b6d
--- /dev/null
+++ b/libical/src/libical/icallexer.l
@@ -0,0 +1,161 @@
+%{
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icallexer.l
+ CREATOR: eric 10 June 1999
+
+ DESCRIPTION:
+
+ $Id: icallexer.l,v 1.10 2003/10/21 18:28:28 ettore Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 1999 Eric Busboom
+ http://www.softwarestudio.org
+
+ The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and
+ limitations under the License.
+
+ The original author is Eric Busboom
+ The original code is icalitip.y
+
+
+
+ ======================================================================*/
+#include "icalparser.h"
+#include "icalenums.h"
+#include "icalmemory.h"
+#include "assert.h"
+#include "icalyacc.h"
+
+#include <string.h> /* For strdup() */
+
+int icalparser_flex_input(char* buf, int max_size);
+void icalparser_clear_flex_input(void);
+
+
+#define ICAL_MAX_STR_CONST 1024
+
+#undef YY_INPUT
+#define YY_INPUT(b,r,ms) ( r= icalparser_flex_input(b,ms))
+#undef yywrap
+
+#undef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) ical_yyerror(msg)
+
+icalvalue_kind value_kind=ICAL_NO_VALUE;
+void set_parser_value_state(icalvalue_kind kind);
+extern int yydebug;
+
+void ical_yyerror(char *s);
+
+void init_str_buf(void);
+
+int last_state;
+
+char *str_buf;
+char *str_buf_p;
+size_t buf_sz; /* = ICAL_MAX_STR_CONST;*/
+
+%}
+
+crlf \x0D?\x0A
+space [ ]
+qsafechar [^\x00-\x1F\"]
+safechar [^\x00-\x1F\"\:\;\,]
+tsafechar [\x20-\x21\x23-\x2B\x2D-\x39\x3C-\x5B\x5D-\x7E]
+valuechar [^\x00-\x08\x10-\x1F]
+xname X-[a-zA-Z0-9\-]+
+xname2 [a-zA-Z0-9\-\ ]
+paramtext {safechar}+
+value {valuechar}+
+quotedstring \"{qsafechar}+\"
+digit [0-9]
+
+%array /* Make yytext an array. Slow, but handy. HACK */
+
+%option caseless
+
+%s quoted_string
+%s binary_value boolean_value uri_value time_value duration_value number_value period_value recur_value text_value utcoffset_value
+%s enum_param_value string_param_value stringlist_param_value keyword line_start component seperator parameter end_of_value paramtext
+
+
+
+%%
+
+%{
+%}
+
+
+<time_value>{
+{digit}+ { ical_yylval.v_string =icalmemory_tmp_copy(yytext) ;
+ return DIGITS; }
+T { return TIME_CHAR; }
+Z { return UTC_CHAR; }
+[\/\+\-PWHMSD] { return yytext[0]; }
+{crlf} { return EOL;}
+
+}
+
+<utcoffset_value>{
+{crlf} { return EOL;}
+\-|\+ { return yytext[0]; }
+{digit}{digit} { ical_yylval.v_int=atoi(yytext); return INTNUMBER; }
+
+}
+
+<enum_param_value>{
+. { return CHARACTER; }
+{crlf} { return EOL;}
+
+}
+
+<seperator>{
+, { BEGIN(last_state); return COMMA; }
+}
+
+
+%%
+
+int yywrap()
+{
+ return 1;
+}
+
+
+void set_parser_value_state(icalvalue_kind kind)
+{
+
+ switch (kind){
+
+ case ICAL_UTCOFFSET_VALUE:
+ {BEGIN(utcoffset_value);break;}
+
+ case ICAL_DATETIMEPERIOD_VALUE:
+ case ICAL_DURATION_VALUE:
+ case ICAL_PERIOD_VALUE:
+ {BEGIN(time_value);break;}
+
+ default:
+ {
+ assert(1==0);
+ }
+ }
+}
+
+void init_str_buf(void)
+{
+ str_buf = icalmemory_tmp_buffer(ICAL_MAX_STR_CONST);
+ str_buf_p = str_buf;
+ buf_sz = ICAL_MAX_STR_CONST;
+
+
+}
+
diff --git a/libical/src/libical/icalyacc.y b/libical/src/libical/icalyacc.y
new file mode 100644
index 0000000000..65f0041ec4
--- /dev/null
+++ b/libical/src/libical/icalyacc.y
@@ -0,0 +1,417 @@
+%{
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalitip.y
+ CREATOR: eric 10 June 1999
+
+ DESCRIPTION:
+
+ $Id: icalyacc.y,v 1.16 2003/10/21 18:28:27 ettore Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 1999 Eric Busboom
+ http://www.softwarestudio.org
+
+ The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and
+ limitations under the License.
+
+ The original author is Eric Busboom
+ The original code is icalitip.y
+
+
+
+ =======================================================================*/
+
+#include <stdlib.h>
+#include <string.h> /* for strdup() */
+#include "icalparser.h"
+#include "pvl.h"
+
+icalvalue *icalparser_yy_value; /* Current Value */
+
+void ical_yyerror(char* s);
+void icalparser_clear_flex_input();
+int ical_yy_lex(void);
+
+/* Globals for UTCOFFSET values */
+int utc;
+int utc_b;
+int utcsign;
+
+/* Globals for DURATION values */
+struct icaldurationtype duration;
+
+/* Globals for TRIGGER values */
+struct icaltriggertype trigger;
+
+void copy_list(short* array, size_t size);
+void add_prop(icalproperty_kind);
+void icalparser_fill_date(struct tm* t, char* dstr);
+void icalparser_fill_time(struct tm* t, char* tstr);
+void set_value_type(icalvalue_kind kind);
+void set_parser_value_state();
+struct icaltimetype fill_datetime(char* d, char* t);
+void ical_yy_error(char *s); /* Don't know why I need this.... */
+int yylex(void); /* Or this. */
+
+
+
+/* Set the state of the lexer so it will interpret values ( iCAL
+ VALUEs, that is, ) correctly. */
+
+%}
+
+%union {
+ float v_float;
+ int v_int;
+ char* v_string;
+}
+
+
+ /* Renaming hack */
+
+/*
+#define yymaxdepth ical_yy_maxdepth
+#define yyparse ical_yy_parse
+#define yyerror ical_yy_error
+#define yylval ical_yy_lval
+#define yychar ical_yy_char
+#define yydebug ical_yy_debug
+#define yypact ical_yy_pact
+#define yyr1 ical_yy_r1
+#define yyr2 ical_yy_r2
+#define yydef ical_yy_def
+#define yychk ical_yy_chk
+#define yypgo ical_yy_pgo
+#define yyact ical_yy_act
+#define yyexca ical_yy_exca
+#define yyerrflag ical_yy_errflag
+#define yynerrs ical_yy_nerrs
+#define yyps ical_yy_ps
+#define yypv ical_yy_pv
+#define yys ical_yy_s
+#define yy_yys ical_yy_yys
+#define yystate ical_yy_state
+#define yytmp ical_yy_tmp
+#define yyv ical_yy_v
+#define yy_yyv ical_yy_yyv
+#define yyval ical_yy_val
+#define yylloc ical_yy_lloc
+#define yyreds ical_yy_reds
+#define yytoks ical_yy_toks
+#define yylhs ical_yy_yylhs
+#define yylen ical_yy_yylen
+#define yydefred ical_yy_yydefred
+#define yydgoto ical_yy_yydgoto
+#define yydefred ical_yy_yydefred
+#define yydgoto ical_yy_yydgoto
+#define yysindex ical_yy_yysindex
+#define yyrindex ical_yy_yyrindex
+#define yygindex ical_yy_yygindex
+#define yytable ical_yy_yytable
+#define yycheck ical_yy_yycheck
+#define yyname ical_yy_yyname
+#define yyrule ical_yy_yyrule
+#define yy_scan_bytes ical_yy_scan_bytes
+#define yy_scan_string ical_yy_scan_string
+#define yy_scan_buffer ical_yy_scan_buffer
+*/
+
+/* These are redefined with the -P option to flex */
+/*
+#define yy_create_buffer ical_yy_create_buffer
+#define yy_delete_buffer ical_yy_delete_buffer
+#define yy_flex_debug ical_yy_flex_debug
+#define yy_init_buffer ical_yy_init_buffer
+#define yy_flush_buffer ical_yy_flush_buffer
+#define yy_load_buffer_state ical_yy_load_buffer_state
+#define yy_switch_to_buffer ical_yy_switch_to_buffer
+#define yyin ical_yyin
+#define yyleng ical_yyleng
+#define yylex ical_yylex
+#define yylineno ical_yylineno
+#define yyout ical_yyout
+#define yyrestart ical_yyrestart
+#define yytext ical_yytext
+#define yywrap ical_yywrap
+*/
+
+
+%token <v_string> DIGITS
+%token <v_int> INTNUMBER
+%token <v_float> FLOATNUMBER
+%token <v_string> STRING
+%token EOL EQUALS CHARACTER COLON COMMA SEMICOLON MINUS TIMESEPERATOR
+
+%token TRUE FALSE
+
+%token FREQ BYDAY BYHOUR BYMINUTE BYMONTH BYMONTHDAY BYSECOND BYSETPOS BYWEEKNO
+%token BYYEARDAY DAILY MINUTELY MONTHLY SECONDLY WEEKLY HOURLY YEARLY
+%token INTERVAL COUNT UNTIL WKST MO SA SU TU WE TH FR
+
+%token BIT8 ACCEPTED ADD AUDIO BASE64 BINARY BOOLEAN BUSY BUSYTENTATIVE
+%token BUSYUNAVAILABLE CALADDRESS CANCEL CANCELLED CHAIR CHILD COMPLETED
+%token CONFIDENTIAL CONFIRMED COUNTER DATE DATETIME DECLINECOUNTER DECLINED
+%token DELEGATED DISPLAY DRAFT DURATION EMAIL END FINAL FLOAT FREE GREGORIAN
+%token GROUP INDIVIDUAL INPROCESS INTEGER NEEDSACTION NONPARTICIPANT
+%token OPAQUE OPTPARTICIPANT PARENT PERIOD PRIVATE PROCEDURE PUBLIC PUBLISH
+%token RECUR REFRESH REPLY REQPARTICIPANT REQUEST RESOURCE ROOM SIBLING
+%token START TENTATIVE TEXT THISANDFUTURE THISANDPRIOR TIME TRANSPAENT
+%token UNKNOWN UTCOFFSET XNAME
+
+%token ALTREP CN CUTYPE DAYLIGHT DIR ENCODING EVENT FBTYPE FMTTYPE LANGUAGE
+%token MEMBER PARTSTAT RANGE RELATED RELTYPE ROLE RSVP SENTBY STANDARD URI
+
+%token TIME_CHAR UTC_CHAR
+
+
+%%
+
+value:
+ date_value
+ | datetime_value
+ | duration_value
+ | period_value
+ | utcoffset_value
+ | error {
+ icalparser_yy_value = 0;
+ icalparser_clear_flex_input();
+ yyclearin;
+ }
+;
+
+
+date_value: DIGITS
+ {
+ struct icaltimetype stm;
+
+ stm = fill_datetime($1,0);
+
+ stm.hour = -1;
+ stm.minute = -1;
+ stm.second = -1;
+ stm.is_utc = 0;
+ stm.is_date = 1;
+
+ icalparser_yy_value = icalvalue_new_date(stm);
+ }
+;
+
+utc_char:
+ /*empty*/ {utc = 0;}
+ | UTC_CHAR {utc = 1;}
+;
+
+/* This is used in the period_value, where there may be two utc characters per rule. */
+utc_char_b:
+ /*empty*/ {utc_b = 0;}
+ | UTC_CHAR {utc_b = 1;}
+;
+
+datetime_value:
+ DIGITS TIME_CHAR DIGITS utc_char
+ {
+ struct icaltimetype stm;
+ stm = fill_datetime($1, $3);
+ stm.is_utc = utc;
+ stm.is_date = 0;
+
+ icalparser_yy_value =
+ icalvalue_new_datetime(stm);
+ }
+;
+
+
+/* Duration */
+
+
+dur_date: dur_day
+ | dur_day dur_time
+;
+
+dur_week: DIGITS 'W'
+ {
+ duration.weeks = atoi($1);
+ }
+;
+
+dur_time: TIME_CHAR dur_hour
+ {
+ }
+ | TIME_CHAR dur_minute
+ {
+ }
+ | TIME_CHAR dur_second
+ {
+ }
+;
+
+dur_hour: DIGITS 'H'
+ {
+ duration.hours = atoi($1);
+ }
+ | DIGITS 'H' dur_minute
+ {
+ duration.hours = atoi($1);
+ }
+;
+
+dur_minute: DIGITS 'M'
+ {
+ duration.minutes = atoi($1);
+ }
+ | DIGITS 'M' dur_second
+ {
+ duration.minutes = atoi($1);
+ }
+;
+
+dur_second: DIGITS 'S'
+ {
+ duration.seconds = atoi($1);
+ }
+;
+
+dur_day: DIGITS 'D'
+ {
+ duration.days = atoi($1);
+ }
+;
+
+dur_prefix: /* empty */
+ {
+ duration.is_neg = 0;
+ }
+ | '+'
+ {
+ duration.is_neg = 0;
+ }
+ | '-'
+ {
+ duration.is_neg = 1;
+ }
+;
+
+duration_value: dur_prefix 'P' dur_date
+ {
+ icalparser_yy_value = icalvalue_new_duration(duration);
+ memset(&duration,0, sizeof(duration));
+ }
+ | dur_prefix 'P' dur_time
+ {
+ icalparser_yy_value = icalvalue_new_duration(duration);
+ memset(&duration,0, sizeof(duration));
+ }
+ | dur_prefix 'P' dur_week
+ {
+ icalparser_yy_value = icalvalue_new_duration(duration);
+ memset(&duration,0, sizeof(duration));
+ }
+;
+
+
+/* Period */
+
+period_value: DIGITS TIME_CHAR DIGITS utc_char '/' DIGITS TIME_CHAR DIGITS utc_char_b
+ {
+ struct icalperiodtype p;
+
+ p.start = fill_datetime($1,$3);
+ p.start.is_utc = utc;
+ p.start.is_date = 0;
+
+
+ p.end = fill_datetime($6,$8);
+ p.end.is_utc = utc_b;
+ p.end.is_date = 0;
+
+ p.duration.days = -1;
+ p.duration.weeks = -1;
+ p.duration.hours = -1;
+ p.duration.minutes = -1;
+ p.duration.seconds = -1;
+
+ icalparser_yy_value = icalvalue_new_period(p);
+ }
+ | DIGITS TIME_CHAR DIGITS utc_char '/' duration_value
+ {
+ struct icalperiodtype p;
+
+ p.start = fill_datetime($1,$3);
+ p.start.is_utc = utc;
+ p.start.is_date = 0;
+
+ p.end.year = -1;
+ p.end.month = -1;
+ p.end.day = -1;
+ p.end.hour = -1;
+ p.end.minute = -1;
+ p.end.second = -1;
+
+ /* The duration_value rule setes the global 'duration'
+ variable, but it also creates a new value in
+ icalparser_yy_value. So, free that, then copy
+ 'duration' into the icalperiodtype struct. */
+
+ p.duration = icalvalue_get_duration(icalparser_yy_value);
+ icalvalue_free(icalparser_yy_value);
+ icalparser_yy_value = 0;
+
+ icalparser_yy_value = icalvalue_new_period(p);
+
+ }
+;
+
+
+/* UTC Offset */
+
+plusminus: '+' { utcsign = 1; }
+ | '-' { utcsign = -1; }
+;
+
+utcoffset_value:
+ plusminus INTNUMBER INTNUMBER
+ {
+ icalparser_yy_value = icalvalue_new_utcoffset( utcsign * (($2*3600) + ($3*60)) );
+ }
+
+ | plusminus INTNUMBER INTNUMBER INTNUMBER
+ {
+ icalparser_yy_value = icalvalue_new_utcoffset(utcsign * (($2*3600) + ($3*60) +($4)));
+ }
+;
+
+%%
+
+struct icaltimetype fill_datetime(char* datestr, char* timestr)
+{
+ struct icaltimetype stm;
+
+ memset(&stm,0,sizeof(stm));
+
+ if (datestr != 0){
+ sscanf(datestr,"%4d%2d%2d",&(stm.year), &(stm.month),
+ &(stm.day));
+ }
+
+ if (timestr != 0){
+ sscanf(timestr,"%2d%2d%2d", &(stm.hour), &(stm.minute),
+ &(stm.second));
+ }
+
+ return stm;
+
+}
+
+void ical_yyerror(char* s)
+{
+ /*fprintf(stderr,"Parse error \'%s\'\n", s);*/
+}
+
diff --git a/libical/src/libicalcap/Makefile.am b/libical/src/libicalcap/Makefile.am
index 519c126905..f6112b7c05 100644
--- a/libical/src/libicalcap/Makefile.am
+++ b/libical/src/libicalcap/Makefile.am
@@ -2,7 +2,7 @@
# FILE: Makefile.am
# CREATOR: acampi
#
-# $Id: Makefile.am,v 1.4 2003/10/07 14:28:18 danw Exp $
+# $Id: Makefile.am,v 1.5 2003/10/21 18:28:26 ettore Exp $
#
#
# (C) COPYRIGHT 2003, Andrea Campi, mailto:a.campi@inet.it
diff --git a/libical/src/libicalss/Makefile.am b/libical/src/libicalss/Makefile.am
index c714e8ca5a..1b72cd03c9 100644
--- a/libical/src/libicalss/Makefile.am
+++ b/libical/src/libicalss/Makefile.am
@@ -2,7 +2,7 @@
# FILE: Makefile.am
# CREATOR: eric
#
-# $Id: Makefile.am,v 1.21 2003/10/09 21:02:25 fejj Exp $
+# $Id: Makefile.am,v 1.22 2003/10/21 18:28:20 ettore Exp $
#
#
# (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
diff --git a/libical/src/libicalss/icalgauge.h b/libical/src/libicalss/icalgauge.h
index c35b4f7508..1064b5f41f 100644
--- a/libical/src/libicalss/icalgauge.h
+++ b/libical/src/libicalss/icalgauge.h
@@ -29,6 +29,8 @@
#ifndef ICALGAUGE_H
#define ICALGAUGE_H
+#include <libical/icalcomponent.h>
+
/** @file icalgauge.h
* @brief Routines implementing a filter for ical components
*/
diff --git a/libical/src/libicalss/icalsslexer.c b/libical/src/libicalss/icalsslexer.c
deleted file mode 100644
index e5afa81f61..0000000000
--- a/libical/src/libicalss/icalsslexer.c
+++ /dev/null
@@ -1,1746 +0,0 @@
-#define yy_create_buffer ss_create_buffer
-#define yy_delete_buffer ss_delete_buffer
-#define yy_scan_buffer ss_scan_buffer
-#define yy_scan_string ss_scan_string
-#define yy_scan_bytes ss_scan_bytes
-#define yy_flex_debug ss_flex_debug
-#define yy_init_buffer ss_init_buffer
-#define yy_flush_buffer ss_flush_buffer
-#define yy_load_buffer_state ss_load_buffer_state
-#define yy_switch_to_buffer ss_switch_to_buffer
-#define yyin ssin
-#define yyleng ssleng
-#define yylex sslex
-#define yyout ssout
-#define yyrestart ssrestart
-#define yytext sstext
-#define yywrap sswrap
-
-/* A lexical scanner generated by flex */
-
-/* Scanner skeleton version:
- * $Header$
- */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-
-#include <stdio.h>
-#include <unistd.h>
-
-
-/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
-#ifdef c_plusplus
-#ifndef __cplusplus
-#define __cplusplus
-#endif
-#endif
-
-
-#ifdef __cplusplus
-
-#include <stdlib.h>
-
-/* Use prototypes in function declarations. */
-#define YY_USE_PROTOS
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else /* ! __cplusplus */
-
-#if __STDC__
-
-#define YY_USE_PROTOS
-#define YY_USE_CONST
-
-#endif /* __STDC__ */
-#endif /* ! __cplusplus */
-
-#ifdef __TURBOC__
- #pragma warn -rch
- #pragma warn -use
-#include <io.h>
-#include <stdlib.h>
-#define YY_USE_CONST
-#define YY_USE_PROTOS
-#endif
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-
-#ifdef YY_USE_PROTOS
-#define YY_PROTO(proto) proto
-#else
-#define YY_PROTO(proto) ()
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index. If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* Enter a start condition. This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN yy_start = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state. The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START ((yy_start - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart( yyin )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#define YY_BUF_SIZE 16384
-
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-
-extern int yyleng;
-extern FILE *yyin, *yyout;
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
-/* The funky do-while in the following #define is used to turn the definition
- * int a single C statement (which needs a semi-colon terminator). This
- * avoids problems with code like:
- *
- * if ( condition_holds )
- * yyless( 5 );
- * else
- * do_something_else();
- *
- * Prior to using the do-while the compiler would get upset at the
- * "else" because it interpreted the "if" statement as being all
- * done when it reached the ';' after the yyless() call.
- */
-
-/* Return all but the first 'n' matched characters back to the input stream. */
-
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- *yy_cp = yy_hold_char; \
- YY_RESTORE_YY_MORE_OFFSET \
- yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
- YY_DO_BEFORE_ACTION; /* set up yytext again */ \
- } \
- while ( 0 )
-
-#define unput(c) yyunput( c, yytext_ptr )
-
-/* The following is because we cannot portably get our hands on size_t
- * (without autoconf's help, which isn't available because we want
- * flex-generated scanners to compile on their own).
- */
-typedef unsigned int yy_size_t;
-
-
-struct yy_buffer_state
- {
- FILE *yy_input_file;
-
- char *yy_ch_buf; /* input buffer */
- char *yy_buf_pos; /* current position in input buffer */
-
- /* Size of input buffer in bytes, not including room for EOB
- * characters.
- */
- yy_size_t yy_buf_size;
-
- /* Number of characters read into yy_ch_buf, not including EOB
- * characters.
- */
- int yy_n_chars;
-
- /* Whether we "own" the buffer - i.e., we know we created it,
- * and can realloc() it to grow it, and should free() it to
- * delete it.
- */
- int yy_is_our_buffer;
-
- /* Whether this is an "interactive" input source; if so, and
- * if we're using stdio for input, then we want to use getc()
- * instead of fread(), to make sure we stop fetching input after
- * each newline.
- */
- int yy_is_interactive;
-
- /* Whether we're considered to be at the beginning of a line.
- * If so, '^' rules will be active on the next match, otherwise
- * not.
- */
- int yy_at_bol;
-
- /* Whether to try to fill the input buffer when we reach the
- * end of it.
- */
- int yy_fill_buffer;
-
- int yy_buffer_status;
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
- /* When an EOF's been seen but there's still some text to process
- * then we mark the buffer as YY_EOF_PENDING, to indicate that we
- * shouldn't try reading from the input source any more. We might
- * still have a bunch of tokens to match, though, because of
- * possible backing-up.
- *
- * When we actually see the EOF, we change the status to "new"
- * (via yyrestart()), so that the user can continue scanning by
- * just pointing yyin at a new input file.
- */
-#define YY_BUFFER_EOF_PENDING 2
- };
-
-static YY_BUFFER_STATE yy_current_buffer = 0;
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- */
-#define YY_CURRENT_BUFFER yy_current_buffer
-
-
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-
-static int yy_n_chars; /* number of characters read into yy_ch_buf */
-
-
-int yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 1; /* whether we need to initialize */
-static int yy_start = 0; /* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin. A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-
-void yyrestart YY_PROTO(( FILE *input_file ));
-
-void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
-void yy_load_buffer_state YY_PROTO(( void ));
-YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
-void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
-void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
-
-YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
-YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
-YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
-
-static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
-static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
-static void yy_flex_free YY_PROTO(( void * ));
-
-#define yy_new_buffer yy_create_buffer
-
-#define yy_set_interactive(is_interactive) \
- { \
- if ( ! yy_current_buffer ) \
- yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
- yy_current_buffer->yy_is_interactive = is_interactive; \
- }
-
-#define yy_set_bol(at_bol) \
- { \
- if ( ! yy_current_buffer ) \
- yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
- yy_current_buffer->yy_at_bol = at_bol; \
- }
-
-#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
-
-typedef unsigned char YY_CHAR;
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
-typedef int yy_state_type;
-extern char yytext[];
-
-
-static yy_state_type yy_get_previous_state YY_PROTO(( void ));
-static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
-static int yy_get_next_buffer YY_PROTO(( void ));
-static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
- yytext_ptr = yy_bp; \
- yyleng = (int) (yy_cp - yy_bp); \
- yy_hold_char = *yy_cp; \
- *yy_cp = '\0'; \
- if ( yyleng >= YYLMAX ) \
- YY_FATAL_ERROR( "token too large, exceeds YYLMAX" ); \
- yy_flex_strncpy( yytext, yytext_ptr, yyleng + 1 ); \
- yy_c_buf_p = yy_cp;
-
-#define YY_NUM_RULES 23
-#define YY_END_OF_BUFFER 24
-static yyconst short int yy_accept[56] =
- { 0,
- 0, 0, 0, 0, 0, 0, 24, 22, 18, 18,
- 22, 17, 21, 4, 19, 8, 5, 9, 21, 21,
- 21, 21, 21, 21, 21, 18, 7, 0, 21, 10,
- 6, 11, 21, 21, 14, 21, 21, 13, 21, 21,
- 20, 12, 21, 15, 21, 21, 21, 2, 16, 21,
- 21, 21, 3, 1, 0
- } ;
-
-static yyconst int yy_ec[256] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
- 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 4, 5, 1, 1, 1, 1, 1, 6, 1,
- 1, 7, 1, 8, 7, 7, 1, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 9, 10, 11,
- 12, 13, 1, 7, 14, 7, 15, 16, 17, 18,
- 7, 19, 20, 7, 7, 21, 22, 23, 24, 7,
- 7, 25, 26, 27, 28, 7, 29, 7, 7, 7,
- 1, 1, 1, 1, 1, 1, 14, 7, 15, 16,
-
- 17, 18, 7, 19, 20, 7, 7, 21, 22, 23,
- 24, 7, 7, 25, 26, 27, 28, 7, 29, 7,
- 7, 7, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1
- } ;
-
-static yyconst int yy_meta[30] =
- { 0,
- 1, 1, 1, 2, 1, 1, 3, 1, 2, 1,
- 1, 1, 1, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3
- } ;
-
-static yyconst short int yy_base[58] =
- { 0,
- 0, 0, 0, 0, 0, 0, 68, 69, 28, 31,
- 55, 0, 0, 69, 69, 54, 53, 52, 40, 37,
- 35, 12, 35, 42, 39, 35, 69, 51, 0, 69,
- 69, 69, 40, 31, 0, 27, 32, 0, 31, 34,
- 69, 0, 28, 0, 28, 31, 22, 0, 0, 31,
- 28, 17, 0, 0, 69, 39, 40
- } ;
-
-static yyconst short int yy_def[58] =
- { 0,
- 55, 1, 1, 1, 1, 1, 55, 55, 55, 55,
- 55, 56, 57, 55, 55, 55, 55, 55, 57, 57,
- 57, 57, 57, 57, 57, 55, 55, 56, 57, 55,
- 55, 55, 57, 57, 57, 57, 57, 57, 57, 57,
- 55, 57, 57, 57, 57, 57, 57, 57, 57, 57,
- 57, 57, 57, 57, 0, 55, 55
- } ;
-
-static yyconst short int yy_nxt[99] =
- { 0,
- 8, 9, 10, 9, 11, 12, 13, 14, 8, 15,
- 16, 17, 18, 19, 13, 13, 13, 20, 13, 21,
- 13, 13, 22, 23, 13, 24, 13, 13, 25, 26,
- 26, 26, 26, 26, 26, 36, 26, 26, 26, 37,
- 28, 28, 29, 54, 53, 52, 51, 50, 49, 48,
- 47, 46, 45, 44, 43, 42, 41, 40, 39, 38,
- 35, 34, 33, 32, 31, 30, 27, 55, 7, 55,
- 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 55, 55, 55, 55, 55, 55
-
- } ;
-
-static yyconst short int yy_chk[99] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 9,
- 9, 9, 10, 10, 10, 22, 26, 26, 26, 22,
- 56, 56, 57, 52, 51, 50, 47, 46, 45, 43,
- 40, 39, 37, 36, 34, 33, 28, 25, 24, 23,
- 21, 20, 19, 18, 17, 16, 11, 7, 55, 55,
- 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 55, 55, 55, 55, 55, 55
-
- } ;
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-#ifndef YYLMAX
-#define YYLMAX 8192
-#endif
-
-char yytext[YYLMAX];
-char *yytext_ptr;
-#line 1 "icalsslexer.l"
-#define INITIAL 0
-#line 2 "icalsslexer.l"
-/* -*- Mode: C -*-
- ======================================================================
- FILE: icalsslexer.l
- CREATOR: eric 8 Aug 2000
-
- DESCRIPTION:
-
- $Id$
- $Locker$
-
-(C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of either:
-
- The LGPL as published by the Free Software Foundation, version
- 2.1, available at: http://www.fsf.org/copyleft/lesser.html
-
- Or:
-
- The Mozilla Public License Version 1.0. You may obtain a copy of
- the License at http://www.mozilla.org/MPL/
-
- The Original Code is eric. The Initial Developer of the Original
- Code is Eric Busboom
-
- ======================================================================*/
-
-#include "icalssyacc.h"
-#include "icalgaugeimpl.h"
-#include "assert.h"
-
-#include <string.h> /* For strdup() */
-
-const char* input_buffer;
-const char* input_buffer_p;
-
-#define min(a,b) ((a) < (b) ? (a) : (b))
-
-int icalss_input(char* buf, int max_size)
-{
- int n = min(max_size,strlen(input_buffer_p));
-
- if (n > 0){
- memcpy(buf, input_buffer_p, n);
- input_buffer_p += n;
- return n;
- } else {
- return 0;
- }
-}
-
-#undef YY_INPUT
-#define YY_INPUT(b,r,ms) ( r= icalss_input(b,ms))
-
-#undef SS_FATAL_ERROR
-#define SS_FATAL_ERROR(msg) sserror(msg)
-
-#define sql 1
-#define string_value 2
-
-#line 488 "icalsslexer.c"
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap YY_PROTO(( void ));
-#else
-extern int yywrap YY_PROTO(( void ));
-#endif
-#endif
-
-#ifndef YY_NO_UNPUT
-static void yyunput YY_PROTO(( int c, char *buf_ptr ));
-#endif
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen YY_PROTO(( yyconst char * ));
-#endif
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
-static int yyinput YY_PROTO(( void ));
-#else
-static int input YY_PROTO(( void ));
-#endif
-#endif
-
-#if YY_STACK_USED
-static int yy_start_stack_ptr = 0;
-static int yy_start_stack_depth = 0;
-static int *yy_start_stack = 0;
-#ifndef YY_NO_PUSH_STATE
-static void yy_push_state YY_PROTO(( int new_state ));
-#endif
-#ifndef YY_NO_POP_STATE
-static void yy_pop_state YY_PROTO(( void ));
-#endif
-#ifndef YY_NO_TOP_STATE
-static int yy_top_state YY_PROTO(( void ));
-#endif
-
-#else
-#define YY_NO_PUSH_STATE 1
-#define YY_NO_POP_STATE 1
-#define YY_NO_TOP_STATE 1
-#endif
-
-#ifdef YY_MALLOC_DECL
-YY_MALLOC_DECL
-#else
-#if __STDC__
-#ifndef __cplusplus
-#include <stdlib.h>
-#endif
-#else
-/* Just try to get by without declaring the routines. This will fail
- * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
- * or sizeof(void*) != sizeof(int).
- */
-#endif
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
-#endif
-
-/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- if ( yy_current_buffer->yy_is_interactive ) \
- { \
- int c = '*', n; \
- for ( n = 0; n < max_size && \
- (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
- buf[n] = (char) c; \
- if ( c == '\n' ) \
- buf[n++] = (char) c; \
- if ( c == EOF && ferror( yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- result = n; \
- } \
- else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
- && ferror( yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" );
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-#endif
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL int yylex YY_PROTO(( void ))
-#endif
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-#define YY_RULE_SETUP \
- YY_USER_ACTION
-
-YY_DECL
- {
- register yy_state_type yy_current_state;
- register char *yy_cp = NULL, *yy_bp = NULL;
- register int yy_act;
-
-#line 83 "icalsslexer.l"
-
-
-
-
-
-
-#line 646 "icalsslexer.c"
-
- if ( yy_init )
- {
- yy_init = 0;
-
-#ifdef YY_USER_INIT
- YY_USER_INIT;
-#endif
-
- if ( ! yy_start )
- yy_start = 1; /* first start state */
-
- if ( ! yyin )
- yyin = stdin;
-
- if ( ! yyout )
- yyout = stdout;
-
- if ( ! yy_current_buffer )
- yy_current_buffer =
- yy_create_buffer( yyin, YY_BUF_SIZE );
-
- yy_load_buffer_state();
- }
-
- while ( 1 ) /* loops until end-of-file is reached */
- {
- yy_cp = yy_c_buf_p;
-
- /* Support of yytext. */
- *yy_cp = yy_hold_char;
-
- /* yy_bp points to the position in yy_ch_buf of the start of
- * the current run.
- */
- yy_bp = yy_cp;
-
- yy_current_state = yy_start;
-yy_match:
- do
- {
- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
- if ( yy_accept[yy_current_state] )
- {
- yy_last_accepting_state = yy_current_state;
- yy_last_accepting_cpos = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 56 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- ++yy_cp;
- }
- while ( yy_base[yy_current_state] != 69 );
-
-yy_find_action:
- yy_act = yy_accept[yy_current_state];
- if ( yy_act == 0 )
- { /* have to back up */
- yy_cp = yy_last_accepting_cpos;
- yy_current_state = yy_last_accepting_state;
- yy_act = yy_accept[yy_current_state];
- }
-
- YY_DO_BEFORE_ACTION;
-
-
-do_action: /* This label is used only to access EOF actions. */
-
-
- switch ( yy_act )
- { /* beginning of action switch */
- case 0: /* must back up */
- /* undo the effects of YY_DO_BEFORE_ACTION */
- *yy_cp = yy_hold_char;
- yy_cp = yy_last_accepting_cpos;
- yy_current_state = yy_last_accepting_state;
- goto yy_find_action;
-
-case 1:
-YY_RULE_SETUP
-#line 89 "icalsslexer.l"
-{ return SELECT; }
- YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 90 "icalsslexer.l"
-{ return FROM; }
- YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 91 "icalsslexer.l"
-{ return WHERE; }
- YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 92 "icalsslexer.l"
-{ return COMMA; }
- YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 93 "icalsslexer.l"
-{ return EQUALS; }
- YY_BREAK
-case 6:
-YY_RULE_SETUP
-#line 94 "icalsslexer.l"
-{ return EQUALS; }
- YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 95 "icalsslexer.l"
-{ return NOTEQUALS; }
- YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 96 "icalsslexer.l"
-{ return LESS; }
- YY_BREAK
-case 9:
-YY_RULE_SETUP
-#line 97 "icalsslexer.l"
-{ return GREATER; }
- YY_BREAK
-case 10:
-YY_RULE_SETUP
-#line 98 "icalsslexer.l"
-{ return LESSEQUALS; }
- YY_BREAK
-case 11:
-YY_RULE_SETUP
-#line 99 "icalsslexer.l"
-{ return GREATEREQUALS; }
- YY_BREAK
-case 12:
-YY_RULE_SETUP
-#line 100 "icalsslexer.l"
-{ return AND; }
- YY_BREAK
-case 13:
-YY_RULE_SETUP
-#line 101 "icalsslexer.l"
-{ return OR; }
- YY_BREAK
-case 14:
-YY_RULE_SETUP
-#line 102 "icalsslexer.l"
-{ return IS; }
- YY_BREAK
-case 15:
-YY_RULE_SETUP
-#line 103 "icalsslexer.l"
-{ return NOT; }
- YY_BREAK
-case 16:
-YY_RULE_SETUP
-#line 104 "icalsslexer.l"
-{ return SQLNULL; }
- YY_BREAK
-case 17:
-YY_RULE_SETUP
-#line 105 "icalsslexer.l"
-{ return QUOTE; }
- YY_BREAK
-case 18:
-YY_RULE_SETUP
-#line 106 "icalsslexer.l"
-;
- YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 107 "icalsslexer.l"
-{ return EOL; }
- YY_BREAK
-case 20:
-YY_RULE_SETUP
-#line 109 "icalsslexer.l"
-{
- int c = input();
- unput(c);
- if(c!='\''){
- sslval.v_string= icalmemory_tmp_copy(yytext);
- return STRING;
- } else {
- /*ssmore();*/
- }
-}
- YY_BREAK
-case 21:
-YY_RULE_SETUP
-#line 120 "icalsslexer.l"
-{
- sslval.v_string= icalmemory_tmp_copy(yytext);
- return STRING;
-}
- YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 126 "icalsslexer.l"
-{ return yytext[0]; }
- YY_BREAK
-case 23:
-YY_RULE_SETUP
-#line 128 "icalsslexer.l"
-ECHO;
- YY_BREAK
-#line 856 "icalsslexer.c"
-case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(sql):
-case YY_STATE_EOF(string_value):
- yyterminate();
-
- case YY_END_OF_BUFFER:
- {
- /* Amount of text matched not including the EOB char. */
- int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
-
- /* Undo the effects of YY_DO_BEFORE_ACTION. */
- *yy_cp = yy_hold_char;
- YY_RESTORE_YY_MORE_OFFSET
-
- if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
- {
- /* We're scanning a new file or input source. It's
- * possible that this happened because the user
- * just pointed yyin at a new source and called
- * yylex(). If so, then we have to assure
- * consistency between yy_current_buffer and our
- * globals. Here is the right place to do so, because
- * this is the first action (other than possibly a
- * back-up) that will match for the new input source.
- */
- yy_n_chars = yy_current_buffer->yy_n_chars;
- yy_current_buffer->yy_input_file = yyin;
- yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
- }
-
- /* Note that here we test for yy_c_buf_p "<=" to the position
- * of the first EOB in the buffer, since yy_c_buf_p will
- * already have been incremented past the NUL character
- * (since all states make transitions on EOB to the
- * end-of-buffer state). Contrast this with the test
- * in input().
- */
- if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
- { /* This was really a NUL. */
- yy_state_type yy_next_state;
-
- yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state();
-
- /* Okay, we're now positioned to make the NUL
- * transition. We couldn't have
- * yy_get_previous_state() go ahead and do it
- * for us because it doesn't know how to deal
- * with the possibility of jamming (and we don't
- * want to build jamming into it because then it
- * will run more slowly).
- */
-
- yy_next_state = yy_try_NUL_trans( yy_current_state );
-
- yy_bp = yytext_ptr + YY_MORE_ADJ;
-
- if ( yy_next_state )
- {
- /* Consume the NUL. */
- yy_cp = ++yy_c_buf_p;
- yy_current_state = yy_next_state;
- goto yy_match;
- }
-
- else
- {
- yy_cp = yy_c_buf_p;
- goto yy_find_action;
- }
- }
-
- else switch ( yy_get_next_buffer() )
- {
- case EOB_ACT_END_OF_FILE:
- {
- yy_did_buffer_switch_on_eof = 0;
-
- if ( yywrap() )
- {
- /* Note: because we've taken care in
- * yy_get_next_buffer() to have set up
- * yytext, we can now set up
- * yy_c_buf_p so that if some total
- * hoser (like flex itself) wants to
- * call the scanner after we return the
- * YY_NULL, it'll still work - another
- * YY_NULL will get returned.
- */
- yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
-
- yy_act = YY_STATE_EOF(YY_START);
- goto do_action;
- }
-
- else
- {
- if ( ! yy_did_buffer_switch_on_eof )
- YY_NEW_FILE;
- }
- break;
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- yy_c_buf_p =
- yytext_ptr + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state();
-
- yy_cp = yy_c_buf_p;
- yy_bp = yytext_ptr + YY_MORE_ADJ;
- goto yy_match;
-
- case EOB_ACT_LAST_MATCH:
- yy_c_buf_p =
- &yy_current_buffer->yy_ch_buf[yy_n_chars];
-
- yy_current_state = yy_get_previous_state();
-
- yy_cp = yy_c_buf_p;
- yy_bp = yytext_ptr + YY_MORE_ADJ;
- goto yy_find_action;
- }
- break;
- }
-
- default:
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--no action found" );
- } /* end of action switch */
- } /* end of scanning one token */
- } /* end of yylex */
-
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- * EOB_ACT_LAST_MATCH -
- * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- * EOB_ACT_END_OF_FILE - end of file
- */
-
-static int yy_get_next_buffer()
- {
- register char *dest = yy_current_buffer->yy_ch_buf;
- register char *source = yytext_ptr;
- register int number_to_move, i;
- int ret_val;
-
- if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--end of buffer missed" );
-
- if ( yy_current_buffer->yy_fill_buffer == 0 )
- { /* Don't try to fill the buffer, so this is an EOF. */
- if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
- {
- /* We matched a single character, the EOB, so
- * treat this as a final EOF.
- */
- return EOB_ACT_END_OF_FILE;
- }
-
- else
- {
- /* We matched some text prior to the EOB, first
- * process it.
- */
- return EOB_ACT_LAST_MATCH;
- }
- }
-
- /* Try to read more data. */
-
- /* First move last chars to start of buffer. */
- number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
-
- for ( i = 0; i < number_to_move; ++i )
- *(dest++) = *(source++);
-
- if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
- /* don't do the read, it's not guaranteed to return an EOF,
- * just force an EOF
- */
- yy_current_buffer->yy_n_chars = yy_n_chars = 0;
-
- else
- {
- int num_to_read =
- yy_current_buffer->yy_buf_size - number_to_move - 1;
-
- while ( num_to_read <= 0 )
- { /* Not enough room in the buffer - grow it. */
-#ifdef YY_USES_REJECT
- YY_FATAL_ERROR(
-"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
-#else
-
- /* just a shorter name for the current buffer */
- YY_BUFFER_STATE b = yy_current_buffer;
-
- int yy_c_buf_p_offset =
- (int) (yy_c_buf_p - b->yy_ch_buf);
-
- if ( b->yy_is_our_buffer )
- {
- int new_size = b->yy_buf_size * 2;
-
- if ( new_size <= 0 )
- b->yy_buf_size += b->yy_buf_size / 8;
- else
- b->yy_buf_size *= 2;
-
- b->yy_ch_buf = (char *)
- /* Include room in for 2 EOB chars. */
- yy_flex_realloc( (void *) b->yy_ch_buf,
- b->yy_buf_size + 2 );
- }
- else
- /* Can't grow it, we don't own it. */
- b->yy_ch_buf = 0;
-
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR(
- "fatal error - scanner input buffer overflow" );
-
- yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
-
- num_to_read = yy_current_buffer->yy_buf_size -
- number_to_move - 1;
-#endif
- }
-
- if ( num_to_read > YY_READ_BUF_SIZE )
- num_to_read = YY_READ_BUF_SIZE;
-
- /* Read in more data. */
- YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
- yy_n_chars, num_to_read );
-
- yy_current_buffer->yy_n_chars = yy_n_chars;
- }
-
- if ( yy_n_chars == 0 )
- {
- if ( number_to_move == YY_MORE_ADJ )
- {
- ret_val = EOB_ACT_END_OF_FILE;
- yyrestart( yyin );
- }
-
- else
- {
- ret_val = EOB_ACT_LAST_MATCH;
- yy_current_buffer->yy_buffer_status =
- YY_BUFFER_EOF_PENDING;
- }
- }
-
- else
- ret_val = EOB_ACT_CONTINUE_SCAN;
-
- yy_n_chars += number_to_move;
- yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
- yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
-
- yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
-
- return ret_val;
- }
-
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-static yy_state_type yy_get_previous_state()
- {
- register yy_state_type yy_current_state;
- register char *yy_cp;
-
- yy_current_state = yy_start;
-
- for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
- {
- register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
- if ( yy_accept[yy_current_state] )
- {
- yy_last_accepting_state = yy_current_state;
- yy_last_accepting_cpos = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 56 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- }
-
- return yy_current_state;
- }
-
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- * next_state = yy_try_NUL_trans( current_state );
- */
-
-#ifdef YY_USE_PROTOS
-static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
-#else
-static yy_state_type yy_try_NUL_trans( yy_current_state )
-yy_state_type yy_current_state;
-#endif
- {
- register int yy_is_jam;
- register char *yy_cp = yy_c_buf_p;
-
- register YY_CHAR yy_c = 1;
- if ( yy_accept[yy_current_state] )
- {
- yy_last_accepting_state = yy_current_state;
- yy_last_accepting_cpos = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 56 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 55);
-
- return yy_is_jam ? 0 : yy_current_state;
- }
-
-
-#ifndef YY_NO_UNPUT
-#ifdef YY_USE_PROTOS
-static void yyunput( int c, register char *yy_bp )
-#else
-static void yyunput( c, yy_bp )
-int c;
-register char *yy_bp;
-#endif
- {
- register char *yy_cp = yy_c_buf_p;
-
- /* undo effects of setting up yytext */
- *yy_cp = yy_hold_char;
-
- if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
- { /* need to shift things up to make room */
- /* +2 for EOB chars. */
- register int number_to_move = yy_n_chars + 2;
- register char *dest = &yy_current_buffer->yy_ch_buf[
- yy_current_buffer->yy_buf_size + 2];
- register char *source =
- &yy_current_buffer->yy_ch_buf[number_to_move];
-
- while ( source > yy_current_buffer->yy_ch_buf )
- *--dest = *--source;
-
- yy_cp += (int) (dest - source);
- yy_bp += (int) (dest - source);
- yy_current_buffer->yy_n_chars =
- yy_n_chars = yy_current_buffer->yy_buf_size;
-
- if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
- YY_FATAL_ERROR( "flex scanner push-back overflow" );
- }
-
- *--yy_cp = (char) c;
-
-
- yytext_ptr = yy_bp;
- yy_hold_char = *yy_cp;
- yy_c_buf_p = yy_cp;
- }
-#endif /* ifndef YY_NO_UNPUT */
-
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
-static int yyinput()
-#else
-static int input()
-#endif
- {
- int c;
-
- *yy_c_buf_p = yy_hold_char;
-
- if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
- {
- /* yy_c_buf_p now points to the character we want to return.
- * If this occurs *before* the EOB characters, then it's a
- * valid NUL; if not, then we've hit the end of the buffer.
- */
- if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
- /* This was really a NUL. */
- *yy_c_buf_p = '\0';
-
- else
- { /* need more input */
- int offset = yy_c_buf_p - yytext_ptr;
- ++yy_c_buf_p;
-
- switch ( yy_get_next_buffer() )
- {
- case EOB_ACT_LAST_MATCH:
- /* This happens because yy_g_n_b()
- * sees that we've accumulated a
- * token and flags that we need to
- * try matching the token before
- * proceeding. But for input(),
- * there's no matching to consider.
- * So convert the EOB_ACT_LAST_MATCH
- * to EOB_ACT_END_OF_FILE.
- */
-
- /* Reset buffer status. */
- yyrestart( yyin );
-
- /* fall through */
-
- case EOB_ACT_END_OF_FILE:
- {
- if ( yywrap() )
- return EOF;
-
- if ( ! yy_did_buffer_switch_on_eof )
- YY_NEW_FILE;
-#ifdef __cplusplus
- return yyinput();
-#else
- return input();
-#endif
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- yy_c_buf_p = yytext_ptr + offset;
- break;
- }
- }
- }
-
- c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
- *yy_c_buf_p = '\0'; /* preserve yytext */
- yy_hold_char = *++yy_c_buf_p;
-
-
- return c;
- }
-#endif /* YY_NO_INPUT */
-
-#ifdef YY_USE_PROTOS
-void yyrestart( FILE *input_file )
-#else
-void yyrestart( input_file )
-FILE *input_file;
-#endif
- {
- if ( ! yy_current_buffer )
- yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
-
- yy_init_buffer( yy_current_buffer, input_file );
- yy_load_buffer_state();
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
-#else
-void yy_switch_to_buffer( new_buffer )
-YY_BUFFER_STATE new_buffer;
-#endif
- {
- if ( yy_current_buffer == new_buffer )
- return;
-
- if ( yy_current_buffer )
- {
- /* Flush out information for old buffer. */
- *yy_c_buf_p = yy_hold_char;
- yy_current_buffer->yy_buf_pos = yy_c_buf_p;
- yy_current_buffer->yy_n_chars = yy_n_chars;
- }
-
- yy_current_buffer = new_buffer;
- yy_load_buffer_state();
-
- /* We don't actually know whether we did this switch during
- * EOF (yywrap()) processing, but the only time this flag
- * is looked at is after yywrap() is called, so it's safe
- * to go ahead and always set it.
- */
- yy_did_buffer_switch_on_eof = 1;
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_load_buffer_state( void )
-#else
-void yy_load_buffer_state()
-#endif
- {
- yy_n_chars = yy_current_buffer->yy_n_chars;
- yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
- yyin = yy_current_buffer->yy_input_file;
- yy_hold_char = *yy_c_buf_p;
- }
-
-
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
-#else
-YY_BUFFER_STATE yy_create_buffer( file, size )
-FILE *file;
-int size;
-#endif
- {
- YY_BUFFER_STATE b;
-
- b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_buf_size = size;
-
- /* yy_ch_buf has to be 2 characters longer than the size given because
- * we need to put in 2 end-of-buffer characters.
- */
- b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_is_our_buffer = 1;
-
- yy_init_buffer( b, file );
-
- return b;
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_delete_buffer( YY_BUFFER_STATE b )
-#else
-void yy_delete_buffer( b )
-YY_BUFFER_STATE b;
-#endif
- {
- if ( ! b )
- return;
-
- if ( b == yy_current_buffer )
- yy_current_buffer = (YY_BUFFER_STATE) 0;
-
- if ( b->yy_is_our_buffer )
- yy_flex_free( (void *) b->yy_ch_buf );
-
- yy_flex_free( (void *) b );
- }
-
-
-
-#ifdef YY_USE_PROTOS
-void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
-#else
-void yy_init_buffer( b, file )
-YY_BUFFER_STATE b;
-FILE *file;
-#endif
-
-
- {
- yy_flush_buffer( b );
-
- b->yy_input_file = file;
- b->yy_fill_buffer = 1;
-
-#if YY_ALWAYS_INTERACTIVE
- b->yy_is_interactive = 1;
-#else
-#if YY_NEVER_INTERACTIVE
- b->yy_is_interactive = 0;
-#else
- b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-#endif
-#endif
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_flush_buffer( YY_BUFFER_STATE b )
-#else
-void yy_flush_buffer( b )
-YY_BUFFER_STATE b;
-#endif
-
- {
- if ( ! b )
- return;
-
- b->yy_n_chars = 0;
-
- /* We always need two end-of-buffer characters. The first causes
- * a transition to the end-of-buffer state. The second causes
- * a jam in that state.
- */
- b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
- b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
- b->yy_buf_pos = &b->yy_ch_buf[0];
-
- b->yy_at_bol = 1;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- if ( b == yy_current_buffer )
- yy_load_buffer_state();
- }
-
-
-#ifndef YY_NO_SCAN_BUFFER
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
-#else
-YY_BUFFER_STATE yy_scan_buffer( base, size )
-char *base;
-yy_size_t size;
-#endif
- {
- YY_BUFFER_STATE b;
-
- if ( size < 2 ||
- base[size-2] != YY_END_OF_BUFFER_CHAR ||
- base[size-1] != YY_END_OF_BUFFER_CHAR )
- /* They forgot to leave room for the EOB's. */
- return 0;
-
- b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
-
- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
- b->yy_buf_pos = b->yy_ch_buf = base;
- b->yy_is_our_buffer = 0;
- b->yy_input_file = 0;
- b->yy_n_chars = b->yy_buf_size;
- b->yy_is_interactive = 0;
- b->yy_at_bol = 1;
- b->yy_fill_buffer = 0;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- yy_switch_to_buffer( b );
-
- return b;
- }
-#endif
-
-
-#ifndef YY_NO_SCAN_STRING
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
-#else
-YY_BUFFER_STATE yy_scan_string( yy_str )
-yyconst char *yy_str;
-#endif
- {
- int len;
- for ( len = 0; yy_str[len]; ++len )
- ;
-
- return yy_scan_bytes( yy_str, len );
- }
-#endif
-
-
-#ifndef YY_NO_SCAN_BYTES
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
-#else
-YY_BUFFER_STATE yy_scan_bytes( bytes, len )
-yyconst char *bytes;
-int len;
-#endif
- {
- YY_BUFFER_STATE b;
- char *buf;
- yy_size_t n;
- int i;
-
- /* Get memory for full buffer, including space for trailing EOB's. */
- n = len + 2;
- buf = (char *) yy_flex_alloc( n );
- if ( ! buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
-
- for ( i = 0; i < len; ++i )
- buf[i] = bytes[i];
-
- buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
-
- b = yy_scan_buffer( buf, n );
- if ( ! b )
- YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
-
- /* It's okay to grow etc. this buffer, and we should throw it
- * away when we're done.
- */
- b->yy_is_our_buffer = 1;
-
- return b;
- }
-#endif
-
-
-#ifndef YY_NO_PUSH_STATE
-#ifdef YY_USE_PROTOS
-static void yy_push_state( int new_state )
-#else
-static void yy_push_state( new_state )
-int new_state;
-#endif
- {
- if ( yy_start_stack_ptr >= yy_start_stack_depth )
- {
- yy_size_t new_size;
-
- yy_start_stack_depth += YY_START_STACK_INCR;
- new_size = yy_start_stack_depth * sizeof( int );
-
- if ( ! yy_start_stack )
- yy_start_stack = (int *) yy_flex_alloc( new_size );
-
- else
- yy_start_stack = (int *) yy_flex_realloc(
- (void *) yy_start_stack, new_size );
-
- if ( ! yy_start_stack )
- YY_FATAL_ERROR(
- "out of memory expanding start-condition stack" );
- }
-
- yy_start_stack[yy_start_stack_ptr++] = YY_START;
-
- BEGIN(new_state);
- }
-#endif
-
-
-#ifndef YY_NO_POP_STATE
-static void yy_pop_state()
- {
- if ( --yy_start_stack_ptr < 0 )
- YY_FATAL_ERROR( "start-condition stack underflow" );
-
- BEGIN(yy_start_stack[yy_start_stack_ptr]);
- }
-#endif
-
-
-#ifndef YY_NO_TOP_STATE
-static int yy_top_state()
- {
- return yy_start_stack[yy_start_stack_ptr - 1];
- }
-#endif
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-#ifdef YY_USE_PROTOS
-static void yy_fatal_error( yyconst char msg[] )
-#else
-static void yy_fatal_error( msg )
-char msg[];
-#endif
- {
- (void) fprintf( stderr, "%s\n", msg );
- exit( YY_EXIT_FAILURE );
- }
-
-
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- yytext[yyleng] = yy_hold_char; \
- yy_c_buf_p = yytext + n; \
- yy_hold_char = *yy_c_buf_p; \
- *yy_c_buf_p = '\0'; \
- yyleng = n; \
- } \
- while ( 0 )
-
-
-/* Internal utility routines. */
-
-#ifndef yytext_ptr
-#ifdef YY_USE_PROTOS
-static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
-#else
-static void yy_flex_strncpy( s1, s2, n )
-char *s1;
-yyconst char *s2;
-int n;
-#endif
- {
- register int i;
- for ( i = 0; i < n; ++i )
- s1[i] = s2[i];
- }
-#endif
-
-#ifdef YY_NEED_STRLEN
-#ifdef YY_USE_PROTOS
-static int yy_flex_strlen( yyconst char *s )
-#else
-static int yy_flex_strlen( s )
-yyconst char *s;
-#endif
- {
- register int n;
- for ( n = 0; s[n]; ++n )
- ;
-
- return n;
- }
-#endif
-
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_alloc( yy_size_t size )
-#else
-static void *yy_flex_alloc( size )
-yy_size_t size;
-#endif
- {
- return (void *) malloc( size );
- }
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_realloc( void *ptr, yy_size_t size )
-#else
-static void *yy_flex_realloc( ptr, size )
-void *ptr;
-yy_size_t size;
-#endif
- {
- /* The cast to (char *) in the following accommodates both
- * implementations that use char* generic pointers, and those
- * that use void* generic pointers. It works with the latter
- * because both ANSI C and C++ allow castless assignment from
- * any pointer type to void*, and deal with argument conversions
- * as though doing an assignment.
- */
- return (void *) realloc( (char *) ptr, size );
- }
-
-#ifdef YY_USE_PROTOS
-static void yy_flex_free( void *ptr )
-#else
-static void yy_flex_free( ptr )
-void *ptr;
-#endif
- {
- free( ptr );
- }
-
-#if YY_MAIN
-int main()
- {
- yylex();
- return 0;
- }
-#endif
-#line 128 "icalsslexer.l"
-
-
-int yywrap()
-{
- return 1;
-}
-
diff --git a/libical/src/libicalss/icalsslexer.l b/libical/src/libicalss/icalsslexer.l
index fe89bfde99..b6bc4dee05 100644
--- a/libical/src/libicalss/icalsslexer.l
+++ b/libical/src/libicalss/icalsslexer.l
@@ -6,7 +6,7 @@
DESCRIPTION:
- $Id: icalsslexer.l,v 1.4 2003/09/24 02:06:52 hansp Exp $
+ $Id: icalsslexer.l,v 1.5 2003/10/21 18:28:18 ettore Exp $
$Locker: $
(C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
diff --git a/libical/src/libicalss/icalssyacc.c b/libical/src/libicalss/icalssyacc.c
deleted file mode 100644
index 8e27cd75ed..0000000000
--- a/libical/src/libicalss/icalssyacc.c
+++ /dev/null
@@ -1,1397 +0,0 @@
-/* A Bison parser, made from /home/hpj/work/cvs/cvs.gnome.org/evolution-trunk/libical/src/libicalss/icalssyacc.y
- by GNU bison 1.35. */
-
-#define YYBISON 1 /* Identify Bison output. */
-
-#define yyparse ssparse
-#define yylex sslex
-#define yyerror sserror
-#define yylval sslval
-#define yychar sschar
-#define yydebug ssdebug
-#define yynerrs ssnerrs
-# define STRING 257
-# define SELECT 258
-# define FROM 259
-# define WHERE 260
-# define COMMA 261
-# define QUOTE 262
-# define EQUALS 263
-# define NOTEQUALS 264
-# define LESS 265
-# define GREATER 266
-# define LESSEQUALS 267
-# define GREATEREQUALS 268
-# define AND 269
-# define OR 270
-# define EOL 271
-# define END 272
-# define IS 273
-# define NOT 274
-# define SQLNULL 275
-
-#line 1 "icalssyacc.y"
-
-/* -*- Mode: C -*-
- ======================================================================
- FILE: icalssyacc.y
- CREATOR: eric 08 Aug 2000
-
- DESCRIPTION:
-
- $Id$
- $Locker$
-
-(C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of either:
-
- The LGPL as published by the Free Software Foundation, version
- 2.1, available at: http://www.fsf.org/copyleft/lesser.html
-
- Or:
-
- The Mozilla Public License Version 1.0. You may obtain a copy of
- the License at http://www.mozilla.org/MPL/
-
- The Original Code is eric. The Initial Developer of the Original
- Code is Eric Busboom
-
- ======================================================================*/
-/*#define YYDEBUG 1*/
-#include <stdlib.h>
-#include <string.h> /* for strdup() */
-#include <limits.h> /* for SHRT_MAX*/
-#include <libical/ical.h>
-#include <libicalss/icalgauge.h>
-#include "icalgaugeimpl.h"
-
-extern struct icalgauge_impl *icalss_yy_gauge;
-
-#define YYPARSE_PARAM yy_globals
-#define YYLEX_PARAM yy_globals
-#define YY_EXTRA_TYPE icalgauge_impl*
-
-
-static void ssyacc_add_where(struct icalgauge_impl* impl, char* prop,
- icalgaugecompare compare , char* value);
-static void ssyacc_add_select(struct icalgauge_impl* impl, char* str1);
-static void ssyacc_add_from(struct icalgauge_impl* impl, char* str1);
-static void set_logic(struct icalgauge_impl* impl,icalgaugelogic l);
-void sserror(char *s); /* Don't know why I need this.... */
-
-
-#line 53 "icalssyacc.y"
-#ifndef YYSTYPE
-typedef union {
- char* v_string;
-} yystype;
-# define YYSTYPE yystype
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-
-
-#define YYFINAL 38
-#define YYFLAG -32768
-#define YYNTBASE 22
-
-/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */
-#define YYTRANSLATE(x) ((unsigned)(x) <= 275 ? yytranslate[x] : 27)
-
-/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */
-static const char yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 3, 4, 5,
- 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21
-};
-
-#if YYDEBUG
-static const short yyprhs[] =
-{
- 0, 0, 7, 12, 14, 16, 20, 22, 26, 27,
- 31, 35, 40, 44, 48, 52, 56, 60, 62, 66
-};
-static const short yyrhs[] =
-{
- 4, 23, 5, 24, 6, 26, 0, 4, 23, 5,
- 24, 0, 1, 0, 3, 0, 23, 7, 3, 0,
- 3, 0, 24, 7, 3, 0, 0, 3, 9, 3,
- 0, 3, 19, 21, 0, 3, 19, 20, 21, 0,
- 3, 10, 3, 0, 3, 11, 3, 0, 3, 12,
- 3, 0, 3, 13, 3, 0, 3, 14, 3, 0,
- 25, 0, 26, 15, 25, 0, 26, 16, 25, 0
-};
-
-#endif
-
-#if YYDEBUG
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const short yyrline[] =
-{
- 0, 64, 65, 66, 72, 74, 78, 80, 83, 85,
- 86, 87, 88, 89, 90, 91, 92, 95, 97, 98
-};
-#endif
-
-
-#if (YYDEBUG) || defined YYERROR_VERBOSE
-
-/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */
-static const char *const yytname[] =
-{
- "$", "error", "$undefined.", "STRING", "SELECT", "FROM", "WHERE", "COMMA",
- "QUOTE", "EQUALS", "NOTEQUALS", "LESS", "GREATER", "LESSEQUALS",
- "GREATEREQUALS", "AND", "OR", "EOL", "END", "IS", "NOT", "SQLNULL",
- "query_min", "select_list", "from_list", "where_clause", "where_list", 0
-};
-#endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const short yyr1[] =
-{
- 0, 22, 22, 22, 23, 23, 24, 24, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 26, 26, 26
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const short yyr2[] =
-{
- 0, 6, 4, 1, 1, 3, 1, 3, 0, 3,
- 3, 4, 3, 3, 3, 3, 3, 1, 3, 3
-};
-
-/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE
- doesn't specify something else to do. Zero means the default is an
- error. */
-static const short yydefact[] =
-{
- 0, 3, 0, 4, 0, 0, 0, 6, 2, 5,
- 8, 0, 0, 17, 1, 7, 0, 0, 0, 0,
- 0, 0, 0, 8, 8, 9, 12, 13, 14, 15,
- 16, 0, 10, 18, 19, 11, 0, 0, 0
-};
-
-static const short yydefgoto[] =
-{
- 36, 4, 8, 13, 14
-};
-
-static const short yypact[] =
-{
- 5,-32768, 9,-32768, 6, 17, 18,-32768, 1,-32768,
- 19, 20, -9,-32768, -1,-32768, 21, 22, 23, 24,
- 25, 26, -4, 19, 19,-32768,-32768,-32768,-32768,-32768,
- -32768, 10,-32768,-32768,-32768,-32768, 30, 32,-32768
-};
-
-static const short yypgoto[] =
-{
- -32768,-32768,-32768, -5,-32768
-};
-
-
-#define YYLAST 32
-
-
-static const short yytable[] =
-{
- 16, 17, 18, 19, 20, 21, 1, 10, 11, 2,
- 22, 5, 3, 6, 23, 24, 31, 32, 33, 34,
- 7, 9, 12, 15, 25, 26, 27, 28, 29, 30,
- 37, 35, 38
-};
-
-static const short yycheck[] =
-{
- 9, 10, 11, 12, 13, 14, 1, 6, 7, 4,
- 19, 5, 3, 7, 15, 16, 20, 21, 23, 24,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 0, 21, 0
-};
-/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
-#line 3 "/usr/share/bison/bison.simple"
-
-/* Skeleton output parser for bison,
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software
- Foundation, Inc.
-
- 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 2, 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. */
-
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
-
-/* This is the parser code that is written into each bison parser when
- the %semantic_parser declaration is not specified in the grammar.
- It was written by Richard Stallman by simplifying the hairy parser
- used when %semantic_parser is specified. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE)
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# if YYSTACK_USE_ALLOCA
-# define YYSTACK_ALLOC alloca
-# else
-# ifndef YYSTACK_USE_ALLOCA
-# if defined (alloca) || defined (_ALLOCA_H)
-# define YYSTACK_ALLOC alloca
-# else
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
-# else
-# if defined (__STDC__) || defined (__cplusplus)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# endif
-# define YYSTACK_ALLOC malloc
-# define YYSTACK_FREE free
-# endif
-#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */
-
-
-#if (! defined (yyoverflow) \
- && (! defined (__cplusplus) \
- || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- short yyss;
- YYSTYPE yyvs;
-# if YYLSP_NEEDED
- YYLTYPE yyls;
-# endif
-};
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# if YYLSP_NEEDED
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
- + 2 * YYSTACK_GAP_MAX)
-# else
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
- + YYSTACK_GAP_MAX)
-# endif
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- register YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (0)
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (0)
-
-#endif
-
-
-#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
-# define YYSIZE_T __SIZE_TYPE__
-#endif
-#if ! defined (YYSIZE_T) && defined (size_t)
-# define YYSIZE_T size_t
-#endif
-#if ! defined (YYSIZE_T)
-# if defined (__STDC__) || defined (__cplusplus)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# endif
-#endif
-#if ! defined (YYSIZE_T)
-# define YYSIZE_T unsigned int
-#endif
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY -2
-#define YYEOF 0
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrlab1
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-#define YYFAIL goto yyerrlab
-#define YYRECOVERING() (!!yyerrstatus)
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yychar1 = YYTRANSLATE (yychar); \
- YYPOPSTACK; \
- goto yybackup; \
- } \
- else \
- { \
- yyerror ("syntax error: cannot back up"); \
- YYERROR; \
- } \
-while (0)
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Compute the default location (before the actions
- are run).
-
- When YYLLOC_DEFAULT is run, CURRENT is set the location of the
- first token. By default, to implement support for ranges, extend
- its range to the last symbol. */
-
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- Current.last_line = Rhs[N].last_line; \
- Current.last_column = Rhs[N].last_column;
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#if YYPURE
-# if YYLSP_NEEDED
-# ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
-# else
-# define YYLEX yylex (&yylval, &yylloc)
-# endif
-# else /* !YYLSP_NEEDED */
-# ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, YYLEX_PARAM)
-# else
-# define YYLEX yylex (&yylval)
-# endif
-# endif /* !YYLSP_NEEDED */
-#else /* !YYPURE */
-# define YYLEX yylex ()
-#endif /* !YYPURE */
-
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (0)
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-#endif /* !YYDEBUG */
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#if YYMAXDEPTH == 0
-# undef YYMAXDEPTH
-#endif
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-#ifdef YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined (__GLIBC__) && defined (_STRING_H)
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-static YYSIZE_T
-# if defined (__STDC__) || defined (__cplusplus)
-yystrlen (const char *yystr)
-# else
-yystrlen (yystr)
- const char *yystr;
-# endif
-{
- register const char *yys = yystr;
-
- while (*yys++ != '\0')
- continue;
-
- return yys - yystr - 1;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-static char *
-# if defined (__STDC__) || defined (__cplusplus)
-yystpcpy (char *yydest, const char *yysrc)
-# else
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-# endif
-{
- register char *yyd = yydest;
- register const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-#endif
-
-#line 315 "/usr/share/bison/bison.simple"
-
-
-/* The user can define YYPARSE_PARAM as the name of an argument to be passed
- into yyparse. The argument should have type void *.
- It should actually point to an object.
- Grammar actions can access the variable by casting it
- to the proper pointer type. */
-
-#ifdef YYPARSE_PARAM
-# if defined (__STDC__) || defined (__cplusplus)
-# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
-# define YYPARSE_PARAM_DECL
-# else
-# define YYPARSE_PARAM_ARG YYPARSE_PARAM
-# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
-# endif
-#else /* !YYPARSE_PARAM */
-# define YYPARSE_PARAM_ARG
-# define YYPARSE_PARAM_DECL
-#endif /* !YYPARSE_PARAM */
-
-/* Prevent warning if -Wstrict-prototypes. */
-#ifdef __GNUC__
-# ifdef YYPARSE_PARAM
-int yyparse (void *);
-# else
-int yyparse (void);
-# endif
-#endif
-
-/* YY_DECL_VARIABLES -- depending whether we use a pure parser,
- variables are global, or local to YYPARSE. */
-
-#define YY_DECL_NON_LSP_VARIABLES \
-/* The lookahead symbol. */ \
-int yychar; \
- \
-/* The semantic value of the lookahead symbol. */ \
-YYSTYPE yylval; \
- \
-/* Number of parse errors so far. */ \
-int yynerrs;
-
-#if YYLSP_NEEDED
-# define YY_DECL_VARIABLES \
-YY_DECL_NON_LSP_VARIABLES \
- \
-/* Location data for the lookahead symbol. */ \
-YYLTYPE yylloc;
-#else
-# define YY_DECL_VARIABLES \
-YY_DECL_NON_LSP_VARIABLES
-#endif
-
-
-/* If nonreentrant, generate the variables here. */
-
-#if !YYPURE
-YY_DECL_VARIABLES
-#endif /* !YYPURE */
-
-int
-yyparse (YYPARSE_PARAM_ARG)
- YYPARSE_PARAM_DECL
-{
- /* If reentrant, generate the variables here. */
-#if YYPURE
- YY_DECL_VARIABLES
-#endif /* !YYPURE */
-
- register int yystate;
- register int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Lookahead token as an internal (translated) token number. */
- int yychar1 = 0;
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- short yyssa[YYINITDEPTH];
- short *yyss = yyssa;
- register short *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- register YYSTYPE *yyvsp;
-
-#if YYLSP_NEEDED
- /* The location stack. */
- YYLTYPE yylsa[YYINITDEPTH];
- YYLTYPE *yyls = yylsa;
- YYLTYPE *yylsp;
-#endif
-
-#if YYLSP_NEEDED
-# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
-#else
-# define YYPOPSTACK (yyvsp--, yyssp--)
-#endif
-
- YYSIZE_T yystacksize = YYINITDEPTH;
-
-
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-#if YYLSP_NEEDED
- YYLTYPE yyloc;
-#endif
-
- /* When reducing, the number of symbols on the RHS of the reduced
- rule. */
- int yylen;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
-
- yyssp = yyss;
- yyvsp = yyvs;
-#if YYLSP_NEEDED
- yylsp = yyls;
-#endif
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. so pushing a state here evens the stacks.
- */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyssp >= yyss + yystacksize - 1)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- short *yyss1 = yyss;
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. */
-# if YYLSP_NEEDED
- YYLTYPE *yyls1 = yyls;
- /* This used to be a conditional around just the two extra args,
- but that might be undefined if yyoverflow is a macro. */
- yyoverflow ("parser stack overflow",
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
- &yyls1, yysize * sizeof (*yylsp),
- &yystacksize);
- yyls = yyls1;
-# else
- yyoverflow ("parser stack overflow",
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
- &yystacksize);
-# endif
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyoverflowlab;
-# else
- /* Extend the stack our own way. */
- if (yystacksize >= YYMAXDEPTH)
- goto yyoverflowlab;
- yystacksize *= 2;
- if (yystacksize > YYMAXDEPTH)
- yystacksize = YYMAXDEPTH;
-
- {
- short *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyoverflowlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-# if YYLSP_NEEDED
- YYSTACK_RELOCATE (yyls);
-# endif
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
-#if YYLSP_NEEDED
- yylsp = yyls + yysize - 1;
-#endif
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyssp >= yyss + yystacksize - 1)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- goto yybackup;
-
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
-/* Do appropriate processing given the current state. */
-/* Read a lookahead token if we need one and don't already have one. */
-/* yyresume: */
-
- /* First try to decide what to do without reference to lookahead token. */
-
- yyn = yypact[yystate];
- if (yyn == YYFLAG)
- goto yydefault;
-
- /* Not known => get a lookahead token if don't already have one. */
-
- /* yychar is either YYEMPTY or YYEOF
- or a valid token in external form. */
-
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- /* Convert token to internal form (in yychar1) for indexing tables with */
-
- if (yychar <= 0) /* This means end of input. */
- {
- yychar1 = 0;
- yychar = YYEOF; /* Don't call YYLEX any more */
-
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yychar1 = YYTRANSLATE (yychar);
-
-#if YYDEBUG
- /* We have to keep this `#if YYDEBUG', since we use variables
- which are defined only if `YYDEBUG' is set. */
- if (yydebug)
- {
- YYFPRINTF (stderr, "Next token is %d (%s",
- yychar, yytname[yychar1]);
- /* Give the individual parser a way to print the precise
- meaning of a token, for further debugging info. */
-# ifdef YYPRINT
- YYPRINT (stderr, yychar, yylval);
-# endif
- YYFPRINTF (stderr, ")\n");
- }
-#endif
- }
-
- yyn += yychar1;
- if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
- goto yydefault;
-
- yyn = yytable[yyn];
-
- /* yyn is what to do for this token type in this state.
- Negative => reduce, -yyn is rule number.
- Positive => shift, yyn is new state.
- New state is final state => don't bother to shift,
- just return success.
- 0, or most negative number => error. */
-
- if (yyn < 0)
- {
- if (yyn == YYFLAG)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
- else if (yyn == 0)
- goto yyerrlab;
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Shift the lookahead token. */
- YYDPRINTF ((stderr, "Shifting token %d (%s), ",
- yychar, yytname[yychar1]));
-
- /* Discard the token being shifted unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- *++yyvsp = yylval;
-#if YYLSP_NEEDED
- *++yylsp = yylloc;
-#endif
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to the semantic value of
- the lookahead token. This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
-#if YYLSP_NEEDED
- /* Similarly for the default location. Let the user run additional
- commands if for instance locations are ranges. */
- yyloc = yylsp[1-yylen];
- YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
-#endif
-
-#if YYDEBUG
- /* We have to keep this `#if YYDEBUG', since we use variables which
- are defined only if `YYDEBUG' is set. */
- if (yydebug)
- {
- int yyi;
-
- YYFPRINTF (stderr, "Reducing via rule %d (line %d), ",
- yyn, yyrline[yyn]);
-
- /* Print the symbols being reduced, and their result. */
- for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++)
- YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
- YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]);
- }
-#endif
-
- switch (yyn) {
-
-case 3:
-#line 66 "icalssyacc.y"
-{
- yyclearin;
- YYABORT;
- }
- break;
-case 4:
-#line 73 "icalssyacc.y"
-{ssyacc_add_select(icalss_yy_gauge,yyvsp[0].v_string);}
- break;
-case 5:
-#line 74 "icalssyacc.y"
-{ssyacc_add_select(icalss_yy_gauge,yyvsp[0].v_string);}
- break;
-case 6:
-#line 79 "icalssyacc.y"
-{ssyacc_add_from(icalss_yy_gauge,yyvsp[0].v_string);}
- break;
-case 7:
-#line 80 "icalssyacc.y"
-{ssyacc_add_from(icalss_yy_gauge,yyvsp[0].v_string);}
- break;
-case 9:
-#line 85 "icalssyacc.y"
-{ssyacc_add_where(icalss_yy_gauge,yyvsp[-2].v_string,ICALGAUGECOMPARE_EQUAL,yyvsp[0].v_string); }
- break;
-case 10:
-#line 86 "icalssyacc.y"
-{ssyacc_add_where(icalss_yy_gauge,yyvsp[-2].v_string,ICALGAUGECOMPARE_ISNULL,""); }
- break;
-case 11:
-#line 87 "icalssyacc.y"
-{ssyacc_add_where(icalss_yy_gauge,yyvsp[-3].v_string,ICALGAUGECOMPARE_ISNOTNULL,""); }
- break;
-case 12:
-#line 88 "icalssyacc.y"
-{ssyacc_add_where(icalss_yy_gauge,yyvsp[-2].v_string,ICALGAUGECOMPARE_NOTEQUAL,yyvsp[0].v_string); }
- break;
-case 13:
-#line 89 "icalssyacc.y"
-{ssyacc_add_where(icalss_yy_gauge,yyvsp[-2].v_string,ICALGAUGECOMPARE_LESS,yyvsp[0].v_string); }
- break;
-case 14:
-#line 90 "icalssyacc.y"
-{ssyacc_add_where(icalss_yy_gauge,yyvsp[-2].v_string,ICALGAUGECOMPARE_GREATER,yyvsp[0].v_string); }
- break;
-case 15:
-#line 91 "icalssyacc.y"
-{ssyacc_add_where(icalss_yy_gauge,yyvsp[-2].v_string,ICALGAUGECOMPARE_LESSEQUAL,yyvsp[0].v_string); }
- break;
-case 16:
-#line 92 "icalssyacc.y"
-{ssyacc_add_where(icalss_yy_gauge,yyvsp[-2].v_string,ICALGAUGECOMPARE_GREATEREQUAL,yyvsp[0].v_string); }
- break;
-case 17:
-#line 96 "icalssyacc.y"
-{set_logic(icalss_yy_gauge,ICALGAUGELOGIC_NONE);}
- break;
-case 18:
-#line 97 "icalssyacc.y"
-{set_logic(icalss_yy_gauge,ICALGAUGELOGIC_AND);}
- break;
-case 19:
-#line 98 "icalssyacc.y"
-{set_logic(icalss_yy_gauge,ICALGAUGELOGIC_OR);}
- break;
-}
-
-#line 705 "/usr/share/bison/bison.simple"
-
-
- yyvsp -= yylen;
- yyssp -= yylen;
-#if YYLSP_NEEDED
- yylsp -= yylen;
-#endif
-
-#if YYDEBUG
- if (yydebug)
- {
- short *yyssp1 = yyss - 1;
- YYFPRINTF (stderr, "state stack now");
- while (yyssp1 != yyssp)
- YYFPRINTF (stderr, " %d", *++yyssp1);
- YYFPRINTF (stderr, "\n");
- }
-#endif
-
- *++yyvsp = yyval;
-#if YYLSP_NEEDED
- *++yylsp = yyloc;
-#endif
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
- if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTBASE];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-
-#ifdef YYERROR_VERBOSE
- yyn = yypact[yystate];
-
- if (yyn > YYFLAG && yyn < YYLAST)
- {
- YYSIZE_T yysize = 0;
- char *yymsg;
- int yyx, yycount;
-
- yycount = 0;
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- for (yyx = yyn < 0 ? -yyn : 0;
- yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
- if (yycheck[yyx + yyn] == yyx)
- yysize += yystrlen (yytname[yyx]) + 15, yycount++;
- yysize += yystrlen ("parse error, unexpected ") + 1;
- yysize += yystrlen (yytname[YYTRANSLATE (yychar)]);
- yymsg = (char *) YYSTACK_ALLOC (yysize);
- if (yymsg != 0)
- {
- char *yyp = yystpcpy (yymsg, "parse error, unexpected ");
- yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]);
-
- if (yycount < 5)
- {
- yycount = 0;
- for (yyx = yyn < 0 ? -yyn : 0;
- yyx < (int) (sizeof (yytname) / sizeof (char *));
- yyx++)
- if (yycheck[yyx + yyn] == yyx)
- {
- const char *yyq = ! yycount ? ", expecting " : " or ";
- yyp = yystpcpy (yyp, yyq);
- yyp = yystpcpy (yyp, yytname[yyx]);
- yycount++;
- }
- }
- yyerror (yymsg);
- YYSTACK_FREE (yymsg);
- }
- else
- yyerror ("parse error; also virtual memory exhausted");
- }
- else
-#endif /* defined (YYERROR_VERBOSE) */
- yyerror ("parse error");
- }
- goto yyerrlab1;
-
-
-/*--------------------------------------------------.
-| yyerrlab1 -- error raised explicitly by an action |
-`--------------------------------------------------*/
-yyerrlab1:
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse lookahead token after an
- error, discard it. */
-
- /* return failure if at end of input */
- if (yychar == YYEOF)
- YYABORT;
- YYDPRINTF ((stderr, "Discarding token %d (%s).\n",
- yychar, yytname[yychar1]));
- yychar = YYEMPTY;
- }
-
- /* Else will try to reuse lookahead token after shifting the error
- token. */
-
- yyerrstatus = 3; /* Each real token shifted decrements this */
-
- goto yyerrhandle;
-
-
-/*-------------------------------------------------------------------.
-| yyerrdefault -- current state does not do anything special for the |
-| error token. |
-`-------------------------------------------------------------------*/
-yyerrdefault:
-#if 0
- /* This is wrong; only states that explicitly want error tokens
- should shift them. */
-
- /* If its default is to accept any token, ok. Otherwise pop it. */
- yyn = yydefact[yystate];
- if (yyn)
- goto yydefault;
-#endif
-
-
-/*---------------------------------------------------------------.
-| yyerrpop -- pop the current state because it cannot handle the |
-| error token |
-`---------------------------------------------------------------*/
-yyerrpop:
- if (yyssp == yyss)
- YYABORT;
- yyvsp--;
- yystate = *--yyssp;
-#if YYLSP_NEEDED
- yylsp--;
-#endif
-
-#if YYDEBUG
- if (yydebug)
- {
- short *yyssp1 = yyss - 1;
- YYFPRINTF (stderr, "Error: state stack now");
- while (yyssp1 != yyssp)
- YYFPRINTF (stderr, " %d", *++yyssp1);
- YYFPRINTF (stderr, "\n");
- }
-#endif
-
-/*--------------.
-| yyerrhandle. |
-`--------------*/
-yyerrhandle:
- yyn = yypact[yystate];
- if (yyn == YYFLAG)
- goto yyerrdefault;
-
- yyn += YYTERROR;
- if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
- goto yyerrdefault;
-
- yyn = yytable[yyn];
- if (yyn < 0)
- {
- if (yyn == YYFLAG)
- goto yyerrpop;
- yyn = -yyn;
- goto yyreduce;
- }
- else if (yyn == 0)
- goto yyerrpop;
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- YYDPRINTF ((stderr, "Shifting error token, "));
-
- *++yyvsp = yylval;
-#if YYLSP_NEEDED
- *++yylsp = yylloc;
-#endif
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-/*---------------------------------------------.
-| yyoverflowab -- parser overflow comes here. |
-`---------------------------------------------*/
-yyoverflowlab:
- yyerror ("parser stack overflow");
- yyresult = 2;
- /* Fall through. */
-
-yyreturn:
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
- return yyresult;
-}
-#line 102 "icalssyacc.y"
-
-
-static void ssyacc_add_where(struct icalgauge_impl* impl, char* str1,
- icalgaugecompare compare , char* value_str)
-{
-
- struct icalgauge_where *where;
- char *compstr, *propstr, *c, *s,*l;
-
- if ( (where = malloc(sizeof(struct icalgauge_where))) ==0){
- icalerror_set_errno(ICAL_NEWFAILED_ERROR);
- return;
- }
-
- memset(where,0,sizeof(struct icalgauge_where));
- where->logic = ICALGAUGELOGIC_NONE;
- where->compare = ICALGAUGECOMPARE_NONE;
- where->comp = ICAL_NO_COMPONENT;
- where->prop = ICAL_NO_PROPERTY;
-
- /* remove enclosing quotes */
- s = value_str;
- if(*s == '\''){
- s++;
- }
- l = s+strlen(s)-1;
- if(*l == '\''){
- *l=0;
- }
-
- where->value = strdup(s);
-
- /* Is there a period in str1 ? If so, the string specified both a
- component and a property*/
- if( (c = strrchr(str1,'.')) != 0){
- compstr = str1;
- propstr = c+1;
- *c = '\0';
- } else {
- compstr = 0;
- propstr = str1;
- }
-
-
- /* Handle the case where a component was specified */
- if(compstr != 0){
- where->comp = icalenum_string_to_component_kind(compstr);
- } else {
- where->comp = ICAL_NO_COMPONENT;
- }
-
- where->prop = icalenum_string_to_property_kind(propstr);
-
- where->compare = compare;
-
- if(where->value == 0){
- icalerror_set_errno(ICAL_NEWFAILED_ERROR);
- free(where->value);
- return;
- }
-
- pvl_push(impl->where,where);
-}
-
-static void set_logic(struct icalgauge_impl* impl,icalgaugelogic l)
-{
- pvl_elem e = pvl_tail(impl->where);
- struct icalgauge_where *where = pvl_data(e);
-
- where->logic = l;
-
-}
-
-
-
-static void ssyacc_add_select(struct icalgauge_impl* impl, char* str1)
-{
- char *c, *compstr, *propstr;
- struct icalgauge_where *where;
-
- /* Uses only the prop and comp fields of the where structure */
- if ( (where = malloc(sizeof(struct icalgauge_where))) ==0){
- icalerror_set_errno(ICAL_NEWFAILED_ERROR);
- return;
- }
-
- memset(where,0,sizeof(struct icalgauge_where));
- where->logic = ICALGAUGELOGIC_NONE;
- where->compare = ICALGAUGECOMPARE_NONE;
- where->comp = ICAL_NO_COMPONENT;
- where->prop = ICAL_NO_PROPERTY;
-
- /* Is there a period in str1 ? If so, the string specified both a
- component and a property*/
- if( (c = strrchr(str1,'.')) != 0){
- compstr = str1;
- propstr = c+1;
- *c = '\0';
- } else {
- compstr = 0;
- propstr = str1;
- }
-
-
- /* Handle the case where a component was specified */
- if(compstr != 0){
- where->comp = icalenum_string_to_component_kind(compstr);
- } else {
- where->comp = ICAL_NO_COMPONENT;
- }
-
-
- /* If the property was '*', then accept all properties */
- if(strcmp("*",propstr) == 0) {
- where->prop = ICAL_ANY_PROPERTY;
- } else {
- where->prop = icalenum_string_to_property_kind(propstr);
- }
-
-
- if(where->prop == ICAL_NO_PROPERTY){
- free(where);
- icalerror_set_errno(ICAL_BADARG_ERROR);
- return;
- }
-
- pvl_push(impl->select,where);
-}
-
-static void ssyacc_add_from(struct icalgauge_impl* impl, char* str1)
-{
- icalcomponent_kind ckind;
-
- ckind = icalenum_string_to_component_kind(str1);
-
- if(ckind == ICAL_NO_COMPONENT){
- assert(0);
- }
-
- pvl_push(impl->from,(void*)ckind);
-
-}
-
-
-void sserror(char *s){
- fprintf(stderr,"Parse error \'%s\'\n", s);
- icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
-}
diff --git a/libical/src/libicalss/icalssyacc.y b/libical/src/libicalss/icalssyacc.y
index 85ee6c64c5..101adc8383 100644
--- a/libical/src/libicalss/icalssyacc.y
+++ b/libical/src/libicalss/icalssyacc.y
@@ -6,7 +6,7 @@
DESCRIPTION:
- $Id: icalssyacc.y,v 1.3 2003/09/24 02:06:52 hansp Exp $
+ $Id: icalssyacc.y,v 1.4 2003/10/21 18:28:18 ettore Exp $
$Locker: $
(C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
@@ -30,7 +30,7 @@
#include <stdlib.h>
#include <string.h> /* for strdup() */
#include <limits.h> /* for SHRT_MAX*/
-#include "ical.h"
+#include <libical/ical.h>
#include "icalgauge.h"
#include "icalgaugeimpl.h"
diff --git a/mail/ChangeLog b/mail/ChangeLog
index 1ca3dae2d2..a5548f1232 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,3 +1,85 @@
+2003-10-21 Not Zed <NotZed@Ximian.com>
+
+ * mail-component.c (emc_popup_properties): implement.
+ (emc_popup_properties_got_folder): builds dynamic
+ folder-properties dialogue.
+ (emc_popup_properties_response): set the properties on the folder
+ on an ok response.
+ (emc_popup_properties_free): free the properties working data.
+
+ * mail-folder-cache.c (unset_folder_info): unhook from the right
+ function for message_changed.
+
+2003-10-20 Not Zed <NotZed@Ximian.com>
+
+ * mail-component.c (emc_popup_new_folder): pass the right object
+ to set_selected(). Fixes a new real bug. Undid reformatting.
+
+2003-10-17 Jeffrey Stedfast <fejj@ximian.com>
+
+ * mail-component.c: General compile fixes.
+ (emc_popup_new_folder): Fixed to not shadow a parameter. Fixes a
+ real bug.
+
+ * mail-component.h: Added some prototypes.
+
+2003-10-13 Not Zed <NotZed@Ximian.com>
+
+ * em-popup.c (em_popup_create_menu_once): only hookup target free
+ if we have a target set.
+
+ * mail-component.c (load_accounts): removed debug i accidentally
+ left in.
+ (emc_tree_right_click): handle right-click context menu, using an
+ EMPopup table.
+ (emc_popup_*): setup empty popup handlers.
+
+2003-10-13 Not Zed <NotZed@Ximian.com>
+
+ * em-folder-selection.c (em_select_folder): asynchornous folder
+ selection call.
+ (emfs_folder_selected): callback for folder selected.
+
+ * em-folder-view.c (emfv_popup_move): implement.
+ (emfv_popup_copy): "
+ (emfv_popup_move_cb): async folder select callback to run it.
+
+2003-10-10 Not Zed <NotZed@Ximian.com>
+
+ * mail-account-gui.c
+ (mail_account_gui_folder_selector_button_new): use
+ em_folder_selection_button.
+ (mail_account_gui_new): "
+ (folder_selected): "
+
+ * em-folder-selection-button.c: Make this use camel uri's rather
+ than camelfolders.
+ (set_selection): removed, redundant.
+ (impl_dispose): removed, not needed.
+
+ * em-folder-selection-button.h: change the selected signal not to
+ actually return the selection, which must get retrieved later.
+
+ * mail-component.c (em_uri_from_camel): create an evo mail uri
+ from a camel one.
+ (em_uri_to_camel): the reverse.
+
+ * mail-signature-editor.c (mail_signature_editor): up the version
+ of the gtkhtml editor.
+
+2003-10-09 Not Zed <NotZed@Ximian.com>
+
+ * em-folder-selection-button.c (set_selection): always set
+ selected_folder, otherwise we don't unset it properly.
+
+ * em-folder-selection.c (em_folder_selection_run_dialog): fix a
+ small memleak.
+ (em_folder_selection_run_dialog_uri): do the same as run_dialog
+ but take, and return physical uri's.
+
+ * mail-component-factory.c (factory): removed some fixme's, and
+ re-hookedup the composer.
+
2003-10-09 Frederic Crozat <fcrozat@mandrakesoft.com>
* em-icon-stream.c: (emis_sync_close):
@@ -10,6 +92,38 @@
create-rule-from-message bars so that we don't segfault when we
right click with a multi-selection.
+2003-10-08 Chris Toshok <toshok@ximian.com>
+
+ * em-utils.c (em_utils_camel_address_to_destination): EDestination
+ => EABDestination, and e_destination => eab_destination.
+ (reply_get_composer): same.
+ (post_reply_to_message): same.
+
+ * em-composer-utils.c (ask_confirm_for_unwanted_html_mail)
+ EDestination => EABDestination, and e_destination =>
+ eab_destination.
+ (composer_get_message):same.
+
+2003-10-08 Not Zed <NotZed@Ximian.com>
+
+ * mail-component.c (mail_component_peek): setup vfolders once we
+ hve the component, since its setup will call mail_component_peek,
+ fun recursion.
+
+2003-10-08 Not Zed <NotZed@Ximian.com>
+
+ * mail-component.c (setup_local_folder): removed.
+ (setup_local_store): setup various needed globals properly.
+ (setup_account_storages): renamed to load_accounts.
+ (go_online): turn on interactivity as well as onlinedness.
+
+ * GNOME_Evolution_Mail.server.in.in: point the preferences pages
+ to the right factory.
+
+2003-10-07 Not Zed <NotZed@Ximian.com>
+
+ * mail-component.[ch]: Fix copyrights.
+
2003-10-06 Jeffrey Stedfast <fejj@ximian.com>
* mail-config-druid.c (identity_prepare): Fixed.
@@ -28,6 +142,22 @@
the first unread message for now. This is actually annoying the
fuck out of me, Radek, and a few other people.
+2003-10-02 Not Zed <NotZed@Ximian.com>
+
+ * mail-component.c (add_storage): Add the storage to the hash
+ after we've initialised it.
+ (mail_component_evomail_uri_from_folder): hardcode "local" account
+ pseudo-id for local folders.
+ (mail_component_get_folder_from_evomail_uri): handle the "local"
+ account case.
+
+2003-10-02 Not Zed <NotZed@Ximian.com>
+
+ * mail-component.c (setup_local_store): use mbox:/path rather than
+ mbox:///path - the mbox code is 'wrong', but this is easier to
+ fix. fixes local unread counts. maybe the provider url-compare
+ should address this too.
+
2003-10-02 Suresh Chandrasekharan <suresh.chandrasekharan@sun.com>
* mail-config-druid.c: Fix for 40917 "Backspace shouldn't
@@ -101,6 +231,27 @@
* em-format.c (emf_init): Oops, put the arguments in the right order.
+2003-09-29 Ettore Perazzoli <ettore@ximian.com>
+
+ * mail-component.c: New member local_store in
+ MailComponentPrivate.
+ (impl_dispose): Unref.
+ (mail_component_load_storage_by_uri): Return the CamelStore.
+ (setup_local_folder): New.
+ (setup_local_store): New.
+ (mail_component_init): Call it.
+ (mail_component_peek_storage_set): New.
+ (mail_component_get_folder_from_evomail_uri): New.
+ (mail_component_evomail_uri_from_folder): New.
+
+ * em-folder-selection-button.c: New.
+ * em-folder-selection-button.h: New.
+
+ * em-folder-selection.c: New.
+ * em-folder-selection.h: New.
+
+ * em-marshal.list: Add NONE:POINTER.
+
2003-09-25 Jeffrey Stedfast <fejj@ximian.com>
* mail-account-gui.c (mail_account_gui_save): Allow any file: uri
@@ -120,6 +271,33 @@
charset string is empty, default the charset to the user's locale
charset. Partial fix for bug #47638.
+2003-09-23 Ettore Perazzoli <ettore@ximian.com>
+
+ * mail-component.c (add_storage): Remove unused arg "uri".
+ (mail_component_add_store): Likewise.
+ (add_storage): Don't set the "Connecting..." node.
+ (mail_component_init): Set up local store at
+ ~/.evolution/mail/local.
+
+ * evolution-mbox-upgrade.c (get_local_store): Remove a double
+ xmlFree() that was causing it to crash.
+
+
+2003-09-23 Ettore Perazzoli <ettore@ximian.com>
+
+ * mail-component.c (add_storage): Note the new store.
+
+ * mail-component-factory.c: Don't include "mail-callbacks.h"
+ anymore.
+
+ * em-format-html.c (em_format_html_get_type): Get the base
+ directory with mail_component_peek_base_directory().
+ * em-utils.c (filter_editor_response): Likewise.
+ (em_utils_edit_filters): Likewise.
+
+ * em-folder-browser.c (emfb_init): Get the search context through
+ mail_component_peek_search_context().
+
2003-09-23 Jeffrey Stedfast <fejj@ximian.com>
* evolution-mbox-upgrade.c (get_local_store): Don't xmlFree (name)
@@ -273,6 +451,14 @@
* evolution-mbox-upgrade.c: New source file to migrate from the
old mbox structure to the new mbox structure.
+2003-09-08 Ettore Perazzoli <ettore@ximian.com>
+
+ * mail-folder-cache.c (mail_note_store): Allow NULL storage in
+ precondition.
+
+ * mail-component.c (mail_component_init): Remove debugging
+ message.
+
2003-08-22 Not Zed <NotZed@Ximian.com>
* mail-format.c (write_date): translate the local time format.
@@ -284,14 +470,13 @@
day names, and the autoconf magic which made Not Zed dislike the
inclusion of the timezone name.
-2003-08-14 Jeffrey Stedfast <fejj@ximian.com>
+2003-08-18 Ettore Perazzoli <ettore@ximian.com>
- * mail-ops.c (mail_send_message): Don't abort at the first failure
- after sending (filtering, appending to Sent, syncing). Instead,
- keep a running tab of exceptions and then set a culmulative
- exception at the end to report to our caller. Also, if we fail to
- append to the account Sent folder, try again with the local Sent
- folder. Fixes bug #46512.
+ * GNOME_Evolution_Mail.server.in.in: Rename
+ GNOME_Evolution_Mail_Component2 to
+ GNOME_Evolution_Mail_Component_2 and GNOME_Evolution_Mail_Factory2
+ to GNOME_Evolution_Mail_Factory_2.
+ * mail-component-factory.c: Update accordingly.
2003-08-18 Jeffrey Stedfast <fejj@ximian.com>
@@ -336,6 +521,15 @@
* mail-display.c (mail_display_render): Change "%P" to "%p" so
that strftime() can work under solaris.
+2003-08-14 Jeffrey Stedfast <fejj@ximian.com>
+
+ * mail-ops.c (mail_send_message): Don't abort at the first failure
+ after sending (filtering, appending to Sent, syncing). Instead,
+ keep a running tab of exceptions and then set a culmulative
+ exception at the end to report to our caller. Also, if we fail to
+ append to the account Sent folder, try again with the local Sent
+ folder. Fixes bug #46512.
+
2003-08-13 Suresh Chandrasekharan <suresh.chandrasekharan@sun.com>
* e-searching-tokenizer.c (searcher_next_token): Fix for 45818 (
@@ -353,6 +547,12 @@
* mail-session.c (remove_timeout): Removed.
(register_timeout): Removed.
+2003-08-09 Ettore Perazzoli <ettore@ximian.com>
+
+ * mail-component.c (storage_go_online): Pass NULL for the
+ operation pointer to mail_note_store(), to sync with Michael's
+ changes.
+
2003-08-05 Jeffrey Stedfast <fejj@ximian.com>
* mail-format.c (handle_multipart_encrypted): Updated for
@@ -1308,6 +1508,154 @@
* message-browser.c (message_browser_new): Handle our own Delete
key presses. Fixes bug #45597.
+2003-07-25 Ettore Perazzoli <ettore@ximian.com>
+
+ * mail-callbacks.c (do_view_message): No need to pass a shell
+ argument to message_browser_new() anymore.
+
+ * message-browser.c (message_browser_new): Removed arg shell. No
+ need to pass it to folder_browser_new() either.
+
+ * mail-component.c (create_view_callback): No need to pass a shell
+ arg to folder_browser_factory_new_control() anymore.
+
+ * folder-browser-factory.c (folder_browser_factory_new_control):
+ Removed arg shell; folder_browser_browser_new() doesn't need it
+ anymore.
+
+ * folder-browser.c (folder_browser_destroy): No need to unref
+ ->shell anymore.
+ (folder_browser_new): Removed shell arg.
+ (folder_browser_gui_init): Removed a const qualifier that was not
+ supposed to be there.
+
+ * folder-browser.h: Removed member shell from struct
+ FolderBrowser.
+
+2003-07-25 Ettore Perazzoli <ettore@ximian.com>
+
+ * folder-browser.c (folder_browser_gui_init): Get the search
+ context through mail_component_peek_search_context(), since it's
+ no longer a global variable.
+ (folder_browser_gui_init): Cleaned up an extra unneeded if()
+ statement.
+
+ * mail-component.c: New member search_context in struct
+ MailComponentPrivate.
+ (mail_component_peek_search_context): New.
+ (setup_search_context): New function to initialize the
+ search_context, based on the old code in component-factory.c.
+ (mail_component_init): Call it here.
+ (impl_dispose): Unref the rule_context.
+
+ * mail-component-factory.c: Removed global variable
+ search_context.
+
+2003-07-25 Ettore Perazzoli <ettore@ximian.com>
+
+ * mail-component.c (browser_page_switched_callback): New callback
+ for the "page_switched" signal on EStorageBrowser; deactivate the
+ previous page, activate the new one.
+ (impl_createControls): Connect.
+
+2003-07-24 Ettore Perazzoli <ettore@ximian.com>
+
+ * mail-mt.c (do_op_status): Pass "evolution-mail" as the ID to
+ evolution_activity_client_new(). [This is just a temporary thing
+ to avoid the fact that we don't have component-factory.h anymore.
+ Eventually we'll just get rid of the activity client stuff.]
+
+ * mail-component-factory.c: Added to the build. Also, finished
+ implementing and moving the factory over from component-factory.c.
+
+ * component-factory.c: Removed from the build.
+ * component-factory.h: Removed from the build.
+
+ * mail-component.c: Removed some debugging messages.
+
+2003-07-23 Ettore Perazzoli <ettore@ximian.com>
+
+ * subscribe-dialog.c: Converted to use EStorages instead of
+ EvolutionStorages and the new MailComponent object.
+
+ * mail.h: Nuked a bunch of stuff. This will go away when I am
+ done refactoring.
+
+ * mail-offline-handler.c: Use the new MailComponent object.
+
+ * mail-folder-cache.c, mail-folder-cache.h: Converted to use
+ EStorages instead of EvolutionStorages.
+
+ * mail-display.c: Use g_timeout and g_source functions instead of
+ gtk_timeout functions.
+
+ * mail-send-recv.c: Use g_timeout and g_source functions instead
+ of gtk_timeout functions.
+ (receive_update_got_store): Updated for the new mail_note_store().
+
+ * mail-session.c: Use g_timeout and g_source functions instead of
+ gtk_timeout functions.
+
+ * mail-config-factory.c (factory): Removed.
+
+ * folder-browser.c (folder_browser_destroy): Use GLib
+ timeout/source functions instead of the deprecated GTK ones.
+ (done_message_selected): Likewise.
+ (folder_browser_gui_init): Protect against fb->search being NULL.
+
+ * mail-account-gui.c (add_new_store): Use new MailComponent object
+ and EStorages instead of EvolutionStorages.
+ (mail_account_gui_save): Likewise.
+
+ * mail-accounts.c (account_delete_clicked): Use new MailComponent
+ object and EStorages instead of EvolutionStorages.
+ (account_able_clicked): Likewise.
+ (account_able_toggled): Likewise.
+
+ * mail-autofilter.c: Use mail_component_peek_base_directory()
+ instead of the evolution_dir global.
+ * mail-callbacks.c: Likewise.
+ * mail-config.c (uri_to_evname): Likewise.
+ (mail_config_get_signature_list): Likewise.
+ (delete_unused_signature_file): Likewise.
+ * mail-display.c (mail_display_class_init): Likewise.
+ * mail-importer.c (mail_importer_make_local_folder): Likewise.
+ * mail-local.c (mlf_getv): Likewise.
+ * mail-ops.c (uid_cachename_hack): Likewise.
+ * mail-summary.c (generate_folder_summaries): Likewise.
+ * mail-tools.c (mail_tool_get_local_inbox): Likewise.
+ (mail_tools_folder_to_url): Likewise.
+ * mail-vfolder.c (mail_vfolder_delete_uri): Likewise.
+ (mail_vfolder_rename_uri): Likewise.
+ (context_rule_removed): Likewise.
+ (store_folder_deleted): Likewise.
+ (store_folder_renamed): Likewise.
+ (vfolder_load_storage): Likewise.
+ (vfolder_editor_response): Likewise.
+ (edit_rule_response): Likewise.
+ (new_rule_clicked): Likewise.
+ (vfolder_gui_add_rule): Likewise.
+ * mail-session.c (main_get_filter_driver): Likewise.
+ (mail_session_forget_password): Likewise.
+ (mail_session_init): Get a base_directory arg.
+
+ * component-factory.c, component-factory.h: Disabled a bunch of
+ stuff to get it to compile in the new configuration. These files
+ will eventually go away when I am done refactoring this.
+
+ * Makefile.am: Do not build importers, compile generate
+ skels/stubs for Evolution.
+
+ * GNOME_Evolution_Mail.server.in.in: Rename control factory to
+ OAFIID:GNOME_Evolution_Mail_Factory2. Add new component
+ GNOME_Evolution_Mail_Component2.
+
+ * mail-component-factory.c: New file implementing the Bonobo
+ factory.
+
+ * mail-component.c, mail-component.h: New files implementing the
+ new mail component, using the new Evolution::Component IDL.
+
2003-07-23 Jeffrey Stedfast <fejj@ximian.com>
* mail-format.c (mail_format_data_wrapper_write_to_stream): Revert
diff --git a/mail/GNOME_Evolution_Mail.server.in.in b/mail/GNOME_Evolution_Mail.server.in.in
index 9d0391d0be..30fcd5b070 100644
--- a/mail/GNOME_Evolution_Mail.server.in.in
+++ b/mail/GNOME_Evolution_Mail.server.in.in
@@ -3,7 +3,7 @@
<!-- Folder display control -->
<!-- (factory) -->
- <oaf_server iid="OAFIID:GNOME_Evolution_Mail_ControlFactory"
+ <oaf_server iid="OAFIID:GNOME_Evolution_Mail_Factory_2"
type="shlib"
location="@COMPONENTDIR@/libevolution-mail.so">
@@ -29,6 +29,22 @@
_value="Evolution Mail folder viewer"/>
</oaf_server>
+ <!-- Component Interface -->
+
+ <oaf_server iid="OAFIID:GNOME_Evolution_Mail_Component_2"
+ type="factory"
+ location="OAFIID:GNOME_Evolution_Mail_Factory_2">
+
+ <oaf_attribute name="repo_ids" type="stringv">
+ <item value="IDL:GNOME/Evolution/Component:1.0"/>
+ </oaf_attribute>
+
+ <oaf_attribute name="name" type="string" _value="Evolution Mail component"/>
+
+ <oaf_attribute name="evolution:component_icon" type="string" value="evolution-inbox.png"/>
+ <oaf_attribute name="evolution:component_display_order" type="number" value="1"/>
+ </oaf_server>
+
<!-- Shell Component -->
<oaf_server iid="OAFIID:GNOME_Evolution_Mail_ShellComponent"
@@ -53,7 +69,7 @@
<!-- (composer) -->
<oaf_server iid="OAFIID:GNOME_Evolution_Mail_Composer"
type="factory"
- location="OAFIID:GNOME_Evolution_Mail_ControlFactory">
+ location="OAFIID:GNOME_Evolution_Mail_Factory_2">
<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:GNOME/Evolution:Composer:1.0"/>
@@ -109,7 +125,7 @@
<!-- Account Editor -->
<oaf_server iid="OAFIID:GNOME_Evolution_Mail_Accounts_ConfigControl"
type="factory"
- location="OAFIID:GNOME_Evolution_Mail_ControlFactory">
+ location="OAFIID:GNOME_Evolution_Mail_Factory_2">
<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:GNOME/Evolution/ConfigControl:1.0"/>
@@ -138,7 +154,7 @@
<!-- Mail Preferences -->
<oaf_server iid="OAFIID:GNOME_Evolution_Mail_Preferences_ConfigControl"
type="factory"
- location="OAFIID:GNOME_Evolution_Mail_ControlFactory">
+ location="OAFIID:GNOME_Evolution_Mail_Factory_2">
<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:GNOME/Evolution/ConfigControl:1.0"/>
@@ -163,7 +179,7 @@
<!-- Composer Preferences -->
<oaf_server iid="OAFIID:GNOME_Evolution_Mail_ComposerPrefs_ConfigControl"
type="factory"
- location="OAFIID:GNOME_Evolution_Mail_ControlFactory">
+ location="OAFIID:GNOME_Evolution_Mail_Factory_2">
<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:GNOME/Evolution/ConfigControl:1.0"/>
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 75802f396e..ac0b6827bd 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = importers
+SUBDIRS = # importers FIXME
libexec_PROGRAMS = \
evolution-mbox-upgrade
@@ -39,128 +39,153 @@ INCLUDES = \
component_LTLIBRARIES = libevolution-mail.la
-EVOLUTION_MAIL_CORBA_GENERATED_H = \
+
+# Code generation for Mailer.idl
+
+MAILER_IDL = Mailer.idl
+
+MAILER_IDL_GENERATED_H = \
Mailer.h
-EVOLUTION_MAIL_CORBA_GENERATED_C = \
+MAILER_IDL_GENERATED_C = \
Mailer-common.c \
Mailer-skels.c \
Mailer-stubs.c
-EVOLUTION_MAIL_CORBA_GENERATED = $(EVOLUTION_MAIL_CORBA_GENERATED_C) $(EVOLUTION_MAIL_CORBA_GENERATED_H)
+MAILER_IDL_GENERATED = $(MAILER_IDL_GENERATED_C) $(MAILER_IDL_GENERATED_H)
+
+$(MAILER_IDL_GENERATED_H): Mailer.idl
+ $(ORBIT_IDL) -I $(srcdir) -I $(datadir)/idl $(IDL_INCLUDES) $(srcdir)/Mailer.idl
+$(MAILER_IDL_GENERATED_C): $(MAILER_IDL_GENERATED_H)
+
+
+# Code generation for Spell.idl
SPELL_IDL = Spell.idl
-IDL_GENERATED_H = \
+SPELL_IDL_GENERATED_H = \
Spell.h
-IDL_GENERATED_C = \
+SPELL_IDL_GENERATED_C = \
Spell-common.c \
Spell-skels.c \
Spell-stubs.c
-IDL_GENERATED = $(IDL_GENERATED_C) $(IDL_GENERATED_H)
+SPELL_IDL_GENERATED = $(SPELL_IDL_GENERATED_C) $(SPELL_IDL_GENERATED_H)
-$(IDL_GENERATED_H): $(SPELL_IDL)
+$(SPELL_IDL_GENERATED_H): $(SPELL_IDL)
$(ORBIT_IDL) -I $(srcdir) -I $(datadir)/idl $(IDL_INCLUDES) $(srcdir)/Spell.idl
-$(IDL_GENERATED_C): $(IDL_GENERATED_H)
+$(SPELL_IDL_GENERATED_C): $(SPELL_IDL_GENERATED_H)
Spell-impl.o: Spell.h
-libevolution_mail_la_SOURCES = \
- $(EVOLUTION_MAIL_CORBA_GENERATED) \
- $(IDL_GENERATED) \
- component-factory.c \
- component-factory.h \
- e-searching-tokenizer.c \
- e-searching-tokenizer.h \
- em-inline-filter.c \
- em-inline-filter.h \
- em-folder-view.c \
- em-folder-view.h \
- em-folder-browser.c \
- em-folder-browser.h \
- em-format.c \
- em-format.h \
- em-format-html.c \
- em-format-html.h \
- em-format-html-display.c \
- em-format-html-display.h \
- em-format-html-print.c \
- em-format-html-print.h \
- em-format-html-quote.c \
- em-format-html-quote.h \
- em-format-quote.c \
- em-format-quote.h \
- em-marshal.c \
- em-marshal.h \
- em-message-browser.c \
- em-message-browser.h \
- em-composer-utils.c \
- em-composer-utils.h \
- em-popup.c \
- em-popup.h \
- em-utils.c \
- em-utils.h \
- em-subscribe-editor.c \
- em-subscribe-editor.h \
- em-sync-stream.c \
- em-sync-stream.h \
- em-icon-stream.c \
- em-icon-stream.h \
- em-html-stream.c \
- em-html-stream.h \
- folder-browser-factory.c \
- folder-browser-factory.h \
- folder-info.c \
- folder-info.h \
- mail-account-editor.c \
- mail-account-editor.h \
- mail-account-gui.c \
- mail-account-gui.h \
- mail-accounts.c \
- mail-accounts.h \
- mail-autofilter.c \
- mail-autofilter.h \
- mail-composer-prefs.c \
- mail-composer-prefs.h \
- mail-config.c \
- mail-config.h \
- mail-config-druid.c \
- mail-config-druid.h \
- mail-crypto.c \
- mail-crypto.h \
- mail-config-factory.c \
- mail-config-factory.h \
- mail-preferences.c \
- mail-preferences.h \
- mail-folder-cache.c \
- mail-folder-cache.h \
- mail-importer.c \
- mail-importer.h \
- mail-local.c \
- mail-local.h \
- mail-mt.c \
- mail-mt.h \
- mail-offline-handler.c \
- mail-offline-handler.h \
- mail-ops.c \
- mail-ops.h \
- mail-send-recv.c \
- mail-send-recv.h \
- mail-session.c \
- mail-session.h \
- mail-signature-editor.c \
- mail-signature-editor.h \
- mail-tools.c \
- mail-tools.h \
- mail-types.h \
- mail-vfolder.c \
- mail-vfolder.h \
- message-list.c \
- message-list.h \
- message-tag-editor.c \
- message-tag-editor.h \
- message-tag-followup.c \
- message-tag-followup.h \
+
+# libevolution-mail
+
+libevolution_mail_la_SOURCES = \
+ $(SPELL_IDL_GENERATED) \
+ $(MAILER_IDL_GENERATED) \
+ e-searching-tokenizer.c \
+ e-searching-tokenizer.h \
+ em-inline-filter.c \
+ em-inline-filter.h \
+ em-folder-selection.c \
+ em-folder-selection.h \
+ em-folder-selection-button.c \
+ em-folder-selection-button.h \
+ em-folder-selector.c \
+ em-folder-selector.h \
+ em-folder-view.c \
+ em-folder-view.h \
+ em-folder-browser.c \
+ em-folder-browser.h \
+ em-format.c \
+ em-format.h \
+ em-format-html.c \
+ em-format-html.h \
+ em-format-html-display.c \
+ em-format-html-display.h \
+ em-format-html-print.c \
+ em-format-html-print.h \
+ em-format-html-quote.c \
+ em-format-html-quote.h \
+ em-format-quote.c \
+ em-format-quote.h \
+ em-marshal.c \
+ em-marshal.h \
+ em-message-browser.c \
+ em-message-browser.h \
+ em-composer-utils.c \
+ em-composer-utils.h \
+ em-popup.c \
+ em-popup.h \
+ em-utils.c \
+ em-utils.h \
+ em-subscribe-editor.c \
+ em-subscribe-editor.h \
+ em-sync-stream.c \
+ em-sync-stream.h \
+ em-icon-stream.c \
+ em-icon-stream.h \
+ em-html-stream.c \
+ em-html-stream.h \
+ folder-browser-factory.c \
+ folder-browser-factory.h \
+ folder-info.c \
+ folder-info.h \
+ mail-account-editor.c \
+ mail-account-editor.h \
+ mail-account-gui.c \
+ mail-account-gui.h \
+ mail-accounts.c \
+ mail-accounts.h \
+ mail-autofilter.c \
+ mail-autofilter.h \
+ mail-component-factory.c \
+ mail-component.c \
+ mail-component.h \
+ mail-composer-prefs.c \
+ mail-composer-prefs.h \
+ mail-config.c \
+ mail-config.h \
+ mail-config-druid.c \
+ mail-config-druid.h \
+ mail-crypto.c \
+ mail-crypto.h \
+ mail-config-factory.c \
+ mail-config-factory.h \
+ mail-preferences.c \
+ mail-preferences.h \
+ mail-folder-cache.c \
+ mail-folder-cache.h \
+ mail-importer.c \
+ mail-importer.h \
+ mail-mt.c \
+ mail-mt.h \
+ mail-offline-handler.c \
+ mail-offline-handler.h \
+ mail-ops.c \
+ mail-ops.h \
+ mail-send-recv.c \
+ mail-send-recv.h \
+ mail-session.c \
+ mail-session.h \
+ mail-signature-editor.c \
+ mail-signature-editor.h \
+ mail-tools.c \
+ mail-tools.h \
+ mail-types.h \
+ mail-vfolder.c \
+ mail-vfolder.h \
+ message-list.c \
+ message-list.h \
+ message-tag-editor.c \
+ message-tag-editor.h \
+ message-tag-followup.c \
+ message-tag-followup.h \
mail.h
+# EPFIXME: Functionality to be brought back to life.
+#
+# mail-local.c
+# mail-local.h
+
libevolution_mail_la_LIBADD = \
$(top_builddir)/shell/importer/libevolution-importer.la \
$(top_builddir)/camel/libcamel.la \
@@ -177,6 +202,9 @@ libevolution_mail_la_LIBADD = \
libevolution_mail_la_LDFLAGS = \
-avoid-version -module
+
+# .server files
+
evolution_mbox_upgrade_SOURCES = evolution-mbox-upgrade.c
evolution_mbox_upgrade_LDADD = \
$(top_builddir)/camel/libcamel.la \
@@ -190,21 +218,16 @@ server_DATA = $(server_in_files:.server.in.in=.server)
sed -e "s|\@COMPONENTDIR\@|$(componentdir)|" $< > $@
@INTLTOOL_SERVER_RULE@
-MARSHAL_GENERATED = em-marshal.c em-marshal.h
-@EVO_MARSHAL_RULE@
-
-glade_DATA = mail-config.glade local-config.glade subscribe-dialog.glade message-tags.glade mail-search.glade
-etspec_DATA = message-list.etspec
+# Misc data to install
-schemadir = $(GCONF_SCHEMA_FILE_DIR)
-schema_DATA = evolution-mail.schemas
+glade_DATA = mail-config.glade local-config.glade subscribe-dialog.glade message-tags.glade mail-search.glade
+MARSHAL_GENERATED = em-marshal.c em-marshal.h
+@EVO_MARSHAL_RULE@
-idl_DATA = Mailer.idl
+etspec_DATA = mail-accounts.etspec message-list.etspec subscribe-dialog.etspec
-$(EVOLUTION_MAIL_CORBA_GENERATED_H): Mailer.idl
- $(ORBIT_IDL) -I $(srcdir) -I $(datadir)/idl $(IDL_INCLUDES) $(srcdir)/Mailer.idl
-$(EVOLUTION_MAIL_CORBA_GENERATED_C): $(EVOLUTION_MAIL_CORBA_GENERATED_H)
+idl_DATA = $(MAILER_IDL)
EXTRA_DIST = \
ChangeLog.pre-1-4 \
@@ -217,6 +240,9 @@ EXTRA_DIST = \
$(server_DATA) \
$(etspec_DATA)
+
+# Purify support
+
if ENABLE_PURIFY
PLINK = $(LIBTOOL) --mode=link $(PURIFY) $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
@@ -228,6 +254,12 @@ evolution-mail.pure: evolution-mail
endif
+
+# GConf
+
+schemadir = $(GCONF_SCHEMA_FILE_DIR)
+schema_DATA = evolution-mail.schemas
+
install-data-local:
if test -z "$(DESTDIR)" ; then \
for p in $(schema_DATA) ; do \
@@ -235,8 +267,11 @@ install-data-local:
done \
fi
+
+# Prologue
+
dist-hook:
cd $(distdir); rm -f $(BUILT_SOURCES)
-BUILT_SOURCES = $(EVOLUTION_MAIL_CORBA_GENERATED) $(IDL_GENERATED) $(MARSHAL_GENERATED) $(server_DATA)
+BUILT_SOURCES = $(MAILER_IDL_GENERATED) $(SPELL_IDL_GENERATED) $(MARSHAL_GENERATED) $(server_DATA)
CLEANFILES = $(BUILT_SOURCES)
diff --git a/mail/component-factory.c b/mail/component-factory.c
index a1d0c322eb..9f361ec5fc 100644
--- a/mail/component-factory.c
+++ b/mail/component-factory.c
@@ -20,6 +20,8 @@
* Boston, MA 02111-1307, USA.
*/
+/* EPFIXME: This file should go away. */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -54,6 +56,7 @@
#include "mail-config.h"
#include "mail-config-factory.h"
#include "mail-preferences.h"
+#include "mail-component.h"
#include "mail-composer-prefs.h"
#include "mail-tools.h"
#include "mail-ops.h"
@@ -79,7 +82,6 @@ char *default_sent_folder_uri;
CamelFolder *sent_folder = NULL;
char *default_outbox_folder_uri;
CamelFolder *outbox_folder = NULL;
-char *evolution_dir;
EvolutionShellClient *global_shell_client = NULL;
@@ -136,6 +138,14 @@ type_is_vtrash (const char *type)
return !strcmp (type, "vtrash");
}
+
+/* Forward decls just to get it to compile without warnings. EPFIXME: This is
+ all junk at this point in the refactoring anyways, so it will all die. */
+static void mail_load_storage_by_uri (GNOME_Evolution_Shell shell, const char *uri, const char *name);
+static void mail_load_storages (GNOME_Evolution_Shell shell, EAccountList *accounts);
+static void mail_hash_storage (CamelService *store, EvolutionStorage *storage);
+
+
/* EvolutionShellComponent methods and signals. */
static BonoboControl *
@@ -766,6 +776,7 @@ owner_set_cb (EvolutionShellComponent *shell_component,
const char *evolution_homedir,
gpointer user_data)
{
+#if 0
GNOME_Evolution_Shell corba_shell;
EAccountList *accounts;
int i;
@@ -774,7 +785,6 @@ owner_set_cb (EvolutionShellComponent *shell_component,
global_shell_client = shell_client;
g_object_weak_ref ((GObject *) shell_client, (GWeakNotify) shell_client_destroy, NULL);
- evolution_dir = g_strdup (evolution_homedir);
mail_session_init ();
async_event = mail_async_event_new();
@@ -831,6 +841,7 @@ owner_set_cb (EvolutionShellComponent *shell_component,
/* Everything should be ready now */
evolution_folder_info_notify_ready ();
+#endif
}
static void
@@ -1037,7 +1048,7 @@ request_quit (EvolutionShellComponent *shell_component,
}
static BonoboObject *
-create_component (void)
+create_shell_component (void)
{
EvolutionShellComponentDndDestinationFolder *destination_interface;
MailOfflineHandler *offline_handler;
@@ -1336,12 +1347,14 @@ storage_xfer_folder (EvolutionStorage *storage,
camel_exception_clear (&ex);
}
+#if 0 /* EPFIXME */
static void
storage_connected (CamelStore *store, CamelFolderInfo *info, void *listener)
{
notify_listener (listener, (info ? GNOME_Evolution_Storage_OK :
GNOME_Evolution_Storage_GENERIC_ERROR));
}
+#endif
static void
storage_connect (EvolutionStorage *storage,
@@ -1349,8 +1362,10 @@ storage_connect (EvolutionStorage *storage,
const char *path,
CamelStore *store)
{
+#if 0 /* EPFIXME */
mail_note_store (CAMEL_STORE (store), NULL, storage, CORBA_OBJECT_NIL,
storage_connected, listener);
+#endif
}
static void
@@ -1373,7 +1388,7 @@ add_storage (const char *name, const char *uri, CamelService *store,
evolution_storage_has_subfolders (storage, "/", _("Connecting..."));
mail_hash_storage (store, storage);
/*if (auto_connect)*/
- mail_note_store ((CamelStore *) store, NULL, storage, CORBA_OBJECT_NIL, NULL, NULL);
+ /* EPFIXME mail_note_store ((CamelStore *) store, NULL, storage, CORBA_OBJECT_NIL, NULL, NULL); */
/* falllll */
case EVOLUTION_STORAGE_ERROR_ALREADYREGISTERED:
case EVOLUTION_STORAGE_ERROR_EXISTS:
@@ -1386,34 +1401,7 @@ add_storage (const char *name, const char *uri, CamelService *store,
}
}
-void
-mail_add_storage (CamelStore *store, const char *name, const char *uri)
-{
- EvolutionShellClient *shell_client;
- GNOME_Evolution_Shell shell;
- CamelException ex;
-
- g_return_if_fail (CAMEL_IS_STORE (store));
-
- shell_client = evolution_shell_component_get_owner (shell_component);
- shell = evolution_shell_client_corba_objref (shell_client);
-
- camel_exception_init (&ex);
-
- if (name == NULL) {
- char *service_name;
-
- service_name = camel_service_get_name ((CamelService *) store, TRUE);
- add_storage (service_name, uri, (CamelService *) store, shell, &ex);
- g_free (service_name);
- } else {
- add_storage (name, uri, (CamelService *) store, shell, &ex);
- }
-
- camel_exception_clear (&ex);
-}
-
-void
+static void
mail_load_storage_by_uri (GNOME_Evolution_Shell shell, const char *uri, const char *name)
{
CamelException ex;
@@ -1468,7 +1456,7 @@ mail_load_storage_by_uri (GNOME_Evolution_Shell shell, const char *uri, const ch
camel_object_unref (CAMEL_OBJECT (store));
}
-void
+static void
mail_load_storages (GNOME_Evolution_Shell shell, EAccountList *accounts)
{
CamelException ex;
@@ -1500,103 +1488,23 @@ mail_load_storages (GNOME_Evolution_Shell shell, EAccountList *accounts)
g_object_unref (iter);
}
-void
+static void
mail_hash_storage (CamelService *store, EvolutionStorage *storage)
{
camel_object_ref (CAMEL_OBJECT (store));
g_hash_table_insert (storages_hash, store, storage);
}
-EvolutionStorage *
-mail_lookup_storage (CamelStore *store)
-{
- EvolutionStorage *storage;
-
- /* Because the storages_hash holds a reference to each store
- * used as a key in it, none of them will ever be gc'ed, meaning
- * any call to camel_session_get_{service,store} with the same
- * URL will always return the same object. So this works.
- */
-
- storage = g_hash_table_lookup (storages_hash, store);
- if (storage)
- bonobo_object_ref (BONOBO_OBJECT (storage));
-
- return storage;
-}
-
+#if 0
static void
store_disconnect(CamelStore *store, void *event_data, void *data)
{
camel_service_disconnect (CAMEL_SERVICE (store), TRUE, NULL);
camel_object_unref (CAMEL_OBJECT (store));
}
+#endif
-void
-mail_remove_storage (CamelStore *store)
-{
- EvolutionStorage *storage;
- EvolutionShellClient *shell_client;
- GNOME_Evolution_Shell corba_shell;
-
- /* Because the storages_hash holds a reference to each store
- * used as a key in it, none of them will ever be gc'ed, meaning
- * any call to camel_session_get_{service,store} with the same
- * URL will always return the same object. So this works.
- */
-
- storage = g_hash_table_lookup (storages_hash, store);
- if (!storage)
- return;
-
- g_hash_table_remove (storages_hash, store);
-
- /* so i guess potentially we could have a race, add a store while one
- being removed. ?? */
- mail_note_store_remove(store);
-
- shell_client = evolution_shell_component_get_owner (shell_component);
- corba_shell = evolution_shell_client_corba_objref(shell_client);
-
- evolution_storage_deregister_on_shell (storage, corba_shell);
-
- mail_async_event_emit(async_event, MAIL_ASYNC_THREAD, (MailAsyncFunc)store_disconnect, store, NULL, NULL);
-}
-
-void
-mail_remove_storage_by_uri (const char *uri)
-{
- CamelProvider *prov;
- CamelService *store;
-
- prov = camel_session_get_provider (session, uri, NULL);
- if (!prov)
- return;
- if (!(prov->flags & CAMEL_PROVIDER_IS_STORAGE) ||
- (prov->flags & CAMEL_PROVIDER_IS_EXTERNAL))
- return;
-
- store = camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, NULL);
- if (store != NULL) {
- mail_remove_storage (CAMEL_STORE (store));
- camel_object_unref (CAMEL_OBJECT (store));
- }
-}
-
-int
-mail_storages_count (void)
-{
- return g_hash_table_size (storages_hash);
-}
-
-void
-mail_storages_foreach (GHFunc func, gpointer data)
-{
- g_hash_table_foreach (storages_hash, func, data);
-}
-
-
-#define FACTORY_ID "OAFIID:GNOME_Evolution_Mail_ControlFactory"
+#define FACTORY_ID "OAFIID:GNOME_Evolution_Mail_Factory_2"
#define MAIL_CONFIG_IID "OAFIID:GNOME_Evolution_MailConfig"
#define WIZARD_IID "OAFIID:GNOME_Evolution_Mail_Wizard"
@@ -1608,9 +1516,14 @@ factory (BonoboGenericFactory *factory,
const char *component_id,
void *closure)
{
- if (strcmp (component_id, COMPONENT_ID) == 0)
- return create_component();
- else if (strcmp(component_id, MAIL_CONFIG_IID) == 0)
+ if (strcmp (component_id, SHELL_COMPONENT_ID) == 0)
+ return create_shell_component();
+ else if (strcmp (component_id, COMPONENT_ID) == 0) {
+ MailComponent *component = mail_component_peek ();
+
+ bonobo_object_ref (BONOBO_OBJECT (component));
+ return BONOBO_OBJECT (component);
+ } else if (strcmp(component_id, MAIL_CONFIG_IID) == 0)
return (BonoboObject *)g_object_new (evolution_mail_config_get_type (), NULL);
else if (strcmp(component_id, FOLDER_INFO_IID) == 0)
return evolution_folder_info_new();
diff --git a/mail/component-factory.h b/mail/component-factory.h
index 3abd058556..fdc7c4056f 100644
--- a/mail/component-factory.h
+++ b/mail/component-factory.h
@@ -23,7 +23,8 @@
#ifndef COMPONENT_FACTORY_H
#define COMPONENT_FACTORY_H
-#define COMPONENT_ID "OAFIID:GNOME_Evolution_Mail_ShellComponent"
+#define COMPONENT_ID "OAFIID:GNOME_Evolution_Mail_Component2"
+#define SHELL_COMPONENT_ID "OAFIID:GNOME_Evolution_Mail_ShellComponent"
#define SUMMARY_FACTORY_ID "OAFIID:GNOME_Evolution_Mail_ExecutiveSummaryComponentFactory"
#endif
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index e181c2cb33..75166a19b4 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -101,7 +101,7 @@ composer_destroy_cb (gpointer user_data, GObject *deadbeef)
}
static gboolean
-ask_confirm_for_unwanted_html_mail (EMsgComposer *composer, EDestination **recipients)
+ask_confirm_for_unwanted_html_mail (EMsgComposer *composer, EABDestination **recipients)
{
gboolean show_again, res;
GConfClient *gconf;
@@ -117,10 +117,10 @@ ask_confirm_for_unwanted_html_mail (EMsgComposer *composer, EDestination **recip
str = g_string_new (_("You are sending an HTML-formatted message. Please make sure that\n"
"the following recipients are willing and able to receive HTML mail:\n"));
for (i = 0; recipients[i] != NULL; ++i) {
- if (!e_destination_get_html_mail_pref (recipients[i])) {
+ if (!eab_destination_get_html_mail_pref (recipients[i])) {
const char *name;
- name = e_destination_get_textrep (recipients[i], FALSE);
+ name = eab_destination_get_textrep (recipients[i], FALSE);
g_string_append_printf (str, " %s\n", name);
}
@@ -262,7 +262,7 @@ static CamelMimeMessage *
composer_get_message (EMsgComposer *composer, gboolean post, gboolean save_html_object_data)
{
CamelMimeMessage *message = NULL;
- EDestination **recipients, **recipients_bcc;
+ EABDestination **recipients, **recipients_bcc;
gboolean send_html, confirm_html;
CamelInternetAddress *cia;
int hidden = 0, shown = 0;
@@ -286,15 +286,15 @@ composer_get_message (EMsgComposer *composer, gboolean post, gboolean save_html_
/* see which ones are visible/present, etc */
if (recipients) {
for (i = 0; recipients[i] != NULL; i++) {
- const char *addr = e_destination_get_address (recipients[i]);
+ const char *addr = eab_destination_get_address (recipients[i]);
if (addr && addr[0]) {
camel_address_decode ((CamelAddress *) cia, addr);
if (camel_address_length ((CamelAddress *) cia) > 0) {
camel_address_remove ((CamelAddress *) cia, -1);
num++;
- if (e_destination_is_evolution_list (recipients[i])
- && !e_destination_list_show_addresses (recipients[i])) {
+ if (eab_destination_is_evolution_list (recipients[i])
+ && !eab_destination_list_show_addresses (recipients[i])) {
hidden++;
} else {
shown++;
@@ -307,7 +307,7 @@ composer_get_message (EMsgComposer *composer, gboolean post, gboolean save_html_
recipients_bcc = e_msg_composer_get_bcc (composer);
if (recipients_bcc) {
for (i = 0; recipients_bcc[i] != NULL; i++) {
- const char *addr = e_destination_get_address (recipients_bcc[i]);
+ const char *addr = eab_destination_get_address (recipients_bcc[i]);
if (addr && addr[0]) {
camel_address_decode ((CamelAddress *) cia, addr);
@@ -318,7 +318,7 @@ composer_get_message (EMsgComposer *composer, gboolean post, gboolean save_html_
}
}
- e_destination_freev (recipients_bcc);
+ eab_destination_freev (recipients_bcc);
}
camel_object_unref (cia);
@@ -347,7 +347,7 @@ composer_get_message (EMsgComposer *composer, gboolean post, gboolean save_html_
if (recipients) {
for (i = 0; recipients[i] != NULL && !html_problem; i++) {
- if (!e_destination_get_html_mail_pref (recipients[i]))
+ if (!eab_destination_get_html_mail_pref (recipients[i]))
html_problem = TRUE;
}
}
@@ -384,12 +384,12 @@ composer_get_message (EMsgComposer *composer, gboolean post, gboolean save_html_
/* Get the message recipients and 'touch' them, boosting their use scores */
if (recipients)
- e_destination_touchv (recipients);
+ eab_destination_touchv (recipients);
finished:
if (recipients)
- e_destination_freev (recipients);
+ eab_destination_freev (recipients);
return message;
}
diff --git a/mail/em-folder-browser.c b/mail/em-folder-browser.c
index 243ea449eb..03ab55800f 100644
--- a/mail/em-folder-browser.c
+++ b/mail/em-folder-browser.c
@@ -156,9 +156,8 @@ static void
emfb_init(GObject *o)
{
EMFolderBrowser *emfb = (EMFolderBrowser *)o;
+ RuleContext *search_context = mail_component_peek_search_context (mail_component_peek ());
struct _EMFolderBrowserPrivate *p;
- /* FIXME ... */
- extern RuleContext *search_context;
p = emfb->priv = g_malloc0(sizeof(struct _EMFolderBrowserPrivate));
diff --git a/mail/em-folder-selection-button.c b/mail/em-folder-selection-button.c
new file mode 100644
index 0000000000..ac5a6e1d06
--- /dev/null
+++ b/mail/em-folder-selection-button.c
@@ -0,0 +1,242 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* em-folder-selection-button.c
+ *
+ * Copyright (C) 2003 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Author: Ettore Perazzoli <ettore@ximian.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "em-folder-selection-button.h"
+
+#include "mail-component.h"
+#include "em-folder-selector.h"
+
+#include <gal/util/e-util.h>
+
+#include <gtk/gtkimage.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkhbox.h>
+
+
+#define PARENT_TYPE gtk_button_get_type ()
+static GtkButtonClass *parent_class = NULL;
+
+
+struct _EMFolderSelectionButtonPrivate {
+ GtkWidget *icon;
+ GtkWidget *label;
+
+ char *uri;
+
+ char *title;
+ char *caption;
+};
+
+enum {
+ SELECTED,
+ LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+
+/* Utility functions. */
+
+static void
+set_contents_unselected (EMFolderSelectionButton *button)
+{
+ gtk_image_set_from_pixbuf (GTK_IMAGE (button->priv->icon), NULL);
+ gtk_label_set_text (GTK_LABEL (button->priv->label), _("<click here to select a folder>"));
+}
+
+static void
+set_contents (EMFolderSelectionButton *button)
+{
+ EMFolderSelectionButtonPrivate *priv = button->priv;
+ char *path, *tmp, *label;
+
+ if (priv->uri == NULL)
+ goto unset;
+
+ /* We set the button name directly from the storage set path, which is /accountname/path/foldername */
+ path = e_storage_set_get_path_for_physical_uri(mail_component_peek_storage_set(mail_component_peek()), priv->uri);
+
+ if (path == NULL)
+ goto unknown;
+
+ tmp = strchr(path+1, '/');
+ if (tmp == NULL)
+ goto unknown;
+ *tmp++ = 0;
+
+ label = g_strdup_printf(_("\"%s\" in \"%s\""), tmp, path+1);
+ gtk_label_set_text (GTK_LABEL (priv->label), label);
+ g_free (label);
+
+ g_free(path);
+ return;
+
+unknown:
+ g_free(path);
+unset:
+ set_contents_unselected(button);
+}
+
+static void
+impl_finalize (GObject *object)
+{
+ EMFolderSelectionButtonPrivate *priv = EM_FOLDER_SELECTION_BUTTON (object)->priv;
+
+ g_free (priv->title);
+ g_free (priv->caption);
+ g_free(priv->uri);
+ g_free (priv);
+
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+static void
+emfsb_selector_response(EMFolderSelector *emfs, int response, EMFolderSelectionButton *button)
+{
+ if (response == GTK_RESPONSE_OK) {
+ const char *uri = em_folder_selector_get_selected_uri(emfs);
+
+ em_folder_selection_button_set_selection(button, uri);
+ g_signal_emit(button, signals[SELECTED], 0);
+ }
+
+ gtk_widget_destroy((GtkWidget *)emfs);
+}
+
+static void
+impl_clicked (GtkButton *button)
+{
+ EMFolderSelectionButtonPrivate *priv = EM_FOLDER_SELECTION_BUTTON (button)->priv;
+ EStorageSet *ess;
+ GtkWidget *w;
+ GtkWidget *toplevel;
+
+ if (GTK_BUTTON_CLASS (parent_class)->clicked != NULL)
+ (* GTK_BUTTON_CLASS (parent_class)->clicked) (button);
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ ess = mail_component_peek_storage_set(mail_component_peek());
+ w = em_folder_selector_new(ess, EM_FOLDER_SELECTOR_CAN_CREATE, priv->title, priv->caption);
+ em_folder_selector_set_selected_uri((EMFolderSelector *)w, priv->uri);
+ g_signal_connect(w, "response", G_CALLBACK(emfsb_selector_response), button);
+ gtk_widget_show(w);
+}
+#if 0
+{
+ uri = em_folder_selection_run_dialog_uri((GtkWindow *)toplevel,
+ priv->title,
+ priv->caption,
+ priv->uri);
+
+ em_folder_selection_button_set_selection (EM_FOLDER_SELECTION_BUTTON (button), uri);
+ g_free(uri);
+
+ g_signal_emit (button, signals[SELECTED], 0);
+}
+#endif
+
+static void
+class_init (EMFolderSelectionButtonClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GtkButtonClass *button_class = GTK_BUTTON_CLASS (class);
+
+ object_class->finalize = impl_finalize;
+
+ button_class->clicked = impl_clicked;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ signals[SELECTED] = g_signal_new ("selected",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EMFolderSelectionButtonClass, selected),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+init (EMFolderSelectionButton *folder_selection_button)
+{
+ EMFolderSelectionButtonPrivate *priv;
+ GtkWidget *box;
+
+ priv = g_new0 (EMFolderSelectionButtonPrivate, 1);
+ folder_selection_button->priv = priv;
+
+ box = gtk_hbox_new (FALSE, 4);
+
+ priv->icon = gtk_image_new ();
+ gtk_box_pack_start (GTK_BOX (box), priv->icon, FALSE, TRUE, 0);
+
+ priv->label = gtk_label_new ("");
+ gtk_label_set_justify (GTK_LABEL (priv->label), GTK_JUSTIFY_LEFT);
+ gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.0);
+ gtk_box_pack_start (GTK_BOX (box), priv->label, TRUE, TRUE, 0);
+
+ gtk_widget_show_all (box);
+ gtk_container_add (GTK_CONTAINER (folder_selection_button), box);
+
+ set_contents (folder_selection_button);
+}
+
+GtkWidget *
+em_folder_selection_button_new(const char *title, const char *caption)
+{
+ EMFolderSelectionButton *button = g_object_new (EM_TYPE_FOLDER_SELECTION_BUTTON, NULL);
+
+ button->priv->title = g_strdup (title);
+ button->priv->caption = g_strdup (caption);
+
+ return GTK_WIDGET (button);
+}
+
+
+void
+em_folder_selection_button_set_selection(EMFolderSelectionButton *button, const char *uri)
+{
+ EMFolderSelectionButtonPrivate *p = button->priv;
+
+ g_return_if_fail(EM_IS_FOLDER_SELECTION_BUTTON(button));
+
+ if (p->uri != uri) {
+ g_free(p->uri);
+ p->uri = g_strdup(uri);
+ }
+
+ set_contents(button);
+}
+
+
+const char *
+em_folder_selection_button_get_selection(EMFolderSelectionButton *button)
+{
+ g_return_val_if_fail (EM_IS_FOLDER_SELECTION_BUTTON (button), NULL);
+
+ return button->priv->uri;
+}
+
+E_MAKE_TYPE (em_folder_selection_button, "EMFolderSelectionButton", EMFolderSelectionButton, class_init, init, PARENT_TYPE)
diff --git a/mail/em-folder-selection-button.h b/mail/em-folder-selection-button.h
new file mode 100644
index 0000000000..1ab4eb461c
--- /dev/null
+++ b/mail/em-folder-selection-button.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* em-folder-selection-button.h
+ *
+ * Copyright (C) 2003 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Author: Ettore Perazzoli <ettore@ximian.com>
+ */
+
+#ifndef _EM_FOLDER_SELECTION_BUTTON_H_
+#define _EM_FOLDER_SELECTION_BUTTON_H_
+
+#include <gtk/gtkbutton.h>
+
+#define EM_TYPE_FOLDER_SELECTION_BUTTON (em_folder_selection_button_get_type ())
+#define EM_FOLDER_SELECTION_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EM_TYPE_FOLDER_SELECTION_BUTTON, EMFolderSelectionButton))
+#define EM_FOLDER_SELECTION_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EM_TYPE_FOLDER_SELECTION_BUTTON, EMFolderSelectionButtonClass))
+#define EM_IS_FOLDER_SELECTION_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EM_TYPE_FOLDER_SELECTION_BUTTON))
+#define EM_IS_FOLDER_SELECTION_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EM_TYPE_FOLDER_SELECTION_BUTTON))
+
+typedef struct _EMFolderSelectionButton EMFolderSelectionButton;
+typedef struct _EMFolderSelectionButtonPrivate EMFolderSelectionButtonPrivate;
+typedef struct _EMFolderSelectionButtonClass EMFolderSelectionButtonClass;
+
+struct _EMFolderSelectionButton {
+ GtkButton parent;
+
+ EMFolderSelectionButtonPrivate *priv;
+};
+
+struct _EMFolderSelectionButtonClass {
+ GtkButtonClass parent_class;
+
+ /* Signals. */
+
+ void (* selected) (EMFolderSelectionButton *button);
+};
+
+GType em_folder_selection_button_get_type (void);
+
+GtkWidget *em_folder_selection_button_new(const char *title, const char *caption);
+
+void em_folder_selection_button_set_selection(EMFolderSelectionButton *button, const char *uri);
+const char *em_folder_selection_button_get_selection(EMFolderSelectionButton *button);
+
+#endif /* _EM_FOLDER_SELECTION_BUTTON_H_ */
diff --git a/mail/em-folder-selection.c b/mail/em-folder-selection.c
new file mode 100644
index 0000000000..c65ad80fc7
--- /dev/null
+++ b/mail/em-folder-selection.c
@@ -0,0 +1,170 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* em-folder-selection.c - UI for selecting folders.
+ *
+ * Copyright (C) 2002 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Author: Ettore Perazzoli <ettore@ximian.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "em-folder-selection.h"
+
+#include "mail-component.h"
+#include "mail-tools.h"
+
+#include "shell/e-folder-selection-dialog.h"
+
+
+CamelFolder *
+em_folder_selection_run_dialog (GtkWindow *parent_window,
+ const char *title,
+ const char *caption,
+ CamelFolder *default_folder)
+{
+ EStorageSet *storage_set = mail_component_peek_storage_set (mail_component_peek ());
+ char *default_path = NULL;
+ CamelStore *default_store;
+ GtkWidget *dialog;
+ EFolder *selected_e_folder;
+ CamelFolder *selected_camel_folder;
+ int response;
+
+ default_store = camel_folder_get_parent_store (default_folder);
+ if (default_store != NULL) {
+ EStorage *storage = mail_component_lookup_storage (mail_component_peek (), default_store);
+
+ if (storage != NULL) {
+ default_path = g_strconcat ("/",
+ e_storage_get_name (storage),
+ "/",
+ camel_folder_get_full_name (default_folder),
+ NULL);
+ }
+ }
+
+ /* EPFIXME: Allowed types? */
+ dialog = e_folder_selection_dialog_new (storage_set, title, caption, default_path, NULL, FALSE);
+ g_free(default_path);
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response != GTK_RESPONSE_OK) {
+ gtk_widget_destroy (dialog);
+ return NULL;
+ }
+
+ selected_e_folder = e_storage_set_get_folder (storage_set,
+ e_folder_selection_dialog_get_selected_path (E_FOLDER_SELECTION_DIALOG (dialog)));
+ if (selected_e_folder == NULL) {
+ gtk_widget_destroy (dialog);
+ return NULL;
+ }
+
+ selected_camel_folder = mail_tool_uri_to_folder (e_folder_get_physical_uri (selected_e_folder), 0, NULL);
+ gtk_widget_destroy (dialog);
+
+ return selected_camel_folder;
+}
+
+/* FIXME: This isn't the way to do it, but then neither is the above, really ... */
+char *
+em_folder_selection_run_dialog_uri(GtkWindow *parent_window,
+ const char *title,
+ const char *caption,
+ const char *default_folder_uri)
+{
+ EStorageSet *storage_set = mail_component_peek_storage_set (mail_component_peek ());
+ char *default_path;
+ GtkWidget *dialog;
+ EFolder *selected_e_folder;
+ int response;
+
+ default_path = e_storage_set_get_path_for_physical_uri(storage_set, default_folder_uri);
+ dialog = e_folder_selection_dialog_new (storage_set, title, caption, default_path, NULL, FALSE);
+ g_free(default_path);
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response != GTK_RESPONSE_OK) {
+ gtk_widget_destroy (dialog);
+ return NULL;
+ }
+
+ selected_e_folder = e_storage_set_get_folder (storage_set,
+ e_folder_selection_dialog_get_selected_path (E_FOLDER_SELECTION_DIALOG (dialog)));
+ gtk_widget_destroy (dialog);
+ if (selected_e_folder == NULL)
+ return NULL;
+
+ return g_strdup(e_folder_get_physical_uri(selected_e_folder));
+}
+
+
+struct _select_folder_data {
+ void (*done)(const char *uri, void *data);
+ void *data;
+};
+
+static void
+emfs_folder_selected(GtkWidget *w, const char *path, struct _select_folder_data *d)
+{
+ const char *uri = NULL;
+ EStorageSet *storage_set = mail_component_peek_storage_set (mail_component_peek ());
+ EFolder *folder;
+
+ folder = e_storage_set_get_folder(storage_set, path);
+ if (folder)
+ uri = e_folder_get_physical_uri(folder);
+
+ gtk_widget_hide(w);
+
+ d->done(uri, d->data);
+
+ gtk_widget_destroy(w);
+}
+
+static void
+emfs_folder_cancelled(GtkWidget *w, struct _select_folder_data *d)
+{
+ gtk_widget_destroy(w);
+}
+
+void
+em_select_folder(GtkWindow *parent_window, const char *title, const char *text, const char *default_folder_uri, void (*done)(const char *uri, void *data), void *data)
+{
+ EStorageSet *storage_set = mail_component_peek_storage_set (mail_component_peek ());
+ char *path;
+ GtkWidget *dialog;
+ struct _select_folder_data *d;
+
+ d = g_malloc0(sizeof(*d));
+ d->data = data;
+ d->done = done;
+
+ if (default_folder_uri)
+ path = e_storage_set_get_path_for_physical_uri(storage_set, default_folder_uri);
+ else
+ path = NULL;
+ dialog = e_folder_selection_dialog_new(storage_set, title, text, path, NULL, TRUE);
+ g_free(path);
+ /* ugh, painful api ... */
+ g_signal_connect(dialog, "folder_selected", G_CALLBACK(emfs_folder_selected), d);
+ g_signal_connect(dialog, "cancelled", G_CALLBACK(emfs_folder_cancelled), d);
+ g_object_set_data_full((GObject *)dialog, "emfs_data", d, g_free);
+ gtk_widget_show(dialog);
+}
diff --git a/mail/em-folder-selection.h b/mail/em-folder-selection.h
new file mode 100644
index 0000000000..374e1eec3f
--- /dev/null
+++ b/mail/em-folder-selection.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* em-folder-selection.h - UI for selecting folders.
+ *
+ * Copyright (C) 2002 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Author: Ettore Perazzoli <ettore@ximian.com>
+ */
+
+#ifndef EM_FOLDER_SELECTION_H
+#define EM_FOLDER_SELECTION_H
+
+#include <camel/camel-folder.h>
+
+#include <gtk/gtkwindow.h>
+
+CamelFolder *em_folder_selection_run_dialog (GtkWindow *parent_window,
+ const char *title,
+ const char *caption,
+ CamelFolder *default_folder);
+char *em_folder_selection_run_dialog_uri(GtkWindow *parent_window,
+ const char *title,
+ const char *caption,
+ const char *default_folder_uri);
+
+void em_select_folder(GtkWindow *parent_window, const char *title, const char *text, const char *default_folder_uri, void (*done)(const char *uri, void *data), void *data);
+
+#endif /* EM_FOLDER_SELECTION_H */
diff --git a/mail/em-folder-selector.c b/mail/em-folder-selector.c
new file mode 100644
index 0000000000..3ccf00e497
--- /dev/null
+++ b/mail/em-folder-selector.c
@@ -0,0 +1,349 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+ *
+ * Copyright(C) 2000, 2001, 2002, 2003 Ximian, Inc.
+ *
+ * Authors: Ettore Perazzoli
+ * Michael Zucchi
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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>
+#endif
+
+#include "em-folder-selector.h"
+
+#include "shell/e-storage-set-view.h"
+#include "shell/e-storage-set.h"
+
+#include <libgnome/gnome-i18n.h>
+
+#include <gal/util/e-util.h>
+#include <gal/widgets/e-gui-utils.h>
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtkbox.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkstock.h>
+
+#include <camel/camel-url.h>
+
+#include <string.h>
+
+#define PARENT_TYPE (gtk_dialog_get_type())
+static GtkDialogClass *parent_class = NULL;
+
+static gboolean
+check_folder_type_valid(EMFolderSelector *emfs)
+{
+ const char *selected;
+ EFolder *folder;
+
+ selected = e_storage_set_view_get_current_folder(emfs->essv);
+ if (selected == NULL)
+ return FALSE;
+
+ folder = e_storage_set_get_folder(emfs->ess, selected);
+ if (folder == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+#if 0 /* EPFIXME */
+static void
+folder_creation_dialog_result_cb(EShell *shell,
+ EShellFolderCreationDialogResult result,
+ const char *path,
+ void *data)
+{
+ EMFolderSelector *dialog;
+
+ dialog = EM_FOLDER_SELECTOR(data);
+
+ if (result == E_SHELL_FOLDER_CREATION_DIALOG_RESULT_SUCCESS)
+ e_storage_set_view_set_current_folder(E_STORAGE_SET_VIEW(priv->storage_set_view),
+ path);
+}
+#endif
+
+static void
+emfs_dispose(GObject *object)
+{
+ EMFolderSelector *emfs = (EMFolderSelector *)object;
+
+ if (emfs->ess != NULL) {
+ g_object_unref(emfs->ess);
+ emfs->ess = NULL;
+ emfs->essv = NULL;
+ }
+
+ (* G_OBJECT_CLASS(parent_class)->dispose)(object);
+}
+
+static void
+emfs_finalize(GObject *object)
+{
+ /*EMFolderSelector *emfs = (EMFolderSelector *)object;*/
+
+ (* G_OBJECT_CLASS(parent_class)->finalize)(object);
+}
+
+static void
+emfs_response(GtkDialog *dialog, int response)
+{
+ EMFolderSelector *emfs = (EMFolderSelector *)dialog;
+ const char *path;
+
+ switch (response) {
+ case EM_FOLDER_SELECTOR_RESPONSE_NEW:
+ path = e_storage_set_view_get_current_folder(emfs->essv);
+
+ printf("create new folder, default parent '%s'\n", path);
+ break;
+ }
+}
+
+static void
+emfs_class_init(EMFolderSelectorClass *klass)
+{
+ GObjectClass *object_class;
+ GtkDialogClass *dialog_class;
+
+ parent_class = g_type_class_ref(PARENT_TYPE);
+ object_class = G_OBJECT_CLASS(klass);
+ dialog_class = GTK_DIALOG_CLASS(klass);
+
+ object_class->dispose = emfs_dispose;
+ object_class->finalize = emfs_finalize;
+
+ dialog_class->response = emfs_response;
+}
+
+static void
+emfs_init(EMFolderSelector *emfs)
+{
+ emfs->flags = 0;
+}
+
+static void
+folder_selected_cb(EStorageSetView *essv, const char *path, EMFolderSelector *emfs)
+{
+ if (check_folder_type_valid(emfs))
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(emfs), GTK_RESPONSE_OK, TRUE);
+ else
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(emfs), GTK_RESPONSE_OK, FALSE);
+}
+
+static void
+double_click_cb(EStorageSetView *essv, int row, ETreePath path, int col, GdkEvent *event, EMFolderSelector *emfs)
+{
+ if (check_folder_type_valid(emfs)) {
+ /*g_signal_emit(emfs, signals[FOLDER_SELECTED], 0,
+ em_folder_selector_get_selected(emfs));*/
+ printf("double clicked!\n");
+ }
+}
+
+void
+em_folder_selector_construct(EMFolderSelector *emfs, EStorageSet *ess, guint32 flags, const char *title, const char *text)
+{
+ GtkWidget *scrolled_window;
+ GtkWidget *text_label;
+
+ gtk_window_set_default_size(GTK_WINDOW(emfs), 350, 300);
+ gtk_window_set_modal(GTK_WINDOW(emfs), TRUE);
+ gtk_window_set_title(GTK_WINDOW(emfs), title);
+ gtk_container_set_border_width(GTK_CONTAINER(emfs), 6);
+
+ emfs->flags = flags;
+ if (flags & EM_FOLDER_SELECTOR_CAN_CREATE)
+ gtk_dialog_add_buttons(GTK_DIALOG(emfs), GTK_STOCK_NEW, EM_FOLDER_SELECTOR_RESPONSE_NEW, NULL);
+
+ gtk_dialog_add_buttons(GTK_DIALOG(emfs),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(emfs), GTK_RESPONSE_OK, FALSE);
+ gtk_dialog_set_default_response(GTK_DIALOG(emfs), GTK_RESPONSE_OK);
+
+ emfs->ess = ess;
+ g_object_ref(ess);
+
+ emfs->essv = (EStorageSetView *)e_storage_set_create_new_view(ess, NULL);
+ e_storage_set_view_set_allow_dnd(emfs->essv, FALSE);
+ e_storage_set_view_enable_search(emfs->essv, TRUE);
+
+ g_signal_connect(emfs->essv, "double_click", G_CALLBACK(double_click_cb), emfs);
+ g_signal_connect(emfs->essv, "folder_selected", G_CALLBACK(folder_selected_cb), emfs);
+
+ scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ gtk_container_add(GTK_CONTAINER(scrolled_window), (GtkWidget *)emfs->essv);
+
+ gtk_box_pack_end(GTK_BOX(GTK_DIALOG(emfs)->vbox), scrolled_window, TRUE, TRUE, 6);
+ gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(emfs)->vbox), 6);
+
+ gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(emfs)->vbox), 6);
+
+ gtk_widget_show((GtkWidget *)emfs->essv);
+ gtk_widget_show(scrolled_window);
+
+ if (text != NULL) {
+ text_label = gtk_label_new(text);
+ gtk_label_set_justify(GTK_LABEL(text_label), GTK_JUSTIFY_LEFT);
+ gtk_widget_show(text_label);
+
+ gtk_box_pack_end(GTK_BOX(GTK_DIALOG(emfs)->vbox), text_label, FALSE, TRUE, 6);
+ gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(emfs)->vbox), 6);
+ }
+
+ GTK_WIDGET_SET_FLAGS((GtkWidget *)emfs->essv, GTK_CAN_FOCUS);
+ gtk_widget_grab_focus((GtkWidget *)emfs->essv);
+}
+
+GtkWidget *
+em_folder_selector_new(EStorageSet *ess, guint32 flags, const char *title, const char *text)
+{
+ EMFolderSelector *emfs;
+
+ g_return_val_if_fail(E_IS_STORAGE_SET(ess), NULL);
+
+ emfs = g_object_new(em_folder_selector_get_type(), NULL);
+ em_folder_selector_construct(emfs, ess, flags, title, text);
+
+ return GTK_WIDGET(emfs);
+}
+
+static void
+emfs_create_name_changed(GtkEntry *entry, EMFolderSelector *emfs)
+{
+ int active;
+
+ active = e_storage_set_view_get_current_folder(emfs->essv) != NULL
+ && emfs->name_entry->text_length > 0;
+
+ gtk_dialog_set_response_sensitive((GtkDialog *)emfs, GTK_RESPONSE_OK, active);
+}
+
+static void
+emfs_create_name_activate(GtkEntry *entry, EMFolderSelector *emfs)
+{
+ printf("entry activated, woop\n");
+}
+
+GtkWidget *
+em_folder_selector_create_new(EStorageSet *ess, guint32 flags, const char *title, const char *text)
+{
+ EMFolderSelector *emfs;
+ GtkWidget *hbox, *w;
+
+ g_return_val_if_fail(E_IS_STORAGE_SET(ess), NULL);
+
+ emfs = g_object_new(em_folder_selector_get_type(), NULL);
+ em_folder_selector_construct(emfs, ess, flags, title, text);
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ w = gtk_label_new_with_mnemonic(_("Folder _name"));
+ gtk_box_pack_start((GtkBox *)hbox, w, FALSE, FALSE, 6);
+ emfs->name_entry = (GtkEntry *)gtk_entry_new();
+ g_signal_connect(emfs->name_entry, "changed", G_CALLBACK(emfs_create_name_changed), emfs);
+ g_signal_connect(emfs->name_entry, "activate", G_CALLBACK(emfs_create_name_activate), emfs);
+ gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)emfs->name_entry, TRUE, FALSE, 6);
+ gtk_widget_show_all(hbox);
+
+ gtk_box_pack_start((GtkBox *)((GtkDialog *)emfs)->vbox, hbox, FALSE, TRUE, 0);
+
+ return GTK_WIDGET(emfs);
+}
+
+void
+em_folder_selector_set_selected(EMFolderSelector *emfs, const char *path)
+{
+ e_storage_set_view_set_current_folder(emfs->essv, path);
+}
+
+void
+em_folder_selector_set_selected_uri(EMFolderSelector *emfs, const char *uri)
+{
+ const char *path;
+
+ path = e_storage_set_get_path_for_physical_uri(emfs->ess, uri);
+ if (path)
+ e_storage_set_view_set_current_folder(emfs->essv, path);
+}
+
+const char *
+em_folder_selector_get_selected(EMFolderSelector *emfs)
+{
+ const char *path;
+
+ path = e_storage_set_view_get_current_folder(emfs->essv);
+ if (emfs->name_entry) {
+ g_free(emfs->selected);
+ emfs->selected = g_strdup_printf("%s/%s", path, gtk_entry_get_text(emfs->name_entry));
+ path = emfs->selected;
+ }
+
+ return path;
+}
+
+const char *
+em_folder_selector_get_selected_uri(EMFolderSelector *emfs)
+{
+ const char *path;
+ EFolder *folder;
+
+ path = e_storage_set_view_get_current_folder(emfs->essv);
+ if (path == NULL) {
+ printf("current folder is null?\n");
+ return NULL;
+ }
+
+ folder = e_storage_set_get_folder(emfs->ess, path);
+ if (folder == NULL) {
+ printf("path ok, but can't get folder?\n");
+ return NULL;
+ }
+
+ path = e_folder_get_physical_uri(folder);
+ if (path && emfs->name_entry) {
+ CamelURL *url;
+ char *newpath;
+
+ url = camel_url_new(path, NULL);
+ newpath = g_strdup_printf("%s/%s", url->fragment?url->fragment:url->path, gtk_entry_get_text(emfs->name_entry));
+ if (url->fragment)
+ camel_url_set_fragment(url, newpath);
+ else
+ camel_url_set_path(url, newpath);
+ g_free(emfs->selected_uri);
+ emfs->selected_uri = camel_url_to_string(url, 0);
+ camel_url_free(url);
+ path = emfs->selected_uri;
+ }
+
+ return path;
+}
+
+E_MAKE_TYPE(em_folder_selector, "EMFolderSelector", EMFolderSelector, emfs_class_init, emfs_init, PARENT_TYPE)
diff --git a/mail/em-folder-selector.h b/mail/em-folder-selector.h
new file mode 100644
index 0000000000..48fc6758b5
--- /dev/null
+++ b/mail/em-folder-selector.h
@@ -0,0 +1,96 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-folder-selection-dialog.h
+ *
+ * Copyright (C) 2000, 2001, 2002, 2003 Ximian, Inc.
+ *
+ * Authors: Ettore Perazzoli
+ * Michael Zucchi
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 EM_FOLDER_SELECTOR_H
+#define EM_FOLDER_SELECTOR_H
+
+#include <gtk/gtkdialog.h>
+
+#ifdef cplusplus
+extern "C" {
+#pragma }
+#endif /* cplusplus */
+
+#define EM_TYPE_FOLDER_SELECTOR (em_folder_selector_get_type ())
+#define EM_FOLDER_SELECTOR(obj) (GTK_CHECK_CAST ((obj), E_TYPEM_FOLDER_SELECTOR, EMFolderSelector))
+#define EM_FOLDER_SELECTOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPEM_FOLDER_SELECTOR, EMFolderSelectorClass))
+#define EM_IS_FOLDER_SELECTOR(obj) (GTK_CHECK_TYPE ((obj), E_TYPEM_FOLDER_SELECTOR))
+#define EM_IS_FOLDER_SELECTOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPEM_FOLDER_SELECTOR))
+
+typedef struct _EMFolderSelector EMFolderSelector;
+typedef struct _EMFolderSelectorPrivate EMFolderSelectorPrivate;
+typedef struct _EMFolderSelectorClass EMFolderSelectorClass;
+
+struct _EStorageSet;
+struct _EStorageSetView;
+
+struct _EMFolderSelector {
+ GtkDialog parent;
+
+ guint32 flags;
+ struct _EStorageSet *ess;
+ struct _EStorageSetView *essv;
+
+ struct _GtkEntry *name_entry;
+ char *selected;
+ char *selected_uri;
+};
+
+struct _EMFolderSelectorClass {
+ GtkDialogClass parent_class;
+
+#if 0
+ void (* folder_selected) (EMFolderSelector *folder_selection_dialog,
+ const char *path);
+ void (* cancelled) (EMFolderSelector *folder_selection_dialog);
+#endif
+};
+
+enum {
+ EM_FOLDER_SELECTOR_CAN_CREATE = 1,
+};
+
+enum {
+ EM_FOLDER_SELECTOR_RESPONSE_NEW = 1,
+};
+
+GtkType em_folder_selector_get_type (void);
+void em_folder_selector_construct(EMFolderSelector *, struct _EStorageSet *, guint32, const char *, const char *);
+/* for selecting folders */
+GtkWidget *em_folder_selector_new (struct _EStorageSet *, guint32, const char *, const char *);
+
+/* for creating folders */
+GtkWidget *em_folder_selector_create_new(struct _EStorageSet *ess, guint32 flags, const char *title, const char *text);
+
+void em_folder_selector_set_selected (EMFolderSelector *emfs, const char *path);
+void em_folder_selector_set_selected_uri(EMFolderSelector *emfs, const char *uri);
+
+const char *em_folder_selector_get_selected (EMFolderSelector *emfs);
+const char *em_folder_selector_get_selected_uri(EMFolderSelector *emfs);
+
+#ifdef cplusplus
+}
+#endif /* cplusplus */
+
+#endif /* EM_FOLDER_SELECTOR_H */
diff --git a/mail/em-folder-view.c b/mail/em-folder-view.c
index 8099191b01..fac7d155d3 100644
--- a/mail/em-folder-view.c
+++ b/mail/em-folder-view.c
@@ -542,16 +542,52 @@ emfv_popup_undelete(GtkWidget *w, EMFolderView *emfv)
em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_DELETED, 0);
}
+struct _move_data {
+ EMFolderView *emfv;
+ GPtrArray *uids;
+ int delete;
+};
+
+static void
+emfv_popup_move_cb(const char *uri, void *data)
+{
+ struct _move_data *d = data;
+
+ if (uri)
+ mail_transfer_messages(d->emfv->folder, d->uids, d->delete, uri, 0, NULL, NULL);
+ else
+ em_utils_uids_free(d->uids);
+
+ g_object_unref(d->emfv);
+ g_free(d);
+}
+
static void
emfv_popup_move(GtkWidget *w, EMFolderView *emfv)
{
- /* FIXME */
+ struct _move_data *d;
+
+ d = g_malloc(sizeof(*d));
+ d->emfv = emfv;
+ g_object_ref(emfv);
+ d->uids = message_list_get_selected(emfv->list);
+ d->delete = TRUE;
+
+ em_select_folder((GtkWidget *)emfv, _("Select folder"), NULL, NULL, emfv_popup_move_cb, d);
}
static void
emfv_popup_copy(GtkWidget *w, EMFolderView *emfv)
{
- /* FIXME */
+ struct _move_data *d;
+
+ d = g_malloc(sizeof(*d));
+ d->emfv = emfv;
+ g_object_ref(emfv);
+ d->uids = message_list_get_selected(emfv->list);
+ d->delete = FALSE;
+
+ em_select_folder((GtkWidget *)emfv, _("Select folder"), NULL, NULL, emfv_popup_move_cb, d);
}
static void
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index 6d38eda3f5..f95624e655 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -62,6 +62,8 @@
#include <camel/camel-file-utils.h>
#include <e-util/e-msgport.h>
+
+#include "mail-component.h"
#include "mail-mt.h"
#include "em-format-html.h"
@@ -214,15 +216,15 @@ em_format_html_get_type(void)
sizeof(EMFormatHTML), 0,
(GInstanceInitFunc)efh_init
};
- extern char *evolution_dir;
+ const char *base_directory = mail_component_peek_base_directory (mail_component_peek ());
char *path;
efh_parent = g_type_class_ref(em_format_get_type());
type = g_type_register_static(em_format_get_type(), "EMFormatHTML", &info, 0);
/* cache expiry - 2 hour access, 1 day max */
- path = alloca(strlen(evolution_dir)+16);
- sprintf(path, "%s/cache", evolution_dir);
+ path = alloca(strlen(base_directory)+16);
+ sprintf(path, "%s/cache", base_directory);
emfh_http_cache = camel_data_cache_new(path, 0, NULL);
camel_data_cache_set_expire_age(emfh_http_cache, 24*60*60);
camel_data_cache_set_expire_access(emfh_http_cache, 2*60*60);
diff --git a/mail/em-marshal.list b/mail/em-marshal.list
index 910bfb1b3d..0c8bfbbbfb 100644
--- a/mail/em-marshal.list
+++ b/mail/em-marshal.list
@@ -1 +1,2 @@
BOOLEAN:BOXED,POINTER,POINTER
+NONE:POINTER
diff --git a/mail/em-popup.c b/mail/em-popup.c
index 69fd1d0b6d..74ba86c33b 100644
--- a/mail/em-popup.c
+++ b/mail/em-popup.c
@@ -353,7 +353,8 @@ em_popup_create_menu_once(EMPopup *emp, EMPopupTarget *target, guint32 hide_mask
menu = em_popup_create_menu(emp, hide_mask, disable_mask);
- g_signal_connect_swapped(menu, "selection_done", G_CALLBACK(em_popup_target_free), target);
+ if (target)
+ g_signal_connect_swapped(menu, "selection_done", G_CALLBACK(em_popup_target_free), target);
g_signal_connect(menu, "selection_done", G_CALLBACK(emp_popup_done), emp);
return menu;
diff --git a/mail/em-popup.h b/mail/em-popup.h
index 877b28fc28..0ad1d0015c 100644
--- a/mail/em-popup.h
+++ b/mail/em-popup.h
@@ -69,6 +69,7 @@ enum _em_popup_target_t {
EM_POPUP_TARGET_SELECT,
EM_POPUP_TARGET_URI,
EM_POPUP_TARGET_PART,
+ EM_POPUP_TARGET_FOLDER,
};
/* Flags that describe a TARGET_SELECT */
@@ -103,6 +104,13 @@ enum {
EM_POPUP_PART_IMAGE = 1<<1,
};
+/* Flags that describe TARGET_FOLDER */
+enum {
+ EM_POPUP_FOLDER_LOCAL = 1<<0,
+ EM_POPUP_FOLDER_REMOTE = 1<<1,
+ EM_POPUP_FOLDER_VFOLDER = 1<<2,
+};
+
struct _EMPopupTarget {
enum _em_popup_target_t type;
guint32 mask; /* depends on type, see above */
@@ -118,6 +126,9 @@ struct _EMPopupTarget {
char *mime_type;
struct _CamelMimePart *part;
} part;
+ struct {
+ char *folder_uri;
+ } folder;
} data;
};
diff --git a/mail/em-utils.c b/mail/em-utils.c
index 49ef9af792..5b16d0cd7b 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -36,6 +36,7 @@
#include <filter/filter-editor.h>
+#include "mail-component.h"
#include "mail-mt.h"
#include "mail-ops.h"
#include "mail-tools.h"
@@ -215,14 +216,14 @@ static GtkWidget *filter_editor = NULL;
static void
filter_editor_response (GtkWidget *dialog, int button, gpointer user_data)
{
- extern char *evolution_dir;
FilterContext *fc;
if (button == GTK_RESPONSE_ACCEPT) {
char *user;
fc = g_object_get_data ((GObject *) dialog, "context");
- user = g_strdup_printf ("%s/filters.xml", evolution_dir);
+ user = g_strdup_printf ("%s/filters.xml",
+ mail_component_peek_base_directory (mail_component_peek ()));
rule_context_save ((RuleContext *) fc, user);
g_free (user);
}
@@ -249,7 +250,7 @@ static const char *filter_source_names[] = {
void
em_utils_edit_filters (GtkWidget *parent)
{
- extern char *evolution_dir;
+ const char *base_directory = mail_component_peek_base_directory (mail_component_peek ());
char *user, *system;
FilterContext *fc;
@@ -259,7 +260,7 @@ em_utils_edit_filters (GtkWidget *parent)
}
fc = filter_context_new ();
- user = g_strdup_printf ("%s/filters.xml", evolution_dir);
+ user = g_strdup_printf ("%s/filters.xml", base_directory);
system = EVOLUTION_PRIVDATADIR "/filtertypes.xml";
rule_context_load ((RuleContext *) fc, system, user);
g_free (user);
@@ -773,10 +774,10 @@ generate_account_hash (void)
return account_hash;
}
-static EDestination **
+static EABDestination **
em_utils_camel_address_to_destination (CamelInternetAddress *iaddr)
{
- EDestination *dest, **destv;
+ EABDestination *dest, **destv;
int n, i, j;
if (iaddr == NULL)
@@ -785,14 +786,14 @@ em_utils_camel_address_to_destination (CamelInternetAddress *iaddr)
if ((n = camel_address_length ((CamelAddress *) iaddr)) == 0)
return NULL;
- destv = g_malloc (sizeof (EDestination *) * (n + 1));
+ destv = g_malloc (sizeof (EABDestination *) * (n + 1));
for (i = 0, j = 0; i < n; i++) {
const char *name, *addr;
if (camel_internet_address_get (iaddr, i, &name, &addr)) {
- dest = e_destination_new ();
- e_destination_set_name (dest, name);
- e_destination_set_email (dest, addr);
+ dest = eab_destination_new ();
+ eab_destination_set_name (dest, name);
+ eab_destination_set_email (dest, addr);
destv[j++] = dest;
}
@@ -813,7 +814,7 @@ reply_get_composer (GtkWidget *parent, CamelMimeMessage *message, EAccount *acco
CamelInternetAddress *to, CamelInternetAddress *cc)
{
const char *message_id, *references;
- EDestination **tov, **ccv;
+ EABDestination **tov, **ccv;
EMsgComposer *composer;
char *subject;
@@ -1211,7 +1212,7 @@ post_reply_to_message (CamelFolder *folder, const char *uid, CamelMimeMessage *m
const char *message_id, *references;
CamelInternetAddress *to = NULL;
GtkWidget *parent = user_data;
- EDestination **tov = NULL;
+ EABDestination **tov = NULL;
EMsgComposer *composer;
char *subject, *url;
EAccount *account;
diff --git a/mail/em-utils.h b/mail/em-utils.h
index 0114c86ae2..a30c9109fb 100644
--- a/mail/em-utils.h
+++ b/mail/em-utils.h
@@ -36,6 +36,7 @@ struct _GtkWindow;
struct _CamelFolder;
struct _CamelStream;
struct _CamelMimeMessage;
+struct _CamelMimePart;
struct _GtkSelectionData;
struct _GtkAdjustment;
struct _EMsgComposer;
diff --git a/mail/folder-browser-factory.c b/mail/folder-browser-factory.c
index f0157bac9a..194396b062 100644
--- a/mail/folder-browser-factory.c
+++ b/mail/folder-browser-factory.c
@@ -118,14 +118,13 @@ control_destroy_cb (GtkObject *fb, GObject *control)
}
BonoboControl *
-folder_browser_factory_new_control (const char *uri,
- const GNOME_Evolution_Shell shell)
+folder_browser_factory_new_control (const char *uri)
{
BonoboControl *control;
GtkWidget *fb;
#if 0
- if (!(fb = folder_browser_new (shell, uri)))
+ if (!(fb = folder_browser_new (uri)))
return NULL;
FOLDER_BROWSER (fb)->pref_master = TRUE; /* save UI settings changed in this FB */
diff --git a/mail/folder-browser-factory.h b/mail/folder-browser-factory.h
index 2c858c9c56..109938c27e 100644
--- a/mail/folder-browser-factory.h
+++ b/mail/folder-browser-factory.h
@@ -15,8 +15,7 @@
#include "Evolution.h"
#include "e-util/e-list.h"
-BonoboControl *folder_browser_factory_new_control (const char *uri,
- const GNOME_Evolution_Shell shell);
+BonoboControl *folder_browser_factory_new_control (const char *uri);
EList *folder_browser_factory_get_control_list (void);
struct _EMFolderBrowser *folder_browser_factory_get_browser(const char *uri);
diff --git a/mail/folder-browser-ui.c b/mail/folder-browser-ui.c
new file mode 100644
index 0000000000..9ccdb2db79
--- /dev/null
+++ b/mail/folder-browser-ui.c
@@ -0,0 +1,816 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Peter Williams <peterw@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * 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 2 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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <libgnome/gnome-util.h> /* gnome_util_prepend_user_home */
+
+#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-ui-component.h>
+#include <bonobo/bonobo-ui-util.h>
+
+#include "widgets/misc/e-charset-picker.h"
+#include "widgets/menus/gal-view-menus.h" /* GalView stuff */
+#include <gal/menus/gal-view-factory-etable.h>
+#include <gal/menus/gal-view-etable.h>
+
+#include "e-util/e-meta.h"
+
+#include "mail-config.h"
+#include "mail-callbacks.h" /* almost all the verbs */
+#include "mail-session.h" /* mail_session_forget_passwords */
+
+#include "folder-browser-ui.h"
+
+#include "evolution-shell-component-utils.h" /* Pixmap stuff */
+
+
+/*
+ * Add with 'folder_browser'
+ */
+
+static BonoboUIVerb message_verbs [] = {
+ BONOBO_UI_UNSAFE_VERB ("MailNext", next_msg),
+ BONOBO_UI_UNSAFE_VERB ("MailNextFlagged", next_flagged_msg),
+ BONOBO_UI_UNSAFE_VERB ("MailNextUnread", next_unread_msg),
+ BONOBO_UI_UNSAFE_VERB ("MailNextThread", next_thread),
+ BONOBO_UI_UNSAFE_VERB ("MailPrevious", previous_msg),
+ BONOBO_UI_UNSAFE_VERB ("MailPreviousFlagged", previous_flagged_msg),
+ BONOBO_UI_UNSAFE_VERB ("MailPreviousUnread", previous_unread_msg),
+ BONOBO_UI_UNSAFE_VERB ("AddSenderToAddressbook", add_sender_to_addrbook),
+ BONOBO_UI_UNSAFE_VERB ("MessageApplyFilters", apply_filters),
+ BONOBO_UI_UNSAFE_VERB ("MessageCopy", copy_msg),
+ BONOBO_UI_UNSAFE_VERB ("MessageDelete", delete_msg),
+ BONOBO_UI_UNSAFE_VERB ("MessageForward", forward),
+ BONOBO_UI_UNSAFE_VERB ("MessageForwardAttached", forward_attached),
+ BONOBO_UI_UNSAFE_VERB ("MessageForwardInline", forward_inline),
+ BONOBO_UI_UNSAFE_VERB ("MessageForwardQuoted", forward_quoted),
+ BONOBO_UI_UNSAFE_VERB ("MessageRedirect", redirect),
+ BONOBO_UI_UNSAFE_VERB ("MessageMarkAsRead", mark_as_seen),
+ BONOBO_UI_UNSAFE_VERB ("MessageMarkAsUnRead", mark_as_unseen),
+ BONOBO_UI_UNSAFE_VERB ("MessageMarkAsImportant", mark_as_important),
+ BONOBO_UI_UNSAFE_VERB ("MessageMarkAsUnimportant", mark_as_unimportant),
+ BONOBO_UI_UNSAFE_VERB ("MessageFollowUpFlag", flag_for_followup),
+ BONOBO_UI_UNSAFE_VERB ("MessageMove", move_msg),
+ BONOBO_UI_UNSAFE_VERB ("MessageOpen", open_message),
+ BONOBO_UI_UNSAFE_VERB ("MessagePostReply", post_reply),
+ BONOBO_UI_UNSAFE_VERB ("MessageReplyAll", reply_to_all),
+ BONOBO_UI_UNSAFE_VERB ("MessageReplyList", reply_to_list),
+ BONOBO_UI_UNSAFE_VERB ("MessageReplySender", reply_to_sender),
+ BONOBO_UI_UNSAFE_VERB ("MessageResend", resend_msg),
+ BONOBO_UI_UNSAFE_VERB ("MessageSaveAs", save_msg),
+ BONOBO_UI_UNSAFE_VERB ("MessageSearch", search_msg),
+ BONOBO_UI_UNSAFE_VERB ("MessageUndelete", undelete_msg),
+ BONOBO_UI_UNSAFE_VERB ("PrintMessage", print_msg),
+ BONOBO_UI_UNSAFE_VERB ("TextZoomIn", zoom_in),
+ BONOBO_UI_UNSAFE_VERB ("TextZoomOut", zoom_out),
+ BONOBO_UI_UNSAFE_VERB ("TextZoomReset", zoom_reset),
+ BONOBO_UI_UNSAFE_VERB ("PrintPreviewMessage", print_preview_msg),
+ BONOBO_UI_UNSAFE_VERB ("ToolsFilterMailingList", filter_mlist),
+ BONOBO_UI_UNSAFE_VERB ("ToolsFilterRecipient", filter_recipient),
+ BONOBO_UI_UNSAFE_VERB ("ToolsFilterSender", filter_sender),
+ BONOBO_UI_UNSAFE_VERB ("ToolsFilterSubject", filter_subject),
+ BONOBO_UI_UNSAFE_VERB ("ToolsVFolderMailingList", vfolder_mlist),
+ BONOBO_UI_UNSAFE_VERB ("ToolsVFolderRecipient", vfolder_recipient),
+ BONOBO_UI_UNSAFE_VERB ("ToolsVFolderSender", vfolder_sender),
+ BONOBO_UI_UNSAFE_VERB ("ToolsVFolderSubject", vfolder_subject),
+ BONOBO_UI_UNSAFE_VERB ("ViewLoadImages", load_images),
+ /* ViewHeaders stuff is a radio */
+ /* CaretMode is a toggle */
+
+ BONOBO_UI_VERB_END
+};
+
+static BonoboUIVerb list_verbs [] = {
+ BONOBO_UI_UNSAFE_VERB ("EditCut", folder_browser_cut),
+ BONOBO_UI_UNSAFE_VERB ("EditCopy", folder_browser_copy),
+ BONOBO_UI_UNSAFE_VERB ("EditPaste", folder_browser_paste),
+ BONOBO_UI_UNSAFE_VERB ("EditInvertSelection", invert_selection),
+ BONOBO_UI_UNSAFE_VERB ("EditSelectAll", select_all),
+ BONOBO_UI_UNSAFE_VERB ("EditSelectThread", select_thread),
+ BONOBO_UI_UNSAFE_VERB ("ChangeFolderProperties", configure_folder),
+ BONOBO_UI_UNSAFE_VERB ("FolderExpunge", expunge_folder),
+ /* HideDeleted is a toggle */
+ BONOBO_UI_UNSAFE_VERB ("MessageMarkAllAsRead", mark_all_as_seen),
+ BONOBO_UI_UNSAFE_VERB ("ViewHideRead", hide_read),
+ BONOBO_UI_UNSAFE_VERB ("ViewHideSelected", hide_selected),
+ BONOBO_UI_UNSAFE_VERB ("ViewShowAll", hide_none),
+ /* ViewThreaded is a toggle */
+
+ BONOBO_UI_VERB_END
+};
+
+static BonoboUIVerb global_verbs [] = {
+ BONOBO_UI_UNSAFE_VERB ("EmptyTrash", empty_trash),
+ BONOBO_UI_UNSAFE_VERB ("ForgetPasswords", mail_session_forget_passwords),
+ BONOBO_UI_UNSAFE_VERB ("MailCompose", compose_msg),
+ BONOBO_UI_UNSAFE_VERB ("MailPost", post_message),
+ BONOBO_UI_UNSAFE_VERB ("MailStop", stop_threads),
+ BONOBO_UI_UNSAFE_VERB ("ToolsFilters", filter_edit),
+ BONOBO_UI_UNSAFE_VERB ("ToolsSubscriptions", manage_subscriptions),
+ BONOBO_UI_UNSAFE_VERB ("ToolsVFolders", vfolder_edit_vfolders),
+ /* ViewPreview is a toggle */
+
+ BONOBO_UI_VERB_END
+};
+
+static EPixmap message_pixcache [] = {
+ E_PIXMAP ("/commands/PrintMessage", "print.xpm"),
+ E_PIXMAP ("/commands/PrintPreviewMessage", "print-preview.xpm"),
+ E_PIXMAP ("/commands/MessageDelete", "evolution-trash-mini.png"),
+ E_PIXMAP ("/commands/MessageUndelete", "undelete_message-16.png"),
+ E_PIXMAP ("/commands/MessageCopy", "copy_16_message.xpm"),
+ E_PIXMAP ("/commands/MessageMove", "move_message.xpm"),
+ E_PIXMAP ("/commands/MessageReplyAll", "reply_to_all.xpm"),
+ E_PIXMAP ("/commands/MessageReplySender", "reply.xpm"),
+ E_PIXMAP ("/commands/MessageForward", "forward.xpm"),
+ E_PIXMAP ("/commands/MessageApplyFilters", "apply-filters-16.xpm"),
+ E_PIXMAP ("/commands/MessageSearch", "search-16.png"),
+ E_PIXMAP ("/commands/MessageSaveAs", "save-as-16.png"),
+ E_PIXMAP ("/commands/MessageMarkAsRead", "mail-read.xpm"),
+ E_PIXMAP ("/commands/MessageMarkAsUnRead", "mail-new.xpm"),
+ E_PIXMAP ("/commands/MessageMarkAsImportant", "priority-high.xpm"),
+ E_PIXMAP ("/commands/MessageFollowUpFlag", "flag-for-followup-16.png"),
+
+ E_PIXMAP ("/Toolbar/MailMessageToolbar/MessageReplySender", "buttons/reply.png"),
+ E_PIXMAP ("/Toolbar/MailMessageToolbar/MessageReplyAll", "buttons/reply-to-all.png"),
+ E_PIXMAP ("/Toolbar/MailMessageToolbar/MessageForward", "buttons/forward.png"),
+ E_PIXMAP ("/Toolbar/MailMessageToolbar/PrintMessage", "buttons/print.png"),
+ E_PIXMAP ("/Toolbar/MailMessageToolbar/MessageMove", "buttons/move-message.png"),
+ E_PIXMAP ("/Toolbar/MailMessageToolbar/MessageCopy", "buttons/copy-message.png"),
+ E_PIXMAP ("/Toolbar/MailMessageToolbar/MessageDelete", "buttons/delete-message.png"),
+
+ E_PIXMAP ("/Toolbar/MailNextButtons/MailNext", "buttons/next-message.png"),
+ E_PIXMAP ("/Toolbar/MailNextButtons/MailPrevious", "buttons/previous-message.png"),
+
+ E_PIXMAP_END
+};
+
+static EPixmap list_pixcache [] = {
+ E_PIXMAP ("/commands/ChangeFolderProperties", "configure_16_folder.xpm"),
+ E_PIXMAP ("/commands/ViewHideRead", "hide_read_messages.xpm"),
+ E_PIXMAP ("/commands/ViewHideSelected", "hide_selected_messages.xpm"),
+ E_PIXMAP ("/commands/ViewShowAll", "show_all_messages.xpm"),
+
+ E_PIXMAP ("/commands/EditCut", "16_cut.png"),
+ E_PIXMAP ("/commands/EditCopy", "16_copy.png"),
+ E_PIXMAP ("/commands/EditPaste", "16_paste.png"),
+
+ E_PIXMAP_END
+};
+
+static EPixmap global_pixcache [] = {
+ E_PIXMAP ("/commands/MailCompose", "new-message.xpm"),
+
+ E_PIXMAP_END
+};
+
+enum {
+ IS_DRAFTS_FOLDER = (1 << 0),
+ IS_OUTBOX_FOLDER = (1 << 1),
+ IS_SENT_FOLDER = (1 << 2),
+
+ IS_OUTGOING_FOLDER = (IS_DRAFTS_FOLDER | IS_OUTBOX_FOLDER | IS_SENT_FOLDER),
+ IS_INCOMING_FOLDER = (1 << 3),
+
+ IS_ANY_FOLDER = (IS_OUTGOING_FOLDER | IS_INCOMING_FOLDER),
+
+ SELECTION_NONE = (1 << 4),
+ SELECTION_SINGLE = (1 << 5),
+ SELECTION_MULTIPLE = (1 << 6),
+
+ SELECTION_ANYTHING = (SELECTION_SINGLE | SELECTION_MULTIPLE),
+
+ IS_THREADED = (1 << 7),
+ NOT_THREADED = (1<<8),
+ ANY_THREADED = (IS_THREADED|NOT_THREADED),
+
+ HAS_UNDELETED = (1 << 9),
+ HAS_DELETED = (1 << 10),
+ HAS_UNREAD = (1 << 11),
+ HAS_READ = (1 << 12),
+ HAS_UNIMPORTANT = (1 << 13),
+ HAS_IMPORTANT = (1 << 14)
+};
+
+#define HAS_FLAGS (HAS_UNDELETED | HAS_DELETED | \
+ HAS_UNREAD | HAS_READ | \
+ HAS_UNIMPORTANT | HAS_IMPORTANT)
+
+#define IS_1MESSAGE (IS_ANY_FOLDER | SELECTION_SINGLE | ANY_THREADED | HAS_FLAGS)
+#define IS_0MESSAGE (IS_ANY_FOLDER | SELECTION_ANYTHING | SELECTION_NONE | ANY_THREADED | HAS_FLAGS)
+#define IS_NMESSAGE (IS_ANY_FOLDER | SELECTION_ANYTHING | ANY_THREADED | HAS_FLAGS)
+
+struct _UINode {
+ const char *name;
+ guint32 enable_mask;
+};
+
+struct _UINode default_ui_nodes[] = {
+ { "ViewLoadImages", IS_1MESSAGE },
+ { "ViewFullHeaders", IS_0MESSAGE },
+ { "ViewNormal", IS_0MESSAGE },
+ { "ViewSource", IS_0MESSAGE },
+ { "CaretMode", IS_0MESSAGE },
+
+ { "AddSenderToAddressbook", IS_INCOMING_FOLDER | SELECTION_SINGLE | ANY_THREADED | HAS_FLAGS },
+
+ { "MessageResend", IS_SENT_FOLDER | SELECTION_SINGLE | ANY_THREADED | HAS_FLAGS },
+
+ /* actions that work on exactly 1 message */
+ { "MessagePostReply", IS_1MESSAGE },
+ { "MessageReplyAll", IS_1MESSAGE },
+ { "MessageReplyList", IS_1MESSAGE },
+ { "MessageReplySender", IS_1MESSAGE },
+ { "MessageForwardInline", IS_1MESSAGE },
+ { "MessageForwardQuoted", IS_1MESSAGE },
+ { "MessageRedirect", IS_1MESSAGE },
+ { "MessageSearch", IS_1MESSAGE },
+
+ { "PrintMessage", IS_1MESSAGE },
+ { "PrintPreviewMessage", IS_1MESSAGE },
+
+ { "ToolsFilterMailingList", IS_1MESSAGE },
+ { "ToolsFilterRecipient", IS_1MESSAGE },
+ { "ToolsFilterSender", IS_1MESSAGE },
+ { "ToolsFilterSubject", IS_1MESSAGE },
+
+ { "ToolsVFolderMailingList", IS_1MESSAGE },
+ { "ToolsVFolderRecipient", IS_1MESSAGE },
+ { "ToolsVFolderSender", IS_1MESSAGE },
+ { "ToolsVFolderSubject", IS_1MESSAGE },
+
+ /* actions that work on >= 1 message */
+ { "MessageApplyFilters", IS_NMESSAGE },
+ { "MessageCopy", IS_NMESSAGE },
+ { "MessageMove", IS_NMESSAGE },
+ { "MessageDelete", IS_NMESSAGE },
+ { "MessageUndelete", IS_NMESSAGE & ~HAS_DELETED },
+ { "MessageMarkAsRead", IS_NMESSAGE & ~HAS_UNREAD },
+ { "MessageMarkAsUnRead", IS_NMESSAGE & ~HAS_READ },
+ { "MessageMarkAsImportant", IS_NMESSAGE & ~HAS_UNIMPORTANT },
+ { "MessageMarkAsUnimportant", IS_NMESSAGE & ~HAS_IMPORTANT },
+ { "MessageFollowUpFlag", IS_NMESSAGE },
+ { "MessageOpen", IS_NMESSAGE },
+ { "MessageSaveAs", IS_NMESSAGE },
+ { "MessageForward", IS_NMESSAGE },
+ { "MessageForwardAttached", IS_NMESSAGE },
+
+ { "EditCut", IS_NMESSAGE },
+ { "EditCopy", IS_NMESSAGE },
+ { "EditPaste", IS_0MESSAGE },
+ { "EditSelectThread", IS_ANY_FOLDER | SELECTION_ANYTHING | IS_THREADED | HAS_FLAGS},
+
+ { "ViewHideSelected", IS_NMESSAGE },
+
+ /* FIXME: should these be single-selection? */
+ { "MailNext", IS_NMESSAGE },
+ { "MailNextFlagged", IS_NMESSAGE },
+ { "MailNextUnread", IS_NMESSAGE },
+ { "MailNextThread", IS_NMESSAGE },
+ { "MailPrevious", IS_NMESSAGE },
+ { "MailPreviousFlagged", IS_NMESSAGE },
+ { "MailPreviousUnread", IS_NMESSAGE },
+};
+
+static int num_default_ui_nodes = sizeof (default_ui_nodes) / sizeof (default_ui_nodes[0]);
+
+
+static void
+ui_add (FolderBrowser *fb, const char *name, BonoboUIVerb verb[], EPixmap pixcache[])
+{
+ BonoboUIComponent *uic = fb->uicomp;
+ char *file;
+
+ bonobo_ui_component_add_verb_list_with_data (uic, verb, fb);
+
+ /*bonobo_ui_component_freeze (uic, NULL);*/
+
+ file = g_strconcat (EVOLUTION_UIDIR "/evolution-mail-", name, ".xml", NULL);
+ bonobo_ui_util_set_ui (uic, PREFIX, file, "evolution-mail", NULL);
+ g_free (file);
+
+ e_pixmaps_update (uic, pixcache);
+
+ /*bonobo_ui_component_thaw (uic, NULL);*/
+}
+
+/* more complex stuff */
+
+static void
+display_view (GalViewInstance *instance, GalView *view, gpointer data)
+{
+ FolderBrowser *fb = data;
+
+ if (GAL_IS_VIEW_ETABLE (view)) {
+ gal_view_etable_attach_tree (GAL_VIEW_ETABLE (view), fb->message_list->tree);
+ }
+}
+
+void
+folder_browser_ui_setup_view_menus (FolderBrowser *fb)
+{
+ static GalViewCollection *collection = NULL;
+ char *id;
+ gboolean outgoing;
+
+ if (fb->uicomp == NULL || fb->folder == NULL)
+ return;
+
+ g_assert (fb->view_instance == NULL);
+ g_assert (fb->view_menus == NULL);
+
+ outgoing = folder_browser_is_drafts (fb) ||
+ folder_browser_is_sent (fb) ||
+ folder_browser_is_outbox (fb);
+
+ if (collection == NULL) {
+ ETableSpecification *spec;
+ char *local_dir;
+ GalViewFactory *factory;
+
+ collection = gal_view_collection_new ();
+
+ gal_view_collection_set_title (collection, _("Mail"));
+
+ local_dir = gnome_util_prepend_user_home ("/evolution/views/mail/");
+ gal_view_collection_set_storage_directories (collection,
+ EVOLUTION_GALVIEWSDIR "/mail/",
+ local_dir);
+ g_free (local_dir);
+
+ spec = e_table_specification_new ();
+ e_table_specification_load_from_file (spec, EVOLUTION_ETSPECDIR "/message-list.etspec");
+
+ factory = gal_view_factory_etable_new (spec);
+ g_object_unref (spec);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+
+ gal_view_collection_load (collection);
+ }
+
+ id = mail_config_folder_to_safe_url (fb->folder);
+ fb->view_instance = gal_view_instance_new (collection, id);
+ g_free (id);
+
+ if (outgoing)
+ gal_view_instance_set_default_view (fb->view_instance, "As_Sent_Folder");
+
+ if (!gal_view_instance_exists (fb->view_instance)) {
+ char *path;
+ struct stat st;
+
+ gal_view_instance_load (fb->view_instance);
+
+ path = mail_config_folder_to_cachename (fb->folder, "et-header-");
+ if (path && stat (path, &st) == 0 && st.st_size > 0 && S_ISREG (st.st_mode)) {
+ ETableSpecification *spec;
+ ETableState *state;
+ GalView *view;
+
+ spec = e_table_specification_new();
+ e_table_specification_load_from_file (spec, EVOLUTION_ETSPECDIR "/message-list.etspec");
+ view = gal_view_etable_new (spec, "");
+ g_object_unref (spec);
+
+ state = e_table_state_new ();
+ e_table_state_load_from_file (state, path);
+ gal_view_etable_set_state (GAL_VIEW_ETABLE (view), state);
+ g_object_unref (state);
+
+ gal_view_instance_set_custom_view (fb->view_instance, view);
+ g_object_unref (view);
+ }
+ g_free (path);
+ }
+
+ fb->view_menus = gal_view_menus_new (fb->view_instance);
+ gal_view_menus_apply (fb->view_menus, fb->uicomp, NULL);
+
+ /* Due to CORBA reentrancy, the view could be gone now. */
+ if (fb->view_instance == NULL)
+ return;
+
+ g_signal_connect (fb->view_instance, "display_view", G_CALLBACK (display_view), fb);
+
+ display_view (fb->view_instance, gal_view_instance_get_current_view (fb->view_instance), fb);
+}
+
+/* Gets rid of the view instance and view menus objects */
+void
+folder_browser_ui_discard_view_menus (FolderBrowser *fb)
+{
+ g_assert (fb->view_instance != NULL);
+ g_assert (fb->view_menus != NULL);
+
+ g_object_unref (fb->view_instance);
+ fb->view_instance = NULL;
+
+ g_object_unref (fb->view_menus);
+ fb->view_menus = NULL;
+}
+
+void
+folder_browser_ui_message_list_focus (FolderBrowser *fb)
+{
+ g_assert (fb->uicomp != NULL);
+
+ bonobo_ui_component_set_prop (fb->uicomp, "/commands/EditInvertSelection",
+ "sensitive", "1", NULL);
+/* bonobo_ui_component_set_prop (fb->uicomp, "/commands/EditSelectThread",
+ "sensitive", "1", NULL);*/
+}
+
+void
+folder_browser_ui_message_list_unfocus (FolderBrowser *fb)
+{
+ g_assert (fb->uicomp != NULL);
+
+ bonobo_ui_component_set_prop (fb->uicomp, "/commands/EditInvertSelection",
+ "sensitive", "0", NULL);
+ /*bonobo_ui_component_set_prop (fb->uicomp, "/commands/EditSelectThread",
+ "sensitive", "0", NULL);*/
+}
+
+static void
+folder_browser_setup_property_menu (FolderBrowser *fb, BonoboUIComponent *uic)
+{
+ char *name, *base = NULL;
+ CamelURL *url;
+
+ url = camel_url_new (fb->uri, NULL);
+ if (url)
+ base = g_path_get_basename(url->fragment?url->fragment:url->path);
+
+ if (base && base[0] != '\0')
+ name = g_strdup_printf (_("Properties for \"%s\""), base);
+ else
+ name = g_strdup (_("Properties"));
+
+ bonobo_ui_component_set_prop (
+ uic, "/menu/File/Folder/ComponentPlaceholder/ChangeFolderProperties",
+ "label", name, NULL);
+ g_free (name);
+ g_free(base);
+
+ if (url)
+ camel_url_free (url);
+
+ fbui_sensitise_item (fb, "ChangeFolderProperties",
+ (strncmp (fb->uri, "vfolder:", 8) == 0 || strncmp (fb->uri, "file:", 5) == 0));
+}
+
+/* Must be in the same order as MailConfigDisplayStyle */
+/* used in folder-browser.c as well (therefore not static) */
+char *message_display_styles[] = {
+ "/commands/ViewNormal",
+ "/commands/ViewFullHeaders",
+ "/commands/ViewSource"
+};
+
+/* public */
+
+void
+folder_browser_ui_add_message (FolderBrowser *fb)
+{
+ BonoboUIComponent *uic = fb->uicomp;
+ FolderBrowserSelectionState prev_state;
+ GConfClient *gconf;
+ int style;
+ gboolean caret_mode;
+
+ gconf = mail_config_get_gconf_client ();
+
+ if (fb->sensitise_state) {
+ g_hash_table_destroy(fb->sensitise_state);
+ fb->sensitise_state = NULL;
+ }
+
+ ui_add (fb, "message", message_verbs, message_pixcache);
+
+ caret_mode = gconf_client_get_bool (gconf, "/apps/evolution/mail/display/caret_mode", NULL);
+ bonobo_ui_component_set_prop(uic, "/commands/CaretMode", "state", caret_mode?"1":"0", NULL);
+ bonobo_ui_component_add_listener (uic, "CaretMode", folder_browser_toggle_caret_mode, fb);
+
+ /* Display Style */
+ style = gconf_client_get_int (gconf, "/apps/evolution/mail/display/message_style", NULL);
+ style = style >= 0 && style < MAIL_CONFIG_DISPLAY_MAX ? style : 0;
+ bonobo_ui_component_set_prop (uic, message_display_styles[style], "state", "1", NULL);
+ bonobo_ui_component_add_listener (uic, "ViewNormal", folder_browser_set_message_display_style, fb);
+ bonobo_ui_component_add_listener (uic, "ViewFullHeaders", folder_browser_set_message_display_style, fb);
+ bonobo_ui_component_add_listener (uic, "ViewSource", folder_browser_set_message_display_style, fb);
+ if (fb->mail_display->display_style != style) {
+ fb->mail_display->display_style = style;
+ mail_display_redisplay (fb->mail_display, TRUE);
+ }
+
+ /* Resend Message */
+ if (fb->folder && !folder_browser_is_sent (fb))
+ fbui_sensitise_item (fb, "MessageResend", FALSE);
+
+ /* sensitivity of message-specific commands */
+ prev_state = fb->selection_state;
+ fb->selection_state = FB_SELSTATE_UNDEFINED;
+ folder_browser_ui_set_selection_state (fb, prev_state);
+
+ /* Charset picker */
+ e_charset_picker_bonobo_ui_populate (uic, "/menu/View", FB_DEFAULT_CHARSET,
+ folder_browser_charset_changed, fb);
+}
+
+void
+folder_browser_ui_add_list (FolderBrowser *fb)
+{
+ BonoboUIComponent *uic = fb->uicomp;
+ GConfClient *gconf;
+ int state;
+
+ gconf = mail_config_get_gconf_client ();
+
+ if (fb->sensitise_state) {
+ g_hash_table_destroy (fb->sensitise_state);
+ fb->sensitise_state = NULL;
+ }
+
+ ui_add (fb, "list", list_verbs, list_pixcache);
+
+ /* Hide Deleted */
+ state = !gconf_client_get_bool (gconf, "/apps/evolution/mail/display/show_deleted", NULL);
+ bonobo_ui_component_set_prop (uic, "/commands/HideDeleted", "state", state ? "1" : "0", NULL);
+ bonobo_ui_component_add_listener (uic, "HideDeleted", folder_browser_toggle_hide_deleted, fb);
+ if (!(fb->folder && (fb->folder->folder_flags & CAMEL_FOLDER_IS_TRASH)))
+ message_list_set_hidedeleted (fb->message_list, state);
+ else
+ fbui_sensitise_item (fb, "HideDeleted", FALSE);
+
+ /* Threaded toggle */
+ state = gconf_client_get_bool (gconf, "/apps/evolution/mail/display/thread_list", NULL);
+ if (fb->meta)
+ state = e_meta_get_bool(fb->meta, "thread_list", state);
+
+ bonobo_ui_component_set_prop (uic, "/commands/ViewThreaded", "state", state ? "1" : "0", NULL);
+ bonobo_ui_component_add_listener (uic, "ViewThreaded", folder_browser_toggle_threads, fb);
+ message_list_set_threaded (fb->message_list, state);
+ state = fb->selection_state;
+ fb->selection_state = FB_SELSTATE_UNDEFINED;
+ folder_browser_ui_set_selection_state (fb, state);
+
+ /* Property menu */
+ folder_browser_setup_property_menu (fb, fb->uicomp);
+
+ /* View menu */
+ if (fb->view_instance == NULL)
+ folder_browser_ui_setup_view_menus (fb);
+}
+
+void
+folder_browser_ui_rm_list (FolderBrowser *fb)
+{
+ /* View menu */
+ if (fb->view_instance != NULL)
+ folder_browser_ui_discard_view_menus (fb);
+}
+
+void
+folder_browser_ui_add_global (FolderBrowser *fb)
+{
+ BonoboUIComponent *uic = fb->uicomp;
+ gboolean show_preview;
+ GConfClient *gconf;
+ int paned_size;
+
+ gconf = mail_config_get_gconf_client ();
+
+ if (fb->sensitise_state) {
+ g_hash_table_destroy (fb->sensitise_state);
+ fb->sensitise_state = NULL;
+ }
+
+ ui_add (fb, "global", global_verbs, global_pixcache);
+
+ /* (Pre)view pane size (do this first because it affects the
+ preview settings - see folder_browser_set_message_preview()
+ internals for details) */
+ paned_size = gconf_client_get_int (gconf, "/apps/evolution/mail/display/paned_size", NULL);
+ g_signal_handler_block (fb->vpaned, fb->paned_resize_id);
+ gtk_paned_set_position (GTK_PANED (fb->vpaned), paned_size);
+ g_signal_handler_unblock (fb->vpaned, fb->paned_resize_id);
+
+ /* (Pre)view toggle */
+ show_preview = gconf_client_get_bool (gconf, "/apps/evolution/mail/display/show_preview", NULL);
+ if (fb->meta)
+ show_preview = e_meta_get_bool(fb->meta, "show_preview", show_preview);
+ bonobo_ui_component_set_prop (uic, "/commands/ViewPreview", "state", show_preview ? "1" : "0", NULL);
+ folder_browser_set_message_preview (fb, show_preview);
+
+ /* listen for user-changes */
+ bonobo_ui_component_add_listener (uic, "ViewPreview", folder_browser_toggle_preview, fb);
+
+ /* Stop button */
+ /* TODO: Go through cache, but we can't becaus eof mail-mt.c:set_stop at the moment */
+ bonobo_ui_component_set_prop (uic, "/commands/MailStop", "sensitive", "0", NULL);
+}
+
+void
+folder_browser_ui_rm_all (FolderBrowser *fb)
+{
+ BonoboUIComponent *uic = fb->uicomp;
+
+ if (bonobo_ui_component_get_container (uic) != NULL) {
+ bonobo_ui_component_rm (uic, "/", NULL);
+ bonobo_ui_component_unset_container (uic, NULL);
+ }
+
+ if (fb->sensitise_state) {
+ g_hash_table_destroy (fb->sensitise_state);
+ fb->sensitise_state = NULL;
+ }
+}
+
+void
+fbui_sensitise_item (FolderBrowser *fb, const char *item, int state)
+{
+ char *name, *key;
+ gpointer val_ptr;
+ int val;
+
+ /* If this whole caching idea doesn't work, remove it here */
+ if (fb->sensitise_state == NULL)
+ fb->sensitise_state = g_hash_table_new (g_str_hash, g_str_equal);
+
+ if (g_hash_table_lookup_extended (fb->sensitise_state, item, (void **)&key, &val_ptr)) {
+ val = GPOINTER_TO_INT(val_ptr);
+ if (val == state)
+ return;
+ }
+
+ if (fb->uicomp) {
+ name = g_alloca (strlen (item) + strlen ("/commands/") + 1);
+ sprintf (name, "/commands/%s", item);
+ bonobo_ui_component_set_prop (fb->uicomp, name, "sensitive", state ? "1" : "0", NULL);
+ g_hash_table_insert (fb->sensitise_state, (char *) item, GINT_TO_POINTER(state));
+ }
+}
+
+static void
+fbui_sensitize_items (FolderBrowser *fb, guint32 enable_mask)
+{
+ gboolean enable;
+ int i;
+
+ for (i = 0; i < num_default_ui_nodes; i++) {
+ enable = (default_ui_nodes[i].enable_mask & enable_mask) == enable_mask;
+ fbui_sensitise_item (fb, default_ui_nodes[i].name, enable);
+ }
+}
+
+void
+folder_browser_ui_scan_selection (FolderBrowser *fb)
+{
+ gboolean outgoing = FALSE;
+ guint32 enable_mask = 0;
+
+ if (fb->selection_state == FB_SELSTATE_SINGLE ||
+ fb->selection_state == FB_SELSTATE_MULTIPLE) {
+ GPtrArray *uids;
+ CamelMessageInfo *info;
+ guint32 temp_mask = 0;
+ int i;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ for (i = 0; i < uids->len; i++) {
+ info = camel_folder_get_message_info (fb->folder, uids->pdata[i]);
+ if (info == NULL)
+ continue;
+
+ if (info->flags & CAMEL_MESSAGE_DELETED)
+ temp_mask |= HAS_DELETED;
+ else
+ temp_mask |= HAS_UNDELETED;
+
+ if (info->flags & CAMEL_MESSAGE_SEEN)
+ temp_mask |= HAS_READ;
+ else
+ temp_mask |= HAS_UNREAD;
+
+ if (info->flags & CAMEL_MESSAGE_FLAGGED)
+ temp_mask |= HAS_IMPORTANT;
+ else
+ temp_mask |= HAS_UNIMPORTANT;
+
+ camel_folder_free_message_info (fb->folder, info);
+ g_free (uids->pdata[i]);
+ }
+
+ g_ptr_array_free (uids, TRUE);
+
+ /* yeah, the naming is a bit backwards, but we need to support
+ * the case when, say, both a deleted and an undeleted message
+ * are selected. Both the Delete and Undelete menu items should
+ * be sensitized, but the only good way to set the flags is as
+ * above. Anyway, the naming is a bit of a lie but it works out
+ * so that it's sensible both above and in the definition of
+ * the UI items, so deal with it.
+ */
+
+ enable_mask |= (~temp_mask & HAS_FLAGS);
+ }
+
+ if (folder_browser_is_drafts (fb)) {
+ enable_mask |= IS_DRAFTS_FOLDER;
+ outgoing = TRUE;
+ }
+
+ if (folder_browser_is_outbox (fb)) {
+ enable_mask |= IS_OUTBOX_FOLDER;
+ outgoing = TRUE;
+ }
+
+ if (folder_browser_is_sent (fb)) {
+ enable_mask |= IS_SENT_FOLDER;
+ outgoing = TRUE;
+ }
+
+ if (fb->message_list && fb->message_list->threaded)
+ enable_mask |= IS_THREADED;
+ else
+ enable_mask |= NOT_THREADED;
+
+ if (outgoing == FALSE)
+ enable_mask |= IS_INCOMING_FOLDER;
+
+ switch (fb->selection_state) {
+ case FB_SELSTATE_SINGLE:
+ enable_mask |= SELECTION_SINGLE;
+ break;
+ case FB_SELSTATE_MULTIPLE:
+ enable_mask |= SELECTION_MULTIPLE;
+ break;
+ case FB_SELSTATE_NONE:
+ default:
+ enable_mask |= SELECTION_NONE;
+ break;
+ }
+
+ fbui_sensitize_items (fb, enable_mask);
+}
+
+void
+folder_browser_ui_set_selection_state (FolderBrowser *fb, FolderBrowserSelectionState state)
+{
+ /* the state may be the same but with
+ * different messages selected, necessitating
+ * a recheck of the flags of the selected
+ * messages.
+ */
+
+ if (state == fb->selection_state &&
+ state != FB_SELSTATE_SINGLE &&
+ state != FB_SELSTATE_MULTIPLE)
+ return;
+
+ fb->selection_state = state;
+ folder_browser_ui_scan_selection (fb);
+}
+
+void
+folder_browser_ui_message_loaded (FolderBrowser *fb)
+{
+ BonoboUIComponent *uic = fb->uicomp;
+
+ if (uic) {
+ fb->selection_state = FB_SELSTATE_NONE;
+ folder_browser_ui_set_selection_state (fb, FB_SELSTATE_SINGLE);
+ }
+}
diff --git a/mail/folder-browser-ui.h b/mail/folder-browser-ui.h
new file mode 100644
index 0000000000..5c2bc1fa28
--- /dev/null
+++ b/mail/folder-browser-ui.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * folder-browser-ui.c: Sets up the Bonobo UI for FolderBrowsers
+ *
+ * Author:
+ * Peter Williams <peterw@ximian.com>
+ *
+ * (C) 2001 Ximian, Inc.
+ */
+
+#ifndef _FOLDER_BROWSER_UI_H
+#define _FOLDER_BROWSER_UI_H
+
+#include "folder-browser.h"
+
+void folder_browser_ui_add_message (FolderBrowser *fb);
+void folder_browser_ui_add_list (FolderBrowser *fb);
+void folder_browser_ui_add_global (FolderBrowser *fb);
+
+void folder_browser_ui_rm_list (FolderBrowser *fb);
+void folder_browser_ui_rm_all (FolderBrowser *fb);
+
+/* these affect the sensitivity of UI elements */
+void folder_browser_ui_scan_selection (FolderBrowser *fb);
+void folder_browser_ui_set_selection_state (FolderBrowser *fb, FolderBrowserSelectionState state);
+void folder_browser_ui_message_loaded (FolderBrowser *fb);
+
+void folder_browser_ui_discard_view_menus (FolderBrowser *fb);
+void folder_browser_ui_setup_view_menus (FolderBrowser *fb);
+/* Set the sensitivity of a single item */
+void fbui_sensitise_item(FolderBrowser *fb, const char *item, int state);
+
+void folder_browser_ui_message_list_focus (FolderBrowser *fb);
+void folder_browser_ui_message_list_unfocus (FolderBrowser *fb);
+
+#endif /* _FOLDER_BROWSER_UI_H */
diff --git a/mail/folder-browser.c b/mail/folder-browser.c
new file mode 100644
index 0000000000..6d7deb2bdb
--- /dev/null
+++ b/mail/folder-browser.c
@@ -0,0 +1,2679 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Miguel De Icaza <miguel@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2000-2003 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkinvisible.h>
+#include <gal/e-table/e-table.h>
+#include <gal/util/e-util.h>
+#include <gal/widgets/e-gui-utils.h>
+#include <gal/widgets/e-popup-menu.h>
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <libgnomeui/gnome-dialog-util.h>
+#include <libgnomeui/gnome-pixmap.h>
+
+#include <gtkhtml/htmlengine.h>
+#include <gtkhtml/htmlobject.h>
+#include <gtkhtml/htmlinterval.h>
+#include <gtkhtml/htmlengine-edit-cut-and-paste.h>
+
+#include "filter/vfolder-rule.h"
+#include "filter/vfolder-context.h"
+#include "filter/filter-option.h"
+#include "filter/filter-input.h"
+#include "filter/filter-label.h"
+
+#include "e-util/e-sexp.h"
+#include "e-util/e-mktemp.h"
+#include "e-util/e-meta.h"
+#include "folder-browser.h"
+#include "e-searching-tokenizer.h"
+#include "mail.h"
+#include "mail-callbacks.h"
+#include "mail-component.h"
+#include "mail-tools.h"
+#include "mail-ops.h"
+#include "mail-vfolder.h"
+#include "mail-autofilter.h"
+#include "mail-mt.h"
+#include "mail-folder-cache.h"
+#include "folder-browser-ui.h"
+
+#include "mail-local.h"
+#include "mail-config.h"
+
+#include <camel/camel-mime-message.h>
+#include <camel/camel-stream-mem.h>
+
+/* maybe this shooudlnt be private ... */
+#include "camel/camel-search-private.h"
+
+#define d(x)
+
+#define PARENT_TYPE (gtk_table_get_type ())
+
+static void folder_changed(CamelObject *o, void *event_data, void *data);
+static void main_folder_changed(CamelObject *o, void *event_data, void *data);
+
+#define X_EVOLUTION_MESSAGE_TYPE "x-evolution-message"
+#define MESSAGE_RFC822_TYPE "message/rfc822"
+#define TEXT_URI_LIST_TYPE "text/uri-list"
+#define TEXT_PLAIN_TYPE "text/plain"
+
+/* Drag & Drop types */
+enum DndTargetType {
+ DND_TARGET_TYPE_X_EVOLUTION_MESSAGE,
+ DND_TARGET_TYPE_MESSAGE_RFC822,
+ DND_TARGET_TYPE_TEXT_URI_LIST,
+};
+
+static GtkTargetEntry drag_types[] = {
+ { X_EVOLUTION_MESSAGE_TYPE, 0, DND_TARGET_TYPE_X_EVOLUTION_MESSAGE },
+ { MESSAGE_RFC822_TYPE, 0, DND_TARGET_TYPE_MESSAGE_RFC822 },
+ { TEXT_URI_LIST_TYPE, 0, DND_TARGET_TYPE_TEXT_URI_LIST },
+};
+
+static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]);
+
+enum PasteTargetType {
+ PASTE_TARGET_TYPE_X_EVOLUTION_MESSAGE,
+ PASTE_TARGET_TYPE_TEXT_PLAIN,
+};
+
+static GtkTargetPair paste_types[] = {
+ { 0, 0, PASTE_TARGET_TYPE_X_EVOLUTION_MESSAGE },
+ { GDK_SELECTION_TYPE_STRING, 0, PASTE_TARGET_TYPE_TEXT_PLAIN },
+};
+
+static const int num_paste_types = sizeof (paste_types) / sizeof (paste_types[0]);
+
+static GdkAtom clipboard_atom = GDK_NONE;
+
+static GtkTableClass *parent_class = NULL;
+
+enum {
+ FOLDER_LOADED,
+ MESSAGE_LOADED,
+ LAST_SIGNAL
+};
+
+static guint folder_browser_signals [LAST_SIGNAL] = {0, };
+
+static void
+folder_browser_finalise (GObject *object)
+{
+ FolderBrowser *folder_browser;
+
+ folder_browser = FOLDER_BROWSER (object);
+
+ g_free (folder_browser->loading_uid);
+ g_free (folder_browser->pending_uid);
+ g_free (folder_browser->new_uid);
+ g_free (folder_browser->loaded_uid);
+
+ g_free (folder_browser->uri);
+ folder_browser->uri = NULL;
+
+ if (folder_browser->clipboard_selection)
+ g_byte_array_free (folder_browser->clipboard_selection, TRUE);
+
+ if (folder_browser->sensitise_state) {
+ g_hash_table_destroy (folder_browser->sensitise_state);
+ folder_browser->sensitise_state = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+folder_browser_destroy (GtkObject *object)
+{
+ FolderBrowser *folder_browser;
+ CORBA_Environment ev;
+
+ folder_browser = FOLDER_BROWSER (object);
+
+ CORBA_exception_init (&ev);
+
+ if (folder_browser->seen_id != 0) {
+ g_source_remove (folder_browser->seen_id);
+ folder_browser->seen_id = 0;
+ }
+
+ if (folder_browser->loading_id != 0) {
+ g_source_remove(folder_browser->loading_id);
+ folder_browser->loading_id = 0;
+ }
+
+ if (folder_browser->message_list) {
+ gtk_widget_destroy (GTK_WIDGET (folder_browser->message_list));
+ folder_browser->message_list = NULL;
+ }
+
+ if (folder_browser->mail_display) {
+ gtk_widget_destroy (GTK_WIDGET (folder_browser->mail_display));
+ folder_browser->mail_display = NULL;
+ }
+
+ if (folder_browser->view_instance) {
+ g_object_unref (folder_browser->view_instance);
+ folder_browser->view_instance = NULL;
+ }
+
+ if (folder_browser->view_menus) {
+ g_object_unref (folder_browser->view_menus);
+ folder_browser->view_menus = NULL;
+ }
+
+ /* wait for all outstanding async events against us */
+ if (folder_browser->async_event) {
+ mail_async_event_destroy (folder_browser->async_event);
+ folder_browser->async_event = NULL;
+ }
+
+ if (folder_browser->search_full) {
+ g_object_unref (folder_browser->search_full);
+ folder_browser->search_full = NULL;
+ }
+
+ if (folder_browser->sensitize_timeout_id) {
+ g_source_remove (folder_browser->sensitize_timeout_id);
+ folder_browser->sensitize_timeout_id = 0;
+ }
+
+ if (folder_browser->shell_view != CORBA_OBJECT_NIL) {
+ CORBA_Object_release (folder_browser->shell_view, &ev);
+ folder_browser->shell_view = CORBA_OBJECT_NIL;
+ }
+
+ if (folder_browser->uicomp) {
+ bonobo_object_unref (BONOBO_OBJECT (folder_browser->uicomp));
+ folder_browser->uicomp = NULL;
+ }
+
+ if (folder_browser->invisible) {
+ g_object_unref (folder_browser->invisible);
+ folder_browser->invisible = NULL;
+ }
+
+ if (folder_browser->get_id != -1) {
+ mail_msg_cancel (folder_browser->get_id);
+ folder_browser->get_id = -1;
+ }
+
+ if (folder_browser->folder) {
+ camel_object_unhook_event (CAMEL_OBJECT (folder_browser->folder), "folder_changed",
+ folder_changed, folder_browser);
+ camel_object_unhook_event (CAMEL_OBJECT (folder_browser->folder), "message_changed",
+ folder_changed, folder_browser);
+ mail_sync_folder (folder_browser->folder, NULL, NULL);
+ camel_object_unref (folder_browser->folder);
+ folder_browser->folder = NULL;
+ }
+
+ CORBA_exception_free (&ev);
+
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
+}
+
+static void
+folder_browser_class_init (FolderBrowserClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_ref(PARENT_TYPE);
+
+ object_class->destroy = folder_browser_destroy;
+ gobject_class->finalize = folder_browser_finalise;
+
+ folder_browser_signals[FOLDER_LOADED] =
+ g_signal_new ("folder_loaded",
+ FOLDER_BROWSER_TYPE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (FolderBrowserClass, folder_loaded),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ folder_browser_signals[MESSAGE_LOADED] =
+ g_signal_new ("message_loaded",
+ FOLDER_BROWSER_TYPE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (FolderBrowserClass, message_loaded),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ /* clipboard atom */
+ if (!clipboard_atom)
+ clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
+
+ if (!paste_types[0].target)
+ paste_types[0].target = gdk_atom_intern (X_EVOLUTION_MESSAGE_TYPE, FALSE);
+}
+
+static void
+add_uid (MessageList *ml, const char *uid, gpointer data)
+{
+ g_ptr_array_add ((GPtrArray *) data, g_strdup (uid));
+}
+
+static void
+message_list_drag_data_get (ETree *tree, int row, ETreePath path, int col,
+ GdkDragContext *context, GtkSelectionData *selection_data,
+ guint info, guint time, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ GPtrArray *uids = NULL;
+ int i;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, add_uid, uids);
+ if (uids->len == 0) {
+ g_ptr_array_free (uids, TRUE);
+ return;
+ }
+
+ switch (info) {
+ case DND_TARGET_TYPE_TEXT_URI_LIST:
+ {
+ const char *filename, *tmpdir;
+ CamelMimeMessage *message;
+ CamelMimeFilter *filter;
+ CamelStream *fstream;
+ CamelStreamFilter *stream;
+ char *uri_list;
+ int fd;
+
+ tmpdir = e_mkdtemp ("drag-n-drop-XXXXXX");
+
+ if (!tmpdir) {
+ char *msg = g_strdup_printf (_("Could not create temporary "
+ "directory: %s"),
+ g_strerror (errno));
+ gnome_error_dialog (msg);
+ /* cleanup and abort */
+ for (i = 0; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+ g_ptr_array_free (uids, TRUE);
+ g_free (msg);
+ return;
+ }
+
+ message = camel_folder_get_message (fb->folder, uids->pdata[0], NULL);
+ g_free (uids->pdata[0]);
+
+ if (uids->len == 1) {
+ filename = camel_mime_message_get_subject (message);
+ if (!filename)
+ filename = _("Unknown");
+ } else
+ filename = "mbox";
+
+ uri_list = g_strdup_printf ("file://%s/%s", tmpdir, filename);
+
+ fd = open (uri_list + 7, O_WRONLY | O_CREAT | O_EXCL, 0600);
+ if (fd == -1) {
+ /* cleanup and abort */
+ camel_object_unref (message);
+ for (i = 1; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+ g_ptr_array_free (uids, TRUE);
+ g_free (uri_list);
+ return;
+ }
+
+ fstream = camel_stream_fs_new_with_fd (fd);
+
+ stream = camel_stream_filter_new_with_stream (fstream);
+ filter = camel_mime_filter_from_new ();
+ camel_stream_filter_add (stream, filter);
+ camel_object_unref (filter);
+
+ camel_stream_write (fstream, "From - \n", 8);
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), CAMEL_STREAM (stream));
+ camel_object_unref (message);
+ camel_stream_flush (CAMEL_STREAM (stream));
+
+ for (i = 1; i < uids->len; i++) {
+ message = camel_folder_get_message (fb->folder, uids->pdata[i], NULL);
+ camel_stream_write (fstream, "From - \n", 8);
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), CAMEL_STREAM (stream));
+ camel_object_unref (message);
+ camel_stream_flush (CAMEL_STREAM (stream));
+ g_free (uids->pdata[i]);
+ }
+
+ g_ptr_array_free (uids, TRUE);
+
+ camel_object_unref (stream);
+ camel_object_unref (fstream);
+
+ gtk_selection_data_set (selection_data, selection_data->target, 8,
+ uri_list, strlen (uri_list));
+ g_free (uri_list);
+ }
+ break;
+ case DND_TARGET_TYPE_MESSAGE_RFC822:
+ {
+ CamelMimeFilter *filter;
+ CamelStream *stream;
+ CamelStream *mem;
+
+ mem = camel_stream_mem_new ();
+
+ stream = camel_stream_filter_new_with_stream (mem);
+ filter = camel_mime_filter_from_new ();
+ camel_stream_filter_add (CAMEL_STREAM_FILTER (stream), filter);
+ camel_object_unref (filter);
+
+ for (i = 0; i < uids->len; i++) {
+ CamelMimeMessage *message;
+
+ message = camel_folder_get_message (fb->folder, uids->pdata[i], NULL);
+ g_free (uids->pdata[i]);
+
+ if (message) {
+ camel_stream_write (mem, "From - \n", 8);
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
+ camel_object_unref (message);
+ camel_stream_flush (stream);
+ }
+ }
+
+ g_ptr_array_free (uids, TRUE);
+ camel_object_unref (stream);
+
+ gtk_selection_data_set (selection_data, selection_data->target, 8,
+ CAMEL_STREAM_MEM (mem)->buffer->data,
+ CAMEL_STREAM_MEM (mem)->buffer->len);
+
+ camel_object_unref (mem);
+ }
+ break;
+ case DND_TARGET_TYPE_X_EVOLUTION_MESSAGE:
+ {
+ GByteArray *array;
+
+ /* format: "uri\0uid1\0uid2\0uid3\0...\0uidn" */
+
+ /* write the uri portion */
+ array = g_byte_array_new ();
+ g_byte_array_append (array, fb->uri, strlen (fb->uri));
+ g_byte_array_append (array, "", 1);
+
+ /* write the uids */
+ for (i = 0; i < uids->len; i++) {
+ g_byte_array_append (array, uids->pdata[i], strlen (uids->pdata[i]));
+ g_free (uids->pdata[i]);
+
+ if (i + 1 < uids->len)
+ g_byte_array_append (array, "", 1);
+ }
+
+ g_ptr_array_free (uids, TRUE);
+
+ gtk_selection_data_set (selection_data, selection_data->target, 8,
+ array->data, array->len);
+
+ g_byte_array_free (array, TRUE);
+ }
+ break;
+ default:
+ for (i = 0; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+
+ g_ptr_array_free (uids, TRUE);
+ break;
+ }
+}
+
+static void
+message_rfc822_dnd (CamelFolder *dest, CamelStream *stream, CamelException *ex)
+{
+ CamelMimeParser *mp;
+
+ mp = camel_mime_parser_new ();
+ camel_mime_parser_scan_from (mp, TRUE);
+ camel_mime_parser_init_with_stream (mp, stream);
+
+ while (camel_mime_parser_step (mp, 0, 0) == HSCAN_FROM) {
+ CamelMessageInfo *info;
+ CamelMimeMessage *msg;
+
+ msg = camel_mime_message_new ();
+ if (camel_mime_part_construct_from_parser (CAMEL_MIME_PART (msg), mp) == -1) {
+ camel_object_unref (CAMEL_OBJECT (msg));
+ break;
+ }
+
+ /* append the message to the folder... */
+ info = g_new0 (CamelMessageInfo, 1);
+ camel_folder_append_message (dest, msg, info, NULL, ex);
+ camel_object_unref (CAMEL_OBJECT (msg));
+
+ if (camel_exception_is_set (ex))
+ break;
+
+ /* skip over the FROM_END state */
+ camel_mime_parser_step (mp, 0, 0);
+ }
+
+ camel_object_unref (CAMEL_OBJECT (mp));
+}
+
+static void
+message_list_drag_data_received (ETree *tree, int row, ETreePath path, int col,
+ GdkDragContext *context, gint x, gint y,
+ GtkSelectionData *selection_data, guint info,
+ guint time, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ CamelFolder *folder = NULL;
+ char *tmp, *url, **urls;
+ GPtrArray *uids = NULL;
+ CamelStream *stream;
+ CamelException ex;
+ CamelURL *uri;
+ int i, fd;
+
+ /* this means we are receiving no data */
+ if (!selection_data->data || selection_data->length == -1)
+ return;
+
+ camel_exception_init (&ex);
+
+ switch (info) {
+ case DND_TARGET_TYPE_TEXT_URI_LIST:
+ tmp = g_strndup (selection_data->data, selection_data->length);
+ urls = g_strsplit (tmp, "\n", 0);
+ g_free (tmp);
+
+ for (i = 0; urls[i] != NULL; i++) {
+ /* get the path component */
+ url = g_strstrip (urls[i]);
+
+ uri = camel_url_new (url, NULL);
+ g_free (url);
+
+ if (!uri)
+ continue;
+
+ url = uri->path;
+ uri->path = NULL;
+ camel_url_free (uri);
+
+ fd = open (url, O_RDONLY);
+ if (fd == -1) {
+ g_free (url);
+ /* FIXME: okay, what do we do in this case? */
+ continue;
+ }
+
+ stream = camel_stream_fs_new_with_fd (fd);
+ message_rfc822_dnd (fb->folder, stream, &ex);
+ camel_object_unref (CAMEL_OBJECT (stream));
+
+ if (context->action == GDK_ACTION_MOVE && !camel_exception_is_set (&ex))
+ unlink (url);
+
+ g_free (url);
+ }
+
+ g_free (urls);
+ break;
+ case DND_TARGET_TYPE_MESSAGE_RFC822:
+ /* write the message(s) out to a CamelStream so we can use it */
+ stream = camel_stream_mem_new ();
+ camel_stream_write (stream, selection_data->data, selection_data->length);
+ camel_stream_reset (stream);
+
+ message_rfc822_dnd (fb->folder, stream, &ex);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ break;
+ case DND_TARGET_TYPE_X_EVOLUTION_MESSAGE:
+ folder = mail_tools_x_evolution_message_parse (selection_data->data, selection_data->length, &uids);
+ if (folder == NULL)
+ goto fail;
+
+ if (uids == NULL) {
+ camel_object_unref (CAMEL_OBJECT (folder));
+ goto fail;
+ }
+
+ mail_transfer_messages (folder, uids, context->action == GDK_ACTION_MOVE,
+ fb->uri, 0, NULL, NULL);
+
+ camel_object_unref (CAMEL_OBJECT (folder));
+ break;
+ }
+
+ camel_exception_clear (&ex);
+
+ gtk_drag_finish (context, TRUE, TRUE, GDK_CURRENT_TIME);
+
+ fail:
+ camel_exception_clear (&ex);
+
+ gtk_drag_finish (context, FALSE, TRUE, GDK_CURRENT_TIME);
+}
+
+static void
+selection_get (GtkWidget *widget, GtkSelectionData *selection_data,
+ guint info, guint time_stamp, FolderBrowser *fb)
+{
+ if (fb->clipboard_selection == NULL)
+ return;
+
+ switch (info) {
+ default:
+ case PASTE_TARGET_TYPE_TEXT_PLAIN:
+ {
+ /* FIXME: this'll be fucking slow for the user... pthread this? */
+ CamelFolder *source;
+ CamelStream *stream;
+ GByteArray *bytes;
+ GPtrArray *uids;
+ int i;
+
+ bytes = fb->clipboard_selection;
+
+ /* Note: source should == fb->folder, but we might as well use `source' instead of fb->folder */
+ source = mail_tools_x_evolution_message_parse (bytes->data, bytes->len, &uids);
+ if (source == NULL)
+ return;
+
+ if (uids == NULL) {
+ camel_object_unref (CAMEL_OBJECT (source));
+ return;
+ }
+
+ bytes = g_byte_array_new ();
+ stream = camel_stream_mem_new ();
+ camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (stream), bytes);
+
+ for (i = 0; i < uids->len; i++) {
+ CamelMimeMessage *message;
+
+ message = camel_folder_get_message (source, uids->pdata[i], NULL);
+ g_free (uids->pdata[i]);
+
+ if (message) {
+ camel_stream_write (stream, "From - \n", 8);
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), stream);
+ camel_object_unref (CAMEL_OBJECT (message));
+ }
+ }
+
+ g_ptr_array_free (uids, TRUE);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ camel_object_unref (CAMEL_OBJECT (source));
+
+ gtk_selection_data_set (selection_data, selection_data->target, 8,
+ bytes->data, bytes->len);
+
+ g_byte_array_free (bytes, FALSE);
+ }
+ break;
+ case PASTE_TARGET_TYPE_X_EVOLUTION_MESSAGE:
+ /* we already have our data in the correct form */
+ gtk_selection_data_set (selection_data,
+ selection_data->target, 8,
+ fb->clipboard_selection->data,
+ fb->clipboard_selection->len);
+ break;
+ }
+}
+
+static void
+selection_clear_event (GtkWidget *widget, GdkEventSelection *event, FolderBrowser *fb)
+{
+ if (fb->clipboard_selection != NULL) {
+ g_byte_array_free (fb->clipboard_selection, TRUE);
+ fb->clipboard_selection = NULL;
+ }
+}
+
+static void
+selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
+ guint time, FolderBrowser *fb)
+{
+ CamelFolder *source = NULL;
+ GPtrArray *uids = NULL;
+
+ if (selection_data == NULL || selection_data->length == -1)
+ return;
+
+ source = mail_tools_x_evolution_message_parse (selection_data->data, selection_data->length, &uids);
+ if (source == NULL)
+ return;
+
+ if (uids == NULL) {
+ camel_object_unref (CAMEL_OBJECT (source));
+ return;
+ }
+
+ mail_transfer_messages (source, uids, FALSE, fb->uri, 0, NULL, NULL);
+
+ camel_object_unref (CAMEL_OBJECT (source));
+}
+
+void
+folder_browser_copy (GtkWidget *menuitem, FolderBrowser *fb)
+{
+ GPtrArray *uids = NULL;
+ GByteArray *bytes;
+ gboolean cut;
+ int i;
+
+ if (fb->message_list == NULL)
+ return;
+
+ cut = menuitem == NULL;
+
+ if (GTK_WIDGET_HAS_FOCUS (fb->mail_display->html)) {
+ gtk_html_copy (fb->mail_display->html);
+ return;
+ }
+
+ if (fb->clipboard_selection) {
+ g_byte_array_free (fb->clipboard_selection, TRUE);
+ fb->clipboard_selection = NULL;
+ }
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, add_uid, uids);
+
+ /* format: "uri\0uid1\0uid2\0uid3\0...\0uidn" */
+
+ /* write the uri portion */
+ bytes = g_byte_array_new ();
+ g_byte_array_append (bytes, fb->uri, strlen (fb->uri));
+ g_byte_array_append (bytes, "", 1);
+
+ /* write the uids */
+ camel_folder_freeze (fb->folder);
+ for (i = 0; i < uids->len; i++) {
+ if (cut) {
+ camel_folder_set_message_flags (fb->folder, uids->pdata[i],
+ CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED,
+ CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED);
+ }
+ g_byte_array_append (bytes, uids->pdata[i], strlen (uids->pdata[i]));
+ g_free (uids->pdata[i]);
+
+ if (i + 1 < uids->len)
+ g_byte_array_append (bytes, "", 1);
+ }
+ camel_folder_thaw (fb->folder);
+
+ g_ptr_array_free (uids, TRUE);
+
+ fb->clipboard_selection = bytes;
+
+ gtk_selection_owner_set (fb->invisible, clipboard_atom, GDK_CURRENT_TIME);
+}
+
+void
+folder_browser_cut (GtkWidget *menuitem, FolderBrowser *fb)
+{
+ folder_browser_copy (NULL, fb);
+}
+
+void
+folder_browser_paste (GtkWidget *menuitem, FolderBrowser *fb)
+{
+ gtk_selection_convert (fb->invisible, clipboard_atom,
+ paste_types[0].target,
+ GDK_CURRENT_TIME);
+}
+
+/* all this crap so we can give the user a whoopee doo status bar */
+static void
+update_status_bar (FolderBrowser *fb)
+{
+ extern CamelFolder *outbox_folder, *sent_folder;
+ CORBA_Environment ev;
+ int tmp, total;
+ GString *work;
+
+ if (fb->folder == NULL
+ || fb->message_list == NULL
+ || fb->shell_view == CORBA_OBJECT_NIL)
+ return;
+
+ if (!fb->message_list->hidedeleted || !camel_folder_has_summary_capability (fb->folder)) {
+ total = camel_folder_get_message_count (fb->folder);
+ } else {
+ GPtrArray *sum = camel_folder_get_summary (fb->folder);
+ int i;
+
+ if (sum) {
+ total = 0;
+ for (i = 0; i < sum->len; i++) {
+ CamelMessageInfo *info = sum->pdata[i];
+
+ if ((info->flags & CAMEL_MESSAGE_DELETED) == 0)
+ total++;
+ }
+ camel_folder_free_summary (fb->folder, sum);
+ } else {
+ total = camel_folder_get_message_count (fb->folder);
+ }
+ }
+
+ work = g_string_new ("");
+ g_string_append_printf (work, _("%d new"), camel_folder_get_unread_message_count (fb->folder));
+ tmp = message_list_hidden (fb->message_list);
+ if (0 < tmp && tmp < total) {
+ g_string_append (work, _(", "));
+ if (tmp < total / 2)
+ g_string_append_printf (work, _("%d hidden"), tmp);
+ else
+ g_string_append_printf (work, _("%d visible"), total - tmp);
+ }
+ tmp = e_selection_model_selected_count (e_tree_get_selection_model (fb->message_list->tree));
+ if (tmp) {
+ g_string_append (work, _(", "));
+ g_string_append_printf (work, _("%d selected"), tmp);
+ }
+ g_string_append (work, _(", "));
+
+ if (fb->folder == outbox_folder)
+ g_string_append_printf (work, _("%d unsent"), total);
+ else if (fb->folder == sent_folder)
+ g_string_append_printf (work, _("%d sent"), total);
+ else
+ g_string_append_printf (work, _("%d total"), total);
+
+ CORBA_exception_init (&ev);
+ GNOME_Evolution_ShellView_setFolderBarLabel (fb->shell_view, work->str, &ev);
+ CORBA_exception_free (&ev);
+
+ if (fb->update_status_bar_idle_id != 0) {
+ g_source_remove (fb->update_status_bar_idle_id);
+ fb->update_status_bar_idle_id = 0;
+ }
+
+ g_string_free (work, TRUE);
+}
+
+static gboolean
+update_status_bar_idle_cb(gpointer data)
+{
+ FolderBrowser *fb = data;
+
+#if 0
+ if (!GTK_OBJECT_DESTROYED (fb))
+#endif
+ update_status_bar (fb);
+
+ fb->update_status_bar_idle_id = 0;
+ g_object_unref (fb);
+
+ return FALSE;
+}
+
+static void
+update_status_bar_idle(FolderBrowser *fb)
+{
+ if (fb->update_status_bar_idle_id == 0) {
+ g_object_ref (fb);
+ fb->update_status_bar_idle_id = g_idle_add (update_status_bar_idle_cb, fb);
+ }
+}
+
+static void main_folder_changed(CamelObject *o, void *event_data, void *data)
+{
+ FolderBrowser *fb = data;
+
+ if (fb->message_list == NULL)
+ return;
+
+ /* so some corba unref doesnt blow us away while we're busy */
+ g_object_ref (fb);
+ update_status_bar (fb);
+ folder_browser_ui_scan_selection (fb);
+ g_object_unref (fb);
+}
+
+static void folder_changed (CamelObject *obj, void *event_data, void *user_data)
+{
+ FolderBrowser *fb = user_data;
+
+ mail_async_event_emit (fb->async_event, MAIL_ASYNC_GUI,
+ (MailAsyncFunc) main_folder_changed,
+ obj, NULL, user_data);
+}
+
+static void
+got_folder (char *uri, CamelFolder *folder, void *user_data)
+{
+ FolderBrowser *fb = user_data;
+ EMeta *meta;
+
+ fb->get_id = -1;
+
+ d(printf ("got folder '%s' = %p, previous folder was %p\n", uri, folder, fb->folder));
+
+ if (fb->message_list == NULL)
+ goto done;
+
+ if (fb->folder) {
+ camel_object_unhook_event (fb->folder, "folder_changed", folder_changed, fb);
+ camel_object_unhook_event (fb->folder, "message_changed", folder_changed, fb);
+ camel_object_unref (fb->folder);
+ }
+
+ if (folder) {
+ fb->folder = folder;
+ camel_object_ref (folder);
+ meta = mail_tool_get_meta_data(fb->uri);
+ if (meta != fb->meta) {
+ g_object_unref(fb->meta);
+ fb->meta = meta;
+ } else {
+ g_object_unref(meta);
+ }
+ } else {
+ fb->folder = NULL;
+ if (fb->meta) {
+ g_object_unref(fb->meta);
+ fb->meta = NULL;
+ }
+ goto done;
+ }
+
+
+ gtk_widget_set_sensitive (GTK_WIDGET (fb->search), camel_folder_has_search_capability (folder));
+ message_list_set_folder (fb->message_list, folder,
+ folder_browser_is_drafts (fb) ||
+ folder_browser_is_sent (fb) ||
+ folder_browser_is_outbox (fb));
+
+ camel_object_hook_event (CAMEL_OBJECT (fb->folder), "folder_changed",
+ folder_changed, fb);
+ camel_object_hook_event (CAMEL_OBJECT (fb->folder), "message_changed",
+ folder_changed, fb);
+
+ if (fb->view_instance != NULL && fb->view_menus != NULL)
+ folder_browser_ui_discard_view_menus (fb);
+
+ folder_browser_ui_setup_view_menus (fb);
+
+ /* when loading a new folder, nothing is selected initially */
+
+ if (fb->uicomp)
+ folder_browser_ui_set_selection_state (fb, FB_SELSTATE_NONE);
+
+ done:
+ g_signal_emit (fb, folder_browser_signals[FOLDER_LOADED], 0, fb->uri);
+ g_object_unref (fb);
+}
+
+
+void
+folder_browser_reload (FolderBrowser *fb)
+{
+ g_return_if_fail (IS_FOLDER_BROWSER (fb));
+
+ if (fb->folder) {
+ mail_refresh_folder (fb->folder, NULL, NULL);
+ } else if (fb->uri && fb->get_id == -1) {
+ g_object_ref (fb);
+ fb->get_id = mail_get_folder (fb->uri, 0, got_folder, fb, mail_thread_new);
+ }
+}
+
+void
+folder_browser_set_folder (FolderBrowser *fb, CamelFolder *folder, const char *uri)
+{
+ g_return_if_fail (IS_FOLDER_BROWSER (fb));
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+ if (fb->get_id != -1) {
+ /* FIXME: cancel the get_folder request? */
+ }
+
+ g_free (fb->uri);
+ fb->uri = g_strdup (uri);
+
+ g_object_ref (fb);
+ got_folder (NULL, folder, fb);
+}
+
+void
+folder_browser_set_ui_component (FolderBrowser *fb, BonoboUIComponent *uicomp)
+{
+ g_return_if_fail (IS_FOLDER_BROWSER (fb));
+
+ if (fb->sensitize_timeout_id) {
+ g_source_remove (fb->sensitize_timeout_id);
+ fb->sensitize_timeout_id = 0;
+ }
+
+ if (fb->sensitise_state) {
+ g_hash_table_destroy (fb->sensitise_state);
+ fb->sensitise_state = NULL;
+ }
+
+ if (fb->uicomp)
+ bonobo_object_unref (BONOBO_OBJECT (fb->uicomp));
+
+ if (uicomp)
+ bonobo_object_ref (BONOBO_OBJECT (uicomp));
+
+ fb->uicomp = uicomp;
+}
+
+void
+folder_browser_set_shell_view(FolderBrowser *fb, GNOME_Evolution_ShellView shell_view)
+{
+ CORBA_Environment ev;
+
+ CORBA_exception_init(&ev);
+ if (fb->shell_view != CORBA_OBJECT_NIL)
+ CORBA_Object_release (fb->shell_view, &ev);
+ CORBA_exception_free (&ev);
+
+ fb->shell_view = CORBA_Object_duplicate (shell_view, &ev);
+ CORBA_exception_free (&ev);
+
+ /* small hack, at this point we've just been activated */
+ if (fb->shell_view != CORBA_OBJECT_NIL)
+ update_status_bar (fb);
+}
+
+extern CamelFolder *drafts_folder, *sent_folder, *outbox_folder;
+
+/**
+ * folder_browser_is_drafts:
+ * @fb: a FolderBrowser
+ *
+ * Return value: %TRUE if @fb refers to /local/Drafts or any other
+ * configured Drafts folder.
+ **/
+gboolean
+folder_browser_is_drafts (FolderBrowser *fb)
+{
+ gboolean is_drafts = FALSE;
+ EAccountList *accounts;
+ EAccount *account;
+ EIterator *iter;
+
+ g_return_val_if_fail (IS_FOLDER_BROWSER (fb), FALSE);
+
+ if (fb->uri == NULL || fb->folder == NULL)
+ return FALSE;
+
+ if (fb->folder == drafts_folder)
+ return TRUE;
+
+ accounts = mail_config_get_accounts ();
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ account = (EAccount *) e_iterator_get (iter);
+ if (account->drafts_folder_uri &&
+ camel_store_uri_cmp (fb->folder->parent_store, account->drafts_folder_uri, fb->uri)) {
+ is_drafts = TRUE;
+ break;
+ }
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ return is_drafts;
+}
+
+/**
+ * folder_browser_is_sent:
+ * @fb: a FolderBrowser
+ *
+ * Return value: %TRUE if @fb refers to /local/Sent or any other
+ * configured Sent folder.
+ **/
+gboolean
+folder_browser_is_sent (FolderBrowser *fb)
+{
+ gboolean is_sent = FALSE;
+ EAccountList *accounts;
+ EAccount *account;
+ EIterator *iter;
+
+ g_return_val_if_fail (IS_FOLDER_BROWSER (fb), FALSE);
+
+ if (fb->uri == NULL || fb->folder == NULL)
+ return FALSE;
+
+ if (fb->folder == sent_folder)
+ return TRUE;
+
+ accounts = mail_config_get_accounts ();
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ account = (EAccount *) e_iterator_get (iter);
+ if (account->sent_folder_uri &&
+ camel_store_uri_cmp (fb->folder->parent_store, account->sent_folder_uri, fb->uri)) {
+ is_sent = TRUE;
+ break;
+ }
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ return is_sent;
+}
+
+/**
+ * folder_browser_is_outbox:
+ * @fb: a FolderBrowser
+ *
+ * Return value: %TRUE if @fb refers to /local/Outbox or any other
+ * configured Outbox folder.
+ **/
+gboolean
+folder_browser_is_outbox (FolderBrowser *fb)
+{
+ /* There can be only one. */
+ return fb->folder == outbox_folder;
+}
+
+static int
+save_cursor_pos (FolderBrowser *fb)
+{
+ ETreePath node;
+ GtkAdjustment *adj;
+ int row, y, height, paned_size;
+ GConfClient *gconf;
+
+ node = e_tree_get_cursor (fb->message_list->tree);
+ if (!node)
+ return -1;
+
+ row = e_tree_row_of_node (fb->message_list->tree, node);
+
+ if (row == -1)
+ return 0;
+
+ e_tree_get_cell_geometry (fb->message_list->tree, row, 0,
+ NULL, &y, NULL, &height);
+
+ gconf = mail_config_get_gconf_client ();
+ paned_size = gconf_client_get_int (gconf, "/apps/evolution/mail/display/paned_size", NULL);
+
+ adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (fb->message_list));
+ y += adj->value - ((paned_size - height) / 2);
+
+ return y;
+}
+
+static void
+set_cursor_pos (FolderBrowser *fb, int y)
+{
+ GtkAdjustment *adj;
+
+ if (y == -1)
+ return;
+
+ adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (fb->message_list));
+ gtk_adjustment_set_value (adj, (gfloat)y);
+}
+
+static gboolean do_message_selected(FolderBrowser *fb);
+
+void
+folder_browser_set_message_preview (FolderBrowser *folder_browser, gboolean show_preview)
+{
+ GConfClient *gconf;
+ int paned_size, y;
+
+ if (folder_browser->preview_shown == show_preview
+ || folder_browser->message_list == NULL)
+ return;
+
+ folder_browser->preview_shown = show_preview;
+
+ gconf = mail_config_get_gconf_client ();
+ paned_size = gconf_client_get_int (gconf, "/apps/evolution/mail/display/paned_size", NULL);
+
+ if (show_preview) {
+ y = save_cursor_pos (folder_browser);
+ gtk_paned_set_position (GTK_PANED (folder_browser->vpaned), paned_size);
+ gtk_widget_show (GTK_WIDGET (folder_browser->mail_display));
+ do_message_selected (folder_browser);
+ set_cursor_pos (folder_browser, y);
+ } else {
+ gtk_widget_hide (GTK_WIDGET (folder_browser->mail_display));
+ mail_display_set_message (folder_browser->mail_display, NULL, NULL, NULL);
+ folder_browser_ui_message_loaded (folder_browser);
+ }
+}
+
+enum {
+ ESB_SAVE,
+};
+
+static ESearchBarItem folder_browser_search_menu_items[] = {
+ E_FILTERBAR_ADVANCED,
+ { NULL, 0, NULL },
+ E_FILTERBAR_SAVE,
+ E_FILTERBAR_EDIT,
+ { NULL, 0, NULL },
+ { N_("Create _Virtual Folder From Search..."), ESB_SAVE, NULL },
+ { NULL, -1, NULL }
+};
+
+static void
+folder_browser_search_menu_activated (ESearchBar *esb, int id, FolderBrowser *fb)
+{
+ EFilterBar *efb = (EFilterBar *)esb;
+
+ d(printf("menu activated\n"));
+
+ switch (id) {
+ case ESB_SAVE:
+ d(printf("Save vfolder\n"));
+ if (efb->current_query) {
+ FilterRule *rule = vfolder_clone_rule(efb->current_query);
+ char *name, *text;
+
+ text = e_search_bar_get_text(esb);
+ name = g_strdup_printf("%s %s", rule->name, (text&&text[0])?text:"''");
+ g_free (text);
+ filter_rule_set_name(rule, name);
+ g_free (name);
+
+ filter_rule_set_source(rule, FILTER_SOURCE_INCOMING);
+ vfolder_rule_add_source((VfolderRule *)rule, fb->uri);
+ vfolder_gui_add_rule((VfolderRule *)rule);
+ }
+ break;
+ }
+}
+
+static void
+folder_browser_config_search (EFilterBar *efb, FilterRule *rule, int id, const char *query, void *data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (data);
+ ESearchingTokenizer *st;
+ GList *partl;
+ struct _camel_search_words *words;
+ int i;
+
+ st = E_SEARCHING_TOKENIZER (fb->mail_display->html->engine->ht);
+
+ e_searching_tokenizer_set_secondary_search_string (st, NULL);
+
+ /* we scan the parts of a rule, and set all the types we know about to the query string */
+ partl = rule->parts;
+ while (partl) {
+ FilterPart *part = partl->data;
+
+ if (!strcmp(part->name, "subject")) {
+ FilterInput *input = (FilterInput *)filter_part_find_element(part, "subject");
+ if (input)
+ filter_input_set_value(input, query);
+ } else if (!strcmp(part->name, "body")) {
+ FilterInput *input = (FilterInput *)filter_part_find_element(part, "word");
+ if (input)
+ filter_input_set_value(input, query);
+
+ words = camel_search_words_split(query);
+ for (i=0;i<words->len;i++)
+ e_searching_tokenizer_add_secondary_search_string (st, words->words[i]->word);
+ camel_search_words_free (words);
+ } else if(!strcmp(part->name, "sender")) {
+ FilterInput *input = (FilterInput *)filter_part_find_element(part, "sender");
+ if (input)
+ filter_input_set_value(input, query);
+ } else if(!strcmp(part->name, "to")) {
+ FilterInput *input = (FilterInput *)filter_part_find_element(part, "recipient");
+ if (input)
+ filter_input_set_value(input, query);
+ }
+
+ partl = partl->next;
+ }
+
+ d(printf("configuring search for search string '%s', rule is '%s'\n", query, rule->name));
+
+ mail_display_redisplay (fb->mail_display, FALSE);
+}
+
+static void
+folder_browser_search_do_search (ESearchBar *esb, FolderBrowser *fb)
+{
+ char *search_word;
+
+ if (fb->message_list == NULL)
+ return;
+
+ d(printf("do search\n"));
+
+ g_object_get (esb, "query", &search_word, NULL);
+
+ message_list_set_search (fb->message_list, search_word);
+
+ d(printf("query is %s\n", search_word));
+ g_free (search_word);
+}
+
+static void
+folder_browser_query_changed (ESearchBar *esb, FolderBrowser *fb)
+{
+ int id;
+
+ id = e_search_bar_get_item_id (esb);
+ if (id == E_FILTERBAR_ADVANCED_ID)
+ folder_browser_search_do_search (esb, fb);
+}
+
+void
+folder_browser_toggle_preview (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data)
+{
+ FolderBrowser *fb = user_data;
+ gboolean bstate;
+ GConfClient *gconf;
+
+ if (type != Bonobo_UIComponent_STATE_CHANGED || fb->message_list == NULL)
+ return;
+
+ bstate = atoi(state);
+ e_meta_set_bool(fb->meta, "show_preview", bstate);
+
+ gconf = mail_config_get_gconf_client ();
+ gconf_client_set_bool (gconf, "/apps/evolution/mail/display/show_preview", bstate, NULL);
+
+ folder_browser_set_message_preview (fb, bstate);
+}
+
+void
+folder_browser_toggle_threads (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data)
+{
+ FolderBrowser *fb = user_data;
+ int prev_state;
+ gboolean bstate;
+ GConfClient *gconf;
+
+ if (type != Bonobo_UIComponent_STATE_CHANGED || fb->message_list == NULL)
+ return;
+
+ bstate = atoi(state);
+ e_meta_set_bool(fb->meta, "thread_list", bstate);
+
+ gconf = mail_config_get_gconf_client ();
+ gconf_client_set_bool (gconf, "/apps/evolution/mail/display/thread_list", bstate, NULL);
+
+ message_list_set_threaded (fb->message_list, bstate);
+
+ prev_state = fb->selection_state;
+ fb->selection_state = FB_SELSTATE_UNDEFINED;
+ folder_browser_ui_set_selection_state (fb, prev_state);
+}
+
+void
+folder_browser_toggle_hide_deleted (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data)
+{
+ FolderBrowser *fb = user_data;
+ GConfClient *gconf;
+
+ if (type != Bonobo_UIComponent_STATE_CHANGED || fb->message_list == NULL)
+ return;
+
+ gconf = mail_config_get_gconf_client ();
+ gconf_client_set_bool (gconf, "/apps/evolution/mail/display/show_deleted",
+ !atoi (state), NULL);
+
+ if (!(fb->folder && (fb->folder->folder_flags & CAMEL_FOLDER_IS_TRASH)))
+ message_list_set_hidedeleted (fb->message_list, atoi (state));
+}
+
+void
+folder_browser_toggle_caret_mode(BonoboUIComponent *component,
+ const char * path,
+ Bonobo_UIComponent_EventType type,
+ const char * state,
+ gpointer user_data)
+{
+ GConfClient *gconf;
+
+ if (type != Bonobo_UIComponent_STATE_CHANGED)
+ return;
+
+ gconf = mail_config_get_gconf_client ();
+ gconf_client_set_bool (gconf, "/apps/evolution/mail/display/caret_mode",
+ atoi(state), NULL);
+}
+
+void
+folder_browser_set_message_display_style (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data)
+{
+ extern char *message_display_styles[];
+ FolderBrowser *fb = user_data;
+ GConfClient *gconf;
+ int i;
+
+ if (type != Bonobo_UIComponent_STATE_CHANGED
+ || atoi (state) == 0
+ || fb->message_list == NULL)
+ return;
+
+ gconf = mail_config_get_gconf_client ();
+
+ for (i = 0; i < MAIL_CONFIG_DISPLAY_MAX; i++) {
+ if (strstr (message_display_styles[i], path)) {
+ fb->mail_display->display_style = i;
+ mail_display_redisplay (fb->mail_display, TRUE);
+
+ if (fb->pref_master)
+ gconf_client_set_int (gconf, "/apps/evolution/mail/display/message_style", i, NULL);
+
+ return;
+ }
+ }
+}
+
+void
+folder_browser_charset_changed (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ const char *charset;
+
+ if (type != Bonobo_UIComponent_STATE_CHANGED
+ || fb->message_list == NULL)
+ return;
+
+ if (atoi (state)) {
+ /* Charset menu names are "Charset-%s" where %s is the charset name */
+ charset = path + strlen ("Charset-");
+ if (!strcmp (charset, FB_DEFAULT_CHARSET))
+ charset = NULL;
+
+ mail_display_set_charset (fb->mail_display, charset);
+ }
+}
+
+static void vfolder_type_uid(CamelFolder *folder, const char *uid, const char *uri, int type);
+
+static void
+vfolder_type_current(FolderBrowser *fb, int type)
+{
+ GPtrArray *uids;
+ int i;
+
+ /* get uid */
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ if (uids->len == 1)
+ vfolder_type_uid (fb->folder, (char *)uids->pdata[0], fb->uri, type);
+
+ for (i = 0; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+ g_ptr_array_free (uids, TRUE);
+}
+
+/* external api to vfolder/filter on X, based on current message */
+void vfolder_subject (GtkWidget *w, FolderBrowser *fb) { vfolder_type_current(fb, AUTO_SUBJECT); }
+void vfolder_sender (GtkWidget *w, FolderBrowser *fb) { vfolder_type_current(fb, AUTO_FROM); }
+void vfolder_recipient (GtkWidget *w, FolderBrowser *fb) { vfolder_type_current(fb, AUTO_TO); }
+void vfolder_mlist (GtkWidget *w, FolderBrowser *fb) { vfolder_type_current(fb, AUTO_MLIST); }
+
+static void filter_type_uid (CamelFolder *folder, const char *uid, const char *source, int type);
+
+static void
+filter_type_current (FolderBrowser *fb, int type)
+{
+ GPtrArray *uids;
+ int i;
+ const char *source;
+
+ if (folder_browser_is_sent (fb) || folder_browser_is_outbox (fb))
+ source = FILTER_SOURCE_OUTGOING;
+ else
+ source = FILTER_SOURCE_INCOMING;
+
+ /* get uid */
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ if (uids->len == 1)
+ filter_type_uid (fb->folder, (char *)uids->pdata[0], source, type);
+
+ for (i = 0; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+ g_ptr_array_free (uids, TRUE);
+}
+
+void filter_subject (GtkWidget *w, FolderBrowser *fb) { filter_type_current (fb, AUTO_SUBJECT); }
+void filter_sender (GtkWidget *w, FolderBrowser *fb) { filter_type_current (fb, AUTO_FROM); }
+void filter_recipient (GtkWidget *w, FolderBrowser *fb) { filter_type_current (fb, AUTO_TO); }
+void filter_mlist (GtkWidget *w, FolderBrowser *fb) { filter_type_current (fb, AUTO_MLIST); }
+
+/* ************************************************************ */
+
+/* popup api to vfolder/filter on X, based on current selection */
+struct _filter_data {
+ CamelFolder *folder;
+ const char *source;
+ char *uid;
+ int type;
+ char *uri;
+ char *mlist;
+};
+
+static void
+filter_data_free (struct _filter_data *fdata)
+{
+ g_free (fdata->uid);
+ g_free (fdata->uri);
+ if (fdata->folder)
+ camel_object_unref (fdata->folder);
+ g_free (fdata->mlist);
+ g_free (fdata);
+}
+
+static void
+vfolder_type_got_message(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *d)
+{
+ struct _filter_data *data = d;
+
+ if (msg)
+ vfolder_gui_add_from_message(msg, data->type, data->uri);
+
+ filter_data_free (data);
+}
+
+static void
+vfolder_type_uid(CamelFolder *folder, const char *uid, const char *uri, int type)
+{
+ struct _filter_data *data;
+
+ data = g_malloc0(sizeof(*data));
+ data->type = type;
+ data->uri = g_strdup(uri);
+ mail_get_message(folder, uid, vfolder_type_got_message, data, mail_thread_new);
+}
+
+static void vfolder_subject_uid (GtkWidget *w, struct _filter_data *fdata) { vfolder_type_uid(fdata->folder, fdata->uid, fdata->uri, AUTO_SUBJECT); }
+static void vfolder_sender_uid(GtkWidget *w, struct _filter_data *fdata) { vfolder_type_uid(fdata->folder, fdata->uid, fdata->uri, AUTO_FROM); }
+static void vfolder_recipient_uid(GtkWidget *w, struct _filter_data *fdata) { vfolder_type_uid(fdata->folder, fdata->uid, fdata->uri, AUTO_TO); }
+static void vfolder_mlist_uid(GtkWidget *w, struct _filter_data *fdata) { vfolder_type_uid(fdata->folder, fdata->uid, fdata->uri, AUTO_MLIST); }
+
+static void
+filter_type_got_message(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *d)
+{
+ struct _filter_data *data = d;
+
+ if (msg)
+ filter_gui_add_from_message(msg, data->source, data->type);
+
+ filter_data_free (data);
+}
+
+static void
+filter_type_uid(CamelFolder *folder, const char *uid, const char *source, int type)
+{
+ struct _filter_data *data;
+
+ data = g_malloc0(sizeof(*data));
+ data->type = type;
+ data->source = source;
+ mail_get_message(folder, uid, filter_type_got_message, data, mail_thread_new);
+}
+
+static void filter_subject_uid (GtkWidget *w, struct _filter_data *fdata) { filter_type_uid(fdata->folder, fdata->uid, fdata->source, AUTO_SUBJECT); }
+static void filter_sender_uid(GtkWidget *w, struct _filter_data *fdata) { filter_type_uid(fdata->folder, fdata->uid, fdata->source, AUTO_FROM); }
+static void filter_recipient_uid(GtkWidget *w, struct _filter_data *fdata) { filter_type_uid(fdata->folder, fdata->uid, fdata->source, AUTO_TO); }
+static void filter_mlist_uid(GtkWidget *w, struct _filter_data *fdata) { filter_type_uid(fdata->folder, fdata->uid, fdata->source, AUTO_MLIST); }
+
+void
+hide_none(GtkWidget *w, FolderBrowser *fb)
+{
+ message_list_hide_clear (fb->message_list);
+}
+
+void
+hide_selected(GtkWidget *w, FolderBrowser *fb)
+{
+ GPtrArray *uids;
+ int i;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+ message_list_hide_uids (fb->message_list, uids);
+ for (i = 0; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+ g_ptr_array_free (uids, TRUE);
+}
+
+void
+hide_deleted(GtkWidget *w, FolderBrowser *fb)
+{
+ MessageList *ml = fb->message_list;
+
+ message_list_hide_add(ml, "(match-all (system-flag \"deleted\"))", ML_HIDE_SAME, ML_HIDE_SAME);
+}
+
+void
+hide_read(GtkWidget *w, FolderBrowser *fb)
+{
+ MessageList *ml = fb->message_list;
+
+ message_list_hide_add(ml, "(match-all (system-flag \"seen\"))", ML_HIDE_SAME, ML_HIDE_SAME);
+}
+
+/* dum de dum, about the 3rd copy of this function throughout the mailer/camel */
+static const char *
+strip_re(const char *subject)
+{
+ const unsigned char *s, *p;
+
+ s = (unsigned char *) subject;
+
+ while (*s) {
+ while(isspace (*s))
+ s++;
+ if (s[0] == 0)
+ break;
+ if ((s[0] == 'r' || s[0] == 'R')
+ && (s[1] == 'e' || s[1] == 'E')) {
+ p = s+2;
+ while (isdigit(*p) || (ispunct(*p) && (*p != ':')))
+ p++;
+ if (*p == ':') {
+ s = p + 1;
+ } else
+ break;
+ } else
+ break;
+ }
+ return (char *) s;
+}
+
+void
+hide_subject(GtkWidget *w, FolderBrowser *fb)
+{
+ const char *subject;
+ GString *expr;
+
+ if (fb->mail_display->current_message) {
+ subject = camel_mime_message_get_subject(fb->mail_display->current_message);
+ if (subject) {
+ subject = strip_re(subject);
+ if (subject && subject[0]) {
+ expr = g_string_new ("(match-all (header-contains \"subject\" ");
+ e_sexp_encode_string (expr, subject);
+ g_string_append (expr, "))");
+ message_list_hide_add (fb->message_list, expr->str, ML_HIDE_SAME, ML_HIDE_SAME);
+ g_string_free (expr, TRUE);
+ return;
+ }
+ }
+ }
+}
+
+void
+hide_sender (GtkWidget *w, FolderBrowser *fb)
+{
+ const CamelInternetAddress *from;
+ const char *real, *addr;
+ GString *expr;
+
+ if (fb->mail_display->current_message) {
+ from = camel_mime_message_get_from (fb->mail_display->current_message);
+ if (camel_internet_address_get (from, 0, &real, &addr)) {
+ expr = g_string_new ("(match-all (header-contains \"from\" ");
+ e_sexp_encode_string (expr, addr);
+ g_string_append (expr, "))");
+ message_list_hide_add (fb->message_list, expr->str, ML_HIDE_SAME, ML_HIDE_SAME);
+ g_string_free (expr, TRUE);
+ return;
+ }
+ }
+}
+
+struct _label_data {
+ FolderBrowser *fb;
+ const char *label;
+};
+
+static void
+set_msg_label (GtkWidget *widget, gpointer user_data)
+{
+ struct _label_data *data = user_data;
+ GPtrArray *uids;
+ int i;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (data->fb->message_list, enumerate_msg, uids);
+ for (i = 0; i < uids->len; i++)
+ camel_folder_set_message_user_tag (data->fb->folder, uids->pdata[i], "label", data->label);
+ g_ptr_array_free (uids, TRUE);
+}
+
+static void
+label_closures_free (GPtrArray *closures)
+{
+ struct _label_data *data;
+ int i;
+
+ for (i = 0; i < closures->len; i++) {
+ data = closures->pdata[i];
+ g_object_unref (data->fb);
+ g_free (data);
+ }
+ g_ptr_array_free (closures, TRUE);
+}
+
+static void
+mark_as_seen_cb (GtkWidget *widget, void *user_data)
+{
+ mark_as_seen (NULL, user_data, NULL);
+}
+
+static void
+mark_as_unseen_cb (GtkWidget *widget, void *user_data)
+{
+ mark_as_unseen (NULL, user_data, NULL);
+}
+
+static void
+mark_as_important_cb (GtkWidget *widget, void *user_data)
+{
+ mark_as_important (NULL, user_data, NULL);
+}
+
+static void
+mark_as_unimportant_cb (GtkWidget *widget, void *user_data)
+{
+ mark_as_unimportant (NULL, user_data, NULL);
+}
+
+enum {
+ SELECTION_SET = 1<<1,
+ CAN_MARK_READ = 1<<2,
+ CAN_MARK_UNREAD = 1<<3,
+ CAN_DELETE = 1<<4,
+ CAN_UNDELETE = 1<<5,
+ IS_MAILING_LIST = 1<<6,
+ CAN_RESEND = 1<<7,
+ CAN_MARK_IMPORTANT = 1<<8,
+ CAN_MARK_UNIMPORTANT = 1<<9,
+ CAN_FLAG_FOR_FOLLOWUP = 1<<10,
+ CAN_FLAG_COMPLETED = 1<<11,
+ CAN_CLEAR_FLAG = 1<<12,
+ CAN_ADD_SENDER = 1<<13
+};
+
+#define MLIST_VFOLDER (3)
+#define MLIST_FILTER (8)
+
+static EPopupMenu filter_menu[] = {
+ E_POPUP_ITEM_CC (N_("VFolder on _Subject"), G_CALLBACK (vfolder_subject_uid), NULL, SELECTION_SET),
+ E_POPUP_ITEM_CC (N_("VFolder on Se_nder"), G_CALLBACK (vfolder_sender_uid), NULL, SELECTION_SET),
+ E_POPUP_ITEM_CC (N_("VFolder on _Recipients"), G_CALLBACK (vfolder_recipient_uid), NULL, SELECTION_SET),
+ E_POPUP_ITEM_CC (N_("VFolder on Mailing _List"), G_CALLBACK (vfolder_mlist_uid), NULL, SELECTION_SET | IS_MAILING_LIST),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM_CC (N_("Filter on Sub_ject"), G_CALLBACK (filter_subject_uid), NULL, SELECTION_SET),
+ E_POPUP_ITEM_CC (N_("Filter on Sen_der"), G_CALLBACK (filter_sender_uid), NULL, SELECTION_SET),
+ E_POPUP_ITEM_CC (N_("Filter on Re_cipients"), G_CALLBACK (filter_recipient_uid), NULL, SELECTION_SET),
+ E_POPUP_ITEM_CC (N_("Filter on _Mailing List"), G_CALLBACK (filter_mlist_uid), NULL, SELECTION_SET | IS_MAILING_LIST),
+
+ E_POPUP_TERMINATOR
+};
+
+static EPopupMenu label_menu[] = {
+ E_POPUP_PIXMAP_WIDGET_ITEM_CC (N_("None"), NULL, G_CALLBACK (set_msg_label), NULL, 0),
+ E_POPUP_SEPARATOR,
+ E_POPUP_PIXMAP_WIDGET_ITEM_CC (NULL, NULL, G_CALLBACK (set_msg_label), NULL, 0),
+ E_POPUP_PIXMAP_WIDGET_ITEM_CC (NULL, NULL, G_CALLBACK (set_msg_label), NULL, 0),
+ E_POPUP_PIXMAP_WIDGET_ITEM_CC (NULL, NULL, G_CALLBACK (set_msg_label), NULL, 0),
+ E_POPUP_PIXMAP_WIDGET_ITEM_CC (NULL, NULL, G_CALLBACK (set_msg_label), NULL, 0),
+ E_POPUP_PIXMAP_WIDGET_ITEM_CC (NULL, NULL, G_CALLBACK (set_msg_label), NULL, 0),
+ E_POPUP_TERMINATOR
+};
+
+static EPopupMenu context_menu[] = {
+ E_POPUP_ITEM (N_("_Open"), G_CALLBACK (open_msg), 0),
+ E_POPUP_ITEM (N_("_Edit as New Message..."), G_CALLBACK (resend_msg), CAN_RESEND),
+ E_POPUP_ITEM (N_("_Save As..."), G_CALLBACK (save_msg), 0),
+ E_POPUP_ITEM (N_("_Print"), G_CALLBACK (print_msg), 0),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("_Reply to Sender"), G_CALLBACK (reply_to_sender), 0),
+ E_POPUP_ITEM (N_("Reply to _List"), G_CALLBACK (reply_to_list), 0),
+ E_POPUP_ITEM (N_("Reply to _All"), G_CALLBACK (reply_to_all), 0),
+ E_POPUP_ITEM (N_("_Forward"), G_CALLBACK (forward), 0),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("Follo_w Up..."), G_CALLBACK (flag_for_followup), CAN_FLAG_FOR_FOLLOWUP),
+ E_POPUP_ITEM (N_("Fla_g Completed"), G_CALLBACK (flag_followup_completed), CAN_FLAG_COMPLETED),
+ E_POPUP_ITEM (N_("Cl_ear Flag"), G_CALLBACK (flag_followup_clear), CAN_CLEAR_FLAG),
+
+ /* separator here? */
+
+ E_POPUP_ITEM (N_("Mar_k as Read"), G_CALLBACK (mark_as_seen_cb), CAN_MARK_READ),
+ E_POPUP_ITEM (N_("Mark as _Unread"), G_CALLBACK (mark_as_unseen_cb), CAN_MARK_UNREAD),
+ E_POPUP_ITEM (N_("Mark as _Important"), G_CALLBACK (mark_as_important_cb), CAN_MARK_IMPORTANT),
+ E_POPUP_ITEM (N_("_Mark as Unimportant"), G_CALLBACK (mark_as_unimportant_cb), CAN_MARK_UNIMPORTANT),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("_Delete"), G_CALLBACK (delete_msg), CAN_DELETE),
+ E_POPUP_ITEM (N_("U_ndelete"), G_CALLBACK (undelete_msg), CAN_UNDELETE),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("Mo_ve to Folder..."), G_CALLBACK (move_msg_cb), 0),
+ E_POPUP_ITEM (N_("_Copy to Folder..."), G_CALLBACK (copy_msg_cb), 0),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_SUBMENU (N_("Label"), label_menu, 0),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("Add Sender to Address_book"), G_CALLBACK (addrbook_sender), SELECTION_SET | CAN_ADD_SENDER),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_ITEM (N_("Appl_y Filters"), G_CALLBACK (apply_filters), 0),
+
+ E_POPUP_SEPARATOR,
+
+ E_POPUP_SUBMENU (N_("Crea_te Rule From Message"), filter_menu, SELECTION_SET),
+
+ E_POPUP_TERMINATOR
+};
+
+/* Note: this must be kept in sync with the context_menu!!! */
+static char *context_pixmaps[] = {
+ NULL, /* Open */
+ NULL, /* Edit */
+ "save-as-16.png",
+ "print.xpm",
+ NULL,
+ "reply.xpm",
+ NULL, /* Reply to List */
+ "reply_to_all.xpm",
+ "forward.xpm",
+ NULL,
+ "flag-for-followup-16.png",
+ NULL, /* Flag */
+ NULL, /* Clear */
+ "mail-read.xpm",
+ "mail-new.xpm",
+ "priority-high.xpm",
+ NULL, /* Mark as Unimportant */
+ NULL,
+ "evolution-trash-mini.png",
+ "undelete_message-16.png",
+ NULL,
+ "move_message.xpm",
+ "copy_16_message.xpm",
+ NULL,
+ NULL, /* Label */
+ NULL,
+ NULL, /* Add Sender to Addressbook */
+ NULL,
+ NULL, /* Apply Filters */
+ NULL,
+ NULL, /* Create Rule from Message */
+};
+
+struct cmpf_data {
+ ETree *tree;
+ int row, col;
+};
+
+static void
+context_menu_position_func (GtkMenu *menu, gint *x, gint *y,
+ gboolean *push_in, gpointer user_data)
+{
+ int tx, ty, tw, th;
+ struct cmpf_data *closure = user_data;
+
+ gdk_window_get_origin (GTK_WIDGET (closure->tree)->window, x, y);
+ e_tree_get_cell_geometry (closure->tree, closure->row, closure->col,
+ &tx, &ty, &tw, &th);
+ *x += tx + tw / 2;
+ *y += ty + th / 2;
+}
+
+static void
+setup_popup_icons (void)
+{
+ int i;
+
+ for (i = 0; context_menu[i].name; i++) {
+ if (context_pixmaps[i]) {
+ char *filename;
+
+ filename = g_strdup_printf ("%s/%s", EVOLUTION_IMAGES, context_pixmaps[i]);
+ context_menu[i].pixmap_widget = gtk_image_new_from_file (filename);
+ g_free (filename);
+ }
+ }
+}
+
+/* handle context menu over message-list */
+static int
+on_right_click (ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, FolderBrowser *fb)
+{
+ struct _filter_data *fdata = NULL;
+ GPtrArray *uids, *closures;
+ CamelMessageInfo *info;
+ GSList *labels;
+ int enable_mask = 0;
+ int hide_mask = 0;
+ char *mlist = NULL;
+ GtkMenu *menu;
+ int i;
+
+ if (!folder_browser_is_sent (fb)) {
+ enable_mask |= CAN_RESEND;
+ hide_mask |= CAN_RESEND;
+ } else {
+ enable_mask |= CAN_ADD_SENDER;
+ hide_mask |= CAN_ADD_SENDER;
+ }
+
+ if (folder_browser_is_drafts (fb)) {
+ enable_mask |= CAN_ADD_SENDER;
+ hide_mask |= CAN_ADD_SENDER;
+ }
+
+ if (fb->folder == outbox_folder) {
+ enable_mask |= CAN_ADD_SENDER;
+ hide_mask |= CAN_ADD_SENDER;
+ }
+
+ enable_mask |= SELECTION_SET;
+
+ /* get a list of uids */
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+ if (uids->len >= 1) {
+ /* gray-out any items we don't need */
+ gboolean have_deleted = FALSE;
+ gboolean have_undeleted = FALSE;
+ gboolean have_seen = FALSE;
+ gboolean have_unseen = FALSE;
+ gboolean have_important = FALSE;
+ gboolean have_unimportant = FALSE;
+ gboolean have_flag_for_followup = FALSE;
+ gboolean have_flag_completed = FALSE;
+ gboolean have_flag_incomplete = FALSE;
+ gboolean have_unflagged = FALSE;
+ const char *tag;
+
+ for (i = 0; i < uids->len; i++) {
+ info = camel_folder_get_message_info (fb->folder, uids->pdata[i]);
+ if (info == NULL)
+ continue;
+
+ if (i == 0 && uids->len == 1) {
+ const char *mname, *p;
+ char c, *o;
+
+ /* used by filter/vfolder from X callbacks */
+ fdata = g_malloc0(sizeof(*fdata));
+ fdata->uid = g_strdup(uids->pdata[i]);
+ fdata->uri = g_strdup(fb->uri);
+ fdata->folder = fb->folder;
+ camel_object_ref((CamelObject *)fdata->folder);
+ if (folder_browser_is_sent (fb) || folder_browser_is_outbox (fb))
+ fdata->source = FILTER_SOURCE_OUTGOING;
+ else
+ fdata->source = FILTER_SOURCE_INCOMING;
+
+ enable_mask &= ~SELECTION_SET;
+ mname = camel_message_info_mlist(info);
+ if (mname && mname[0]) {
+ fdata->mlist = g_strdup(mname);
+
+ /* Escape the mailing list name before showing it */
+ mlist = g_alloca ((strlen (mname) * 2) + 1);
+ p = mname;
+ o = mlist;
+ while ((c = *p++)) {
+ if (c == '_')
+ *o++ = '_';
+ *o++ = c;
+ }
+ *o = 0;
+ }
+ }
+
+ if (info->flags & CAMEL_MESSAGE_SEEN)
+ have_seen = TRUE;
+ else
+ have_unseen = TRUE;
+
+ if (info->flags & CAMEL_MESSAGE_DELETED)
+ have_deleted = TRUE;
+ else
+ have_undeleted = TRUE;
+
+ if (info->flags & CAMEL_MESSAGE_FLAGGED)
+ have_important = TRUE;
+ else
+ have_unimportant = TRUE;
+
+ tag = camel_tag_get (&info->user_tags, "follow-up");
+ if (tag && *tag) {
+ have_flag_for_followup = TRUE;
+ tag = camel_tag_get (&info->user_tags, "completed-on");
+ if (tag && *tag)
+ have_flag_completed = TRUE;
+ else
+ have_flag_incomplete = TRUE;
+ } else
+ have_unflagged = TRUE;
+
+ camel_folder_free_message_info (fb->folder, info);
+
+ if (have_seen && have_unseen && have_deleted && have_undeleted)
+ break;
+ }
+
+ if (!have_unseen)
+ enable_mask |= CAN_MARK_READ;
+ if (!have_seen)
+ enable_mask |= CAN_MARK_UNREAD;
+
+ if (!have_undeleted)
+ enable_mask |= CAN_DELETE;
+ if (!have_deleted)
+ enable_mask |= CAN_UNDELETE;
+
+ if (!have_unimportant)
+ enable_mask |= CAN_MARK_IMPORTANT;
+ if (!have_important)
+ enable_mask |= CAN_MARK_UNIMPORTANT;
+
+ if (!have_flag_for_followup)
+ enable_mask |= CAN_CLEAR_FLAG;
+ if (!have_unflagged)
+ enable_mask |= CAN_FLAG_FOR_FOLLOWUP;
+ if (!have_flag_incomplete)
+ enable_mask |= CAN_FLAG_COMPLETED;
+
+ /*
+ * Hide items that wont get used.
+ */
+ if (!(have_unseen && have_seen)) {
+ if (have_seen)
+ hide_mask |= CAN_MARK_READ;
+ else
+ hide_mask |= CAN_MARK_UNREAD;
+ }
+
+ if (!(have_undeleted && have_deleted)) {
+ if (have_deleted)
+ hide_mask |= CAN_DELETE;
+ else
+ hide_mask |= CAN_UNDELETE;
+ }
+
+ if (!(have_important && have_unimportant)) {
+ if (have_important)
+ hide_mask |= CAN_MARK_IMPORTANT;
+ else
+ hide_mask |= CAN_MARK_UNIMPORTANT;
+ }
+
+ if (!have_flag_for_followup)
+ hide_mask |= CAN_CLEAR_FLAG;
+ if (!have_unflagged)
+ hide_mask |= CAN_FLAG_FOR_FOLLOWUP;
+ if (!have_flag_incomplete)
+ hide_mask |= CAN_FLAG_COMPLETED;
+ }
+
+ /* free uids */
+ for (i = 0; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+ g_ptr_array_free (uids, TRUE);
+
+ /* generate the "Filter on Mailing List" menu item name */
+ if (mlist == NULL) {
+ enable_mask |= IS_MAILING_LIST;
+ filter_menu[MLIST_FILTER].name = g_strdup (_("Filter on _Mailing List"));
+ filter_menu[MLIST_VFOLDER].name = g_strdup (_("VFolder on M_ailing List"));
+ } else {
+ filter_menu[MLIST_FILTER].name = g_strdup_printf (_("Filter on _Mailing List (%s)"), mlist);
+ filter_menu[MLIST_VFOLDER].name = g_strdup_printf (_("VFolder on M_ailing List (%s)"), mlist);
+ }
+
+ /* create the label/colour menu */
+ closures = g_ptr_array_new ();
+ label_menu[0].closure = g_new (struct _label_data, 1);
+ g_ptr_array_add (closures, label_menu[0].closure);
+ g_object_ref (fb);
+ ((struct _label_data *) label_menu[0].closure)->fb = fb;
+ ((struct _label_data *) label_menu[0].closure)->label = NULL;
+
+ i = 0;
+ labels = mail_config_get_labels ();
+ while (labels != NULL && i < 5) {
+ struct _label_data *closure;
+ MailConfigLabel *label;
+ GdkPixmap *pixmap;
+ GdkColormap *map;
+ GdkColor colour;
+ GdkGC *gc;
+
+ label = labels->data;
+ gdk_color_parse (label->colour, &colour);
+ map = gdk_colormap_get_system ();
+ gdk_color_alloc (map, &colour);
+
+ pixmap = gdk_pixmap_new (GTK_WIDGET (fb)->window, 16, 16, -1);
+ gc = gdk_gc_new (GTK_WIDGET (fb)->window);
+ gdk_gc_set_foreground (gc, &colour);
+ gdk_draw_rectangle (pixmap, gc, TRUE, 0, 0, 16, 16);
+ gdk_gc_unref (gc);
+
+ closure = g_new (struct _label_data, 1);
+ g_object_ref (fb);
+ closure->fb = fb;
+ closure->label = label->tag;
+
+ g_ptr_array_add (closures, closure);
+
+ label_menu[i + 2].name = label->name;
+ label_menu[i + 2].pixmap_widget = gtk_image_new_from_pixmap (pixmap, NULL);
+ label_menu[i + 2].closure = closure;
+
+ i++;
+ labels = labels->next;
+ }
+
+ setup_popup_icons ();
+
+ for (i = 0; i < sizeof (filter_menu) / sizeof (filter_menu[0]); i++)
+ filter_menu[i].closure = fdata;
+
+ menu = e_popup_menu_create (context_menu, enable_mask, hide_mask, fb);
+ e_auto_kill_popup_menu_on_selection_done (menu);
+
+ g_object_set_data_full ((GObject *) menu, "label_closures", closures, (GtkDestroyNotify) label_closures_free);
+
+ if (fdata)
+ g_object_set_data_full ((GObject *) menu, "filter_data", fdata, (GtkDestroyNotify) filter_data_free);
+
+ if (event->type == GDK_KEY_PRESS) {
+ struct cmpf_data closure;
+
+ closure.tree = tree;
+ closure.row = row;
+ closure.col = col;
+ gtk_menu_popup (menu, NULL, NULL, context_menu_position_func,
+ &closure, 0, event->key.time);
+ } else {
+ gtk_menu_popup (menu, NULL, NULL, NULL, NULL,
+ event->button.button, event->button.time);
+ }
+
+ g_free (filter_menu[MLIST_FILTER].name);
+ g_free (filter_menu[MLIST_VFOLDER].name);
+
+ return TRUE;
+}
+
+static int
+html_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+ FolderBrowser *fb = data;
+ HTMLEngine *engine;
+ HTMLPoint *point;
+ ETreePath *path;
+ int row;
+
+ if (event->type != GDK_BUTTON_PRESS || event->button != 3)
+ return FALSE;
+
+ engine = GTK_HTML (widget)->engine;
+ point = html_engine_get_point_at (engine, event->x, event->y, FALSE);
+
+ if (point) {
+ /* don't popup a menu if the mouse is hovering over a
+ url or a source image because those situations are
+ handled in mail-display.c's button_press_event
+ callback */
+ const char *src, *url;
+
+ url = html_object_get_url (point->object);
+ src = html_object_get_src (point->object);
+
+ if (url || src) {
+ html_point_destroy (point);
+ return FALSE;
+ }
+
+ html_point_destroy (point);
+ }
+
+ path = e_tree_get_cursor (fb->message_list->tree);
+ row = e_tree_row_of_node (fb->message_list->tree, path);
+
+ on_right_click (fb->message_list->tree, row, path, 2,
+ (GdkEvent *) event, fb);
+
+ return TRUE;
+}
+
+static int
+on_key_press (GtkWidget *widget, GdkEventKey *key, gpointer data)
+{
+ FolderBrowser *fb = data;
+ ETreePath *path;
+ int row;
+
+ if (key->state & GDK_CONTROL_MASK)
+ return FALSE;
+
+ path = e_tree_get_cursor (fb->message_list->tree);
+ row = e_tree_row_of_node (fb->message_list->tree, path);
+
+ switch (key->keyval) {
+ case GDK_Delete:
+ case GDK_KP_Delete:
+ delete_msg (NULL, fb);
+ return TRUE;
+
+ case GDK_Menu:
+ on_right_click (fb->message_list->tree, row, path, 2,
+ (GdkEvent *)key, fb);
+ return TRUE;
+ case '!':
+ toggle_as_important (NULL, fb, NULL);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int
+etree_key (ETree *tree, int row, ETreePath path, int col, GdkEvent *ev, FolderBrowser *fb)
+{
+ GtkAdjustment *vadj;
+ gfloat page_size;
+
+ if ((ev->key.state & GDK_CONTROL_MASK) != 0)
+ return FALSE;
+
+ vadj = gtk_scrolled_window_get_vadjustment (fb->mail_display->scroll);
+ page_size = vadj->page_size - vadj->step_increment;
+
+ switch (ev->key.keyval) {
+ case GDK_space:
+ /* Work around Ximian 4939 */
+ if (vadj->upper < vadj->page_size)
+ break;
+ if (vadj->value < vadj->upper - vadj->page_size - page_size)
+ vadj->value += page_size;
+ else
+ vadj->value = vadj->upper - vadj->page_size;
+ gtk_adjustment_value_changed (vadj);
+ break;
+ case GDK_BackSpace:
+ if (vadj->value > vadj->lower + page_size)
+ vadj->value -= page_size;
+ else
+ vadj->value = vadj->lower;
+ gtk_adjustment_value_changed (vadj);
+ break;
+ case GDK_Return:
+ case GDK_KP_Enter:
+ case GDK_ISO_Enter:
+ open_msg (NULL, fb);
+ break;
+ default:
+ return on_key_press ((GtkWidget *)tree, (GdkEventKey *)ev, fb);
+ }
+
+ return TRUE;
+}
+
+static void
+on_double_click (ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, FolderBrowser *fb)
+{
+ /* Ignore double-clicks on columns where single-click doesn't
+ * just select.
+ */
+ if (MESSAGE_LIST_COLUMN_IS_ACTIVE (col))
+ return;
+
+ open_msg (NULL, fb);
+}
+
+static void
+on_selection_changed (GtkObject *obj, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ FolderBrowserSelectionState state;
+
+ /* we can get this signal at strange times...
+ * if no uicomp, don't even bother */
+
+ if (fb->uicomp == NULL)
+ return;
+
+ switch (e_selection_model_selected_count (E_SELECTION_MODEL (obj))) {
+ case 0:
+ state = FB_SELSTATE_NONE;
+ break;
+ case 1:
+ state = FB_SELSTATE_SINGLE;
+ break;
+ default:
+ state = FB_SELSTATE_MULTIPLE;
+ break;
+ }
+
+ folder_browser_ui_set_selection_state (fb, state);
+
+ update_status_bar_idle (fb);
+}
+
+
+static void
+on_cursor_activated (ETree *tree, int row, ETreePath path, gpointer user_data)
+{
+ on_selection_changed ((GtkObject *)tree, user_data);
+}
+
+static gboolean
+fb_resize_cb (GtkWidget *w, GdkEventButton *e, FolderBrowser *fb)
+{
+ GConfClient *gconf;
+
+ if (GTK_WIDGET_REALIZED (w) && fb->preview_shown) {
+ gconf = mail_config_get_gconf_client ();
+ gconf_client_set_int (gconf, "/apps/evolution/mail/display/paned_size", gtk_paned_get_position (GTK_PANED (w)), NULL);
+ }
+
+ return FALSE;
+}
+
+/* hack to get around the fact setting the paned size doesn't work */
+static void
+paned_realised(GtkWidget *w, FolderBrowser *fb)
+{
+ GConfClient *gconf;
+ int size;
+
+ gconf = mail_config_get_gconf_client ();
+ size = gconf_client_get_int (gconf, "/apps/evolution/mail/display/paned_size", NULL);
+ gtk_paned_set_position (GTK_PANED (fb->vpaned), size);
+}
+
+static void
+folder_browser_gui_init (FolderBrowser *fb)
+{
+ RuleContext *search_context = mail_component_peek_search_context (mail_component_peek ());
+ ESelectionModel *esm;
+
+ /* The panned container */
+ fb->vpaned = gtk_vpaned_new ();
+ g_signal_connect(fb->vpaned, "realize", G_CALLBACK(paned_realised), fb);
+ gtk_widget_show (fb->vpaned);
+
+ gtk_table_attach (GTK_TABLE (fb), fb->vpaned,
+ 0, 1, 1, 3,
+ GTK_FILL | GTK_EXPAND,
+ GTK_FILL | GTK_EXPAND,
+ 0, 0);
+
+ /* quick-search bar */
+ if (search_context) {
+ const char *systemrules = g_object_get_data (G_OBJECT (search_context), "system");
+ const char *userrules = g_object_get_data (G_OBJECT (search_context), "user");
+
+ fb->search = e_filter_bar_new (search_context, systemrules, userrules,
+ folder_browser_config_search, fb);
+ e_search_bar_set_menu ((ESearchBar *)fb->search, folder_browser_search_menu_items);
+ gtk_widget_show (GTK_WIDGET (fb->search));
+
+ g_signal_connect (fb->search, "menu_activated",
+ G_CALLBACK (folder_browser_search_menu_activated), fb);
+ g_signal_connect (fb->search, "search_activated",
+ G_CALLBACK (folder_browser_search_do_search), fb);
+ g_signal_connect (fb->search, "query_changed",
+ G_CALLBACK (folder_browser_query_changed), fb);
+
+ gtk_table_attach (GTK_TABLE (fb), GTK_WIDGET (fb->search),
+ 0, 1, 0, 1,
+ GTK_FILL | GTK_EXPAND,
+ 0,
+ 0, 0);
+ }
+
+ esm = e_tree_get_selection_model (E_TREE (fb->message_list->tree));
+ g_signal_connect (esm, "selection_changed", G_CALLBACK (on_selection_changed), fb);
+ g_signal_connect (esm, "cursor_activated", G_CALLBACK (on_cursor_activated), fb);
+ fb->selection_state = FB_SELSTATE_NONE; /* default to none */
+
+ gtk_paned_add1 (GTK_PANED (fb->vpaned), GTK_WIDGET (fb->message_list));
+ gtk_widget_show (GTK_WIDGET (fb->message_list));
+
+ fb->paned_resize_id = g_signal_connect (fb->vpaned, "button_release_event",
+ G_CALLBACK (fb_resize_cb), fb);
+
+ gtk_paned_add2 (GTK_PANED (fb->vpaned), GTK_WIDGET (fb->mail_display));
+ gtk_widget_show (GTK_WIDGET (fb->mail_display));
+ gtk_widget_show (GTK_WIDGET (fb));
+}
+
+/* mark the message seen if the current message still matches */
+static gint
+do_mark_seen (gpointer data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (data);
+
+ if (fb->new_uid && fb->loaded_uid && !strcmp (fb->new_uid, fb->loaded_uid)) {
+ camel_folder_set_message_flags (fb->folder, fb->new_uid,
+ CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
+ }
+
+ return FALSE;
+}
+
+/* callback when we have the message to display, after async loading it (see below) */
+/* if we have pending uid's, it means another was selected before we finished displaying
+ the last one - so we cycle through and start loading the pending one immediately now */
+static void
+done_message_selected (CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data)
+{
+ FolderBrowser *fb = data;
+ CamelMessageInfo *info;
+ GConfClient *gconf;
+ int timeout;
+
+ if (folder != fb->folder || fb->mail_display == NULL)
+ return;
+
+ gconf = mail_config_get_gconf_client ();
+ timeout = gconf_client_get_int (gconf, "/apps/evolution/mail/display/mark_seen_timeout", NULL);
+
+ info = camel_folder_get_message_info (fb->folder, uid);
+ mail_display_set_message (fb->mail_display, (CamelMedium *) msg, fb->folder, info);
+ if (info)
+ camel_folder_free_message_info (fb->folder, info);
+
+ /* FIXME: should this signal be emitted here?? */
+ g_signal_emit (fb, folder_browser_signals[MESSAGE_LOADED], 0, uid);
+
+ /* pain, if we have pending stuff, re-run */
+ if (fb->pending_uid) {
+ g_free (fb->loading_uid);
+ fb->loading_uid = fb->pending_uid;
+ fb->pending_uid = NULL;
+
+ mail_get_message (fb->folder, fb->loading_uid, done_message_selected, fb, mail_thread_new);
+ return;
+ }
+
+ g_free (fb->loaded_uid);
+ fb->loaded_uid = fb->loading_uid;
+ fb->loading_uid = NULL;
+
+ folder_browser_ui_message_loaded (fb);
+
+ /* if we are still on the same message, do the 'idle read' thing */
+ if (fb->seen_id)
+ g_source_remove (fb->seen_id);
+
+ if (msg && gconf_client_get_bool (gconf, "/apps/evolution/mail/display/mark_seen", NULL)) {
+ if (timeout > 0)
+ fb->seen_id = g_timeout_add (timeout, do_mark_seen, fb);
+ else
+ do_mark_seen (fb);
+ }
+}
+
+/* ok we waited enough, display it anyway (see below) */
+static gboolean
+do_message_selected (FolderBrowser *fb)
+{
+ d(printf ("%p: selecting uid %s (delayed)\n", fb, fb->new_uid ? fb->new_uid : "NONE"));
+
+ fb->loading_id = 0;
+
+ /* if we are loading, then set a pending, but leave the loading, coudl cancel here (?) */
+ if (fb->loading_uid) {
+ if (fb->new_uid == NULL || fb->pending_uid == NULL || strcmp(fb->pending_uid, fb->new_uid) != 0) {
+ g_free (fb->pending_uid);
+ fb->pending_uid = g_strdup (fb->new_uid);
+ }
+ } else {
+ if (fb->new_uid) {
+ if (fb->loaded_uid == NULL || strcmp(fb->new_uid, fb->loaded_uid) != 0) {
+ fb->loading_uid = g_strdup (fb->new_uid);
+ mail_get_message (fb->folder, fb->loading_uid, done_message_selected, fb, mail_thread_new);
+ }
+ } else {
+ mail_display_set_message (fb->mail_display, NULL, NULL, NULL);
+ }
+ }
+
+ return FALSE;
+}
+
+/* when a message is selected, wait a while before trying to display it */
+static void
+on_message_selected (MessageList *ml, const char *uid, FolderBrowser *fb)
+{
+ d(printf ("%p: selecting uid %s (direct)\n", fb, uid ? uid : "NONE"));
+
+ if (fb->loading_id != 0)
+ g_source_remove (fb->loading_id);
+
+ g_free (fb->new_uid);
+ fb->new_uid = g_strdup (uid);
+
+ if (fb->preview_shown)
+ fb->loading_id = g_timeout_add (100, (GtkFunction)do_message_selected, fb);
+}
+
+static gboolean
+on_message_list_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
+{
+ FolderBrowser *fb = (FolderBrowser *) user_data;
+
+ d(printf ("got focus!\n"));
+ folder_browser_ui_message_list_focus (fb);
+
+ return FALSE;
+}
+
+static gboolean
+on_message_list_focus_out (GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
+{
+ FolderBrowser *fb = (FolderBrowser *) user_data;
+
+ d(printf ("got unfocus!\n"));
+ folder_browser_ui_message_list_unfocus (fb);
+
+ return FALSE;
+}
+
+static void
+folder_browser_init (FolderBrowser *fb)
+{
+ fb->async_event = mail_async_event_new ();
+ fb->get_id = -1;
+}
+
+static void
+my_folder_browser_init (FolderBrowser *fb)
+{
+ int i;
+
+ fb->view_instance = NULL;
+ fb->view_menus = NULL;
+
+ fb->pref_master = FALSE;
+
+ /*
+ * Setup parent class fields.
+ */
+ GTK_TABLE (fb)->homogeneous = FALSE;
+ gtk_table_resize (GTK_TABLE (fb), 1, 2);
+
+ /*
+ * Our instance data
+ */
+ fb->message_list = (MessageList *)message_list_new ();
+ fb->mail_display = (MailDisplay *)mail_display_new ();
+
+ fb->preview_shown = TRUE;
+
+ g_signal_connect (fb->mail_display->html, "key_press_event",
+ G_CALLBACK (on_key_press), fb);
+ g_signal_connect (fb->mail_display->html, "button_press_event",
+ G_CALLBACK (html_button_press_event), fb);
+
+ g_signal_connect (fb->message_list->tree, "key_press",
+ G_CALLBACK (etree_key), fb);
+
+ g_signal_connect (fb->message_list->tree, "right_click",
+ G_CALLBACK (on_right_click), fb);
+
+ g_signal_connect (fb->message_list->tree, "double_click",
+ G_CALLBACK (on_double_click), fb);
+
+ g_signal_connect (fb->message_list, "focus_in_event",
+ G_CALLBACK (on_message_list_focus_in), fb);
+
+ g_signal_connect (fb->message_list, "focus_out_event",
+ G_CALLBACK (on_message_list_focus_out), fb);
+
+ g_signal_connect (fb->message_list, "message_selected",
+ G_CALLBACK (on_message_selected), fb);
+
+ /* drag & drop */
+ e_tree_drag_source_set (fb->message_list->tree, GDK_BUTTON1_MASK,
+ drag_types, num_drag_types, GDK_ACTION_MOVE | GDK_ACTION_COPY);
+
+ g_signal_connect (fb->message_list->tree, "tree_drag_data_get",
+ G_CALLBACK (message_list_drag_data_get), fb);
+
+ e_tree_drag_dest_set (fb->message_list->tree, GTK_DEST_DEFAULT_ALL,
+ drag_types, num_drag_types, GDK_ACTION_MOVE | GDK_ACTION_COPY);
+
+ g_signal_connect (fb->message_list->tree, "tree_drag_data_received",
+ G_CALLBACK (message_list_drag_data_received), fb);
+
+ /* cut, copy & paste */
+ fb->invisible = gtk_invisible_new ();
+ g_object_ref (fb->invisible);
+ gtk_object_sink ((GtkObject *) fb->invisible);
+
+ for (i = 0; i < num_paste_types; i++)
+ gtk_selection_add_target (fb->invisible, clipboard_atom,
+ paste_types[i].target,
+ paste_types[i].info);
+
+ g_signal_connect (fb->invisible, "selection_get",
+ G_CALLBACK (selection_get), fb);
+ g_signal_connect (fb->invisible, "selection_clear_event",
+ G_CALLBACK (selection_clear_event), fb);
+ g_signal_connect (fb->invisible, "selection_received",
+ G_CALLBACK (selection_received), fb);
+
+ folder_browser_gui_init (fb);
+}
+
+GtkWidget *
+folder_browser_new (const char *uri)
+{
+ CORBA_Environment ev;
+ FolderBrowser *folder_browser;
+
+ CORBA_exception_init (&ev);
+
+ folder_browser = g_object_new (folder_browser_get_type (), NULL);
+
+ my_folder_browser_init (folder_browser);
+
+ CORBA_exception_free (&ev);
+
+ if (uri) {
+ folder_browser->uri = g_strdup (uri);
+ folder_browser->meta = mail_tool_get_meta_data(uri);
+ g_object_ref (folder_browser);
+ folder_browser->get_id = mail_get_folder (folder_browser->uri, 0, got_folder,
+ folder_browser, mail_thread_new);
+ }
+
+ return GTK_WIDGET (folder_browser);
+}
+
+
+E_MAKE_TYPE (folder_browser, "FolderBrowser", FolderBrowser, folder_browser_class_init, folder_browser_init, PARENT_TYPE);
diff --git a/mail/folder-browser.h b/mail/folder-browser.h
new file mode 100644
index 0000000000..1b03ec9efb
--- /dev/null
+++ b/mail/folder-browser.h
@@ -0,0 +1,192 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+
+#ifndef _FOLDER_BROWSER_H_
+#define _FOLDER_BROWSER_H_
+
+#include <gtk/gtktable.h>
+#include "camel/camel-stream.h"
+#include <bonobo/bonobo-property-bag.h>
+#include <bonobo/bonobo-ui-component.h>
+#include <widgets/misc/e-filter-bar.h>
+#include "widgets/menus/gal-view-menus.h"
+#include "filter/filter-rule.h"
+#include "filter/filter-context.h" /*eek*/
+#include "message-list.h"
+#include "mail-display.h"
+#include "mail-types.h"
+#include "shell/Evolution.h"
+
+#define FOLDER_BROWSER_TYPE (folder_browser_get_type ())
+#define FOLDER_BROWSER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FOLDER_BROWSER_TYPE, FolderBrowser))
+#define FOLDER_BROWSER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), FOLDER_BROWSER_TYPE, FolderBrowserClass))
+#define IS_FOLDER_BROWSER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), FOLDER_BROWSER_TYPE))
+#define IS_FOLDER_BROWSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), FOLDER_BROWSER_TYPE))
+
+#define FB_DEFAULT_CHARSET _("Default")
+
+#define FOLDER_BROWSER_IS_DESTROYED(fb) (!fb || !fb->message_list || !fb->mail_display || !fb->folder)
+
+typedef enum _FolderBrowserSelectionState {
+ FB_SELSTATE_NONE,
+ FB_SELSTATE_SINGLE,
+ FB_SELSTATE_MULTIPLE,
+ FB_SELSTATE_UNDEFINED
+} FolderBrowserSelectionState;
+
+struct _FolderBrowser {
+ GtkTable parent;
+
+ BonoboPropertyBag *properties;
+
+ GNOME_Evolution_ShellView shell_view;
+
+ BonoboUIComponent *uicomp;
+
+ /*
+ * The current URI being displayed by the FolderBrowser
+ */
+ char *uri;
+ CamelFolder *folder;
+ int unread_count; /* last known unread message count */
+
+ /* async loading stuff */
+ char *loading_uid; /* what uid am i loading now */
+ char *pending_uid; /* what uid should i load next */
+ char *new_uid; /* place to save the next uid during idle timeout */
+ char *loaded_uid; /* what we have loaded */
+ guint loading_id;
+ guint seen_id;
+
+ gulong paned_resize_id;
+
+ /* a folder we are expunging, dont use other than to compare the pointer value */
+ CamelFolder *expunging;
+ int expunge_mlfocussed; /* true if the ml was focussed before we expunged */
+
+ MessageList *message_list;
+ MailDisplay *mail_display;
+ GtkWidget *vpaned;
+
+ EFilterBar *search;
+ FilterRule *search_full; /* if we have a full search active */
+
+ struct _EMeta *meta; /* various per-folder meta-data */
+
+ guint32 preview_shown : 1;
+ guint32 threaded : 1;
+ guint32 pref_master : 1;
+
+ FolderBrowserSelectionState selection_state;
+ GSList *sensitize_changes;
+ GHashTable *sensitise_state; /* the last sent sensitise state, to avoid much bonobo overhead */
+ int sensitize_timeout_id;
+ int update_status_bar_idle_id;
+
+ /* View instance and the menu handler object */
+ GalViewInstance *view_instance;
+ GalViewMenus *view_menus;
+
+ GtkWidget *invisible;
+ GByteArray *clipboard_selection;
+
+ /* for async events */
+ struct _MailAsyncEvent *async_event;
+
+ int get_id; /* for getting folder op */
+
+ /* info used by popup for filter/vfolder */
+ struct _popup_filter_data *popup;
+};
+
+typedef struct {
+ GtkTableClass parent_class;
+
+ /* signals */
+ void (*folder_loaded) (FolderBrowser *fb, const char *uri);
+ void (*message_loaded) (FolderBrowser *fb, const char *uid);
+} FolderBrowserClass;
+
+struct fb_ondemand_closure {
+ FilterRule *rule;
+ FolderBrowser *fb;
+ gchar *path;
+};
+
+GtkType folder_browser_get_type (void);
+GtkWidget *folder_browser_new (const char *uri);
+
+void folder_browser_set_folder (FolderBrowser *fb, CamelFolder *folder, const char *uri);
+
+void folder_browser_set_ui_component (FolderBrowser *fb, BonoboUIComponent *uicomp);
+void folder_browser_set_shell_view (FolderBrowser *fb, GNOME_Evolution_ShellView shell_view);
+
+void folder_browser_set_message_preview (FolderBrowser *folder_browser,
+ gboolean show_message_preview);
+void folder_browser_clear_search (FolderBrowser *fb);
+
+void folder_browser_cut (GtkWidget *widget, FolderBrowser *fb);
+void folder_browser_copy (GtkWidget *widget, FolderBrowser *fb);
+void folder_browser_paste (GtkWidget *widget, FolderBrowser *fb);
+
+void folder_browser_reload (FolderBrowser *fb);
+
+/* callbacks for functions on the folder-browser */
+void vfolder_subject (GtkWidget *w, FolderBrowser *fb);
+void vfolder_sender (GtkWidget *w, FolderBrowser *fb);
+void vfolder_recipient (GtkWidget *w, FolderBrowser *fb);
+void vfolder_mlist (GtkWidget *w, FolderBrowser *fb);
+
+void filter_subject (GtkWidget *w, FolderBrowser *fb);
+void filter_sender (GtkWidget *w, FolderBrowser *fb);
+void filter_recipient (GtkWidget *w, FolderBrowser *fb);
+void filter_mlist (GtkWidget *w, FolderBrowser *fb);
+
+void hide_read(GtkWidget *w, FolderBrowser *fb);
+void hide_deleted(GtkWidget *w, FolderBrowser *fb);
+void hide_selected(GtkWidget *w, FolderBrowser *fb);
+void hide_none(GtkWidget *w, FolderBrowser *fb);
+void hide_subject(GtkWidget *w, FolderBrowser *fb);
+void hide_sender(GtkWidget *w, FolderBrowser *fb);
+
+void folder_browser_toggle_preview (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data);
+
+void folder_browser_toggle_threads (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data);
+
+void folder_browser_toggle_hide_deleted (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data);
+
+void folder_browser_toggle_caret_mode (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data);
+
+void folder_browser_set_message_display_style (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data);
+
+void folder_browser_charset_changed (BonoboUIComponent *component,
+ const char *path,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ gpointer user_data);
+
+gboolean folder_browser_is_drafts (FolderBrowser *fb);
+gboolean folder_browser_is_sent (FolderBrowser *fb);
+gboolean folder_browser_is_outbox (FolderBrowser *fb);
+
+#endif /* _FOLDER_BROWSER_H_ */
diff --git a/mail/mail-account-gui.c b/mail/mail-account-gui.c
index 62ddfc4d06..6e6ce85d2c 100644
--- a/mail/mail-account-gui.c
+++ b/mail/mail-account-gui.c
@@ -36,17 +36,21 @@
#include <e-util/e-account-list.h>
#include <e-util/e-dialog-utils.h>
-#include "evolution-folder-selector-button.h"
+#include "em-folder-selection-button.h"
#include "mail-account-gui.h"
#include "mail-session.h"
#include "mail-send-recv.h"
#include "mail-signature-editor.h"
+#include "mail-component.h"
#include "mail-composer-prefs.h"
#include "mail-config.h"
#include "mail-ops.h"
#include "mail-mt.h"
#include "mail.h"
+#include "e-storage.h"
+
+
#define d(x)
extern char *default_drafts_folder_uri, *default_sent_folder_uri;
@@ -1060,16 +1064,13 @@ extract_values (MailAccountGuiService *source, GHashTable *extra_config, CamelUR
}
}
-
static void
-folder_selected (EvolutionFolderSelectorButton *button,
- GNOME_Evolution_Folder *corba_folder,
- gpointer user_data)
+folder_selected (EMFolderSelectionButton *button, gpointer user_data)
{
char **folder_name = user_data;
g_free (*folder_name);
- *folder_name = g_strdup (corba_folder->physicalUri);
+ *folder_name = g_strdup(em_folder_selection_button_get_selection(button));
}
static void
@@ -1080,14 +1081,12 @@ default_folders_clicked (GtkButton *button, gpointer user_data)
/* Drafts folder */
g_free (gui->drafts_folder_uri);
gui->drafts_folder_uri = g_strdup (default_drafts_folder_uri);
- evolution_folder_selector_button_set_uri (EVOLUTION_FOLDER_SELECTOR_BUTTON (gui->drafts_folder_button),
- gui->drafts_folder_uri);
+ em_folder_selection_button_set_selection((EMFolderSelectionButton *)gui->drafts_folder_button, gui->drafts_folder_uri);
/* Sent folder */
g_free (gui->sent_folder_uri);
gui->sent_folder_uri = g_strdup (default_sent_folder_uri);
- evolution_folder_selector_button_set_uri (EVOLUTION_FOLDER_SELECTOR_BUTTON (gui->sent_folder_button),
- gui->sent_folder_uri);
+ em_folder_selection_button_set_selection((EMFolderSelectionButton *)gui->sent_folder_button, gui->sent_folder_uri);
}
GtkWidget *mail_account_gui_folder_selector_button_new (char *widget_name, char *string1, char *string2, int int1, int int2);
@@ -1097,7 +1096,7 @@ mail_account_gui_folder_selector_button_new (char *widget_name,
char *string1, char *string2,
int int1, int int2)
{
- return (GtkWidget *)g_object_new (EVOLUTION_TYPE_FOLDER_SELECTOR_BUTTON, NULL);
+ return (GtkWidget *)em_folder_selection_button_new(_("Select Folder"), NULL);
}
static gboolean
@@ -1410,7 +1409,6 @@ prepare_signatures (MailAccountGui *gui)
MailAccountGui *
mail_account_gui_new (EAccount *account, MailAccountsTab *dialog)
{
- const char *allowed_types[] = { "mail/*", NULL };
MailAccountGui *gui;
GtkWidget *button;
@@ -1499,31 +1497,21 @@ mail_account_gui_new (EAccount *account, MailAccountsTab *dialog)
/* Drafts folder */
gui->drafts_folder_button = GTK_BUTTON (glade_xml_get_widget (gui->xml, "drafts_button"));
- g_signal_connect (gui->drafts_folder_button, "selected",
- G_CALLBACK (folder_selected), &gui->drafts_folder_uri);
+ g_signal_connect (gui->drafts_folder_button, "selected", G_CALLBACK (folder_selected), &gui->drafts_folder_uri);
if (account->drafts_folder_uri)
gui->drafts_folder_uri = g_strdup (account->drafts_folder_uri);
else
gui->drafts_folder_uri = g_strdup (default_drafts_folder_uri);
- evolution_folder_selector_button_construct (EVOLUTION_FOLDER_SELECTOR_BUTTON (gui->drafts_folder_button),
- global_shell_client,
- _("Select Folder"),
- gui->drafts_folder_uri,
- allowed_types);
+ em_folder_selection_button_set_selection((EMFolderSelectionButton *)gui->drafts_folder_button, gui->drafts_folder_uri);
/* Sent folder */
gui->sent_folder_button = GTK_BUTTON (glade_xml_get_widget (gui->xml, "sent_button"));
- g_signal_connect (gui->sent_folder_button, "selected",
- G_CALLBACK (folder_selected), &gui->sent_folder_uri);
+ g_signal_connect (gui->sent_folder_button, "selected", G_CALLBACK (folder_selected), &gui->sent_folder_uri);
if (account->sent_folder_uri)
gui->sent_folder_uri = g_strdup (account->sent_folder_uri);
else
gui->sent_folder_uri = g_strdup (default_sent_folder_uri);
- evolution_folder_selector_button_construct (EVOLUTION_FOLDER_SELECTOR_BUTTON (gui->sent_folder_button),
- global_shell_client,
- _("Select Folder"),
- gui->sent_folder_uri,
- allowed_types);
+ em_folder_selection_button_set_selection((EMFolderSelectionButton *)gui->sent_folder_button, gui->sent_folder_uri);
/* Special Folders "Reset Defaults" button */
button = glade_xml_get_widget (gui->xml, "default_folders_button");
@@ -1842,18 +1830,21 @@ static void
add_new_store (char *uri, CamelStore *store, void *user_data)
{
EAccount *account = user_data;
- EvolutionStorage *storage;
+ MailComponent *component = mail_component_peek ();
+ EStorage *storage;
if (store == NULL)
return;
+
+ /* EPFIXME: Strange refcounting semantics here?! */
- storage = mail_lookup_storage (store);
+ storage = mail_component_lookup_storage (component, store);
if (storage) {
/* store is already in the folder tree, so do nothing */
- bonobo_object_unref (BONOBO_OBJECT (storage));
+ g_object_unref (storage);
} else {
/* store is *not* in the folder tree, so lets add it. */
- mail_add_storage (store, account->name, account->source->url);
+ mail_component_add_store (component, store, account->name);
}
}
@@ -1968,7 +1959,7 @@ mail_account_gui_save (MailAccountGui *gui)
#define sources_equal(old,new) (new->url && !strcmp (old->url, new->url))
if (!sources_equal (account->source, new->source)) {
/* Remove the old storage from the folder-tree */
- mail_remove_storage_by_uri (account->source->url);
+ mail_component_remove_storage_by_uri (mail_component_peek (), account->source->url);
}
}
diff --git a/mail/mail-accounts.c b/mail/mail-accounts.c
index fb06efd6ba..b17652bb66 100644
--- a/mail/mail-accounts.c
+++ b/mail/mail-accounts.c
@@ -33,9 +33,11 @@
#include <gtk/gtktreeselection.h>
#include "mail.h"
+#include "mail-component.h"
#include "mail-config.h"
#include "mail-config-druid.h"
#include "mail-account-editor.h"
+#include "mail-ops.h"
#include "mail-send-recv.h"
#include "art/mark.xpm"
@@ -248,8 +250,8 @@ account_delete_clicked (GtkButton *button, gpointer user_data)
/* remove it from the folder-tree in the shell */
if (account->enabled && account->source && account->source->url)
- mail_remove_storage_by_uri (account->source->url);
-
+ mail_component_remove_storage_by_uri (mail_component_peek (), account->source->url);
+
/* remove it from the config file */
mail_config_remove_account (account);
accounts = mail_config_get_accounts ();
@@ -297,6 +299,7 @@ account_default_clicked (GtkButton *button, gpointer user_data)
static void
account_able_clicked (GtkButton *button, gpointer user_data)
{
+ MailComponent *component = mail_component_peek ();
MailAccountsTab *prefs = user_data;
GtkTreeSelection *selection;
EAccount *account = NULL;
@@ -317,9 +320,11 @@ account_able_clicked (GtkButton *button, gpointer user_data)
folder-tree, otherwise add it to the folder-tree */
if (account->source->url) {
if (account->enabled)
- mail_load_storage_by_uri (prefs->shell, account->source->url, account->name);
+ mail_component_load_storage_by_uri (component,
+ account->source->url,
+ account->name);
else
- mail_remove_storage_by_uri (account->source->url);
+ mail_component_remove_storage_by_uri (component, account->source->url);
}
mail_autoreceive_setup ();
@@ -354,17 +359,18 @@ account_able_toggled (GtkCellRendererToggle *renderer, char *arg1, gpointer user
gtk_tree_path_free (path);
if (account) {
+ MailComponent *component = mail_component_peek ();
+
/* if the account got disabled, remove it from the
folder-tree, otherwise add it to the folder-tree */
if (account->source->url) {
if (account->enabled)
- mail_load_storage_by_uri (prefs->shell, account->source->url, account->name);
+ mail_component_load_storage_by_uri (component, account->source->url, account->name);
else
- mail_remove_storage_by_uri (account->source->url);
+ mail_component_remove_storage_by_uri (component, account->source->url);
}
mail_autoreceive_setup ();
-
mail_config_write ();
}
}
diff --git a/mail/mail-accounts.etspec b/mail/mail-accounts.etspec
new file mode 100644
index 0000000000..22c09370b1
--- /dev/null
+++ b/mail/mail-accounts.etspec
@@ -0,0 +1,12 @@
+<ETableSpecification cursor-mode="line" draw-grid="false" draw-focus="true" selection-mode="single">
+ <ETableColumn model_col= "0" _title="Enabled" pixbuf="enabled" expansion="0.0" minimum_width="18" resizable="false" cell="render_message_status" compare="integer" sortable="false"/>
+
+ <ETableColumn model_col= "1" _title="Account name" expansion="1.6" minimum_width="32" resizable="true" cell="render_text" compare="string"/>
+
+ <ETableColumn model_col= "2" _title="Protocol" expansion="0.8" minimum_width="32" resizable="true" cell="render_text" compare="string"/>
+
+ <ETableState>
+ <column source="0"/> <column source="1"/> <column source="2"/>
+ <grouping> </grouping>
+ </ETableState>
+</ETableSpecification>
diff --git a/mail/mail-autofilter.c b/mail/mail-autofilter.c
index ac116aea7d..9e98758700 100644
--- a/mail/mail-autofilter.c
+++ b/mail/mail-autofilter.c
@@ -51,7 +51,6 @@
#include "filter/filter-editor.h"
#include "filter/filter-option.h"
-extern char *evolution_dir;
static void
rule_match_recipients (RuleContext *context, FilterRule *rule, CamelInternetAddress *iaddr)
@@ -313,7 +312,8 @@ filter_gui_add_from_message (CamelMimeMessage *msg, const char *source, int flag
g_return_if_fail (msg != NULL);
fc = filter_context_new ();
- user = g_strdup_printf ("%s/filters.xml", evolution_dir);
+ user = g_strdup_printf ("%s/filters.xml",
+ mail_component_peek_base_directory (mail_component_peek ()));
system = EVOLUTION_PRIVDATADIR "/filtertypes.xml";
rule_context_load ((RuleContext *)fc, system, user);
rule = filter_rule_from_message (fc, msg, flags);
@@ -334,7 +334,7 @@ mail_filter_rename_uri(CamelStore *store, const char *olduri, const char *newuri
GList *changed;
fc = filter_context_new ();
- user = g_strdup_printf ("%s/filters.xml", evolution_dir);
+ user = g_strdup_printf ("%s/filters.xml", mail_component_peek_base_directory (mail_component_peek ()));
system = EVOLUTION_PRIVDATADIR "/filtertypes.xml";
rule_context_load ((RuleContext *)fc, system, user);
@@ -359,7 +359,7 @@ mail_filter_delete_uri(CamelStore *store, const char *uri)
GList *deleted;
fc = filter_context_new ();
- user = g_strdup_printf ("%s/filters.xml", evolution_dir);
+ user = g_strdup_printf ("%s/filters.xml", mail_component_peek_base_directory (mail_component_peek ()));
system = EVOLUTION_PRIVDATADIR "/filtertypes.xml";
rule_context_load ((RuleContext *)fc, system, user);
diff --git a/mail/mail-callbacks.c b/mail/mail-callbacks.c
new file mode 100644
index 0000000000..cfb657b542
--- /dev/null
+++ b/mail/mail-callbacks.c
@@ -0,0 +1,3228 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* mail-ops.c: callbacks for the mail toolbar/menus */
+
+/*
+ * Authors:
+ * Dan Winship <danw@ximian.com>
+ * Peter Williams <peterw@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2000 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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>
+#endif
+
+#include <time.h>
+#include <errno.h>
+
+#include <gtkhtml/gtkhtml.h>
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <gtk/gtkmessagedialog.h>
+
+#include <libgnomeprint/gnome-print-job.h>
+#include <libgnomeprintui/gnome-print-dialog.h>
+#include <libgnomeprintui/gnome-print-job-preview.h>
+
+#include <bonobo/bonobo-widget.h>
+#include <bonobo/bonobo-socket.h>
+#include <gal/e-table/e-table.h>
+#include <e-util/e-dialog-utils.h>
+#include <filter/filter-editor.h>
+
+#include "mail.h"
+#include "message-browser.h"
+#include "mail-callbacks.h"
+#include "mail-component.h"
+#include "mail-config.h"
+#include "mail-accounts.h"
+#include "mail-config-druid.h"
+#include "mail-mt.h"
+#include "mail-tools.h"
+#include "mail-ops.h"
+#include "mail-local.h"
+#include "mail-search.h"
+#include "mail-send-recv.h"
+#include "mail-vfolder.h"
+#include "mail-folder-cache.h"
+#include "folder-browser.h"
+#include "subscribe-dialog.h"
+#include "message-tag-editor.h"
+#include "message-tag-followup.h"
+
+#include "Evolution.h"
+#include "evolution-storage.h"
+
+#include "evolution-shell-client.h"
+
+#define d(x) x
+
+#define FB_WINDOW(fb) GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (fb), GTK_TYPE_WINDOW))
+
+
+/* default is default gtk response
+ if again is != NULL, a checkbox "dont show this again" will appear, and the result stored in *again
+*/
+static gboolean
+e_question (GtkWindow *parent, int def, gboolean *again, const char *fmt, ...)
+{
+ GtkWidget *mbox, *check = NULL;
+ va_list ap;
+ int button;
+ char *str;
+
+ va_start (ap, fmt);
+ str = g_strdup_vprintf (fmt, ap);
+ va_end (ap);
+ mbox = gtk_message_dialog_new (parent, GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
+ "%s", str);
+ g_free (str);
+ gtk_dialog_set_default_response ((GtkDialog *) mbox, def);
+ if (again) {
+ check = gtk_check_button_new_with_label (_("Don't show this message again."));
+ gtk_box_pack_start ((GtkBox *)((GtkDialog *) mbox)->vbox, check, TRUE, TRUE, 10);
+ gtk_widget_show (check);
+ }
+
+ button = gtk_dialog_run ((GtkDialog *) mbox);
+ if (again)
+ *again = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check));
+ gtk_widget_destroy (mbox);
+
+ return button == GTK_RESPONSE_YES;
+}
+
+
+struct _composer_callback_data {
+ unsigned int ref_count;
+
+ CamelFolder *drafts_folder;
+ char *drafts_uid;
+
+ CamelFolder *folder;
+ guint32 flags, set;
+ char *uid;
+};
+
+static struct _composer_callback_data *
+ccd_new (void)
+{
+ struct _composer_callback_data *ccd;
+
+ ccd = g_new (struct _composer_callback_data, 1);
+ ccd->ref_count = 1;
+ ccd->drafts_folder = NULL;
+ ccd->drafts_uid = NULL;
+ ccd->folder = NULL;
+ ccd->flags = 0;
+ ccd->set = 0;
+ ccd->uid = NULL;
+
+ return ccd;
+}
+
+static void
+free_ccd (struct _composer_callback_data *ccd)
+{
+ if (ccd->drafts_folder)
+ camel_object_unref (ccd->drafts_folder);
+ g_free (ccd->drafts_uid);
+
+ if (ccd->folder)
+ camel_object_unref (ccd->folder);
+ g_free (ccd->uid);
+ g_free (ccd);
+}
+
+static void
+ccd_ref (struct _composer_callback_data *ccd)
+{
+ ccd->ref_count++;
+}
+
+static void
+ccd_unref (struct _composer_callback_data *ccd)
+{
+ ccd->ref_count--;
+ if (ccd->ref_count == 0)
+ free_ccd (ccd);
+}
+
+
+static void
+composer_destroy_cb (gpointer user_data, GObject *deadbeef)
+{
+ ccd_unref (user_data);
+}
+
+
+static void
+druid_destroy_cb (gpointer user_data, GObject *deadbeef)
+{
+ gtk_main_quit ();
+}
+
+static gboolean
+configure_mail (FolderBrowser *fb)
+{
+ MailConfigDruid *druid;
+
+ if (e_question (FB_WINDOW (fb), GTK_RESPONSE_YES, NULL,
+ _("You have not configured the mail client.\n"
+ "You need to do this before you can send,\n"
+ "receive or compose mail.\n"
+ "Would you like to configure it now?"))) {
+ druid = mail_config_druid_new ();
+ g_object_weak_ref ((GObject *) druid, (GWeakNotify) druid_destroy_cb, NULL);
+ gtk_widget_show ((GtkWidget *) druid);
+ gtk_grab_add ((GtkWidget *) druid);
+ gtk_main ();
+ }
+
+ return mail_config_is_configured ();
+}
+
+static gboolean
+check_send_configuration (FolderBrowser *fb)
+{
+ EAccount *account;
+
+ if (!mail_config_is_configured ()) {
+ if (fb == NULL) {
+ e_notice (NULL, GTK_MESSAGE_WARNING,
+ _("You need to configure an account\nbefore you can compose mail."));
+ return FALSE;
+ }
+
+ if (!configure_mail (fb))
+ return FALSE;
+ }
+
+ /* Get the default account */
+ account = mail_config_get_default_account ();
+
+ /* Check for an identity */
+ if (!account) {
+ e_notice (FB_WINDOW (fb), GTK_MESSAGE_WARNING,
+ _("You need to configure an identity\nbefore you can compose mail."));
+ return FALSE;
+ }
+
+ /* Check for a transport */
+ if (!account->transport->url) {
+ e_notice (FB_WINDOW (fb), GTK_MESSAGE_WARNING,
+ _("You need to configure a mail transport\n"
+ "before you can compose mail."));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+ask_confirm_for_unwanted_html_mail (EMsgComposer *composer, EDestination **recipients)
+{
+ gboolean show_again, res;
+ GConfClient *gconf;
+ GString *str;
+ int i;
+
+ gconf = mail_config_get_gconf_client ();
+
+ if (!gconf_client_get_bool (gconf, "/apps/evolution/mail/prompts/unwanted_html", NULL))
+ return TRUE;
+
+ /* FIXME: this wording sucks */
+ str = g_string_new (_("You are sending an HTML-formatted message. Please make sure that\n"
+ "the following recipients are willing and able to receive HTML mail:\n"));
+ for (i = 0; recipients[i] != NULL; ++i) {
+ if (!e_destination_get_html_mail_pref (recipients[i])) {
+ const char *name;
+
+ name = e_destination_get_textrep (recipients[i], FALSE);
+
+ g_string_append_printf (str, " %s\n", name);
+ }
+ }
+
+ g_string_append (str, _("Send anyway?"));
+ res = e_question ((GtkWindow *) composer, GTK_RESPONSE_YES, &show_again, "%s", str->str);
+ g_string_free (str, TRUE);
+
+ gconf_client_set_bool (gconf, "/apps/evolution/mail/prompts/unwanted_html", show_again, NULL);
+
+ return res;
+}
+
+static gboolean
+ask_confirm_for_empty_subject (EMsgComposer *composer)
+{
+ gboolean show_again, res;
+ GConfClient *gconf;
+
+ gconf = mail_config_get_gconf_client ();
+
+ if (!gconf_client_get_bool (gconf, "/apps/evolution/mail/prompts/empty_subject", NULL))
+ return TRUE;
+
+ res = e_question ((GtkWindow *) composer, GTK_RESPONSE_YES, &show_again,
+ _("This message has no subject.\nReally send?"));
+
+ gconf_client_set_bool (gconf, "/apps/evolution/mail/prompts/empty_subject", show_again, NULL);
+
+ return res;
+}
+
+static gboolean
+ask_confirm_for_only_bcc (EMsgComposer *composer, gboolean hidden_list_case)
+{
+ gboolean show_again, res;
+ const char *first_text;
+ GConfClient *gconf;
+
+ gconf = mail_config_get_gconf_client ();
+
+ if (!gconf_client_get_bool (gconf, "/apps/evolution/mail/prompts/only_bcc", NULL))
+ return TRUE;
+
+ /* If the user is mailing a hidden contact list, it is possible for
+ them to create a message with only Bcc recipients without really
+ realizing it. To try to avoid being totally confusing, I've changed
+ this dialog to provide slightly different text in that case, to
+ better explain what the hell is going on. */
+
+ if (hidden_list_case) {
+ first_text = _("Since the contact list you are sending to "
+ "is configured to hide the list's addresses, "
+ "this message will contain only Bcc recipients.");
+ } else {
+ first_text = _("This message contains only Bcc recipients.");
+ }
+
+ res = e_question ((GtkWindow *) composer, GTK_RESPONSE_YES, &show_again,
+ "%s\n%s", first_text,
+ _("It is possible that the mail server may reveal the recipients "
+ "by adding an Apparently-To header.\nSend anyway?"));
+
+ gconf_client_set_bool (gconf, "/apps/evolution/mail/prompts/only_bcc", show_again, NULL);
+
+ return res;
+}
+
+
+struct _send_data {
+ struct _composer_callback_data *ccd;
+ EMsgComposer *composer;
+ gboolean send;
+};
+
+static void
+composer_send_queued_cb (CamelFolder *folder, CamelMimeMessage *msg, CamelMessageInfo *info,
+ int queued, const char *appended_uid, void *data)
+{
+ struct _composer_callback_data *ccd;
+ struct _send_data *send = data;
+
+ ccd = send->ccd;
+
+ if (queued) {
+ if (ccd && ccd->drafts_folder) {
+ /* delete the old draft message */
+ camel_folder_set_message_flags (ccd->drafts_folder, ccd->drafts_uid,
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
+ camel_object_unref (ccd->drafts_folder);
+ ccd->drafts_folder = NULL;
+ g_free (ccd->drafts_uid);
+ ccd->drafts_uid = NULL;
+ }
+
+ if (ccd && ccd->folder) {
+ /* set any replied flags etc */
+ camel_folder_set_message_flags (ccd->folder, ccd->uid, ccd->flags, ccd->set);
+ camel_object_unref (ccd->folder);
+ ccd->folder = NULL;
+ g_free (ccd->uid);
+ ccd->uid = NULL;
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (send->composer));
+
+ if (send->send && camel_session_is_online (session)) {
+ /* queue a message send */
+ mail_send ();
+ }
+ } else {
+ if (!ccd) {
+ ccd = ccd_new ();
+
+ /* disconnect the previous signal handlers */
+ g_signal_handlers_disconnect_matched(send->composer, G_SIGNAL_MATCH_FUNC, 0,
+ 0, NULL, composer_send_cb, NULL);
+ g_signal_handlers_disconnect_matched(send->composer, G_SIGNAL_MATCH_FUNC, 0,
+ 0, NULL, composer_save_draft_cb, NULL);
+
+ /* reconnect to the signals using a non-NULL ccd for the callback data */
+ g_signal_connect (send->composer, "send", G_CALLBACK (composer_send_cb), ccd);
+ g_signal_connect (send->composer, "save-draft", G_CALLBACK (composer_save_draft_cb), ccd);
+
+ g_object_weak_ref ((GObject *) send->composer, (GWeakNotify) composer_destroy_cb, ccd);
+ }
+
+ e_msg_composer_set_enable_autosave (send->composer, TRUE);
+ gtk_widget_show (GTK_WIDGET (send->composer));
+ }
+
+ camel_message_info_free (info);
+
+ if (send->ccd)
+ ccd_unref (send->ccd);
+
+ g_object_unref(send->composer);
+ g_free (send);
+}
+
+static CamelMimeMessage *
+composer_get_message (EMsgComposer *composer, gboolean post, gboolean save_html_object_data)
+{
+ CamelMimeMessage *message = NULL;
+ EDestination **recipients, **recipients_bcc;
+ gboolean send_html, confirm_html;
+ CamelInternetAddress *cia;
+ int hidden = 0, shown = 0;
+ int num = 0, num_bcc = 0;
+ const char *subject;
+ GConfClient *gconf;
+ EAccount *account;
+ int i;
+
+ gconf = mail_config_get_gconf_client ();
+
+ /* We should do all of the validity checks based on the composer, and not on
+ the created message, as extra interaction may occur when we get the message
+ (e.g. to get a passphrase to sign a message) */
+
+ /* get the message recipients */
+ recipients = e_msg_composer_get_recipients (composer);
+
+ cia = camel_internet_address_new ();
+
+ /* see which ones are visible/present, etc */
+ if (recipients) {
+ for (i = 0; recipients[i] != NULL; i++) {
+ const char *addr = e_destination_get_address (recipients[i]);
+
+ if (addr && addr[0]) {
+ camel_address_decode ((CamelAddress *) cia, addr);
+ if (camel_address_length ((CamelAddress *) cia) > 0) {
+ camel_address_remove ((CamelAddress *) cia, -1);
+ num++;
+ if (e_destination_is_evolution_list (recipients[i])
+ && !e_destination_list_show_addresses (recipients[i])) {
+ hidden++;
+ } else {
+ shown++;
+ }
+ }
+ }
+ }
+ }
+
+ recipients_bcc = e_msg_composer_get_bcc (composer);
+ if (recipients_bcc) {
+ for (i = 0; recipients_bcc[i] != NULL; i++) {
+ const char *addr = e_destination_get_address (recipients_bcc[i]);
+
+ if (addr && addr[0]) {
+ camel_address_decode ((CamelAddress *) cia, addr);
+ if (camel_address_length ((CamelAddress *) cia) > 0) {
+ camel_address_remove ((CamelAddress *) cia, -1);
+ num_bcc++;
+ }
+ }
+ }
+
+ e_destination_freev (recipients_bcc);
+ }
+
+ camel_object_unref (cia);
+
+ /* I'm sensing a lack of love, er, I mean recipients. */
+ if (num == 0 && !post) {
+ e_notice ((GtkWindow *) composer, GTK_MESSAGE_WARNING,
+ _("You must specify recipients in order to send this message."));
+ goto finished;
+ }
+
+ if (num > 0 && (num == num_bcc || shown == 0)) {
+ /* this means that the only recipients are Bcc's */
+ if (!ask_confirm_for_only_bcc (composer, shown == 0))
+ goto finished;
+ }
+
+ send_html = gconf_client_get_bool (gconf, "/apps/evolution/mail/composer/send_html", NULL);
+ confirm_html = gconf_client_get_bool (gconf, "/apps/evolution/mail/prompts/unwanted_html", NULL);
+
+ /* Only show this warning if our default is to send html. If it isn't, we've
+ manually switched into html mode in the composer and (presumably) had a good
+ reason for doing this. */
+ if (e_msg_composer_get_send_html (composer) && send_html && confirm_html) {
+ gboolean html_problem = FALSE;
+
+ if (recipients) {
+ for (i = 0; recipients[i] != NULL && !html_problem; i++) {
+ if (!e_destination_get_html_mail_pref (recipients[i]))
+ html_problem = TRUE;
+ }
+ }
+
+ if (html_problem) {
+ html_problem = !ask_confirm_for_unwanted_html_mail (composer, recipients);
+ if (html_problem)
+ goto finished;
+ }
+ }
+
+ /* Check for no subject */
+ subject = e_msg_composer_get_subject (composer);
+ if (subject == NULL || subject[0] == '\0') {
+ if (!ask_confirm_for_empty_subject (composer))
+ goto finished;
+ }
+
+ /* actually get the message now, this will sign/encrypt etc */
+ message = e_msg_composer_get_message (composer, save_html_object_data);
+ if (message == NULL)
+ goto finished;
+
+ /* Add info about the sending account */
+ account = e_msg_composer_get_preferred_account (composer);
+
+ if (account) {
+ camel_medium_set_header (CAMEL_MEDIUM (message), "X-Evolution-Account", account->name);
+ camel_medium_set_header (CAMEL_MEDIUM (message), "X-Evolution-Transport", account->transport->url);
+ camel_medium_set_header (CAMEL_MEDIUM (message), "X-Evolution-Fcc", account->sent_folder_uri);
+ if (account->id->organization && *account->id->organization)
+ camel_medium_set_header (CAMEL_MEDIUM (message), "Organization", account->id->organization);
+ }
+
+ /* Get the message recipients and 'touch' them, boosting their use scores */
+ if (recipients)
+ e_destination_touchv (recipients);
+
+ finished:
+
+ if (recipients)
+ e_destination_freev (recipients);
+
+ return message;
+}
+
+static void
+got_post_folder (char *uri, CamelFolder *folder, void *data)
+{
+ CamelFolder **fp = data;
+
+ *fp = folder;
+
+ if (folder)
+ camel_object_ref (folder);
+}
+
+void
+composer_send_cb (EMsgComposer *composer, gpointer user_data)
+{
+ extern CamelFolder *outbox_folder;
+ CamelMimeMessage *message;
+ CamelMessageInfo *info;
+ struct _send_data *send;
+ gboolean post = FALSE;
+ CamelFolder *folder;
+ XEvolution *xev;
+ char *url;
+
+ url = e_msg_composer_hdrs_get_post_to ((EMsgComposerHdrs *) composer->hdrs);
+ if (url && *url) {
+ post = TRUE;
+
+ mail_msg_wait (mail_get_folder (url, 0, got_post_folder, &folder, mail_thread_new));
+
+ if (!folder) {
+ g_free (url);
+ return;
+ }
+ } else {
+ folder = outbox_folder;
+ camel_object_ref (folder);
+ }
+
+ g_free (url);
+
+ message = composer_get_message (composer, post, FALSE);
+ if (!message)
+ return;
+
+ if (post) {
+ /* Remove the X-Evolution* headers if we are in Post-To mode */
+ xev = mail_tool_remove_xevolution_headers (message);
+ mail_tool_destroy_xevolution (xev);
+ }
+
+ info = camel_message_info_new ();
+ info->flags = CAMEL_MESSAGE_SEEN;
+
+ send = g_malloc (sizeof (*send));
+ send->ccd = user_data;
+ if (send->ccd)
+ ccd_ref (send->ccd);
+ send->send = !post;
+ send->composer = composer;
+ g_object_ref (composer);
+ gtk_widget_hide (GTK_WIDGET (composer));
+
+ e_msg_composer_set_enable_autosave (composer, FALSE);
+
+ mail_append_mail (folder, message, info, composer_send_queued_cb, send);
+ camel_object_unref (message);
+ camel_object_unref (folder);
+}
+
+struct _save_draft_info {
+ struct _composer_callback_data *ccd;
+ EMsgComposer *composer;
+ int quit;
+};
+
+static void
+save_draft_done (CamelFolder *folder, CamelMimeMessage *msg, CamelMessageInfo *info, int ok,
+ const char *appended_uid, void *user_data)
+{
+ struct _save_draft_info *sdi = user_data;
+ struct _composer_callback_data *ccd;
+ CORBA_Environment ev;
+
+ if (!ok)
+ goto done;
+ CORBA_exception_init (&ev);
+ GNOME_GtkHTML_Editor_Engine_runCommand (sdi->composer->editor_engine, "saved", &ev);
+ CORBA_exception_free (&ev);
+
+ if ((ccd = sdi->ccd) == NULL) {
+ ccd = ccd_new ();
+
+ /* disconnect the previous signal handlers */
+ g_signal_handlers_disconnect_by_func (sdi->composer, G_CALLBACK (composer_send_cb), NULL);
+ g_signal_handlers_disconnect_by_func (sdi->composer, G_CALLBACK (composer_save_draft_cb), NULL);
+
+ /* reconnect to the signals using a non-NULL ccd for the callback data */
+ g_signal_connect (sdi->composer, "send", G_CALLBACK (composer_send_cb), ccd);
+ g_signal_connect (sdi->composer, "save-draft", G_CALLBACK (composer_save_draft_cb), ccd);
+
+ g_object_weak_ref ((GObject *) sdi->composer, (GWeakNotify) composer_destroy_cb, ccd);
+ }
+
+ if (ccd->drafts_folder) {
+ /* delete the original draft message */
+ camel_folder_set_message_flags (ccd->drafts_folder, ccd->drafts_uid,
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
+ camel_object_unref (ccd->drafts_folder);
+ ccd->drafts_folder = NULL;
+ g_free (ccd->drafts_uid);
+ ccd->drafts_uid = NULL;
+ }
+
+ if (ccd->folder) {
+ /* set the replied flags etc */
+ camel_folder_set_message_flags (ccd->folder, ccd->uid, ccd->flags, ccd->set);
+ camel_object_unref (ccd->folder);
+ ccd->folder = NULL;
+ g_free (ccd->uid);
+ ccd->uid = NULL;
+ }
+
+ if (appended_uid) {
+ camel_object_ref (folder);
+ ccd->drafts_folder = folder;
+ ccd->drafts_uid = g_strdup (appended_uid);
+ }
+
+ if (sdi->quit)
+ gtk_widget_destroy (GTK_WIDGET (sdi->composer));
+
+ done:
+ g_object_unref (sdi->composer);
+ if (sdi->ccd)
+ ccd_unref (sdi->ccd);
+ g_free (info);
+ g_free (sdi);
+}
+
+static void
+save_draft_folder (char *uri, CamelFolder *folder, gpointer data)
+{
+ CamelFolder **save = data;
+
+ if (folder) {
+ *save = folder;
+ camel_object_ref (folder);
+ }
+}
+
+void
+composer_save_draft_cb (EMsgComposer *composer, int quit, gpointer user_data)
+{
+ extern char *default_drafts_folder_uri;
+ extern CamelFolder *drafts_folder;
+ struct _save_draft_info *sdi;
+ CamelFolder *folder = NULL;
+ CamelMimeMessage *msg;
+ CamelMessageInfo *info;
+ EAccount *account;
+
+ account = e_msg_composer_get_preferred_account (composer);
+ if (account && account->drafts_folder_uri &&
+ strcmp (account->drafts_folder_uri, default_drafts_folder_uri) != 0) {
+ int id;
+
+ id = mail_get_folder (account->drafts_folder_uri, 0, save_draft_folder, &folder, mail_thread_new);
+ mail_msg_wait (id);
+
+ if (!folder) {
+ if (!e_question ((GtkWindow *) composer, GTK_RESPONSE_YES, NULL,
+ _("Unable to open the drafts folder for this account.\n"
+ "Would you like to use the default drafts folder?")))
+ return;
+
+ folder = drafts_folder;
+ camel_object_ref (drafts_folder);
+ }
+ } else {
+ folder = drafts_folder;
+ camel_object_ref (folder);
+ }
+
+ msg = e_msg_composer_get_message_draft (composer);
+
+ info = g_new0 (CamelMessageInfo, 1);
+ info->flags = CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_SEEN;
+
+ sdi = g_malloc (sizeof (struct _save_draft_info));
+ sdi->composer = composer;
+ g_object_ref (composer);
+ sdi->ccd = user_data;
+ if (sdi->ccd)
+ ccd_ref (sdi->ccd);
+ sdi->quit = quit;
+
+ mail_append_mail (folder, msg, info, save_draft_done, sdi);
+ camel_object_unref (folder);
+ camel_object_unref (msg);
+}
+
+static GtkWidget *
+create_msg_composer (EAccount *account, gboolean post, const char *url)
+{
+ EMsgComposer *composer;
+ GConfClient *gconf;
+ gboolean send_html;
+
+ /* Make sure that we've actually been passed in an account. If one has
+ * not been passed in, grab the default account.
+ */
+ if (account == NULL)
+ account = mail_config_get_default_account ();
+
+ gconf = mail_config_get_gconf_client ();
+ send_html = gconf_client_get_bool (gconf, "/apps/evolution/mail/composer/send_html", NULL);
+
+ if (post)
+ composer = e_msg_composer_new_post ();
+ else if (url)
+ composer = e_msg_composer_new_from_url (url);
+ else
+ composer = e_msg_composer_new ();
+
+ if (composer) {
+ e_msg_composer_hdrs_set_from_account (E_MSG_COMPOSER_HDRS (composer->hdrs), account->name);
+ e_msg_composer_set_send_html (composer, send_html);
+ e_msg_composer_unset_changed (composer);
+ e_msg_composer_drop_editor_undo (composer);
+ return GTK_WIDGET (composer);
+ } else
+ return NULL;
+}
+
+void
+compose_msg (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ struct _composer_callback_data *ccd;
+ GtkWidget *composer;
+ EAccount *account;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb) || !check_send_configuration (fb))
+ return;
+
+ /* Figure out which account we want to initially compose from */
+ account = mail_config_get_account_by_source_url (fb->uri);
+
+ composer = create_msg_composer (account, FALSE, NULL);
+ if (!composer)
+ return;
+
+ ccd = ccd_new ();
+
+ g_signal_connect (composer, "send", G_CALLBACK (composer_send_cb), ccd);
+ g_signal_connect (composer, "save-draft", G_CALLBACK (composer_save_draft_cb), ccd);
+
+ g_object_weak_ref ((GObject *) composer, (GWeakNotify) composer_destroy_cb, ccd);
+
+ gtk_widget_show (composer);
+}
+
+/* Send according to a mailto (RFC 2368) URL. */
+void
+send_to_url (const char *url, const char *parent_uri)
+{
+ struct _composer_callback_data *ccd;
+ GtkWidget *composer;
+ EAccount *account = NULL;
+
+ /* FIXME: no way to get folder browser? Not without
+ * big pain in the ass, as far as I can tell */
+ if (!check_send_configuration (NULL))
+ return;
+
+ if (parent_uri)
+ account = mail_config_get_account_by_source_url (parent_uri);
+
+ composer = create_msg_composer (account, FALSE, url);
+
+ if (!composer)
+ return;
+
+ ccd = ccd_new ();
+
+ g_signal_connect (composer, "send", G_CALLBACK (composer_send_cb), ccd);
+ g_signal_connect (composer, "save-draft", G_CALLBACK (composer_save_draft_cb), ccd);
+
+ g_object_weak_ref ((GObject *) composer, (GWeakNotify) composer_destroy_cb, ccd);
+
+ gtk_widget_show (composer);
+}
+
+static GList *
+list_add_addresses (GList *list, const CamelInternetAddress *cia, GHashTable *account_hash,
+ GHashTable *rcpt_hash, EAccount **me)
+{
+ const char *name, *addr;
+ EAccount *account;
+ int i;
+
+ for (i = 0; camel_internet_address_get (cia, i, &name, &addr); i++) {
+ /* Here I'll check to see if the cc:'d address is the address
+ of the sender, and if so, don't add it to the cc: list; this
+ is to fix Bugzilla bug #455. */
+ account = g_hash_table_lookup (account_hash, addr);
+ if (account && me && !*me)
+ *me = account;
+
+ if (!account && !g_hash_table_lookup (rcpt_hash, addr)) {
+ EDestination *dest;
+
+ dest = e_destination_new ();
+ e_destination_set_name (dest, name);
+ e_destination_set_email (dest, addr);
+
+ list = g_list_append (list, dest);
+ g_hash_table_insert (rcpt_hash, (char *) addr, GINT_TO_POINTER (1));
+ }
+ }
+
+ return list;
+}
+
+static EAccount *
+guess_me (const CamelInternetAddress *to, const CamelInternetAddress *cc, GHashTable *account_hash)
+{
+ EAccount *account = NULL;
+ const char *addr;
+ int i;
+
+ /* "optimization" */
+ if (!to && !cc)
+ return NULL;
+
+ if (to) {
+ for (i = 0; camel_internet_address_get (to, i, NULL, &addr); i++) {
+ account = g_hash_table_lookup (account_hash, addr);
+ if (account)
+ goto found;
+ }
+ }
+
+ if (cc) {
+ for (i = 0; camel_internet_address_get (cc, i, NULL, &addr); i++) {
+ account = g_hash_table_lookup (account_hash, addr);
+ if (account)
+ goto found;
+ }
+ }
+
+ found:
+
+ return account;
+}
+
+static EAccount *
+guess_me_from_accounts (const CamelInternetAddress *to, const CamelInternetAddress *cc, EAccountList *accounts)
+{
+ EAccount *account, *def;
+ GHashTable *account_hash;
+ EIterator *iter;
+
+ account_hash = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
+
+ /* add the default account to the hash first */
+ if ((def = mail_config_get_default_account ())) {
+ if (def->id->address)
+ g_hash_table_insert (account_hash, (char *) def->id->address, (void *) def);
+ }
+
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ account = (EAccount *) e_iterator_get (iter);
+
+ if (account->id->address) {
+ EAccount *acnt;
+
+ /* Accounts with identical email addresses that are enabled
+ * take precedence over the accounts that aren't. If all
+ * accounts with matching email addresses are disabled, then
+ * the first one in the list takes precedence. The default
+ * account always takes precedence no matter what.
+ */
+ acnt = g_hash_table_lookup (account_hash, account->id->address);
+ if (acnt && acnt != def && !acnt->enabled && account->enabled) {
+ g_hash_table_remove (account_hash, acnt->id->address);
+ acnt = NULL;
+ }
+
+ if (!acnt)
+ g_hash_table_insert (account_hash, (char *) account->id->address, (void *) account);
+ }
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ account = guess_me (to, cc, account_hash);
+
+ g_hash_table_destroy (account_hash);
+
+ return account;
+}
+
+inline static void
+mail_ignore (EMsgComposer *composer, const char *name, const char *address)
+{
+ e_msg_composer_ignore (composer, name && *name ? name : address);
+}
+
+static void
+mail_ignore_address (EMsgComposer *composer, const CamelInternetAddress *addr)
+{
+ const char *name, *address;
+ int i, max;
+
+ max = camel_address_length (CAMEL_ADDRESS (addr));
+ for (i = 0; i < max; i++) {
+ camel_internet_address_get (addr, i, &name, &address);
+ mail_ignore (composer, name, address);
+ }
+}
+
+#define MAX_SUBJECT_LEN 1024
+
+static EMsgComposer *
+mail_generate_reply (CamelFolder *folder, CamelMimeMessage *message, const char *uid, int mode)
+{
+ const CamelInternetAddress *reply_to, *sender, *to_addrs, *cc_addrs;
+ const char *name = NULL, *address = NULL, *source = NULL;
+ const char *message_id, *references, *mlist = NULL;
+ char *text = NULL, *subject, format[256];
+ EAccount *def, *account, *me = NULL;
+ EAccountList *accounts = NULL;
+ GHashTable *account_hash = NULL;
+ CamelMessageInfo *info = NULL;
+ GList *to = NULL, *cc = NULL;
+ EDestination **tov, **ccv;
+ EMsgComposer *composer;
+ CamelMimePart *part;
+ GConfClient *gconf;
+ EIterator *iter;
+ time_t date;
+ int date_ofs;
+ char *url;
+
+ gconf = mail_config_get_gconf_client ();
+
+ if (mode == REPLY_POST) {
+ composer = e_msg_composer_new_post ();
+ if (composer != NULL) {
+ url = mail_tools_folder_to_url (folder);
+ e_msg_composer_hdrs_set_post_to ((EMsgComposerHdrs *) composer->hdrs, url);
+ g_free (url);
+ }
+ } else
+ composer = e_msg_composer_new ();
+
+ if (!composer)
+ return NULL;
+
+ e_msg_composer_add_message_attachments (composer, message, TRUE);
+
+ /* Set the recipients */
+ accounts = mail_config_get_accounts ();
+ account_hash = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
+
+ /* add the default account to the hash first */
+ if ((def = mail_config_get_default_account ())) {
+ if (def->id->address)
+ g_hash_table_insert (account_hash, (char *) def->id->address, (void *) def);
+ }
+
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ account = (EAccount *) e_iterator_get (iter);
+
+ if (account->id->address) {
+ EAccount *acnt;
+
+ /* Accounts with identical email addresses that are enabled
+ * take precedence over the accounts that aren't. If all
+ * accounts with matching email addresses are disabled, then
+ * the first one in the list takes precedence. The default
+ * account always takes precedence no matter what.
+ */
+ acnt = g_hash_table_lookup (account_hash, account->id->address);
+ if (acnt && acnt != def && !acnt->enabled && account->enabled) {
+ g_hash_table_remove (account_hash, acnt->id->address);
+ acnt = NULL;
+ }
+
+ if (!acnt)
+ g_hash_table_insert (account_hash, (char *) account->id->address, (void *) account);
+ }
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ to_addrs = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO);
+ cc_addrs = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC);
+ mail_ignore_address (composer, to_addrs);
+ mail_ignore_address (composer, cc_addrs);
+
+ if (mode == REPLY_LIST) {
+ /* make sure we can reply to an mlist */
+ info = camel_folder_get_message_info (folder, uid);
+ if (!(mlist = camel_message_info_mlist (info)) || *mlist == '\0') {
+ camel_folder_free_message_info (folder, info);
+ mode = REPLY_ALL;
+ info = NULL;
+ }
+ }
+
+ determine_recipients:
+ if (mode == REPLY_LIST) {
+ EDestination *dest;
+ int i, max;
+
+ /* look through the recipients to find the *real* mailing list address */
+ d(printf ("we are looking for the mailing list called: %s\n", mlist));
+
+ max = camel_address_length (CAMEL_ADDRESS (to_addrs));
+ for (i = 0; i < max; i++) {
+ camel_internet_address_get (to_addrs, i, &name, &address);
+ if (!strcasecmp (address, mlist))
+ break;
+ }
+
+ if (i == max) {
+ max = camel_address_length (CAMEL_ADDRESS (cc_addrs));
+ for (i = 0; i < max; i++) {
+ camel_internet_address_get (cc_addrs, i, &name, &address);
+ if (!strcasecmp (address, mlist))
+ break;
+ }
+ }
+
+ if (address && i != max) {
+ dest = e_destination_new ();
+ e_destination_set_name (dest, name);
+ e_destination_set_email (dest, address);
+
+ to = g_list_append (to, dest);
+ } else {
+ /* mailing list address wasn't found */
+ if (strchr (mlist, '@')) {
+ /* mlist string has an @, maybe it's valid? */
+ dest = e_destination_new ();
+ e_destination_set_email (dest, mlist);
+
+ to = g_list_append (to, dest);
+ } else {
+ /* give up and just reply to all recipients? */
+ mode = REPLY_ALL;
+ camel_folder_free_message_info (folder, info);
+ goto determine_recipients;
+ }
+ }
+
+ me = guess_me (to_addrs, cc_addrs, account_hash);
+ camel_folder_free_message_info (folder, info);
+ } else {
+ GHashTable *rcpt_hash;
+ EDestination *dest;
+
+ rcpt_hash = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
+
+ reply_to = camel_mime_message_get_reply_to (message);
+ if (!reply_to)
+ reply_to = camel_mime_message_get_from (message);
+
+ if (reply_to) {
+ int i;
+
+ for (i = 0; camel_internet_address_get (reply_to, i, &name, &address); i++) {
+ /* ignore references to the Reply-To address in the To and Cc lists */
+ if (address && !(mode == REPLY_ALL && g_hash_table_lookup (account_hash, address))) {
+ /* In the case that we are doing a Reply-To-All, we do not want
+ to include the user's email address because replying to oneself
+ is kinda silly. */
+ dest = e_destination_new ();
+ e_destination_set_name (dest, name);
+ e_destination_set_email (dest, address);
+ to = g_list_append (to, dest);
+ g_hash_table_insert (rcpt_hash, (char *) address, GINT_TO_POINTER (1));
+ mail_ignore (composer, name, address);
+ }
+ }
+ }
+
+ if (mode == REPLY_ALL) {
+ cc = list_add_addresses (cc, to_addrs, account_hash, rcpt_hash, me ? NULL : &me);
+ cc = list_add_addresses (cc, cc_addrs, account_hash, rcpt_hash, me ? NULL : &me);
+
+ /* promote the first Cc: address to To: if To: is empty */
+ if (to == NULL && cc != NULL) {
+ to = cc;
+ cc = g_list_remove_link (cc, to);
+ }
+ } else {
+ me = guess_me (to_addrs, cc_addrs, account_hash);
+ }
+
+ g_hash_table_destroy (rcpt_hash);
+ }
+
+ g_hash_table_destroy (account_hash);
+
+ if (!me) {
+ /* default 'me' to the source account... */
+ if ((source = camel_mime_message_get_source (message)))
+ me = mail_config_get_account_by_source_url (source);
+ }
+
+ /* set body text here as we want all ignored words to take effect */
+ switch (gconf_client_get_int (gconf, "/apps/evolution/mail/format/reply_style", NULL)) {
+ case MAIL_CONFIG_REPLY_DO_NOT_QUOTE:
+ /* do nothing */
+ break;
+ case MAIL_CONFIG_REPLY_ATTACH:
+ /* attach the original message as an attachment */
+ part = mail_tool_make_message_attachment (message);
+ e_msg_composer_attach (composer, part);
+ camel_object_unref (part);
+ break;
+ case MAIL_CONFIG_REPLY_QUOTED:
+ default:
+ /* do what any sane user would want when replying... */
+ sender = camel_mime_message_get_from (message);
+ if (sender != NULL && camel_address_length (CAMEL_ADDRESS (sender)) > 0) {
+ camel_internet_address_get (sender, 0, &name, &address);
+ } else {
+ name = _("an unknown sender");
+ }
+
+ date = camel_mime_message_get_date (message, &date_ofs);
+ /* Convert to UTC */
+ date += (date_ofs / 100) * 60 * 60;
+ date += (date_ofs % 100) * 60;
+
+ /* translators: attribution string used when quoting messages */
+ e_utf8_strftime (format, sizeof (format), _("On %a, %Y-%m-%d at %H:%M %%+05d, %%s wrote:"), gmtime (&date));
+ text = mail_tool_quote_message (message, format, date_ofs, name && *name ? name : address);
+ mail_ignore (composer, name, address);
+ if (text) {
+ e_msg_composer_set_body_text (composer, text);
+ g_free (text);
+ }
+ break;
+ }
+
+ /* Set the subject of the new message. */
+ subject = (char *) camel_mime_message_get_subject (message);
+ if (!subject)
+ subject = g_strdup ("");
+ else {
+ if (!strncasecmp (subject, "Re: ", 4))
+ subject = g_strndup (subject, MAX_SUBJECT_LEN);
+ else {
+ if (strlen (subject) < MAX_SUBJECT_LEN) {
+ subject = g_strdup_printf ("Re: %s", subject);
+ } else {
+ /* We can't use %.*s because it depends on the locale being C/POSIX
+ or UTF-8 to work correctly in glibc */
+ char *sub;
+
+ /*subject = g_strdup_printf ("Re: %.*s...", MAX_SUBJECT_LEN, subject);*/
+ sub = g_malloc (MAX_SUBJECT_LEN + 8);
+ memcpy (sub, "Re: ", 4);
+ memcpy (sub + 4, subject, MAX_SUBJECT_LEN);
+ memcpy (sub + 4 + MAX_SUBJECT_LEN, "...", 4);
+ subject = sub;
+ }
+ }
+ }
+
+ tov = e_destination_list_to_vector (to);
+ ccv = e_destination_list_to_vector (cc);
+
+ g_list_free (to);
+ g_list_free (cc);
+
+ e_msg_composer_set_headers (composer, me ? me->name : NULL, tov, ccv, NULL, subject);
+
+ e_destination_freev (tov);
+ e_destination_freev (ccv);
+
+ g_free (subject);
+
+ /* Add In-Reply-To and References. */
+ message_id = camel_medium_get_header (CAMEL_MEDIUM (message), "Message-Id");
+ references = camel_medium_get_header (CAMEL_MEDIUM (message), "References");
+ if (message_id) {
+ char *reply_refs;
+
+ e_msg_composer_add_header (composer, "In-Reply-To", message_id);
+
+ if (references)
+ reply_refs = g_strdup_printf ("%s %s", references, message_id);
+ else
+ reply_refs = g_strdup (message_id);
+
+ e_msg_composer_add_header (composer, "References", reply_refs);
+ g_free (reply_refs);
+ } else if (references) {
+ e_msg_composer_add_header (composer, "References", references);
+ }
+
+ e_msg_composer_drop_editor_undo (composer);
+
+ return composer;
+}
+
+static void
+requeue_mail_reply (CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data)
+{
+ int mode = GPOINTER_TO_INT (data);
+
+ if (msg != NULL)
+ mail_reply (folder, msg, uid, mode);
+}
+
+void
+mail_reply (CamelFolder *folder, CamelMimeMessage *msg, const char *uid, int mode)
+{
+ struct _composer_callback_data *ccd;
+ EMsgComposer *composer;
+
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (uid != NULL);
+
+ if (!msg) {
+ mail_get_message (folder, uid, requeue_mail_reply,
+ GINT_TO_POINTER (mode), mail_thread_new);
+ return;
+ }
+
+ composer = mail_generate_reply (folder, msg, uid, mode);
+ if (!composer)
+ return;
+
+ ccd = ccd_new ();
+
+ camel_object_ref (folder);
+ ccd->folder = folder;
+ ccd->uid = g_strdup (uid);
+ ccd->flags = CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_SEEN;
+ if (mode == REPLY_LIST || mode == REPLY_ALL)
+ ccd->flags |= CAMEL_MESSAGE_ANSWERED_ALL;
+ ccd->set = ccd->flags;
+
+ g_signal_connect (composer, "send", G_CALLBACK (composer_send_cb), ccd);
+ g_signal_connect (composer, "save-draft", G_CALLBACK (composer_save_draft_cb), ccd);
+
+ g_object_weak_ref ((GObject *) composer, (GWeakNotify) composer_destroy_cb, ccd);
+
+ gtk_widget_show (GTK_WIDGET (composer));
+ e_msg_composer_unset_changed (composer);
+}
+
+void
+reply_to_sender (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb) || !check_send_configuration (fb))
+ return;
+
+ mail_reply (fb->folder, NULL, fb->message_list->cursor_uid, REPLY_SENDER);
+}
+
+void
+reply_to_list (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb) || !check_send_configuration (fb))
+ return;
+
+ mail_reply (fb->folder, NULL, fb->message_list->cursor_uid, REPLY_LIST);
+}
+
+void
+reply_to_all (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb) || !check_send_configuration (fb))
+ return;
+
+ mail_reply(fb->folder, NULL, fb->message_list->cursor_uid, REPLY_ALL);
+}
+
+void
+enumerate_msg (MessageList *ml, const char *uid, gpointer data)
+{
+ g_return_if_fail (ml != NULL);
+
+ g_ptr_array_add ((GPtrArray *) data, g_strdup (uid));
+}
+
+
+static EMsgComposer *
+forward_get_composer (CamelMimeMessage *message, const char *subject)
+{
+ struct _composer_callback_data *ccd;
+ EAccount *account = NULL;
+ EMsgComposer *composer;
+
+ if (message) {
+ const CamelInternetAddress *to_addrs, *cc_addrs;
+ EAccountList *accounts;
+
+ accounts = mail_config_get_accounts ();
+ to_addrs = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO);
+ cc_addrs = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC);
+
+ account = guess_me_from_accounts (to_addrs, cc_addrs, accounts);
+
+ if (!account) {
+ const char *source;
+
+ source = camel_mime_message_get_source (message);
+ account = mail_config_get_account_by_source_url (source);
+ }
+ }
+
+ if (!account)
+ account = mail_config_get_default_account ();
+
+ composer = e_msg_composer_new ();
+ if (composer) {
+ ccd = ccd_new ();
+
+ g_signal_connect (composer, "send", G_CALLBACK (composer_send_cb), ccd);
+ g_signal_connect (composer, "save-draft", G_CALLBACK (composer_save_draft_cb), ccd);
+
+ g_object_weak_ref ((GObject *) composer, (GWeakNotify) composer_destroy_cb, ccd);
+
+ e_msg_composer_set_headers (composer, account->name, NULL, NULL, NULL, subject);
+ } else {
+ g_warning ("Could not create composer");
+ }
+
+ return composer;
+}
+
+static void
+do_forward_non_attached (CamelFolder *folder, GPtrArray *uids, GPtrArray *messages, void *data)
+{
+ MailConfigForwardStyle style = GPOINTER_TO_INT (data);
+ CamelMimeMessage *message;
+ char *subject, *text;
+ int i;
+
+ if (messages->len == 0)
+ return;
+
+ for (i = 0; i < messages->len; i++) {
+ message = messages->pdata[i];
+ subject = mail_tool_generate_forward_subject (message);
+ text = mail_tool_forward_message (message, style == MAIL_CONFIG_FORWARD_QUOTED);
+
+ if (text) {
+ EMsgComposer *composer = forward_get_composer (message, subject);
+ if (composer) {
+ CamelDataWrapper *wrapper;
+
+ e_msg_composer_set_body_text (composer, text);
+
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (message));
+ if (CAMEL_IS_MULTIPART (wrapper))
+ e_msg_composer_add_message_attachments (composer, message, FALSE);
+
+ gtk_widget_show (GTK_WIDGET (composer));
+ e_msg_composer_unset_changed (composer);
+ e_msg_composer_drop_editor_undo (composer);
+ }
+ g_free (text);
+ }
+
+ g_free (subject);
+ }
+}
+
+static void
+forward_message (FolderBrowser *fb, MailConfigForwardStyle style)
+{
+ GPtrArray *uids;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ if (!check_send_configuration (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ mail_get_messages (fb->folder, uids, do_forward_non_attached, GINT_TO_POINTER (style));
+}
+
+void
+forward_inline (GtkWidget *widget, gpointer user_data)
+{
+ forward_message (user_data, MAIL_CONFIG_FORWARD_INLINE);
+}
+
+void
+forward_quoted (GtkWidget *widget, gpointer user_data)
+{
+ forward_message (user_data, MAIL_CONFIG_FORWARD_QUOTED);
+}
+
+static void
+do_forward_attach (CamelFolder *folder, GPtrArray *messages, CamelMimePart *part, char *subject, void *data)
+{
+ CamelMimeMessage *message = data;
+
+ if (part) {
+ EMsgComposer *composer = forward_get_composer (message, subject);
+ if (composer) {
+ e_msg_composer_attach (composer, part);
+ gtk_widget_show (GTK_WIDGET (composer));
+ e_msg_composer_unset_changed (composer);
+ e_msg_composer_drop_editor_undo (composer);
+ }
+ }
+}
+
+void
+forward_attached (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = (FolderBrowser *) user_data;
+ GPtrArray *uids;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb) || !check_send_configuration (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+ mail_build_attachment (fb->folder, uids, do_forward_attach,
+ uids->len == 1 ? fb->mail_display->current_message : NULL);
+}
+
+void
+forward (GtkWidget *widget, gpointer user_data)
+{
+ MailConfigForwardStyle style;
+ GConfClient *gconf;
+
+ gconf = mail_config_get_gconf_client ();
+ style = gconf_client_get_int (gconf, "/apps/evolution/mail/format/forward_style", NULL);
+
+ if (style == MAIL_CONFIG_FORWARD_ATTACHED)
+ forward_attached (widget, user_data);
+ else
+ forward_message (user_data, style);
+}
+
+
+void
+post_to_url (const char *url)
+{
+ struct _composer_callback_data *ccd;
+ GtkWidget *composer;
+ EAccount *account = NULL;
+
+ /* FIXME: no way to get folder browser? Not without
+ * big pain in the ass, as far as I can tell */
+ if (!check_send_configuration (NULL))
+ return;
+
+ if (url)
+ account = mail_config_get_account_by_source_url (url);
+
+ composer = create_msg_composer (account, TRUE, NULL);
+ if (!composer)
+ return;
+
+ e_msg_composer_hdrs_set_post_to ((EMsgComposerHdrs *) ((EMsgComposer *) composer)->hdrs, url);
+
+ ccd = ccd_new ();
+
+ g_signal_connect (composer, "send", G_CALLBACK (composer_send_cb), ccd);
+ g_signal_connect (composer, "save-draft", G_CALLBACK (composer_save_draft_cb), ccd);
+
+ g_object_weak_ref ((GObject *) composer, (GWeakNotify) composer_destroy_cb, ccd);
+
+ gtk_widget_show (composer);
+}
+
+void
+post_message (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ char *url;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb) || !check_send_configuration (fb))
+ return;
+
+ url = mail_tools_folder_to_url (fb->folder);
+ post_to_url (url);
+ g_free (url);
+}
+
+void
+post_reply (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb) || !check_send_configuration (fb))
+ return;
+
+ mail_reply (fb->folder, NULL, fb->message_list->cursor_uid, REPLY_POST);
+}
+
+
+static EMsgComposer *
+redirect_get_composer (CamelMimeMessage *message)
+{
+ const CamelInternetAddress *to_addrs, *cc_addrs;
+ struct _composer_callback_data *ccd;
+ EAccountList *accounts = NULL;
+ EAccount *account = NULL;
+ EMsgComposer *composer;
+
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+
+ accounts = mail_config_get_accounts ();
+ to_addrs = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO);
+ cc_addrs = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC);
+
+ account = guess_me_from_accounts (to_addrs, cc_addrs, accounts);
+
+ if (!account) {
+ const char *source;
+
+ source = camel_mime_message_get_source (message);
+ account = mail_config_get_account_by_source_url (source);
+ }
+
+ if (!account)
+ account = mail_config_get_default_account ();
+
+ /* QMail will refuse to send a message if it finds one of
+ it's Delivered-To headers in the message, so remove all
+ Delivered-To headers. Fixes bug #23635. */
+ while (camel_medium_get_header (CAMEL_MEDIUM (message), "Delivered-To"))
+ camel_medium_remove_header (CAMEL_MEDIUM (message), "Delivered-To");
+
+ composer = e_msg_composer_new_redirect (message, account->name);
+ if (composer) {
+ ccd = ccd_new ();
+
+ g_signal_connect (composer, "send", G_CALLBACK (composer_send_cb), ccd);
+ g_signal_connect (composer, "save-draft", G_CALLBACK (composer_save_draft_cb), ccd);
+
+ g_object_weak_ref ((GObject *) composer, (GWeakNotify) composer_destroy_cb, ccd);
+ } else {
+ g_warning ("Could not create composer");
+ }
+
+ return composer;
+}
+
+static void
+do_redirect (CamelFolder *folder, const char *uid, CamelMimeMessage *message, void *data)
+{
+ EMsgComposer *composer;
+
+ if (!message)
+ return;
+
+ composer = redirect_get_composer (message);
+ if (composer) {
+ CamelDataWrapper *wrapper;
+
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (message));
+ if (CAMEL_IS_MULTIPART (wrapper))
+ e_msg_composer_add_message_attachments (composer, message, FALSE);
+
+ gtk_widget_show (GTK_WIDGET (composer));
+ e_msg_composer_unset_changed (composer);
+ e_msg_composer_drop_editor_undo (composer);
+ }
+}
+
+void
+redirect (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = (FolderBrowser *) user_data;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ if (!check_send_configuration (fb))
+ return;
+
+ mail_get_message (fb->folder, fb->message_list->cursor_uid,
+ do_redirect, NULL, mail_thread_new);
+}
+
+static void
+transfer_msg_done (gboolean ok, void *data)
+{
+ FolderBrowser *fb = data;
+ gboolean hide_deleted;
+ GConfClient *gconf;
+ int row;
+
+ if (ok && !FOLDER_BROWSER_IS_DESTROYED (fb)) {
+ gconf = mail_config_get_gconf_client ();
+ hide_deleted = !gconf_client_get_bool (gconf, "/apps/evolution/mail/display/show_deleted", NULL);
+
+ row = e_tree_row_of_node (fb->message_list->tree,
+ e_tree_get_cursor (fb->message_list->tree));
+
+ /* If this is the last message and deleted messages
+ are hidden, select the previous */
+ if ((row + 1 == e_tree_row_count (fb->message_list->tree)) && hide_deleted)
+ message_list_select (fb->message_list, MESSAGE_LIST_SELECT_PREVIOUS,
+ 0, CAMEL_MESSAGE_DELETED, FALSE);
+ else
+ message_list_select (fb->message_list, MESSAGE_LIST_SELECT_NEXT,
+ 0, 0, FALSE);
+ }
+
+ g_object_unref (fb);
+}
+
+static void
+transfer_msg (FolderBrowser *fb, gboolean delete_from_source)
+{
+ static const char *allowed_types[] = { "mail/*", "vtrash", NULL };
+ extern EvolutionShellClient *global_shell_client;
+ GNOME_Evolution_Folder *folder;
+ static char *last_uri = NULL;
+ GPtrArray *uids;
+ char *desc;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ if (last_uri == NULL)
+ last_uri = g_strdup (fb->uri);
+
+ if (delete_from_source)
+ desc = _("Move message(s) to");
+ else
+ desc = _("Copy message(s) to");
+
+ evolution_shell_client_user_select_folder (global_shell_client,
+ GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (fb))),
+ desc, last_uri, allowed_types,
+ &folder);
+ if (!folder)
+ return;
+
+ if (strcmp (last_uri, folder->evolutionUri) != 0) {
+ g_free (last_uri);
+ last_uri = g_strdup (folder->evolutionUri);
+ }
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ if (delete_from_source) {
+ g_object_ref (fb);
+ mail_transfer_messages (fb->folder, uids, delete_from_source,
+ folder->physicalUri, 0,
+ transfer_msg_done, fb);
+ } else {
+ mail_transfer_messages (fb->folder, uids, delete_from_source,
+ folder->physicalUri, 0, NULL, NULL);
+ }
+
+ CORBA_free (folder);
+}
+
+void
+move_msg_cb (GtkWidget *widget, gpointer user_data)
+{
+ transfer_msg (user_data, TRUE);
+}
+
+void
+move_msg (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ transfer_msg (user_data, TRUE);
+}
+
+void
+copy_msg_cb (GtkWidget *widget, gpointer user_data)
+{
+ transfer_msg (user_data, FALSE);
+}
+
+void
+copy_msg (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ transfer_msg (user_data, FALSE);
+}
+
+/* Copied from e-shell-view.c */
+static GtkWidget *
+find_socket (GtkContainer *container)
+{
+ GList *children, *tmp;
+
+ children = gtk_container_get_children (container);
+ while (children) {
+ if (BONOBO_IS_SOCKET (children->data))
+ return children->data;
+ else if (GTK_IS_CONTAINER (children->data)) {
+ GtkWidget *socket = find_socket (children->data);
+ if (socket)
+ return socket;
+ }
+ tmp = children->next;
+ g_list_free_1 (children);
+ children = tmp;
+ }
+
+ return NULL;
+}
+
+static void
+popup_listener_cb (BonoboListener *listener,
+ const char *event_name,
+ const CORBA_any *any,
+ CORBA_Environment *ev,
+ gpointer user_data)
+{
+ char *type = bonobo_event_subtype (event_name);
+
+ if (!strcmp (type, "Destroy")) {
+ gtk_widget_destroy (GTK_WIDGET (user_data));
+ }
+
+ g_free (type);
+}
+
+void
+addrbook_sender (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ const char *addr_str;
+ CamelMessageInfo *info;
+ GtkWidget *win;
+ GtkWidget *control;
+ GtkWidget *socket;
+ GPtrArray *uids;
+ int i;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+ if (uids->len != 1)
+ goto done;
+
+ info = camel_folder_get_message_info (fb->folder, uids->pdata[0]);
+ if (info == NULL || (addr_str = camel_message_info_from (info)) == NULL)
+ goto done;
+
+ win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (win), _("Sender"));
+
+ control = bonobo_widget_new_control ("OAFIID:GNOME_Evolution_Addressbook_AddressPopup",
+ CORBA_OBJECT_NIL);
+ bonobo_widget_set_property (BONOBO_WIDGET (control),
+ "email", TC_CORBA_string, addr_str,
+ NULL);
+
+ bonobo_event_source_client_add_listener (bonobo_widget_get_objref (BONOBO_WIDGET (control)),
+ popup_listener_cb, NULL, NULL, win);
+
+ socket = find_socket (GTK_CONTAINER (control));
+
+ g_object_weak_ref ((GObject *) socket, (GWeakNotify) gtk_widget_destroy, win);
+
+ gtk_container_add (GTK_CONTAINER (win), control);
+ gtk_widget_show_all (win);
+
+done:
+ for (i = 0; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+ g_ptr_array_free (uids, TRUE);
+}
+
+void
+add_sender_to_addrbook (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ addrbook_sender (NULL, user_data);
+}
+
+void
+apply_filters (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ GPtrArray *uids;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ mail_filter_on_demand (fb->folder, uids);
+}
+
+void
+select_all (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ ESelectionModel *etsm;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ if (GTK_WIDGET_HAS_FOCUS (fb->mail_display->html)) {
+ gtk_html_select_all (fb->mail_display->html);
+ } else {
+ etsm = e_tree_get_selection_model (fb->message_list->tree);
+
+ e_selection_model_select_all (etsm);
+ }
+}
+
+/* Thread selection */
+
+typedef struct thread_select_info {
+ MessageList *ml;
+ GPtrArray *paths;
+} thread_select_info_t;
+
+static gboolean
+select_node (ETreeModel *tm, ETreePath path, gpointer user_data)
+{
+ thread_select_info_t *tsi = (thread_select_info_t *) user_data;
+
+ g_ptr_array_add (tsi->paths, path);
+ return FALSE; /*not done yet*/
+}
+
+static void
+thread_select_foreach (ETreePath path, gpointer user_data)
+{
+ thread_select_info_t *tsi = (thread_select_info_t *) user_data;
+ ETreeModel *tm = tsi->ml->model;
+ ETreePath node;
+
+ /* @path part of the initial selection. If it has children,
+ * we select them as well. If it doesn't, we select its siblings and
+ * their children (ie, the current node must be inside the thread
+ * that the user wants to mark.
+ */
+
+ if (e_tree_model_node_get_first_child (tm, path))
+ node = path;
+ else {
+ node = e_tree_model_node_get_parent (tm, path);
+
+ /* Let's make an exception: if no parent, then we're about
+ * to mark the whole tree. No. */
+ if (e_tree_model_node_is_root (tm, node))
+ node = path;
+ }
+
+ e_tree_model_node_traverse (tm, node, select_node, tsi);
+}
+
+void
+select_thread (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ ETreeSelectionModel *selection_model;
+ thread_select_info_t tsi;
+ int i;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ /* For every selected item, select the thread containing it.
+ * We can't alter the selection while iterating through it,
+ * so build up a list of paths.
+ */
+
+ tsi.ml = fb->message_list;
+ tsi.paths = g_ptr_array_new ();
+
+ e_tree_selected_path_foreach (fb->message_list->tree, thread_select_foreach, &tsi);
+
+ selection_model = E_TREE_SELECTION_MODEL (e_tree_get_selection_model (fb->message_list->tree));
+
+ for (i = 0; i < tsi.paths->len; i++)
+ e_tree_selection_model_add_to_selection (selection_model,
+ tsi.paths->pdata[i]);
+ g_ptr_array_free (tsi.paths, TRUE);
+}
+
+void
+invert_selection (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ ESelectionModel *etsm;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ etsm = e_tree_get_selection_model (fb->message_list->tree);
+
+ e_selection_model_invert_selection (etsm);
+}
+
+/* flag all selected messages. Return number flagged */
+static int
+flag_messages (FolderBrowser *fb, guint32 mask, guint32 set)
+{
+ GPtrArray *uids;
+ int i;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return 0;
+
+ /* could just use specific callback but i'm lazy */
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+ camel_folder_freeze (fb->folder);
+ for (i = 0; i < uids->len; i++) {
+ camel_folder_set_message_flags (fb->folder, uids->pdata[i], mask, set);
+ g_free (uids->pdata[i]);
+ }
+
+ camel_folder_thaw (fb->folder);
+
+ g_ptr_array_free (uids, TRUE);
+
+ return i;
+}
+
+static int
+toggle_flags (FolderBrowser *fb, guint32 mask)
+{
+ GPtrArray *uids;
+ int i;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return 0;
+
+ /* could just use specific callback but i'm lazy */
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+ camel_folder_freeze (fb->folder);
+ for (i = 0; i < uids->len; i++) {
+ guint32 flags;
+
+ flags = ~(camel_folder_get_message_flags (fb->folder, uids->pdata[i]));
+
+ /* if we're flagging a message important, always undelete it too */
+ if (mask & flags & CAMEL_MESSAGE_FLAGGED) {
+ flags &= ~CAMEL_MESSAGE_DELETED;
+ mask |= CAMEL_MESSAGE_DELETED;
+ }
+
+ /* if we're flagging a message deleted, mark it seen. If
+ * we're undeleting it, we also want it to be seen, so always do this.
+ */
+ if (mask & CAMEL_MESSAGE_DELETED) {
+ flags |= CAMEL_MESSAGE_SEEN;
+ mask |= CAMEL_MESSAGE_SEEN;
+ }
+
+ camel_folder_set_message_flags (fb->folder, uids->pdata[i], mask, flags);
+
+ g_free (uids->pdata[i]);
+ }
+ camel_folder_thaw (fb->folder);
+
+ g_ptr_array_free (uids, TRUE);
+
+ return i;
+}
+
+void
+mark_as_seen (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ flag_messages (FOLDER_BROWSER (user_data), CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
+}
+
+void
+mark_as_unseen (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ /* Remove the automatic mark-as-read timer first */
+ if (fb->seen_id) {
+ g_source_remove (fb->seen_id);
+ fb->seen_id = 0;
+ }
+
+ flag_messages (fb, CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED, 0);
+}
+
+void
+mark_all_as_seen (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ GPtrArray *uids;
+ int i;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ uids = camel_folder_get_uids (fb->folder);
+ camel_folder_freeze (fb->folder);
+ for (i = 0; i < uids->len; i++)
+ camel_folder_set_message_flags (fb->folder, uids->pdata[i], CAMEL_MESSAGE_SEEN, ~0);
+ camel_folder_free_uids (fb->folder, uids);
+ camel_folder_thaw (fb->folder);
+}
+
+void
+mark_as_important (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ flag_messages (FOLDER_BROWSER (user_data), CAMEL_MESSAGE_FLAGGED|CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_FLAGGED);
+}
+
+void
+mark_as_unimportant (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ flag_messages (FOLDER_BROWSER (user_data), CAMEL_MESSAGE_FLAGGED, 0);
+}
+
+void
+toggle_as_important (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ toggle_flags (FOLDER_BROWSER (user_data), CAMEL_MESSAGE_FLAGGED);
+}
+
+
+struct _tag_editor_data {
+ MessageTagEditor *editor;
+ FolderBrowser *fb;
+ GPtrArray *uids;
+};
+
+static void
+tag_editor_response(GtkWidget *gd, int button, struct _tag_editor_data *data)
+{
+ CamelFolder *folder;
+ CamelTag *tags, *t;
+ GPtrArray *uids;
+ int i;
+
+ /*if (FOLDER_BROWSER_IS_DESTROYED (data->fb))
+ goto done;*/
+
+ if (button == GTK_RESPONSE_OK
+ && (tags = message_tag_editor_get_tag_list (data->editor))) {
+ folder = data->fb->folder;
+ uids = data->uids;
+
+ camel_folder_freeze (folder);
+ for (i = 0; i < uids->len; i++) {
+ for (t = tags; t; t = t->next)
+ camel_folder_set_message_user_tag (folder, uids->pdata[i], t->name, t->value);
+ }
+ camel_folder_thaw (folder);
+ camel_tag_list_free (&tags);
+ }
+
+ gtk_widget_destroy(gd);
+
+ g_object_unref (data->fb);
+ g_ptr_array_free (data->uids, TRUE);
+ g_free (data);
+}
+
+void
+flag_for_followup (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ struct _tag_editor_data *data;
+ GtkWidget *editor;
+ GPtrArray *uids;
+ int i;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ editor = (GtkWidget *) message_tag_followup_new ();
+
+ data = g_new (struct _tag_editor_data, 1);
+ data->editor = MESSAGE_TAG_EDITOR (editor);
+ gtk_widget_ref (GTK_WIDGET (fb));
+ data->fb = fb;
+ data->uids = uids;
+
+ for (i = 0; i < uids->len; i++) {
+ CamelMessageInfo *info;
+
+ info = camel_folder_get_message_info (fb->folder, uids->pdata[i]);
+ message_tag_followup_append_message (MESSAGE_TAG_FOLLOWUP (editor),
+ camel_message_info_from (info),
+ camel_message_info_subject (info));
+ }
+
+ g_signal_connect(editor, "response", G_CALLBACK(tag_editor_response), data);
+
+ /* special-case... */
+ if (uids->len == 1) {
+ CamelMessageInfo *info;
+
+ info = camel_folder_get_message_info (fb->folder, uids->pdata[0]);
+ if (info) {
+ if (info->user_tags)
+ message_tag_editor_set_tag_list (MESSAGE_TAG_EDITOR (editor), info->user_tags);
+ camel_folder_free_message_info (fb->folder, info);
+ }
+ }
+
+ gtk_widget_show (editor);
+}
+
+void
+flag_followup_completed (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ GPtrArray *uids;
+ char *now;
+ int i;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ now = header_format_date (time (NULL), 0);
+
+ camel_folder_freeze (fb->folder);
+ for (i = 0; i < uids->len; i++) {
+ const char *tag;
+
+ tag = camel_folder_get_message_user_tag (fb->folder, uids->pdata[i], "follow-up");
+ if (tag == NULL || *tag == '\0')
+ continue;
+
+ camel_folder_set_message_user_tag (fb->folder, uids->pdata[i], "completed-on", now);
+ }
+ camel_folder_thaw (fb->folder);
+
+ g_free (now);
+
+ g_ptr_array_free (uids, TRUE);
+}
+
+void
+flag_followup_clear (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ GPtrArray *uids;
+ int i;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ camel_folder_freeze (fb->folder);
+ for (i = 0; i < uids->len; i++) {
+ camel_folder_set_message_user_tag (fb->folder, uids->pdata[i], "follow-up", "");
+ camel_folder_set_message_user_tag (fb->folder, uids->pdata[i], "due-by", "");
+ camel_folder_set_message_user_tag (fb->folder, uids->pdata[i], "completed-on", "");
+ }
+ camel_folder_thaw (fb->folder);
+
+ g_ptr_array_free (uids, TRUE);
+}
+
+void
+zoom_in (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ gtk_html_zoom_in (fb->mail_display->html);
+}
+
+void
+zoom_out (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ gtk_html_zoom_out (fb->mail_display->html);
+}
+
+void
+zoom_reset (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ gtk_html_zoom_reset (fb->mail_display->html);
+}
+
+static void
+do_edit_messages (CamelFolder *folder, GPtrArray *uids, GPtrArray *messages, void *data)
+{
+ FolderBrowser *fb = (FolderBrowser *) data;
+ int i;
+
+ if (messages == NULL)
+ return;
+
+ for (i = 0; i < messages->len; i++) {
+ struct _composer_callback_data *ccd;
+ EMsgComposer *composer;
+
+ camel_medium_remove_header (CAMEL_MEDIUM (messages->pdata[i]), "X-Mailer");
+
+ composer = e_msg_composer_new_with_message (messages->pdata[i]);
+ e_msg_composer_unset_changed (composer);
+ e_msg_composer_drop_editor_undo (composer);
+
+ if (composer) {
+ ccd = ccd_new ();
+ if (folder_browser_is_drafts (fb)) {
+ camel_object_ref (folder);
+ ccd->drafts_folder = folder;
+ ccd->drafts_uid = g_strdup (uids->pdata[i]);
+ }
+
+ g_signal_connect (composer, "send", G_CALLBACK (composer_send_cb), ccd);
+ g_signal_connect (composer, "save-draft", G_CALLBACK (composer_save_draft_cb), ccd);
+
+ g_object_weak_ref ((GObject *) composer, (GWeakNotify) composer_destroy_cb, ccd);
+
+ gtk_widget_show (GTK_WIDGET (composer));
+ }
+ }
+}
+
+static gboolean
+are_you_sure (const char *msg, GPtrArray *uids, FolderBrowser *fb)
+{
+ GtkWidget *dialog;
+ int button, i;
+
+ dialog = gtk_message_dialog_new (FB_WINDOW (fb), GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL,
+ msg, uids->len);
+ button = gtk_dialog_run ((GtkDialog *) dialog);
+ gtk_widget_destroy (dialog);
+
+ if (button != GTK_RESPONSE_OK) {
+ for (i = 0; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+ g_ptr_array_free (uids, TRUE);
+ }
+
+ return button == GTK_RESPONSE_OK;
+}
+
+static void
+edit_msg_internal (FolderBrowser *fb)
+{
+ GPtrArray *uids;
+
+ if (!check_send_configuration (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ if (uids->len > 10 && !are_you_sure (_("Are you sure you want to edit all %d messages?"), uids, fb))
+ return;
+
+ mail_get_messages (fb->folder, uids, do_edit_messages, fb);
+}
+
+void
+edit_msg (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ if (!folder_browser_is_drafts (fb)) {
+ e_notice(FB_WINDOW(fb), GTK_MESSAGE_ERROR,
+ _("You may only edit messages saved\nin the Drafts folder."));
+ return;
+ }
+
+ edit_msg_internal (fb);
+}
+
+static void
+do_resend_messages (CamelFolder *folder, GPtrArray *uids, GPtrArray *messages, void *data)
+{
+ int i;
+
+ for (i = 0; i < messages->len; i++) {
+ /* generate a new Message-Id because they need to be unique */
+ camel_mime_message_set_message_id (messages->pdata[i], NULL);
+ }
+
+ /* "Resend" should open up the composer to let the user edit the message */
+ do_edit_messages (folder, uids, messages, data);
+}
+
+
+void
+resend_msg (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ GPtrArray *uids;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ if (!folder_browser_is_sent (fb)) {
+ e_notice (FB_WINDOW (fb), GTK_MESSAGE_ERROR,
+ _("You may only resend messages\nin the Sent folder."));
+ return;
+ }
+
+ if (!check_send_configuration (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ if (uids->len > 10 && !are_you_sure (_("Are you sure you want to resend all %d messages?"), uids, fb))
+ return;
+
+ mail_get_messages (fb->folder, uids, do_resend_messages, fb);
+}
+
+
+void
+search_msg (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ GtkWidget *w;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ if (fb->mail_display->current_message == NULL) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (FB_WINDOW(fb), GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE,
+ _("No Message Selected"));
+ g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
+ gtk_widget_show (dialog);
+ return;
+ }
+
+ w = mail_search_new (fb->mail_display);
+ gtk_widget_show_all (w);
+}
+
+void
+load_images (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ mail_display_load_images (fb->mail_display);
+}
+
+static void
+save_msg_ok (GtkWidget *widget, gpointer user_data)
+{
+ CamelFolder *folder;
+ GPtrArray *uids;
+ const char *path;
+ struct stat st;
+ gboolean ret = TRUE;
+
+ path = gtk_file_selection_get_filename (GTK_FILE_SELECTION (user_data));
+ if (path[0] == '\0')
+ return;
+
+ /* make sure we can actually save to it... */
+ if (stat (path, &st) != -1 && !S_ISREG (st.st_mode))
+ return;
+
+ if (access(path, F_OK) == 0) {
+ if (access(path, W_OK) != 0) {
+ e_notice(GTK_WINDOW(user_data), GTK_MESSAGE_ERROR,
+ _("Cannot save to `%s'\n %s"), path, g_strerror(errno));
+ return;
+ }
+
+ ret = e_question(GTK_WINDOW(user_data), GTK_RESPONSE_NO, NULL,
+ _("`%s' already exists.\nOverwrite it?"), path);
+ }
+
+ if (ret) {
+ folder = g_object_get_data ((GObject *) user_data, "folder");
+ uids = g_object_steal_data (G_OBJECT (user_data), "uids");
+ mail_save_messages (folder, uids, path, NULL, NULL);
+ gtk_widget_destroy (GTK_WIDGET (user_data));
+ }
+}
+
+static void
+save_msg_destroy (gpointer user_data)
+{
+ GPtrArray *uids = user_data;
+
+ if (uids) {
+ int i;
+
+ for (i = 0; i < uids->len; i++)
+ g_free (uids->pdata[i]);
+
+ g_ptr_array_free (uids, TRUE);
+ }
+}
+
+void
+save_msg (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ GtkFileSelection *filesel;
+ GPtrArray *uids;
+ char *title, *path;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ if (uids->len == 1)
+ title = _("Save Message As...");
+ else
+ title = _("Save Messages As...");
+
+ filesel = GTK_FILE_SELECTION (gtk_file_selection_new (title));
+ path = g_strdup_printf ("%s/", g_get_home_dir ());
+ gtk_file_selection_set_filename (filesel, path);
+ g_free (path);
+
+ g_object_set_data_full ((GObject *) filesel, "uids", uids, save_msg_destroy);
+ g_object_set_data ((GObject *) filesel, "folder", fb->folder);
+
+ g_signal_connect (filesel->ok_button, "clicked", G_CALLBACK (save_msg_ok), filesel);
+ g_signal_connect_swapped (filesel->cancel_button, "clicked",
+ G_CALLBACK (gtk_widget_destroy), filesel);
+
+ gtk_widget_show (GTK_WIDGET (filesel));
+}
+
+void
+colour_msg (GtkWidget *widget, gpointer user_data)
+{
+ /* FIXME: implement me? */
+}
+
+void
+delete_msg (GtkWidget *button, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ gboolean hide_deleted;
+ GConfClient *gconf;
+ int deleted, row;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ deleted = flag_messages (fb, CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
+
+ /* Select the next message if we are only deleting one message */
+ if (deleted == 1) {
+ row = e_tree_row_of_node (fb->message_list->tree,
+ e_tree_get_cursor (fb->message_list->tree));
+
+ gconf = mail_config_get_gconf_client ();
+ hide_deleted = !gconf_client_get_bool (gconf, "/apps/evolution/mail/display/show_deleted", NULL);
+
+ /* If this is the last message and deleted messages
+ are hidden, select the previous */
+ if ((row + 1 == e_tree_row_count (fb->message_list->tree)) && hide_deleted)
+ message_list_select (fb->message_list, MESSAGE_LIST_SELECT_PREVIOUS,
+ 0, CAMEL_MESSAGE_DELETED, FALSE);
+ else
+ message_list_select (fb->message_list, MESSAGE_LIST_SELECT_NEXT,
+ 0, 0, FALSE);
+ }
+}
+
+void
+undelete_msg (GtkWidget *button, gpointer user_data)
+{
+ flag_messages (FOLDER_BROWSER (user_data), CAMEL_MESSAGE_DELETED, 0);
+}
+
+void
+next_msg (GtkWidget *button, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ message_list_select (fb->message_list, MESSAGE_LIST_SELECT_NEXT, 0, 0, FALSE);
+}
+
+void
+next_unread_msg (GtkWidget *button, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ message_list_select (fb->message_list, MESSAGE_LIST_SELECT_NEXT, 0, CAMEL_MESSAGE_SEEN, TRUE);
+}
+
+void
+next_flagged_msg (GtkWidget *button, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ message_list_select (fb->message_list, MESSAGE_LIST_SELECT_NEXT,
+ CAMEL_MESSAGE_FLAGGED, CAMEL_MESSAGE_FLAGGED, FALSE);
+}
+
+void
+next_thread (GtkWidget *button, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ message_list_select_next_thread (fb->message_list);
+}
+
+void
+previous_msg (GtkWidget *button, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ message_list_select (fb->message_list, MESSAGE_LIST_SELECT_PREVIOUS,
+ 0, 0, FALSE);
+}
+
+void
+previous_unread_msg (GtkWidget *button, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ message_list_select (fb->message_list, MESSAGE_LIST_SELECT_PREVIOUS,
+ 0, CAMEL_MESSAGE_SEEN, TRUE);
+}
+
+void
+previous_flagged_msg (GtkWidget *button, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ message_list_select (fb->message_list, MESSAGE_LIST_SELECT_PREVIOUS,
+ CAMEL_MESSAGE_FLAGGED, CAMEL_MESSAGE_FLAGGED, TRUE);
+}
+
+static void
+expunged_folder (CamelFolder *f, void *data)
+{
+ FolderBrowser *fb = data;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ fb->expunging = NULL;
+ gtk_widget_set_sensitive (GTK_WIDGET (fb->message_list), TRUE);
+
+ /* FIXME: we should check that the focus hasn't changed in the
+ * mean time, otherwise we steal the focus unecessarily.
+ * Check :get_toplevel()->focus_widget? */
+ if (fb->expunge_mlfocussed)
+ gtk_widget_grab_focus((GtkWidget *)fb->message_list);
+}
+
+static gboolean
+confirm_expunge (FolderBrowser *fb)
+{
+ gboolean res, show_again;
+ GConfClient *gconf;
+
+ gconf = mail_config_get_gconf_client ();
+
+ if (!gconf_client_get_bool (gconf, "/apps/evolution/mail/prompts/expunge", NULL))
+ return TRUE;
+
+ res = e_question (FB_WINDOW (fb), GTK_RESPONSE_NO, &show_again,
+ _("This operation will permanently erase all messages marked as\n"
+ "deleted. If you continue, you will not be able to recover these messages.\n"
+ "\nReally erase these messages?"));
+
+ gconf_client_set_bool (gconf, "/apps/evolution/mail/prompts/expunge", show_again, NULL);
+
+ return res;
+}
+
+void
+expunge_folder (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ if (fb->folder && (fb->expunging == NULL || fb->folder != fb->expunging) && confirm_expunge (fb)) {
+ CamelMessageInfo *info;
+ GtkWindow *top;
+ GtkWidget *focus;
+
+ /* disable the message list so user can't click on them while we expunge */
+
+ /* nasty hack to find out if some widget inside the message list is focussed ... */
+ top = GTK_WINDOW (gtk_widget_get_toplevel((GtkWidget *)fb->message_list));
+ focus = top?top->focus_widget:NULL;
+ while (focus && focus != (GtkWidget *)fb->message_list)
+ focus = focus->parent;
+ fb->expunge_mlfocussed = focus == (GtkWidget *)fb->message_list;
+ gtk_widget_set_sensitive (GTK_WIDGET (fb->message_list), FALSE);
+
+ /* Only blank the mail display if the message being
+ viewed is one of those to be expunged */
+ if (fb->loaded_uid) {
+ info = camel_folder_get_message_info (fb->folder, fb->loaded_uid);
+
+ if (!info || info->flags & CAMEL_MESSAGE_DELETED)
+ mail_display_set_message (fb->mail_display, NULL, NULL, NULL);
+ }
+
+ fb->expunging = fb->folder;
+ mail_expunge_folder (fb->folder, expunged_folder, fb);
+ }
+}
+
+/********************** Begin Filter Editor ********************/
+
+static GtkWidget *filter_editor = NULL;
+
+static void
+filter_editor_response (GtkWidget *dialog, int button, FolderBrowser *fb)
+{
+ FilterContext *fc;
+
+ if (button == GTK_RESPONSE_ACCEPT) {
+ char *user;
+
+ fc = g_object_get_data(G_OBJECT(dialog), "context");
+ user = g_strdup_printf ("%s/filters.xml", mail_component_peek_base_directory (mail_component_peek ()));
+ rule_context_save ((RuleContext *)fc, user);
+ g_free (user);
+ }
+
+ gtk_widget_destroy(dialog);
+
+ filter_editor = NULL;
+}
+
+static const char *filter_source_names[] = {
+ "incoming",
+ "outgoing",
+ NULL,
+};
+
+void
+filter_edit (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ FilterContext *fc;
+ char *user, *system;
+
+ if (filter_editor) {
+ gdk_window_raise (GTK_WIDGET (filter_editor)->window);
+ return;
+ }
+
+ fc = filter_context_new ();
+ user = g_strdup_printf ("%s/filters.xml", mail_component_peek_base_directory (mail_component_peek ()));
+ system = EVOLUTION_PRIVDATADIR "/filtertypes.xml";
+ rule_context_load ((RuleContext *)fc, system, user);
+ g_free (user);
+
+ if (((RuleContext *)fc)->error) {
+ e_notice(FB_WINDOW (fb), GTK_MESSAGE_ERROR,
+ _("Error loading filter information:\n%s"),
+ ((RuleContext *)fc)->error);
+ return;
+ }
+
+ filter_editor = (GtkWidget *)filter_editor_new (fc, filter_source_names);
+ /* FIXME: maybe this needs destroy func? */
+ gtk_window_set_transient_for ((GtkWindow *) filter_editor, FB_WINDOW (fb));
+ gtk_window_set_title (GTK_WINDOW (filter_editor), _("Filters"));
+ g_object_set_data_full ((GObject *) filter_editor, "context", fc, (GtkDestroyNotify) g_object_unref);
+ g_signal_connect (filter_editor, "response", G_CALLBACK (filter_editor_response), fb);
+ gtk_widget_show (GTK_WIDGET (filter_editor));
+}
+
+/********************** End Filter Editor ********************/
+
+void
+vfolder_edit_vfolders (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ vfolder_edit ();
+}
+
+
+/* static void
+header_print_cb (GtkHTML *html, GnomePrintContext *print_context,
+ double x, double y, double width, double height, gpointer user_data)
+{
+ printf ("header_print_cb %f,%f x %f,%f\n", x, y, width, height);
+
+ gnome_print_newpath (print_context);
+ gnome_print_setlinewidth (print_context, 12.0);
+ gnome_print_setrgbcolor (print_context, 1.0, 0.0, 0.0);
+ gnome_print_moveto (print_context, x, y);
+ gnome_print_lineto (print_context, x+width, y-height);
+ gnome_print_strokepath (print_context);
+} */
+
+struct footer_info {
+ GnomeFont *local_font;
+ gint page_num, pages;
+};
+
+static void
+footer_print_cb (GtkHTML *html, GnomePrintContext *print_context,
+ double x, double y, double width, double height, gpointer user_data)
+{
+ struct footer_info *info = (struct footer_info *) user_data;
+
+ if (info->local_font) {
+ char *text = g_strdup_printf (_("Page %d of %d"), info->page_num, info->pages);
+ /*gdouble tw = gnome_font_get_width_string (info->local_font, text);*/
+ /* FIXME: work out how to measure this */
+ gdouble tw = strlen (text) * 8;
+
+ gnome_print_gsave (print_context);
+ gnome_print_newpath (print_context);
+ gnome_print_setrgbcolor (print_context, .0, .0, .0);
+ gnome_print_moveto (print_context, x + width - tw, y - gnome_font_get_ascender (info->local_font));
+ gnome_print_setfont (print_context, info->local_font);
+ gnome_print_show (print_context, text);
+ gnome_print_grestore (print_context);
+
+ g_free (text);
+ info->page_num++;
+ }
+}
+
+static void
+footer_info_free (struct footer_info *info)
+{
+ if (info->local_font)
+ gnome_font_unref (info->local_font);
+ g_free (info);
+}
+
+static struct footer_info *
+footer_info_new (GtkHTML *html, GnomePrintContext *pc, gdouble *line)
+{
+ struct footer_info *info;
+
+ info = g_new (struct footer_info, 1);
+ info->local_font = gnome_font_find_closest ("Helvetica", 10.0);
+
+ if (info->local_font)
+ *line = gnome_font_get_ascender (info->local_font) - gnome_font_get_descender (info->local_font);
+
+ info->page_num = 1;
+ info->pages = gtk_html_print_get_pages_num (html, pc, 0.0, *line);
+
+ return info;
+}
+
+static void
+do_mail_print (FolderBrowser *fb, gboolean preview)
+{
+ GtkHTML *html;
+ GtkWidget *w = NULL;
+ GnomePrintContext *print_context;
+ GnomePrintJob *print_master;
+ GnomePrintConfig *config = NULL;
+ GtkDialog *dialog;
+ gdouble line = 0.0;
+ struct footer_info *info;
+
+ if (!preview) {
+ dialog = (GtkDialog *) gnome_print_dialog_new (NULL, _("Print Message"), GNOME_PRINT_DIALOG_COPIES);
+ gtk_dialog_set_default_response (dialog, GNOME_PRINT_DIALOG_RESPONSE_PRINT);
+ gtk_window_set_transient_for ((GtkWindow *) dialog, (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) fb));
+
+ switch (gtk_dialog_run (dialog)) {
+ case GNOME_PRINT_DIALOG_RESPONSE_PRINT:
+ break;
+ case GNOME_PRINT_DIALOG_RESPONSE_PREVIEW:
+ preview = TRUE;
+ break;
+ default:
+ gtk_widget_destroy ((GtkWidget *) dialog);
+ return;
+ }
+
+ config = gnome_print_dialog_get_config ((GnomePrintDialog *) dialog);
+ gtk_widget_destroy ((GtkWidget *)dialog);
+ }
+
+ if (config) {
+ print_master = gnome_print_job_new (config);
+ gnome_print_config_unref (config);
+ } else
+ print_master = gnome_print_job_new (NULL);
+
+ /* paper size settings? */
+ /*gnome_print_master_set_paper (print_master, paper);*/
+ print_context = gnome_print_job_get_context (print_master);
+
+ html = GTK_HTML (gtk_html_new ());
+ gtk_widget_set_name (GTK_WIDGET (html), "EvolutionMailPrintHTMLWidget");
+ mail_display_initialize_gtkhtml (fb->mail_display, html);
+
+ /* Set our 'printing' flag to true and render. This causes us
+ to ignoring any adjustments we made to accomodate the
+ user's theme. */
+ fb->mail_display->printing = TRUE;
+
+ if (!GTK_WIDGET_REALIZED (GTK_WIDGET (html))) {
+ /* gtk widgets don't like to be realized outside top level widget
+ so we put new html widget into gtk window */
+ w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (html));
+ gtk_widget_realize (GTK_WIDGET (html));
+ }
+ mail_display_render (fb->mail_display, html, TRUE);
+ gtk_html_print_set_master (html, print_master);
+
+ info = footer_info_new (html, print_context, &line);
+ gtk_html_print_with_header_footer (html, print_context, 0.0, line, NULL, footer_print_cb, info);
+ footer_info_free (info);
+
+ fb->mail_display->printing = FALSE;
+
+ gnome_print_job_close (print_master);
+ gtk_widget_destroy (GTK_WIDGET (html));
+ if (w)
+ gtk_widget_destroy (w);
+
+ if (preview){
+ GtkWidget *pw;
+
+ pw = gnome_print_job_preview_new (print_master, _("Print Preview"));
+ gtk_widget_show (pw);
+ } else {
+ int result = gnome_print_job_print (print_master);
+
+ if (result == -1)
+ e_notice (FB_WINDOW (fb), GTK_MESSAGE_ERROR, _("Printing of message failed"));
+ }
+
+ g_object_unref (print_master);
+}
+
+/* This is pretty evil. FolderBrowser's API should be extended to allow these sorts of
+ things to be done in a more natural way. */
+
+/* <evil_code> */
+
+struct blarg_this_sucks {
+ FolderBrowser *fb;
+ gboolean preview;
+};
+
+static void
+done_message_selected (CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data)
+{
+ struct blarg_this_sucks *blarg = data;
+ FolderBrowser *fb = blarg->fb;
+ gboolean preview = blarg->preview;
+ CamelMessageInfo *info;
+
+ g_free (blarg);
+
+ info = camel_folder_get_message_info (fb->folder, uid);
+ mail_display_set_message (fb->mail_display, (CamelMedium *) msg, fb->folder, info);
+ if (info)
+ camel_folder_free_message_info (fb->folder, info);
+
+ g_free (fb->loaded_uid);
+ fb->loaded_uid = fb->loading_uid;
+ fb->loading_uid = NULL;
+
+ if (msg)
+ do_mail_print (fb, preview);
+}
+
+/* Ack! Most of this is copied from folder-browser.c */
+static void
+do_mail_fetch_and_print (FolderBrowser *fb, gboolean preview)
+{
+ if (!fb->preview_shown || fb->mail_display->current_message == NULL) {
+ /* If the preview pane is closed, we have to do some
+ extra magic to load the message. */
+ struct blarg_this_sucks *blarg = g_new (struct blarg_this_sucks, 1);
+
+ blarg->fb = fb;
+ blarg->preview = preview;
+
+ fb->loading_id = 0;
+
+ /* if we are loading, then set a pending, but leave the loading, coudl cancel here (?) */
+ if (fb->loading_uid) {
+ g_free (fb->pending_uid);
+ fb->pending_uid = g_strdup (fb->new_uid);
+ } else {
+ if (fb->new_uid) {
+ fb->loading_uid = g_strdup (fb->new_uid);
+ mail_get_message (fb->folder, fb->loading_uid, done_message_selected, blarg, mail_thread_new);
+ } else {
+ mail_display_set_message (fb->mail_display, NULL, NULL, NULL);
+ g_free (blarg);
+ }
+ }
+ } else {
+ do_mail_print (fb, preview);
+ }
+}
+
+/* </evil_code> */
+
+
+void
+print_msg (GtkWidget *button, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ do_mail_fetch_and_print (fb, FALSE);
+}
+
+void
+print_preview_msg (GtkWidget *button, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ do_mail_fetch_and_print (fb, TRUE);
+}
+
+/******************** Begin Subscription Dialog ***************************/
+
+static GtkObject *subscribe_dialog = NULL;
+
+static void
+subscribe_dialog_destroy (GtkObject *dialog, GObject *deadbeef)
+{
+ if (subscribe_dialog) {
+ g_object_unref (subscribe_dialog);
+ subscribe_dialog = NULL;
+ }
+}
+
+void
+manage_subscriptions (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ if (!subscribe_dialog) {
+ subscribe_dialog = subscribe_dialog_new ();
+
+ g_object_weak_ref ((GObject *) SUBSCRIBE_DIALOG (subscribe_dialog)->app,
+ (GWeakNotify) subscribe_dialog_destroy, subscribe_dialog);
+ g_object_ref(subscribe_dialog);
+ gtk_object_sink((GtkObject *)subscribe_dialog);
+ subscribe_dialog_show (subscribe_dialog);
+ } else {
+ gdk_window_raise (SUBSCRIBE_DIALOG (subscribe_dialog)->app->window);
+ }
+}
+
+/******************** End Subscription Dialog ***************************/
+
+static void
+local_configure_done(const char *uri, CamelFolder *folder, void *data)
+{
+ FolderBrowser *fb = data;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb)) {
+ g_object_unref(fb);
+ return;
+ }
+
+ if (folder == NULL)
+ folder = fb->folder;
+
+ message_list_set_folder(fb->message_list, folder, FALSE);
+ g_object_unref(fb);
+}
+
+void
+configure_folder (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ if (fb->uri) {
+ if (strncmp (fb->uri, "vfolder:", 8) == 0) {
+ vfolder_edit_rule (fb->uri);
+ } else {
+ message_list_set_folder(fb->message_list, NULL, FALSE);
+ g_object_ref((GtkObject *)fb);
+ mail_local_reconfigure_folder(fb->uri, local_configure_done, fb);
+ }
+ }
+}
+
+static void
+do_view_messages(CamelFolder *folder, GPtrArray *uids, GPtrArray *msgs, void *data)
+{
+ FolderBrowser *fb = data;
+ int i;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ for (i = 0; i < uids->len && i < msgs->len; i++) {
+ char *uid = uids->pdata[i];
+ CamelMimeMessage *msg = msgs->pdata[i];
+ GtkWidget *mb;
+
+ camel_folder_set_message_flags (folder, uid, CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
+ mb = message_browser_new (fb->uri, uid);
+ gtk_widget_show (mb);
+ }
+}
+
+void
+view_msg (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ GPtrArray *uids;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (fb->message_list, enumerate_msg, uids);
+
+ if (uids->len > 10 && !are_you_sure (_("Are you sure you want to open all %d messages in separate windows?"), uids, fb))
+ return;
+
+ mail_get_messages(fb->folder, uids, do_view_messages, fb);
+}
+
+void
+open_msg (GtkWidget *widget, gpointer user_data)
+{
+ FolderBrowser *fb = FOLDER_BROWSER (user_data);
+ extern CamelFolder *outbox_folder;
+
+ if (FOLDER_BROWSER_IS_DESTROYED (fb))
+ return;
+
+ if (folder_browser_is_drafts (fb) || fb->folder == outbox_folder)
+ edit_msg_internal (fb);
+ else
+ view_msg (NULL, user_data);
+}
+
+void
+open_message (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ open_msg (NULL, user_data);
+}
+
+void
+edit_message (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ edit_msg (NULL, user_data);
+}
+
+void
+stop_threads (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ camel_operation_cancel (NULL);
+}
+
+void
+empty_trash (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ CamelProvider *provider;
+ EAccountList *accounts;
+ FolderBrowser *fb;
+ CamelException ex;
+ EAccount *account;
+ EIterator *iter;
+
+ fb = user_data ? FOLDER_BROWSER (user_data) : NULL;
+
+ if (fb && !confirm_expunge (fb))
+ return;
+
+ camel_exception_init (&ex);
+
+ /* expunge all remote stores */
+ accounts = mail_config_get_accounts ();
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ account = (EAccount *) e_iterator_get (iter);
+
+ /* make sure this is a valid source */
+ if (account->enabled && account->source->url) {
+ provider = camel_session_get_provider (session, account->source->url, &ex);
+ if (provider) {
+ /* make sure this store is a remote store */
+ if (provider->flags & CAMEL_PROVIDER_IS_STORAGE &&
+ provider->flags & CAMEL_PROVIDER_IS_REMOTE) {
+ mail_empty_trash (account, NULL, NULL);
+ }
+ }
+
+ /* clear the exception for the next round */
+ camel_exception_clear (&ex);
+ }
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ /* Now empty the local trash folder */
+ mail_empty_trash (NULL, NULL, NULL);
+}
diff --git a/mail/mail-callbacks.h b/mail/mail-callbacks.h
new file mode 100644
index 0000000000..6b2c4573c9
--- /dev/null
+++ b/mail/mail-callbacks.h
@@ -0,0 +1,144 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2000 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 MAIL_CALLBACKS_H
+#define MAIL_CALLBACKS_H
+
+#include <camel/camel.h>
+#include "composer/e-msg-composer.h"
+#include <mail/mail-types.h>
+#include "evolution-storage.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* these are the possible modes for replying */
+enum {
+ REPLY_SENDER,
+ REPLY_LIST,
+ REPLY_ALL,
+ REPLY_POST,
+ REPLY_NO_QUOTE = 0x80 /* dont quote reply */
+};
+
+void enumerate_msg (MessageList *ml, const char *uid, gpointer data);
+
+void fetch_mail (GtkWidget *widget, gpointer user_data);
+void send_queued_mail (GtkWidget *widget, gpointer user_data);
+
+void compose_msg (GtkWidget *widget, gpointer user_data);
+void send_to_url (const char *url, const char *parent_uri);
+
+void forward_inline (GtkWidget *widget, gpointer user_data);
+void forward_quoted (GtkWidget *widget, gpointer user_data);
+void forward_attached (GtkWidget *widget, gpointer user_data);
+void forward (GtkWidget *widget, gpointer user_data);
+
+void post_to_url (const char *url);
+void post_message (GtkWidget *widget, gpointer user_data);
+void post_reply (GtkWidget *widget, gpointer user_data);
+
+void redirect (GtkWidget *widget, gpointer user_data);
+
+void reply_to_sender (GtkWidget *widget, gpointer user_data);
+void reply_to_list (GtkWidget *widget, gpointer user_data);
+void reply_to_all (GtkWidget *widget, gpointer user_data);
+
+void colour_msg (GtkWidget *widget, gpointer user_data);
+void delete_msg (GtkWidget *widget, gpointer user_data);
+void undelete_msg (GtkWidget *widget, gpointer user_data);
+void move_msg_cb (GtkWidget *widget, gpointer user_data);
+void copy_msg_cb (GtkWidget *widget, gpointer user_data);
+void addrbook_sender (GtkWidget *widget, gpointer user_data);
+void apply_filters (GtkWidget *widget, gpointer user_data);
+void print_msg (GtkWidget *widget, gpointer user_data);
+void print_preview_msg (GtkWidget *widget, gpointer user_data);
+void edit_msg (GtkWidget *widget, gpointer user_data);
+void open_msg (GtkWidget *widget, gpointer user_data);
+void save_msg (GtkWidget *widget, gpointer user_data);
+void view_msg (GtkWidget *widget, gpointer user_data);
+void view_digest (GtkWidget *widget, gpointer user_data);
+void view_source (GtkWidget *widget, gpointer user_data);
+void next_msg (GtkWidget *widget, gpointer user_data);
+void next_unread_msg (GtkWidget *widget, gpointer user_data);
+void next_flagged_msg (GtkWidget *widget, gpointer user_data);
+void next_thread (GtkWidget *widget, gpointer user_data);
+void previous_msg (GtkWidget *widget, gpointer user_data);
+void previous_unread_msg (GtkWidget *widget, gpointer user_data);
+void previous_flagged_msg (GtkWidget *widget, gpointer user_data);
+void resend_msg (GtkWidget *widget, gpointer user_data);
+void search_msg (GtkWidget *widget, gpointer user_data);
+void load_images (GtkWidget *widget, gpointer user_data);
+
+void add_sender_to_addrbook (BonoboUIComponent *uih, void *user_data, const char *path);
+void move_msg (BonoboUIComponent *uih, void *user_data, const char *path);
+void copy_msg (BonoboUIComponent *uih, void *user_data, const char *path);
+void select_all (BonoboUIComponent *uih, void *user_data, const char *path);
+void select_thread (BonoboUIComponent *uih, void *user_data, const char *path);
+void invert_selection (BonoboUIComponent *uih, void *user_data, const char *path);
+void mark_as_seen (BonoboUIComponent *uih, void *user_data, const char *path);
+void mark_all_as_seen (BonoboUIComponent *uih, void *user_data, const char *path);
+void mark_as_unseen (BonoboUIComponent *uih, void *user_data, const char *path);
+void mark_as_important (BonoboUIComponent *uih, void *user_data, const char *path);
+void mark_as_unimportant (BonoboUIComponent *uih, void *user_data, const char *path);
+void toggle_as_important (BonoboUIComponent *uih, void *user_data, const char *path);
+void flag_for_followup (BonoboUIComponent *uih, void *user_data, const char *path);
+void flag_followup_completed (BonoboUIComponent *uih, void *user_data, const char *path);
+void flag_followup_clear (BonoboUIComponent *uih, void *user_data, const char *path);
+
+void zoom_in (BonoboUIComponent *uih, void *user_data, const char *path);
+void zoom_out (BonoboUIComponent *uih, void *user_data, const char *path);
+void zoom_reset (BonoboUIComponent *uih, void *user_data, const char *path);
+
+void edit_message (BonoboUIComponent *uih, void *user_data, const char *path);
+void open_message (BonoboUIComponent *uih, void *user_data, const char *path);
+void expunge_folder (BonoboUIComponent *uih, void *user_data, const char *path);
+void filter_edit (BonoboUIComponent *uih, void *user_data, const char *path);
+void vfolder_edit_vfolders (BonoboUIComponent *uih, void *user_data, const char *path);
+void manage_subscriptions (BonoboUIComponent *uih, void *user_data, const char *path);
+
+void configure_folder (BonoboUIComponent *uih, void *user_data, const char *path);
+
+void stop_threads (BonoboUIComponent *uih, void *user_data, const char *path);
+
+void empty_trash (BonoboUIComponent *uih, void *user_data, const char *path);
+
+void mail_reply (CamelFolder *folder, CamelMimeMessage *msg, const char *uid, int mode);
+
+void composer_send_cb (EMsgComposer *composer, gpointer data);
+void composer_save_draft_cb (EMsgComposer *composer, int quit, gpointer data);
+
+void forward_messages (CamelFolder *folder, GPtrArray *uids, gboolean inline);
+
+/* CamelStore callbacks */
+void folder_created (CamelStore *store, const char *prefix, CamelFolderInfo *fi);
+void folder_deleted (CamelStore *store, CamelFolderInfo *fi);
+
+void mail_storage_create_folder (EvolutionStorage *storage, CamelStore *store, CamelFolderInfo *fi);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* ! MAIL_CALLBACKS_H */
diff --git a/mail/mail-component-factory.c b/mail/mail-component-factory.c
new file mode 100644
index 0000000000..00087b7439
--- /dev/null
+++ b/mail/mail-component-factory.c
@@ -0,0 +1,104 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* mail-component-factory.c
+ *
+ * Authors: Ettore Perazzoli <ettore@ximian.com>
+ *
+ * Copyright (C) 2003 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 "em-utils.h"
+#include "evolution-composer.h"
+#include "mail-accounts.h"
+#include "mail-component.h"
+#include "mail-composer-prefs.h"
+#include "mail-config-druid.h"
+#include "mail-config-factory.h"
+#include "mail-config.h"
+#include "mail-mt.h"
+#include "mail-preferences.h"
+
+#include <bonobo-activation/bonobo-activation.h>
+#include <bonobo/bonobo-shlib-factory.h>
+
+#include <string.h>
+
+
+#define FACTORY_ID "OAFIID:GNOME_Evolution_Mail_Factory_2"
+
+#define COMPONENT_ID "OAFIID:GNOME_Evolution_Mail_Component_2"
+#define COMPOSER_ID "OAFIID:GNOME_Evolution_Mail_Composer"
+#define FOLDER_INFO_ID "OAFIID:GNOME_Evolution_FolderInfo"
+#define MAIL_CONFIG_ID "OAFIID:GNOME_Evolution_MailConfig"
+#define WIZARD_ID "OAFIID:GNOME_Evolution_Mail_Wizard"
+
+
+/* EPFIXME: This stuff is here just to get it to compile, it should be moved
+ out of the way (was originally in component-factory.c). */
+EvolutionShellClient *global_shell_client = NULL;
+
+static BonoboObject *
+factory (BonoboGenericFactory *factory,
+ const char *component_id,
+ void *closure)
+{
+ /* EPFIXME this is messy. The IDs are defined all over the place
+ without a logic... */
+
+ if (strcmp (component_id, COMPONENT_ID) == 0) {
+ MailComponent *component = mail_component_peek ();
+
+ bonobo_object_ref (BONOBO_OBJECT (component));
+ return BONOBO_OBJECT (component);
+ } else if (strcmp(component_id, MAIL_CONFIG_ID) == 0) {
+ return (BonoboObject *)g_object_new (evolution_mail_config_get_type (), NULL);
+ } else if (strcmp(component_id, WIZARD_ID) == 0) {
+ return evolution_mail_config_wizard_new();
+ } else if (strcmp (component_id, MAIL_ACCOUNTS_CONTROL_ID) == 0
+ || strcmp (component_id, MAIL_PREFERENCES_CONTROL_ID) == 0
+ || strcmp (component_id, MAIL_COMPOSER_PREFS_CONTROL_ID) == 0) {
+ return mail_config_control_factory_cb (factory, component_id, CORBA_OBJECT_NIL);
+ } else if (strcmp(component_id, COMPOSER_ID) == 0) {
+ /* FIXME: how to remove need for callbacks, probably make the composer more tightly integrated with mail */
+ return (BonoboObject *) evolution_composer_new (em_utils_composer_send_cb, em_utils_composer_save_draft_cb);
+ }
+
+ g_warning (FACTORY_ID ": Don't know what to do with %s", component_id);
+ return NULL;
+}
+
+static Bonobo_Unknown
+make_factory (PortableServer_POA poa, const char *iid, gpointer impl_ptr, CORBA_Environment *ev)
+{
+ static int init = 0;
+
+ if (!init) {
+ mail_config_init ();
+ mail_msg_init ();
+ init = 1;
+ }
+
+ return bonobo_shlib_factory_std (FACTORY_ID, poa, impl_ptr, factory, NULL, ev);
+}
+
+static BonoboActivationPluginObject plugin_list[] = {
+ { FACTORY_ID, make_factory},
+ { NULL }
+};
+
+const BonoboActivationPlugin Bonobo_Plugin_info = {
+ plugin_list, "Evolution Mail component factory"
+};
diff --git a/mail/mail-component.c b/mail/mail-component.c
new file mode 100644
index 0000000000..e4289eda19
--- /dev/null
+++ b/mail/mail-component.c
@@ -0,0 +1,1625 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* mail-component.c
+ *
+ * Copyright (C) 2003 Ximian Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Author: Ettore Perazzoli <ettore@ximian.com>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "e-storage.h"
+#include "e-storage-set.h"
+#include "e-storage-browser.h"
+#include "e-storage-set-view.h"
+#include "em-folder-selector.h"
+#include "em-folder-selection.h"
+
+#include "folder-browser-factory.h"
+#include "mail-config.h"
+#include "mail-component.h"
+#include "mail-folder-cache.h"
+#include "mail-vfolder.h"
+#include "mail-mt.h"
+#include "mail-ops.h"
+#include "mail-send-recv.h"
+#include "mail-session.h"
+
+#include "em-popup.h"
+
+#include <gtk/gtklabel.h>
+
+#include <gal/e-table/e-tree.h>
+#include <gal/e-table/e-tree-memory.h>
+
+#include <camel/camel.h>
+
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-widget.h>
+
+
+#define PARENT_TYPE bonobo_object_get_type ()
+static BonoboObjectClass *parent_class = NULL;
+
+struct _MailComponentPrivate {
+ char *base_directory;
+
+ MailAsyncEvent *async_event;
+ GHashTable *storages_hash; /* storage by store */
+
+ EFolderTypeRegistry *folder_type_registry;
+ EStorageSet *storage_set;
+
+ RuleContext *search_context;
+
+ char *context_path; /* current path for right-click menu */
+
+ CamelStore *local_store;
+};
+
+static int emc_tree_right_click(ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, MailComponent *component);
+
+/* Utility functions. */
+
+/* EPFIXME: Eeek, this totally sucks. See comment in e-storage.h,
+ async_open_folder() should NOT be a signal. */
+
+struct _StorageConnectedData {
+ EStorage *storage;
+ char *path;
+ EStorageDiscoveryCallback callback;
+ void *callback_data;
+};
+typedef struct _StorageConnectedData StorageConnectedData;
+
+static void
+storage_connected_callback (CamelStore *store,
+ CamelFolderInfo *info,
+ StorageConnectedData *data)
+{
+ EStorageResult result;
+
+ if (info != NULL)
+ result = E_STORAGE_OK;
+ else
+ result = E_STORAGE_GENERICERROR;
+
+ (* data->callback) (data->storage, result, data->path, data->callback_data);
+
+ g_object_unref (data->storage);
+ g_free (data->path);
+ g_free (data);
+}
+
+static void
+storage_async_open_folder_callback (EStorage *storage,
+ const char *path,
+ EStorageDiscoveryCallback callback,
+ void *callback_data,
+ CamelStore *store)
+{
+ StorageConnectedData *storage_connected_data = g_new0 (StorageConnectedData, 1);
+
+ g_object_ref (storage);
+
+ storage_connected_data->storage = storage;
+ storage_connected_data->path = g_strdup (path);
+ storage_connected_data->callback = callback;
+ storage_connected_data->callback_data = callback_data;
+
+ mail_note_store (store, NULL, storage,
+ (void *) storage_connected_callback, storage_connected_data);
+}
+
+static void
+add_storage (MailComponent *component,
+ const char *name,
+ CamelService *store,
+ CamelException *ex)
+{
+ EStorage *storage;
+ EFolder *root_folder;
+
+ root_folder = e_folder_new (name, "noselect", "");
+ storage = e_storage_new (name, root_folder);
+ e_storage_declare_has_subfolders(storage, "/", _("Connecting..."));
+
+ camel_object_ref(store);
+
+ g_object_set_data((GObject *)storage, "em-store", store);
+ g_hash_table_insert (component->priv->storages_hash, store, storage);
+
+ g_signal_connect(storage, "async_open_folder",
+ G_CALLBACK (storage_async_open_folder_callback), store);
+
+#if 0
+ /* EPFIXME these are not needed anymore. */
+ g_signal_connect(storage, "create_folder", G_CALLBACK(storage_create_folder), store);
+ g_signal_connect(storage, "remove_folder", G_CALLBACK(storage_remove_folder), store);
+ g_signal_connect(storage, "xfer_folder", G_CALLBACK(storage_xfer_folder), store);
+#endif
+
+ e_storage_set_add_storage (component->priv->storage_set, storage);
+
+ mail_note_store ((CamelStore *) store, NULL, storage, NULL, NULL);
+
+ g_object_unref (storage);
+}
+
+static void
+load_accounts(MailComponent *component, EAccountList *accounts)
+{
+ EIterator *iter;
+
+ /* Load each service (don't connect!). Check its provider and
+ * see if this belongs in the shell's folder list. If so, add
+ * it.
+ */
+
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ EAccountService *service;
+ EAccount *account;
+ const char *name;
+
+ account = (EAccount *) e_iterator_get (iter);
+ service = account->source;
+ name = account->name;
+
+ if (account->enabled && service->url != NULL)
+ mail_component_load_storage_by_uri (component, service->url, name);
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+}
+
+static inline gboolean
+type_is_mail (const char *type)
+{
+ return !strcmp (type, "mail") || !strcmp (type, "mail/public");
+}
+
+static inline gboolean
+type_is_vtrash (const char *type)
+{
+ return !strcmp (type, "vtrash");
+}
+
+static void
+storage_go_online (gpointer key, gpointer value, gpointer data)
+{
+ CamelStore *store = key;
+ CamelService *service = CAMEL_SERVICE (store);
+
+ if (! (service->provider->flags & CAMEL_PROVIDER_IS_REMOTE)
+ || (service->provider->flags & CAMEL_PROVIDER_IS_EXTERNAL))
+ return;
+
+ if ((CAMEL_IS_DISCO_STORE (service)
+ && camel_disco_store_status (CAMEL_DISCO_STORE (service)) == CAMEL_DISCO_STORE_OFFLINE)
+ || service->status != CAMEL_SERVICE_DISCONNECTED) {
+ mail_store_set_offline (store, FALSE, NULL, NULL);
+ mail_note_store (store, NULL, NULL, NULL, NULL);
+ }
+}
+
+static void
+go_online (MailComponent *component)
+{
+ camel_session_set_online(session, TRUE);
+ mail_session_set_interactive(TRUE);
+ mail_component_storages_foreach(component, storage_go_online, NULL);
+}
+
+static void
+setup_search_context (MailComponent *component)
+{
+ MailComponentPrivate *priv = component->priv;
+ char *user = g_strdup_printf ("%s/evolution/searches.xml", g_get_home_dir ()); /* EPFIXME should be somewhere else. */
+ char *system = g_strdup (EVOLUTION_PRIVDATADIR "/vfoldertypes.xml");
+
+ priv->search_context = rule_context_new ();
+ g_object_set_data_full (G_OBJECT (priv->search_context), "user", user, g_free);
+ g_object_set_data_full (G_OBJECT (priv->search_context), "system", system, g_free);
+
+ rule_context_add_part_set (priv->search_context, "partset", filter_part_get_type (),
+ rule_context_add_part, rule_context_next_part);
+
+ rule_context_add_rule_set (priv->search_context, "ruleset", filter_rule_get_type (),
+ rule_context_add_rule, rule_context_next_rule);
+
+ rule_context_load (priv->search_context, system, user);
+}
+
+/* Local store setup. */
+char *default_drafts_folder_uri;
+CamelFolder *drafts_folder = NULL;
+char *default_sent_folder_uri;
+CamelFolder *sent_folder = NULL;
+char *default_outbox_folder_uri;
+CamelFolder *outbox_folder = NULL;
+char *default_inbox_folder_uri;
+CamelFolder *inbox_folder = NULL;
+
+static struct {
+ char *base;
+ char **uri;
+ CamelFolder **folder;
+} default_folders[] = {
+ { "Inbox", &default_inbox_folder_uri, &inbox_folder },
+ { "Drafts", &default_drafts_folder_uri, &drafts_folder },
+ { "Outbox", &default_outbox_folder_uri, &outbox_folder },
+ { "Sent", &default_sent_folder_uri, &sent_folder },
+};
+
+static void
+setup_local_store(MailComponent *component)
+{
+ MailComponentPrivate *p = component->priv;
+ CamelException ex;
+ char *store_uri;
+ int i;
+
+ g_assert(p->local_store == NULL);
+
+ /* EPFIXME It should use base_directory once we have moved it. */
+ store_uri = g_strconcat("mbox:", g_get_home_dir(), "/.evolution/mail/local", NULL);
+ p->local_store = mail_component_load_storage_by_uri(component, store_uri, _("On this Computer"));
+ camel_object_ref(p->local_store);
+
+ camel_exception_init (&ex);
+ for (i=0;i<sizeof(default_folders)/sizeof(default_folders[0]);i++) {
+ /* FIXME: should this uri be account relative? */
+ *default_folders[i].uri = g_strdup_printf("%s#%s", store_uri, default_folders[i].base);
+ *default_folders[i].folder = camel_store_get_folder(p->local_store, default_folders[i].base,
+ CAMEL_STORE_FOLDER_CREATE, &ex);
+ camel_exception_clear(&ex);
+ }
+
+ g_free(store_uri);
+}
+
+/* EStorageBrowser callbacks. */
+
+static BonoboControl *
+create_noselect_control (void)
+{
+ GtkWidget *label;
+
+ label = gtk_label_new (_("This folder cannot contain messages."));
+ gtk_widget_show (label);
+ return bonobo_control_new (label);
+}
+
+static GtkWidget *
+create_view_callback (EStorageBrowser *browser,
+ const char *path,
+ void *unused_data)
+{
+ BonoboControl *control;
+ EFolder *folder;
+ const char *folder_type;
+ const char *physical_uri;
+
+ folder = e_storage_set_get_folder (e_storage_browser_peek_storage_set (browser), path);
+ if (folder == NULL) {
+ g_warning ("No folder at %s", path);
+ return gtk_label_new ("(You should not be seeing this label)");
+ }
+
+ folder_type = e_folder_get_type_string (folder);
+ physical_uri = e_folder_get_physical_uri (folder);
+
+ if (type_is_mail (folder_type)) {
+ const char *noselect;
+ CamelURL *url;
+
+ url = camel_url_new (physical_uri, NULL);
+ noselect = url ? camel_url_get_param (url, "noselect") : NULL;
+ if (noselect && !strcasecmp (noselect, "yes"))
+ control = create_noselect_control ();
+ else
+ control = folder_browser_factory_new_control (physical_uri);
+ camel_url_free (url);
+ } else if (type_is_vtrash (folder_type)) {
+ if (!strncasecmp (physical_uri, "file:", 5))
+ control = folder_browser_factory_new_control ("vtrash:file:/");
+ else
+ control = folder_browser_factory_new_control (physical_uri);
+ } else
+ return NULL;
+
+ if (!control)
+ return NULL;
+
+ /* EPFIXME: This leaks the control. */
+ return bonobo_widget_new_control_from_objref (BONOBO_OBJREF (control), CORBA_OBJECT_NIL);
+}
+
+static void
+browser_page_switched_callback (EStorageBrowser *browser,
+ GtkWidget *old_page,
+ GtkWidget *new_page,
+ BonoboControl *parent_control)
+{
+ if (BONOBO_IS_WIDGET (old_page)) {
+ BonoboControlFrame *control_frame = bonobo_widget_get_control_frame (BONOBO_WIDGET (old_page));
+
+ bonobo_control_frame_control_deactivate (control_frame);
+ }
+
+ if (BONOBO_IS_WIDGET (new_page)) {
+ BonoboControlFrame *control_frame = bonobo_widget_get_control_frame (BONOBO_WIDGET (new_page));
+ Bonobo_UIContainer ui_container = bonobo_control_get_remote_ui_container (parent_control, NULL);
+
+ /* This is necessary because we are not embedding the folder browser control
+ directly; we are putting the folder browser control into a notebook which
+ is then exported to the shell as a control. So we need to forward the
+ notebook's UIContainer to the folder browser. */
+ bonobo_control_frame_set_ui_container (control_frame, ui_container, NULL);
+
+ bonobo_control_frame_control_activate (control_frame);
+ }
+}
+
+/* GObject methods. */
+
+static void
+impl_dispose (GObject *object)
+{
+ MailComponentPrivate *priv = MAIL_COMPONENT (object)->priv;
+
+ if (priv->storage_set != NULL) {
+ g_object_unref (priv->storage_set);
+ priv->storage_set = NULL;
+ }
+
+ if (priv->folder_type_registry != NULL) {
+ g_object_unref (priv->folder_type_registry);
+ priv->folder_type_registry = NULL;
+ }
+
+ if (priv->search_context != NULL) {
+ g_object_unref (priv->search_context);
+ priv->search_context = NULL;
+ }
+
+ if (priv->local_store != NULL) {
+ camel_object_unref (CAMEL_OBJECT (priv->local_store));
+ priv->local_store = NULL;
+ }
+
+ (* G_OBJECT_CLASS (parent_class)->dispose) (object);
+}
+
+static void
+impl_finalize (GObject *object)
+{
+ MailComponentPrivate *priv = MAIL_COMPONENT (object)->priv;
+
+ g_free (priv->base_directory);
+
+ mail_async_event_destroy (priv->async_event);
+
+ g_hash_table_destroy (priv->storages_hash); /* EPFIXME free the data within? */
+
+ if (mail_async_event_destroy (priv->async_event) == -1) {
+ g_warning("Cannot destroy async event: would deadlock");
+ g_warning(" system may be unstable at exit");
+ }
+
+ g_free(priv->context_path);
+ g_free (priv);
+
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+
+/* Evolution::Component CORBA methods. */
+
+static void
+impl_createControls (PortableServer_Servant servant,
+ Bonobo_Control *corba_sidebar_control,
+ Bonobo_Control *corba_view_control,
+ CORBA_Environment *ev)
+{
+ MailComponent *mail_component = MAIL_COMPONENT (bonobo_object_from_servant (servant));
+ MailComponentPrivate *priv = mail_component->priv;
+ EStorageBrowser *browser;
+ GtkWidget *tree_widget;
+ GtkWidget *view_widget;
+ BonoboControl *sidebar_control;
+ BonoboControl *view_control;
+
+ browser = e_storage_browser_new (priv->storage_set, "/", create_view_callback, NULL);
+
+ tree_widget = e_storage_browser_peek_tree_widget (browser);
+ view_widget = e_storage_browser_peek_view_widget (browser);
+
+ gtk_widget_show (tree_widget);
+ gtk_widget_show (view_widget);
+
+ sidebar_control = bonobo_control_new (tree_widget);
+ view_control = bonobo_control_new (view_widget);
+
+ *corba_sidebar_control = CORBA_Object_duplicate (BONOBO_OBJREF (sidebar_control), ev);
+ *corba_view_control = CORBA_Object_duplicate (BONOBO_OBJREF (view_control), ev);
+
+ g_signal_connect_object (browser, "page_switched",
+ G_CALLBACK (browser_page_switched_callback), view_control, 0);
+
+ g_signal_connect(tree_widget, "right_click", G_CALLBACK(emc_tree_right_click), mail_component);
+}
+
+
+/* Initialization. */
+
+static void
+mail_component_class_init (MailComponentClass *class)
+{
+ POA_GNOME_Evolution_Component__epv *epv = &class->epv;
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class->dispose = impl_dispose;
+ object_class->finalize = impl_finalize;
+
+ epv->createControls = impl_createControls;
+}
+
+static void
+mail_component_init (MailComponent *component)
+{
+ MailComponentPrivate *priv;
+ EAccountList *accounts;
+
+ priv = g_new0 (MailComponentPrivate, 1);
+ component->priv = priv;
+
+ /* EPFIXME: Move to a private directory. */
+ /* EPFIXME: Create the directory. */
+ priv->base_directory = g_build_filename (g_get_home_dir (), "evolution", NULL);
+
+ /* EPFIXME: Turn into an object? */
+ mail_session_init (priv->base_directory);
+
+ priv->async_event = mail_async_event_new();
+ priv->storages_hash = g_hash_table_new (NULL, NULL);
+
+ priv->folder_type_registry = e_folder_type_registry_new ();
+ priv->storage_set = e_storage_set_new (priv->folder_type_registry);
+
+#if 0 /* EPFIXME TODO somehow */
+ for (i = 0; i < sizeof (standard_folders) / sizeof (standard_folders[0]); i++)
+ *standard_folders[i].uri = g_strdup_printf ("file://%s/local/%s", evolution_dir, standard_folders[i].name);
+#endif
+ setup_local_store (component);
+
+ accounts = mail_config_get_accounts ();
+ load_accounts(component, accounts);
+
+#if 0
+ /* EPFIXME? */
+ mail_local_storage_startup (shell_client, evolution_dir);
+ mail_importer_init (shell_client);
+
+ for (i = 0; i < sizeof (standard_folders) / sizeof (standard_folders[0]); i++) {
+ mail_msg_wait (mail_get_folder (*standard_folders[i].uri, CAMEL_STORE_FOLDER_CREATE,
+ got_folder, standard_folders[i].folder, mail_thread_new));
+ }
+#endif
+
+ /* mail_autoreceive_setup (); EPFIXME keep it off for testing */
+
+ setup_search_context (component);
+
+#if 0
+ /* EPFIXME this shouldn't be here. */
+ if (mail_config_is_corrupt ()) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE,
+ _("Some of your mail settings seem corrupt, "
+ "please check that everything is in order."));
+ g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
+ gtk_widget_show (dialog);
+ }
+#endif
+
+#if 0
+ /* EPFIXME if we nuke the summary this is not necessary anymore. */
+
+ /* Everything should be ready now */
+ evolution_folder_info_notify_ready ();
+#endif
+
+ /* EPFIXME not sure about this. */
+ go_online (component);
+}
+
+
+/* Public API. */
+
+MailComponent *
+mail_component_peek (void)
+{
+ static MailComponent *component = NULL;
+
+ if (component == NULL) {
+ component = g_object_new (mail_component_get_type (), NULL);
+
+ /* FIXME: this should all be initialised in a starutp routine, not from the peek function,
+ this covers much of the ::init method's content too */
+ vfolder_load_storage();
+ }
+
+ return component;
+}
+
+
+const char *
+mail_component_peek_base_directory (MailComponent *component)
+{
+ return component->priv->base_directory;
+}
+
+RuleContext *
+mail_component_peek_search_context (MailComponent *component)
+{
+ return component->priv->search_context;
+}
+
+
+void
+mail_component_add_store (MailComponent *component,
+ CamelStore *store,
+ const char *name)
+{
+ CamelException ex;
+
+ camel_exception_init (&ex);
+
+ if (name == NULL) {
+ char *service_name;
+
+ service_name = camel_service_get_name ((CamelService *) store, TRUE);
+ add_storage (component, service_name, (CamelService *) store, &ex);
+ g_free (service_name);
+ } else {
+ add_storage (component, name, (CamelService *) store, &ex);
+ }
+
+ camel_exception_clear (&ex);
+}
+
+
+/**
+ * mail_component_load_storage_by_uri:
+ * @component:
+ * @uri:
+ * @name:
+ *
+ *
+ *
+ * Return value: Pointer to the newly added CamelStore. The caller is supposed
+ * to ref the object if it wants to store it.
+ **/
+CamelStore *
+mail_component_load_storage_by_uri (MailComponent *component,
+ const char *uri,
+ const char *name)
+{
+ CamelException ex;
+ CamelService *store;
+ CamelProvider *prov;
+
+ camel_exception_init (&ex);
+
+ /* Load the service (don't connect!). Check its provider and
+ * see if this belongs in the shell's folder list. If so, add
+ * it.
+ */
+
+ prov = camel_session_get_provider (session, uri, &ex);
+ if (prov == NULL) {
+ /* EPFIXME: real error dialog */
+ g_warning ("couldn't get service %s: %s\n", uri,
+ camel_exception_get_description (&ex));
+ camel_exception_clear (&ex);
+ return NULL;
+ }
+
+ if (!(prov->flags & CAMEL_PROVIDER_IS_STORAGE) ||
+ (prov->flags & CAMEL_PROVIDER_IS_EXTERNAL))
+ return NULL;
+
+ store = camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex);
+ if (store == NULL) {
+ /* EPFIXME: real error dialog */
+ g_warning ("couldn't get service %s: %s\n", uri,
+ camel_exception_get_description (&ex));
+ camel_exception_clear (&ex);
+ return NULL;
+ }
+
+ if (name != NULL) {
+ add_storage (component, name, store, &ex);
+ } else {
+ char *service_name;
+
+ service_name = camel_service_get_name (store, TRUE);
+ add_storage (component, service_name, store, &ex);
+ g_free (service_name);
+ }
+
+ if (camel_exception_is_set (&ex)) {
+ /* EPFIXME: real error dialog */
+ g_warning ("Cannot load storage: %s",
+ camel_exception_get_description (&ex));
+ camel_exception_clear (&ex);
+ }
+
+ camel_object_unref (CAMEL_OBJECT (store));
+ return CAMEL_STORE (store); /* (Still has one ref in the hash.) */
+}
+
+
+static void
+store_disconnect (CamelStore *store,
+ void *event_data,
+ void *data)
+{
+ camel_service_disconnect (CAMEL_SERVICE (store), TRUE, NULL);
+ camel_object_unref (CAMEL_OBJECT (store));
+}
+
+void
+mail_component_remove_storage (MailComponent *component,
+ CamelStore *store)
+{
+ MailComponentPrivate *priv = component->priv;
+ EStorage *storage;
+
+ /* Because the storages_hash holds a reference to each store
+ * used as a key in it, none of them will ever be gc'ed, meaning
+ * any call to camel_session_get_{service,store} with the same
+ * URL will always return the same object. So this works.
+ */
+
+ storage = g_hash_table_lookup (priv->storages_hash, store);
+ if (!storage)
+ return;
+
+ g_hash_table_remove (priv->storages_hash, store);
+
+ /* so i guess potentially we could have a race, add a store while one
+ being removed. ?? */
+ mail_note_store_remove (store);
+
+ e_storage_set_remove_storage (priv->storage_set, storage);
+
+ mail_async_event_emit(priv->async_event, MAIL_ASYNC_THREAD, (MailAsyncFunc) store_disconnect, store, NULL, NULL);
+}
+
+
+void
+mail_component_remove_storage_by_uri (MailComponent *component,
+ const char *uri)
+{
+ CamelProvider *prov;
+ CamelService *store;
+
+ prov = camel_session_get_provider (session, uri, NULL);
+ if (!prov)
+ return;
+ if (!(prov->flags & CAMEL_PROVIDER_IS_STORAGE) ||
+ (prov->flags & CAMEL_PROVIDER_IS_EXTERNAL))
+ return;
+
+ store = camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, NULL);
+ if (store != NULL) {
+ mail_component_remove_storage (component, CAMEL_STORE (store));
+ camel_object_unref (CAMEL_OBJECT (store));
+ }
+}
+
+
+EStorage *
+mail_component_lookup_storage (MailComponent *component,
+ CamelStore *store)
+{
+ EStorage *storage;
+
+ /* Because the storages_hash holds a reference to each store
+ * used as a key in it, none of them will ever be gc'ed, meaning
+ * any call to camel_session_get_{service,store} with the same
+ * URL will always return the same object. So this works.
+ */
+
+ storage = g_hash_table_lookup (component->priv->storages_hash, store);
+ if (storage)
+ g_object_ref (storage);
+
+ return storage;
+}
+
+
+int
+mail_component_get_storage_count (MailComponent *component)
+{
+ return g_hash_table_size (component->priv->storages_hash);
+}
+
+
+EStorageSet *
+mail_component_peek_storage_set (MailComponent *component)
+{
+ return component->priv->storage_set;
+}
+
+
+void
+mail_component_storages_foreach (MailComponent *component,
+ GHFunc func,
+ void *data)
+{
+ g_hash_table_foreach (component->priv->storages_hash, func, data);
+}
+
+extern struct _CamelSession *session;
+
+char *em_uri_from_camel(const char *curi)
+{
+ CamelURL *curl;
+ EAccount *account;
+ const char *uid, *path;
+ char *euri;
+ CamelProvider *provider;
+
+ provider = camel_session_get_provider(session, curi, NULL);
+ if (provider == NULL)
+ return g_strdup(curi);
+
+ curl = camel_url_new(curi, NULL);
+ if (curl == NULL)
+ return g_strdup(curi);
+
+ account = mail_config_get_account_by_source_url(curi);
+ uid = (account == NULL)?"local@local":account->uid;
+ path = (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)?curl->fragment:curl->path;
+ if (path[0] == '/')
+ path++;
+ euri = g_strdup_printf("email://%s/%s", uid, path);
+ printf("em uri from camel '%s' -> '%s'\n", curi, euri);
+
+ return euri;
+}
+
+char *em_uri_to_camel(const char *euri)
+{
+ EAccountList *accounts;
+ const EAccount *account;
+ EAccountService *service;
+ CamelProvider *provider;
+ CamelURL *eurl, *curl;
+ char *uid, *curi;
+
+ eurl = camel_url_new(euri, NULL);
+ if (eurl == NULL)
+ return g_strdup(euri);
+
+ if (strcmp(eurl->protocol, "email") != 0) {
+ camel_url_free(eurl);
+ return g_strdup(euri);
+ }
+
+ g_assert(eurl->user != NULL);
+ g_assert(eurl->host != NULL);
+
+ if (strcmp(eurl->user, "local") == 0 && strcmp(eurl->host, "local") == 0) {
+ /* FIXME: needs to track real local store location */
+ curi = g_strdup_printf("mbox:%s/.evolution/mail/local#%s", g_get_home_dir(), eurl->path);
+ camel_url_free(eurl);
+ return curi;
+ }
+
+ uid = g_strdup_printf("%s@%s", eurl->user, eurl->host);
+
+ accounts = mail_config_get_accounts();
+ account = e_account_list_find(accounts, E_ACCOUNT_FIND_UID, uid);
+ g_free(uid);
+
+ if (account == NULL) {
+ camel_url_free(eurl);
+ return g_strdup(euri);
+ }
+
+ service = account->source;
+ provider = camel_session_get_provider(session, service->url, NULL);
+
+ curl = camel_url_new(service->url, NULL);
+ if (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)
+ camel_url_set_fragment(curl, eurl->path);
+ else
+ camel_url_set_path(curl, eurl->path);
+
+ curi = camel_url_to_string(curl, 0);
+
+ camel_url_free(eurl);
+ camel_url_free(curl);
+
+ printf("em uri to camel '%s' -> '%s'\n", euri, curi);
+
+ return curi;
+}
+
+
+CamelFolder *
+mail_component_get_folder_from_evomail_uri (MailComponent *component,
+ guint32 flags,
+ const char *evomail_uri,
+ CamelException *ex)
+{
+ CamelException local_ex;
+ EAccountList *accounts;
+ EIterator *iter;
+ const char *p;
+ const char *q;
+ const char *folder_name;
+ char *uid;
+
+ camel_exception_init (&local_ex);
+
+ if (strncmp (evomail_uri, "evomail:", 8) != 0)
+ return NULL;
+
+ p = evomail_uri + 8;
+ while (*p == '/')
+ p ++;
+
+ q = strchr (p, '/');
+ if (q == NULL)
+ return NULL;
+
+ uid = g_strndup (p, q - p);
+ folder_name = q + 1;
+
+ /* since we have no explicit account for 'local' folders, make one up */
+ if (strcmp(uid, "local") == 0) {
+ g_free(uid);
+ return camel_store_get_folder(component->priv->local_store, folder_name, flags, ex);
+ }
+
+ accounts = mail_config_get_accounts ();
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ EAccount *account = (EAccount *) e_iterator_get (iter);
+ EAccountService *service = account->source;
+ CamelProvider *provider;
+ CamelStore *store;
+
+ if (strcmp (account->uid, uid) != 0)
+ continue;
+
+ provider = camel_session_get_provider (session, service->url, &local_ex);
+ if (provider == NULL)
+ goto fail;
+
+ store = (CamelStore *) camel_session_get_service (session, service->url, CAMEL_PROVIDER_STORE, &local_ex);
+ if (store == NULL)
+ goto fail;
+
+ g_free (uid);
+ return camel_store_get_folder (store, folder_name, flags, ex);
+ }
+
+ fail:
+ camel_exception_clear (&local_ex);
+ g_free (uid);
+ return NULL;
+}
+
+
+char *
+mail_component_evomail_uri_from_folder (MailComponent *component,
+ CamelFolder *folder)
+{
+ CamelStore *store = camel_folder_get_parent_store (folder);
+ EAccount *account;
+ char *service_url;
+ char *evomail_uri;
+ const char *uid;
+
+ if (store == NULL)
+ return NULL;
+
+ service_url = camel_service_get_url (CAMEL_SERVICE (store));
+ account = mail_config_get_account_by_source_url (service_url);
+
+ if (account == NULL) {
+ /* since we have no explicit account for 'local' folders, make one up */
+ /* TODO: check the folder is really a local one, folder->parent_store == local_store? */
+ uid = "local";
+ /*g_free (service_url);
+ return NULL;*/
+ } else {
+ uid = account->uid;
+ }
+
+ evomail_uri = g_strconcat ("evomail:///", uid, "/", camel_folder_get_full_name (folder), NULL);
+ g_free (service_url);
+
+ return evomail_uri;
+}
+
+
+BONOBO_TYPE_FUNC_FULL (MailComponent, GNOME_Evolution_Component, PARENT_TYPE, mail_component)
+
+
+/* ********************************************************************** */
+#if 0
+static void
+emc_popup_view(GtkWidget *w, MailComponent *mc)
+{
+
+}
+
+static void
+emc_popup_open_new(GtkWidget *w, MailComponent *mc)
+{
+}
+#endif
+
+static void
+em_copy_folders(CamelStore *tostore, const char *tobase, CamelStore *fromstore, const char *frombase, int delete)
+{
+ GString *toname, *fromname;
+ CamelFolderInfo *fi;
+ GList *pending = NULL;
+ guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE;
+ CamelException *ex = camel_exception_new();
+ int fromlen;
+ const char *tmp;
+
+ if (camel_store_supports_subscriptions(fromstore))
+ flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+
+ fi = camel_store_get_folder_info(fromstore, frombase, flags, ex);
+ if (camel_exception_is_set(ex))
+ goto done;
+
+ pending = g_list_append(pending, fi);
+
+ toname = g_string_new("");
+ fromname = g_string_new("");
+
+ tmp = strrchr(frombase, '/');
+ if (tmp == NULL)
+ fromlen = 0;
+ else
+ fromlen = tmp-frombase;
+
+ printf("top name is '%s'\n", fi->full_name);
+
+ while (pending) {
+ CamelFolderInfo *info = pending->data;
+
+ pending = g_list_remove_link(pending, pending);
+ while (info) {
+ CamelFolder *fromfolder, *tofolder;
+ GPtrArray *uids;
+
+ if (info->child)
+ pending = g_list_append(pending, info->child);
+ g_string_printf(toname, "%s/%s", tobase, info->full_name + fromlen);
+
+ printf("Copying from '%s' to '%s'\n", info->full_name, toname->str);
+
+ /* This makes sure we create the same tree, e.g. from a nonselectable source */
+ /* Not sure if this is really the 'right thing', e.g. for spool stores, but it makes the ui work */
+ fromfolder = camel_store_get_folder(fromstore, info->full_name, 0, ex);
+ tofolder = camel_store_get_folder(tostore, toname->str, CAMEL_STORE_FOLDER_CREATE, ex);
+ if (tofolder == NULL) {
+ if (fromfolder)
+ camel_object_unref(fromfolder);
+ goto exception;
+ }
+
+ if (fromfolder) {
+ uids = camel_folder_get_uids(fromfolder);
+ camel_folder_transfer_messages_to(fromfolder, uids, tofolder, NULL, FALSE, ex);
+ camel_folder_free_uids(fromfolder, uids);
+
+ camel_object_unref(fromfolder);
+ }
+ camel_object_unref(tofolder);
+ if (camel_exception_is_set(ex))
+ goto exception;
+ info = info->sibling;
+ }
+ }
+
+ camel_store_free_folder_info(fromstore, fi);
+
+exception:
+ g_string_free(toname, TRUE);
+ g_string_free(fromname, TRUE);
+done:
+ printf("exception: %s\n", ex->desc?ex->desc:"<none>");
+ camel_exception_free(ex);
+}
+
+struct _copy_folder_data {
+ MailComponent *mc;
+ int delete;
+};
+
+static void
+emc_popup_copy_folder_selected(const char *uri, void *data)
+{
+ struct _copy_folder_data *d = data;
+
+ if (uri == NULL) {
+ g_free(d);
+ return;
+ }
+
+ if (uri) {
+ EFolder *folder = e_storage_set_get_folder(d->mc->priv->storage_set, d->mc->priv->context_path);
+ CamelException *ex = camel_exception_new();
+ CamelStore *fromstore, *tostore;
+ char *tobase, *frombase;
+ CamelURL *url;
+
+ printf("copying folder '%s' to '%s'\n", d->mc->priv->context_path, uri);
+
+ fromstore = camel_session_get_store(session, e_folder_get_physical_uri(folder), ex);
+ frombase = strchr(d->mc->priv->context_path+1, '/')+1;
+
+ tostore = camel_session_get_store(session, uri, ex);
+ url = camel_url_new(uri, NULL);
+ if (url->fragment)
+ tobase = url->fragment;
+ else
+ tobase = url->path;
+
+ em_copy_folders(tostore, tobase, fromstore, frombase, d->delete);
+
+ camel_url_free(url);
+ camel_exception_free(ex);
+ }
+ g_free(d);
+}
+
+static void
+emc_popup_copy(GtkWidget *w, MailComponent *mc)
+{
+ struct _copy_folder_data *d;
+
+ d = g_malloc(sizeof(*d));
+ d->mc = mc;
+ d->delete = 0;
+ em_select_folder(NULL, _("Select folder"), _("Select destination to copy folder into"), NULL, emc_popup_copy_folder_selected, d);
+}
+
+static void
+emc_popup_move(GtkWidget *w, MailComponent *mc)
+{
+ struct _copy_folder_data *d;
+
+ d = g_malloc(sizeof(*d));
+ d->mc = mc;
+ d->delete = 1;
+ em_select_folder(NULL, _("Select folder"), _("Select destination to move folder into"), NULL, emc_popup_copy_folder_selected, d);
+}
+static void
+emc_popup_new_folder_create(EStorageSet *ess, EStorageResult result, void *data)
+{
+ printf("folder created %s\n", result == E_STORAGE_OK?"ok":"failed");
+}
+
+static void
+emc_popup_new_folder_response(EMFolderSelector *emfs, guint response, MailComponent *mc)
+{
+ if (response == GTK_RESPONSE_OK) {
+ char *path, *tmp, *name, *full;
+ EStorage *storage;
+ CamelStore *store;
+ CamelException *ex;
+
+ printf("Creating folder: %s (%s)\n", em_folder_selector_get_selected(emfs),
+ em_folder_selector_get_selected_uri(emfs));
+
+ path = g_strdup(em_folder_selector_get_selected(emfs));
+ tmp = strchr(path+1, '/');
+ *tmp++ = 0;
+ /* FIXME: camel_store_create_folder should just take full path names */
+ full = g_strdup(tmp);
+ name = strrchr(tmp, '/');
+ if (name == NULL) {
+ name = tmp;
+ tmp = "";
+ } else
+ *name++ = 0;
+
+ storage = e_storage_set_get_storage(mc->priv->storage_set, path+1);
+ store = g_object_get_data((GObject *)storage, "em-store");
+
+ printf("creating folder '%s' / '%s' on '%s'\n", tmp, name, path+1);
+
+ ex = camel_exception_new();
+ camel_store_create_folder(store, tmp, name, ex);
+ if (camel_exception_is_set(ex)) {
+ printf("Create failed: %s\n", ex->desc);
+ } else if (camel_store_supports_subscriptions(store)) {
+ camel_store_subscribe_folder(store, full, ex);
+ if (camel_exception_is_set(ex)) {
+ printf("Subscribe failed: %s\n", ex->desc);
+ }
+ }
+
+ camel_exception_free(ex);
+
+ g_free(full);
+ g_free(path);
+
+ /* Blah, this should just use camel, we get better error reporting if we do too */
+ /*e_storage_set_async_create_folder(mc->priv->storage_set, path, "mail", "", emc_popup_new_folder_create, mc);*/
+ }
+ gtk_widget_destroy((GtkWidget *)emfs);
+}
+
+static void
+emc_popup_new_folder (GtkWidget *w, MailComponent *mc)
+{
+ GtkWidget *dialog;
+
+ dialog = em_folder_selector_create_new(mc->priv->storage_set, 0, _("Create folder"), _("Specify where to create the folder:"));
+ em_folder_selector_set_selected((EMFolderSelector *)dialog, mc->priv->context_path);
+ g_signal_connect(dialog, "response", G_CALLBACK(emc_popup_new_folder_response), mc);
+ gtk_widget_show(dialog);
+}
+
+static void
+em_delete_rec(CamelStore *store, CamelFolderInfo *fi, CamelException *ex)
+{
+ while (fi) {
+ CamelFolder *folder;
+
+ if (fi->child)
+ em_delete_rec(store, fi->child, ex);
+ if (camel_exception_is_set(ex))
+ return;
+
+ printf("deleting folder '%s'\n", fi->full_name);
+
+ if (camel_store_supports_subscriptions(store))
+ camel_store_unsubscribe_folder(store, fi->full_name, NULL);
+
+ folder = camel_store_get_folder(store, fi->full_name, 0, NULL);
+ if (folder) {
+ GPtrArray *uids = camel_folder_get_uids(folder);
+ int i;
+
+ camel_folder_freeze(folder);
+ for (i = 0; i < uids->len; i++)
+ camel_folder_delete_message(folder, uids->pdata[i]);
+ camel_folder_sync(folder, TRUE, NULL);
+ camel_folder_thaw(folder);
+ camel_folder_free_uids(folder, uids);
+ }
+
+ camel_store_delete_folder(store, fi->full_name, ex);
+ if (camel_exception_is_set(ex))
+ return;
+ fi = fi->sibling;
+ }
+}
+
+static void
+em_delete_folders(CamelStore *store, const char *base, CamelException *ex)
+{
+ CamelFolderInfo *fi;
+ guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE;
+
+ if (camel_store_supports_subscriptions(store))
+ flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+
+ fi = camel_store_get_folder_info(store, base, flags, ex);
+ if (camel_exception_is_set(ex))
+ return;
+
+ em_delete_rec(store, fi, ex);
+ camel_store_free_folder_info(store, fi);
+}
+
+static void
+emc_popup_delete_response(GtkWidget *w, guint response, MailComponent *mc)
+{
+ gtk_widget_destroy(w);
+
+ if (response == GTK_RESPONSE_OK) {
+ const char *path = strchr(mc->priv->context_path+1, '/')+1;
+ EFolder *folder = e_storage_set_get_folder(mc->priv->storage_set, mc->priv->context_path);
+ CamelException *ex = camel_exception_new();
+ CamelStore *store;
+
+ /* FIXME: need to hook onto store changed event and delete view as well, somewhere else tho */
+ store = camel_session_get_store(session, e_folder_get_physical_uri(folder), ex);
+ if (camel_exception_is_set(ex))
+ goto exception;
+
+ em_delete_folders(store, path, ex);
+ if (!camel_exception_is_set(ex))
+ goto noexception;
+ exception:
+ e_notice(NULL, GTK_MESSAGE_ERROR,
+ _("Could not delete folder: %s"), ex->desc);
+ noexception:
+ camel_exception_free(ex);
+ if (store)
+ camel_object_unref(store);
+ }
+}
+
+static void
+emc_popup_delete_folder(GtkWidget *w, MailComponent *mc)
+{
+ GtkWidget *dialog;
+ char *title;
+ const char *path = strchr(mc->priv->context_path+1, '/')+1;
+ EFolder *folder;
+
+ folder = e_storage_set_get_folder(mc->priv->storage_set, mc->priv->context_path);
+ if (folder == NULL)
+ return;
+
+ dialog = gtk_message_dialog_new(NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("Really delete folder \"%s\" and all of its subfolders?"), path);
+
+ gtk_dialog_add_button((GtkDialog *)dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button((GtkDialog *)dialog, GTK_STOCK_DELETE, GTK_RESPONSE_OK);
+
+ gtk_dialog_set_default_response((GtkDialog *)dialog, GTK_RESPONSE_OK);
+ gtk_container_set_border_width((GtkContainer *)dialog, 6);
+ gtk_box_set_spacing((GtkBox *)((GtkDialog *)dialog)->vbox, 6);
+
+ title = g_strdup_printf(_("Delete \"%s\""), path);
+ gtk_window_set_title((GtkWindow *)dialog, title);
+ g_free(title);
+
+ g_signal_connect(dialog, "response", G_CALLBACK(emc_popup_delete_response), mc);
+ gtk_widget_show(dialog);
+}
+
+static void
+emc_popup_rename_folder(GtkWidget *w, MailComponent *mc)
+{
+ char *prompt, *new;
+ EFolder *folder;
+ const char *old, *why;
+ int done = 0;
+
+ folder = e_storage_set_get_folder(mc->priv->storage_set, mc->priv->context_path);
+ if (folder == NULL)
+ return;
+
+ old = e_folder_get_name(folder);
+ prompt = g_strdup_printf (_("Rename the \"%s\" folder to:"), e_folder_get_name(folder));
+ while (!done) {
+ new = e_request_string(NULL, _("Rename Folder"), prompt, old);
+ if (new == NULL || strcmp(old, new) == 0)
+ done = 1;
+#if 0
+ else if (!e_shell_folder_name_is_valid(new, &why))
+ e_notice(NULL, GTK_MESSAGE_ERROR, _("The specified folder name is not valid: %s"), why);
+#endif
+ else {
+ char *base, *path;
+
+ /* FIXME: we can't use the os independent path crap here, since we want to control the format */
+ base = g_path_get_dirname(mc->priv->context_path);
+ path = g_build_filename(base, new, NULL);
+
+ if (e_storage_set_get_folder(mc->priv->storage_set, path) != NULL) {
+ e_notice(NULL, GTK_MESSAGE_ERROR,
+ _("A folder named \"%s\" already exists. Please use a different name."), new);
+ } else {
+ CamelStore *store;
+ CamelException *ex = camel_exception_new();
+ const char *oldpath, *newpath;
+
+ oldpath = strchr(mc->priv->context_path+1, '/');
+ g_assert(oldpath);
+ newpath = strchr(path+1, '/');
+ g_assert(newpath);
+ oldpath++;
+ newpath++;
+
+ printf("renaming %s to %s\n", oldpath, newpath);
+
+ store = camel_session_get_store(session, e_folder_get_physical_uri(folder), ex);
+ if (camel_exception_is_set(ex))
+ goto exception;
+
+ camel_store_rename_folder(store, oldpath, newpath, ex);
+ if (!camel_exception_is_set(ex))
+ goto noexception;
+
+ exception:
+ e_notice(NULL, GTK_MESSAGE_ERROR,
+ _("Could not rename folder: %s"), ex->desc);
+ noexception:
+ if (store)
+ camel_object_unref(store);
+ camel_exception_free(ex);
+
+ done = 1;
+ }
+ g_free(path);
+ g_free(base);
+ }
+ g_free(new);
+ }
+}
+
+struct _prop_data {
+ void *object;
+ CamelArgV *argv;
+ GtkWidget **widgets;
+};
+
+static void
+emc_popup_properties_response(GtkWidget *dialog, int response, struct _prop_data *prop_data)
+{
+ int i;
+ CamelArgV *argv = prop_data->argv;
+
+ if (response != GTK_RESPONSE_OK) {
+ gtk_widget_destroy(dialog);
+ return;
+ }
+
+ for (i=0;i<argv->argc;i++) {
+ CamelArg *arg = &argv->argv[i];
+
+ switch (arg->tag & CAMEL_ARG_TYPE) {
+ case CAMEL_ARG_BOO:
+ arg->ca_int = gtk_toggle_button_get_active(prop_data->widgets[i]);
+ break;
+ case CAMEL_ARG_STR:
+ g_free(arg->ca_str);
+ arg->ca_str = gtk_entry_get_text(prop_data->widgets[i]);
+ break;
+ default:
+ printf("unknown property type set\n");
+ }
+ }
+
+ camel_object_setv(prop_data->object, NULL, argv);
+ gtk_widget_destroy(dialog);
+}
+
+static void
+emc_popup_properties_free(void *data)
+{
+ struct _prop_data *prop_data = data;
+ int i;
+
+ for (i=0; i<prop_data->argv->argc; i++) {
+ if ((prop_data->argv->argv[i].tag & CAMEL_ARG_TYPE) == CAMEL_ARG_STR)
+ g_free(prop_data->argv->argv[i].ca_str);
+ }
+ camel_object_unref(prop_data->object);
+ g_free(prop_data->argv);
+ g_free(prop_data);
+}
+
+static void
+emc_popup_properties_got_folder(const char *uri, CamelFolder *folder, void *data)
+{
+ MailComponent *mc = data;
+
+ if (folder) {
+ GtkWidget *dialog, *w, *table, *label;
+ GSList *list, *l;
+ char *name, *txt;
+ int row = 1;
+ gint32 count, i;
+ struct _prop_data *prop_data;
+ CamelArgV *argv;
+ CamelArgGetV *arggetv;
+
+ camel_object_get(folder, NULL, CAMEL_FOLDER_PROPERTIES, &list, CAMEL_FOLDER_NAME, &name, NULL);
+
+ dialog = gtk_dialog_new_with_buttons(_("Folder properties"),
+ NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK,
+ NULL);
+
+ /* TODO: maybe we want some basic properties here, like message counts/approximate size/etc */
+ w = gtk_frame_new(_("Properties"));
+ gtk_box_pack_start(((GtkDialog *)dialog)->vbox, w, TRUE, TRUE, 6);
+ table = gtk_table_new(g_slist_length(list)+1, 2, FALSE);
+ gtk_container_add((GtkContainer *)w, table);
+ label = gtk_label_new(_("Folder Name"));
+ gtk_misc_set_alignment(label, 1.0, 0.5);
+ gtk_table_attach(table, label, 0, 1, 0, 1, GTK_FILL|GTK_EXPAND, 0, 3, 0);
+ label = gtk_label_new(name);
+ gtk_misc_set_alignment(label, 0.0, 0.5);
+ gtk_table_attach(table, label, 1, 2, 0, 1, GTK_FILL|GTK_EXPAND, 0, 3, 0);
+
+ /* build an arggetv/argv to retrieve/store the results */
+ count = g_slist_length(list);
+ arggetv = g_malloc0(sizeof(*arggetv) + (count - CAMEL_ARGV_MAX) * sizeof(arggetv->argv[0]));
+ arggetv->argc = count;
+ argv = g_malloc0(sizeof(*argv) + (count - CAMEL_ARGV_MAX) * sizeof(argv->argv[0]));
+ argv->argc = count;
+ i = 0;
+ l = list;
+ while (l) {
+ CamelProperty *prop = l->data;
+
+ argv->argv[i].tag = prop->tag;
+ arggetv->argv[i].tag = prop->tag;
+ arggetv->argv[i].ca_ptr = &argv->argv[i].ca_ptr;
+
+ l = l->next;
+ i++;
+ }
+ camel_object_getv(folder, NULL, arggetv);
+ g_free(arggetv);
+
+ prop_data = g_malloc0(sizeof(*prop_data));
+ prop_data->widgets = g_malloc0(sizeof(prop_data->widgets[0]) * count);
+ prop_data->argv = argv;
+
+ /* setup the ui with the values retrieved */
+ l = list;
+ i = 0;
+ while (l) {
+ CamelProperty *prop = l->data;
+
+ switch (prop->tag & CAMEL_ARG_TYPE) {
+ case CAMEL_ARG_BOO:
+ w = gtk_check_button_new_with_label(prop->description);
+ gtk_toggle_button_set_active((GtkToggleButton *)w, argv->argv[i].ca_int != 0);
+ gtk_table_attach(table, w, 0, 2, row, row+1, 0, 0, 3, 3);
+ prop_data->widgets[i] = w;
+ break;
+ case CAMEL_ARG_STR:
+ label = gtk_label_new(prop->description);
+ gtk_misc_set_alignment(label, 1.0, 0.5);
+ gtk_table_attach(table, label, 0, 1, row, row+1, GTK_FILL|GTK_EXPAND, 0, 3, 3);
+
+ w = gtk_entry_new();
+ if (argv->argv[i].ca_str) {
+ gtk_entry_set_text((GtkEntry *)w, txt);
+ camel_object_free(folder, argv->argv[i].tag, argv->argv[i].ca_str);
+ argv->argv[i].ca_str = NULL;
+ }
+ gtk_table_attach(table, w, 1, 2, row, row+1, GTK_FILL, 0, 3, 3);
+ prop_data->widgets[i] = w;
+ break;
+ default:
+ w = gtk_label_new("CamelFolder error: unsupported propery type");
+ gtk_table_attach(table, w, 0, 2, row, row+1, 0, 0, 3, 3);
+ break;
+ }
+
+ row++;
+ l = l->next;
+ }
+
+ prop_data->object = folder;
+ camel_object_ref(folder);
+
+ camel_object_free(folder, CAMEL_FOLDER_PROPERTIES, list);
+ camel_object_free(folder, CAMEL_FOLDER_NAME, name);
+
+ /* we do 'apply on ok' ... since instant apply may apply some very long running tasks */
+
+ g_signal_connect(dialog, "response", G_CALLBACK(emc_popup_properties_response), prop_data);
+ g_object_set_data_full((GObject *)dialog, "e-prop-data", prop_data, emc_popup_properties_free);
+ gtk_widget_show_all(dialog);
+ }
+}
+
+static void
+emc_popup_properties(GtkWidget *w, MailComponent *mc)
+{
+ EFolder *efolder;
+
+ /* TODO: Make sure we only have one dialog open for any given folder */
+
+ efolder = e_storage_set_get_folder(mc->priv->storage_set, mc->priv->context_path);
+ if (efolder == NULL)
+ return;
+
+ mail_get_folder(e_folder_get_physical_uri(efolder), 0, emc_popup_properties_got_folder, mc, mail_thread_new);
+}
+
+static EMPopupItem emc_popup_menu[] = {
+#if 0
+ { EM_POPUP_ITEM, "00.emc.00", N_("_View"), G_CALLBACK(emc_popup_view), NULL, NULL, 0 },
+ { EM_POPUP_ITEM, "00.emc.01", N_("Open in _New Window"), G_CALLBACK(emc_popup_open_new), NULL, NULL, 0 },
+
+ { EM_POPUP_BAR, "10.emc" },
+#endif
+ { EM_POPUP_ITEM, "10.emc.00", N_("_Copy"), G_CALLBACK(emc_popup_copy), NULL, "folder-copy-16.png", 0 },
+ { EM_POPUP_ITEM, "10.emc.01", N_("_Move"), G_CALLBACK(emc_popup_move), NULL, "folder-move-16.png", 0 },
+
+ { EM_POPUP_BAR, "20.emc" },
+ { EM_POPUP_ITEM, "20.emc.00", N_("_New Folder..."), G_CALLBACK(emc_popup_new_folder), NULL, "folder-mini.png", 0 },
+ { EM_POPUP_ITEM, "20.emc.01", N_("_Delete"), G_CALLBACK(emc_popup_delete_folder), NULL, "evolution-trash-mini.png", 0 },
+ { EM_POPUP_ITEM, "20.emc.01", N_("_Rename"), G_CALLBACK(emc_popup_rename_folder), NULL, NULL, 0 },
+
+ { EM_POPUP_BAR, "80.emc" },
+ { EM_POPUP_ITEM, "80.emc.00", N_("_Properties..."), G_CALLBACK(emc_popup_properties), NULL, "configure_16_folder.xpm", 0 },
+};
+
+
+static int
+emc_tree_right_click(ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, MailComponent *component)
+{
+ char *name;
+ ETreeModel *model = e_tree_get_model(tree);
+ EMPopup *emp;
+ int i;
+ GSList *menus = NULL;
+ struct _GtkMenu *menu;
+
+ name = e_tree_memory_node_get_data((ETreeMemory *)model, path);
+ g_free(component->priv->context_path);
+ component->priv->context_path = g_strdup(name);
+ printf("right click, path = '%s'\n", name);
+
+ emp = em_popup_new("com.ximian.mail.storageset.popup.select");
+
+ for (i=0;i<sizeof(emc_popup_menu)/sizeof(emc_popup_menu[0]);i++) {
+ EMPopupItem *item = &emc_popup_menu[i];
+
+ item->activate_data = component;
+ menus = g_slist_prepend(menus, item);
+ }
+
+ em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free);
+
+ menu = em_popup_create_menu_once(emp, NULL, 0, 0);
+
+ if (event == NULL || event->type == GDK_KEY_PRESS) {
+ /* FIXME: menu pos function */
+ gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, event->key.time);
+ } else {
+ gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button.button, event->button.time);
+ }
+
+ return TRUE;
+}
diff --git a/mail/mail-component.h b/mail/mail-component.h
new file mode 100644
index 0000000000..3e832752df
--- /dev/null
+++ b/mail/mail-component.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* mail-component.h
+ *
+ * Copyright (C) 2003 Ximian Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * Authors:
+ * Michael Zucchi <notzed@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ * Ettore Perazzoli <ettore@ximian.com>
+ */
+
+#ifndef _MAIL_COMPONENT_H_
+#define _MAIL_COMPONENT_H_
+
+#include <bonobo/bonobo-object.h>
+
+#include <camel/camel-store.h>
+
+#include "e-storage-set.h"
+#include "Evolution.h"
+
+#include "filter/rule-context.h"
+
+
+#define MAIL_TYPE_COMPONENT (mail_component_get_type ())
+#define MAIL_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAIL_TYPE_COMPONENT, MailComponent))
+#define MAIL_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAIL_TYPE_COMPONENT, MailComponentClass))
+#define MAIL_IS_COMPONENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAIL_TYPE_COMPONENT))
+#define MAIL_IS_COMPONENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), MAIL_TYPE_COMPONENT))
+
+
+typedef struct _MailComponent MailComponent;
+typedef struct _MailComponentPrivate MailComponentPrivate;
+typedef struct _MailComponentClass MailComponentClass;
+
+struct _MailComponent {
+ BonoboObject parent;
+
+ MailComponentPrivate *priv;
+};
+
+struct _MailComponentClass {
+ BonoboObjectClass parent_class;
+
+ POA_GNOME_Evolution_Component__epv epv;
+};
+
+
+GType mail_component_get_type (void);
+
+MailComponent *mail_component_peek (void);
+
+const char *mail_component_peek_base_directory (MailComponent *component);
+RuleContext *mail_component_peek_search_context (MailComponent *component);
+
+void mail_component_add_store (MailComponent *component,
+ CamelStore *store,
+ const char *name);
+CamelStore *mail_component_load_storage_by_uri (MailComponent *component,
+ const char *uri,
+ const char *name);
+void mail_component_remove_storage (MailComponent *component,
+ CamelStore *store);
+void mail_component_remove_storage_by_uri (MailComponent *component,
+ const char *uri);
+EStorage *mail_component_lookup_storage (MailComponent *component,
+ CamelStore *store);
+
+int mail_component_get_storage_count (MailComponent *component);
+EStorageSet *mail_component_peek_storage_set (MailComponent *component);
+void mail_component_storages_foreach (MailComponent *component,
+ GHFunc func,
+ void *data);
+
+char *em_uri_from_camel (const char *curi);
+char *em_uri_to_camel (const char *euri);
+
+CamelFolder *mail_component_get_folder_from_evomail_uri (MailComponent *component,
+ guint32 flags,
+ const char *evomail_uri,
+ CamelException *ex);
+char *mail_component_evomail_uri_from_folder (MailComponent *component,
+ CamelFolder *folder);
+
+#endif /* _MAIL_COMPONENT_H_ */
diff --git a/mail/mail-config-factory.c b/mail/mail-config-factory.c
index 5a6db2cb47..50fddb9be9 100644
--- a/mail/mail-config-factory.c
+++ b/mail/mail-config-factory.c
@@ -34,8 +34,6 @@
#define CONFIG_CONTROL_FACTORY_ID "OAFIID:GNOME_Evolution_Mail_ConfigControlFactory"
-static BonoboGenericFactory *factory = NULL;
-
typedef void (*ApplyFunc) (GtkWidget *prefs);
diff --git a/mail/mail-config.c b/mail/mail-config.c
index a357f74498..f75babcf36 100644
--- a/mail/mail-config.c
+++ b/mail/mail-config.c
@@ -53,7 +53,9 @@
#include <gal/widgets/e-gui-utils.h>
#include <e-util/e-url.h>
#include <e-util/e-passwords.h>
+
#include "mail.h"
+#include "mail-component.h"
#include "mail-config.h"
#include "mail-mt.h"
#include "mail-tools.h"
@@ -448,6 +450,8 @@ config_write_style (void)
* may not have been set yet
*
* filename = g_build_filename (evolution_dir, MAIL_CONFIG_RC, NULL);
+ *
+ * EPFIXME this kludge needs to go away.
*/
filename = g_build_filename (g_get_home_dir (), "evolution", MAIL_CONFIG_RC, NULL);
@@ -528,6 +532,7 @@ mail_config_init (void)
mail_config_clear ();
/*
+ EPFIXME: This kludge needs to go away.
filename = g_build_filename (evolution_dir, MAIL_CONFIG_RC, NULL);
*/
filename = g_build_filename (g_get_home_dir (), "evolution", MAIL_CONFIG_RC, NULL);
@@ -933,6 +938,7 @@ mail_config_get_default_transport (void)
static char *
uri_to_evname (const char *uri, const char *prefix)
{
+ const char *base_directory = mail_component_peek_base_directory (mail_component_peek ());
char *safe;
char *tmp;
@@ -940,9 +946,9 @@ uri_to_evname (const char *uri, const char *prefix)
e_filename_make_safe (safe);
/* blah, easiest thing to do */
if (prefix[0] == '*')
- tmp = g_strdup_printf ("%s/%s%s.xml", evolution_dir, prefix + 1, safe);
+ tmp = g_strdup_printf ("%s/%s%s.xml", base_directory, prefix + 1, safe);
else
- tmp = g_strdup_printf ("%s/%s%s", evolution_dir, prefix, safe);
+ tmp = g_strdup_printf ("%s/%s%s", base_directory, prefix, safe);
g_free (safe);
return tmp;
}
@@ -1057,7 +1063,10 @@ mail_config_folder_to_cachename (CamelFolder *folder, const char *prefix)
char *url, *filename;
url = mail_config_folder_to_safe_url (folder);
- filename = g_strdup_printf ("%s/config/%s%s", evolution_dir, prefix, url);
+ filename = g_strdup_printf ("%s/config/%s%s",
+ mail_component_peek_base_directory (mail_component_peek ()),
+ prefix,
+ url);
g_free (url);
return filename;
@@ -1328,22 +1337,24 @@ mail_config_get_signature_list (void)
static char *
get_new_signature_filename (void)
{
+ const char *base_directory;
char *filename, *id;
struct stat st;
int i;
-
- filename = g_build_filename (evolution_dir, "/signatures", NULL);
+
+ base_directory = mail_component_peek_base_directory (mail_component_peek ());
+ filename = g_build_filename (base_directory, "signatures", NULL);
if (lstat (filename, &st)) {
if (errno == ENOENT) {
if (mkdir (filename, 0700))
- g_warning ("Fatal problem creating %s/signatures directory.", evolution_dir);
+ g_warning ("Fatal problem creating %s directory.", filename);
} else
- g_warning ("Fatal problem with %s/signatures directory.", evolution_dir);
+ g_warning ("Fatal problem with %s directory.", filename);
}
g_free (filename);
- filename = g_malloc (strlen (evolution_dir) + sizeof ("/signatures/signature-") + 12);
- id = g_stpcpy (filename, evolution_dir);
+ filename = g_malloc (strlen (base_directory) + sizeof ("/signatures/signature-") + 12);
+ id = g_stpcpy (filename, base_directory);
id = g_stpcpy (id, "/signatures/signature-");
for (i = 0; i < (INT_MAX - 1); i++) {
@@ -1400,7 +1411,8 @@ delete_unused_signature_file (const char *filename)
char *signatures_dir;
int len;
- signatures_dir = g_strconcat (evolution_dir, "/signatures", NULL);
+ signatures_dir = g_strconcat (mail_component_peek_base_directory (mail_component_peek ()),
+ "/signatures", NULL);
/* remove signature file if it's in evolution dir and no other signature uses it */
len = strlen (signatures_dir);
diff --git a/mail/mail-display-stream.c b/mail/mail-display-stream.c
new file mode 100644
index 0000000000..ae81401680
--- /dev/null
+++ b/mail/mail-display-stream.c
@@ -0,0 +1,104 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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>
+#endif
+
+#include "mail-display-stream.h"
+
+
+static void mail_display_stream_class_init (MailDisplayStreamClass *klass);
+static void mail_display_stream_init (CamelObject *object);
+static void mail_display_stream_finalize (CamelObject *object);
+
+static ssize_t stream_write (CamelStream *stream, const char *buffer, size_t n);
+
+
+static CamelStreamClass *parent_class = NULL;
+
+
+CamelType
+mail_display_stream_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (CAMEL_STREAM_TYPE,
+ "MailDisplayStream",
+ sizeof (MailDisplayStream),
+ sizeof (MailDisplayStreamClass),
+ (CamelObjectClassInitFunc) mail_display_stream_class_init,
+ NULL,
+ (CamelObjectInitFunc) mail_display_stream_init,
+ (CamelObjectFinalizeFunc) mail_display_stream_finalize);
+ }
+
+ return type;
+}
+
+static void
+mail_display_stream_class_init (MailDisplayStreamClass *klass)
+{
+ CamelStreamClass *stream_class = CAMEL_STREAM_CLASS (klass);
+
+ parent_class = (CamelStreamClass *) CAMEL_STREAM_TYPE;
+
+ /* virtual method overload */
+ stream_class->write = stream_write;
+}
+
+static void
+mail_display_stream_init (CamelObject *object)
+{
+ ;
+}
+
+static void
+mail_display_stream_finalize (CamelObject *object)
+{
+ ;
+}
+
+static ssize_t
+stream_write (CamelStream *stream, const char *buffer, size_t n)
+{
+ MailDisplayStream *dstream = MAIL_DISPLAY_STREAM (stream);
+
+ gtk_html_write (dstream->html, dstream->html_stream, buffer, n);
+
+ return (ssize_t) n;
+}
+
+
+CamelStream *
+mail_display_stream_new (GtkHTML *html, GtkHTMLStream *html_stream)
+{
+ MailDisplayStream *new;
+
+ new = MAIL_DISPLAY_STREAM (camel_object_new (MAIL_DISPLAY_STREAM_TYPE));
+ new->html = html;
+ new->html_stream = html_stream;
+
+ return CAMEL_STREAM (new);
+}
diff --git a/mail/mail-display-stream.h b/mail/mail-display-stream.h
new file mode 100644
index 0000000000..943398c49a
--- /dev/null
+++ b/mail/mail-display-stream.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 MAIL_DISPLAY_STREAM_H
+#define MAIL_DISPLAY_STREAM_H
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <camel/camel-stream.h>
+#include <gtkhtml/gtkhtml.h>
+
+#define MAIL_DISPLAY_STREAM_TYPE (mail_display_stream_get_type ())
+#define MAIL_DISPLAY_STREAM(obj) (CAMEL_CHECK_CAST((obj), MAIL_DISPLAY_STREAM_TYPE, MailDisplayStream))
+#define MAIL_DISPLAY_STREAM_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), MAIL_DISPLAY_STREAM_TYPE, MailDisplayStreamClass))
+#define MAIL_IS_DISPLAY_STREAM(o) (CAMEL_CHECK_TYPE((o), MAIL_DISPLAY_STREAM_TYPE))
+
+typedef struct _MailDisplayStream {
+ CamelStream parent_stream;
+
+ GtkHTML *html;
+ GtkHTMLStream *html_stream;
+} MailDisplayStream;
+
+typedef struct {
+ CamelStreamClass parent_class;
+
+} MailDisplayStreamClass;
+
+
+CamelType mail_display_stream_get_type (void);
+
+/* Note: stream does not ref these objects! */
+CamelStream *mail_display_stream_new (GtkHTML *html, GtkHTMLStream *html_stream);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* MAIL_DISPLAY_STREAM_H */
diff --git a/mail/mail-display.c b/mail/mail-display.c
new file mode 100644
index 0000000000..6c6d9aaf2a
--- /dev/null
+++ b/mail/mail-display.c
@@ -0,0 +1,2995 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Dan Winship <danw@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
+ * Miguel de Icaza <miguel@ximian.com>
+ * Larry Ewing <lewing@ximian.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * 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 2 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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <gtk/gtkinvisible.h>
+#include <libgnome/gnome-program.h>
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <libgnomevfs/gnome-vfs.h>
+#include <libgnome/gnome-url.h>
+#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-control-frame.h>
+#include <bonobo/bonobo-stream-memory.h>
+#include <bonobo/bonobo-widget.h>
+#include <bonobo/bonobo-socket.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk-pixbuf/gdk-pixbuf-loader.h>
+#include <gal/util/e-util.h>
+#include <gal/widgets/e-gui-utils.h>
+#include <gal/widgets/e-popup-menu.h>
+
+#include <gtkhtml/gtkhtml.h>
+#include <gtkhtml/gtkhtml-embedded.h>
+#include <gtkhtml/htmlengine.h>
+#include <gtkhtml/htmlobject.h>
+#include <gtkhtml/htmltext.h>
+#include <gtkhtml/htmlinterval.h>
+#include <gtkhtml/gtkhtml-stream.h>
+
+#include <libsoup/soup-message.h>
+
+#include "e-util/e-gui-utils.h"
+#include "e-util/e-mktemp.h"
+#include "addressbook/backend/ebook/e-book-util.h"
+
+#include "e-searching-tokenizer.h"
+#include "folder-browser-factory.h"
+#include "mail-display-stream.h"
+#include "folder-browser.h"
+#include "mail-component.h"
+#include "mail-config.h"
+#include "mail-display.h"
+#include "mail-format.h"
+#include "mail-ops.h"
+#include "mail-mt.h"
+#include "mail.h"
+
+#include "camel/camel-data-cache.h"
+
+#define d(x)
+
+struct _MailDisplayPrivate {
+
+ /* because we want to control resource usage, we need our own queues, etc */
+ EDList fetch_active;
+ EDList fetch_queue;
+
+ /* used to try and make some sense with progress reporting */
+ int fetch_total;
+ int fetch_total_done;
+
+ /* bit hackish, 'fake' an async message and processing,
+ so we can use that to get cancel and report progress */
+ struct _mail_msg *fetch_msg ;
+ GIOChannel *fetch_cancel_channel;
+ guint fetch_cancel_watch;
+
+ guint display_notify_id;
+};
+
+/* max number of connections to download images */
+#define FETCH_MAX_CONNECTIONS (4)
+
+/* path to http cache in fetch_cache */
+#define FETCH_HTTP_CACHE "http"
+
+/* for asynchronously downloading remote content */
+struct _remote_data {
+ struct _remote_data *next;
+ struct _remote_data *prev;
+
+ MailDisplay *md; /* not ref'd */
+
+ SoupMessage *msg;
+ char *uri;
+ GtkHTML *html;
+ GtkHTMLStream *stream;
+ CamelStream *cstream; /* cache stream */
+ size_t length;
+ size_t total;
+};
+
+static void fetch_remote(MailDisplay *md, const char *uri, GtkHTML *html, GtkHTMLStream *stream);
+static void fetch_cancel(MailDisplay *md);
+static void fetch_next(MailDisplay *md);
+static void fetch_data(SoupMessage *req, void *data);
+static void fetch_free(struct _remote_data *rd);
+static void fetch_done(SoupMessage *req, void *data);
+
+/* global http cache, relies on external evolution_dir as well */
+static CamelDataCache *fetch_cache;
+
+#define PARENT_TYPE (gtk_vbox_get_type ())
+
+static GtkObjectClass *mail_display_parent_class;
+
+struct _PixbufLoader {
+ CamelDataWrapper *wrapper; /* The data */
+ CamelStream *mstream;
+ GdkPixbufLoader *loader;
+ GtkHTMLEmbedded *eb;
+ char *type; /* Type of data, in case the conversion fails */
+ char *cid; /* Strdupped on creation, but not freed until
+ the hashtable is destroyed */
+ GtkWidget *pixmap;
+ guint32 destroy_id;
+};
+static GHashTable *thumbnail_cache = NULL;
+
+/* Drag & Drop types */
+#define TEXT_URI_LIST_TYPE "text/uri-list"
+
+enum DndTargetType {
+ DND_TARGET_TYPE_TEXT_URI_LIST,
+ DND_TARGET_TYPE_PART_MIME_TYPE
+};
+
+static GtkTargetEntry drag_types[] = {
+ { TEXT_URI_LIST_TYPE, 0, DND_TARGET_TYPE_TEXT_URI_LIST },
+ { NULL, 0, DND_TARGET_TYPE_PART_MIME_TYPE }
+};
+
+static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]);
+
+/*----------------------------------------------------------------------*
+ * Callbacks
+ *----------------------------------------------------------------------*/
+
+static void
+write_data_written(CamelMimePart *part, char *name, int done, void *data)
+{
+ int *ret = data;
+
+ /* should we popup a dialogue to say its done too? */
+ *ret = done;
+}
+
+static gboolean
+write_data_to_file (CamelMimePart *part, const char *name, gboolean unique)
+{
+ int fd, ret = FALSE;
+
+ g_return_val_if_fail (CAMEL_IS_MIME_PART (part), FALSE);
+
+ fd = open (name, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ if (fd == -1 && errno == EEXIST && !unique) {
+ GtkWidget *dialog;
+ int button;
+
+ dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
+ _("File `%s' already exists.\nOverwrite it?"),
+ name);
+
+ g_object_set (dialog, "title", _("Overwrite file?"), "allow_grow", TRUE, NULL);
+ button = gtk_dialog_run ((GtkDialog *) dialog);
+ gtk_widget_destroy (dialog);
+
+ if (button != GTK_RESPONSE_YES)
+ return FALSE;
+ }
+
+ if (fd != -1)
+ close (fd);
+
+ /* should this have progress of what its doing? */
+ mail_msg_wait (mail_save_part (part, name, write_data_written, &ret));
+
+ return ret;
+}
+
+static char *
+make_safe_filename (const char *prefix, CamelMimePart *part)
+{
+ const char *name;
+ char *safe, *p;
+
+ name = part ? camel_mime_part_get_filename (part) : NULL;
+
+ if (!name) {
+ /* This is a filename. Translators take note. */
+ name = _("attachment");
+ }
+
+ p = strrchr (name, '/');
+ if (p)
+ safe = g_strdup_printf ("%s%s", prefix, p);
+ else
+ safe = g_strdup_printf ("%s/%s", prefix, name);
+
+ p = strrchr (safe, '/');
+ if (p)
+ e_filename_make_safe (p + 1);
+
+ return safe;
+}
+
+static void
+save_data_cb (GtkWidget *widget, gpointer user_data)
+{
+ GtkFileSelection *file_select;
+ GConfClient *gconf;
+ char *dir;
+
+ file_select = (GtkFileSelection *) gtk_widget_get_ancestor (widget, GTK_TYPE_FILE_SELECTION);
+
+ /* uh, this doesn't really feel right, but i dont know what to do better */
+ gtk_widget_hide (GTK_WIDGET (file_select));
+ write_data_to_file (user_data, gtk_file_selection_get_filename (file_select), FALSE);
+
+ /* preserve the pathname */
+ dir = g_path_get_dirname (gtk_file_selection_get_filename (file_select));
+ gconf = mail_config_get_gconf_client ();
+ gconf_client_set_string (gconf, "/apps/evolution/mail/save_dir", dir, NULL);
+ g_free (dir);
+
+ gtk_widget_destroy (GTK_WIDGET (file_select));
+}
+
+static void
+save_destroy_cb (CamelMimePart *part, GObject *deadbeef)
+{
+ camel_object_unref (part);
+}
+
+static gboolean
+idle_redisplay (gpointer data)
+{
+ MailDisplay *md = data;
+
+ md->idle_id = 0;
+ mail_display_redisplay (md, FALSE);
+
+ return FALSE;
+}
+
+void
+mail_display_queue_redisplay (MailDisplay *md)
+{
+ if (!md->idle_id) {
+ md->idle_id = g_idle_add_full (G_PRIORITY_LOW, idle_redisplay,
+ md, NULL);
+ }
+}
+
+static void
+mail_display_jump_to_anchor (MailDisplay *md, const char *url)
+{
+ char *anchor = strstr (url, "#");
+
+ g_return_if_fail (anchor != NULL);
+
+ if (anchor)
+ gtk_html_jump_to_anchor (md->html, anchor + 1);
+}
+
+static void
+on_link_clicked (GtkHTML *html, const char *url, MailDisplay *md)
+{
+ if (!strncasecmp (url, "mailto:", 7)) {
+ send_to_url (url, NULL);
+ } else if (*url == '#') {
+ mail_display_jump_to_anchor (md, url);
+ } else {
+ GError *err = NULL;
+
+ gnome_url_show (url, &err);
+
+ if (err) {
+ g_warning ("gnome_url_show: %s", err->message);
+ g_error_free (err);
+ }
+ }
+}
+
+static void
+save_part (CamelMimePart *part)
+{
+ char *filename, *dir, *home, *base;
+ GtkFileSelection *file_select;
+ GConfClient *gconf;
+
+ camel_object_ref (part);
+
+ home = getenv ("HOME");
+ gconf = mail_config_get_gconf_client ();
+ dir = gconf_client_get_string (gconf, "/apps/evolution/mail/save_dir", NULL);
+ filename = make_safe_filename (dir ? dir : (home ? home : ""), part);
+ g_free (dir);
+
+ file_select = GTK_FILE_SELECTION (gtk_file_selection_new (_("Save Attachment")));
+ gtk_file_selection_set_filename (file_select, filename);
+ /* set the GtkEntry with the locale filename by breaking abstraction */
+ base = g_path_get_basename (filename);
+ gtk_entry_set_text (GTK_ENTRY (file_select->selection_entry), base);
+ g_free (filename);
+ g_free (base);
+
+ g_signal_connect (file_select->ok_button, "clicked",
+ G_CALLBACK (save_data_cb), part);
+
+ g_signal_connect_swapped (file_select->cancel_button, "clicked",
+ G_CALLBACK (gtk_widget_destroy), file_select);
+
+ g_object_weak_ref ((GObject *) file_select, (GWeakNotify) save_destroy_cb, part);
+
+ gtk_widget_show (GTK_WIDGET (file_select));
+}
+
+static void
+save_cb (GtkWidget *widget, gpointer user_data)
+{
+ CamelMimePart *part = g_object_get_data ((GObject *) user_data, "CamelMimePart");
+
+ save_part (part);
+}
+
+static void
+launch_cb (GtkWidget *widget, gpointer user_data)
+{
+ CamelMimePart *part = g_object_get_data(user_data, "CamelMimePart");
+ MailMimeHandler *handler;
+ GList *apps, *children, *c;
+ GnomeVFSMimeApplication *app;
+ char *command, *filename;
+ const char *tmpdir;
+
+ handler = mail_lookup_handler (g_object_get_data(user_data, "mime_type"));
+ g_return_if_fail (handler != NULL && handler->applications != NULL);
+
+ /* Yum. Too bad EPopupMenu doesn't allow per-item closures. */
+ children = gtk_container_get_children (GTK_CONTAINER (widget->parent));
+ /* We need to bypass the first 2 menu items */
+ g_return_if_fail (children != NULL && children->next != NULL
+ && children->next->next != NULL && children->next->next->next != NULL);
+
+ for (c = children->next->next->next, apps = handler->applications; c && apps; c = c->next, apps = apps->next) {
+ if (c->data == widget)
+ break;
+ }
+ g_list_free (children);
+ g_return_if_fail (c != NULL && apps != NULL);
+ app = apps->data;
+
+ tmpdir = e_mkdtemp ("app-launcher-XXXXXX");
+
+ if (!tmpdir) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_RESPONSE_CLOSE,
+ _("Could not create temporary directory: %s"),
+ g_strerror (errno));
+
+ /* FIXME: this should be async */
+ gtk_dialog_run ((GtkDialog *) dialog);
+ gtk_widget_destroy (dialog);
+ return;
+ }
+
+ filename = make_safe_filename (tmpdir, part);
+
+ if (!write_data_to_file (part, filename, TRUE)) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_RESPONSE_CLOSE,
+ _("Could not create temporary file '%s': %s"),
+ filename, g_strerror (errno));
+
+ /* FIXME: this should be async */
+ gtk_dialog_run ((GtkDialog *) dialog);
+ gtk_widget_destroy (dialog);
+ g_free (filename);
+ return;
+ }
+
+ command = g_strdup_printf ("%s %s%s &", app->command,
+ app->expects_uris == GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS ?
+ "file://" : "", filename);
+ g_free (filename);
+
+ system (command);
+ g_free (command);
+}
+
+static void
+inline_cb (GtkWidget *widget, gpointer user_data)
+{
+ MailDisplay *md = g_object_get_data (user_data, "MailDisplay");
+ CamelMimePart *part = g_object_get_data (user_data, "CamelMimePart");
+
+ mail_part_toggle_displayed (part, md);
+ mail_display_queue_redisplay (md);
+}
+
+static void
+save_all_parts_cb (GtkWidget *widget, gpointer user_data)
+{
+ GtkFileSelection *dir_select = (GtkFileSelection *)
+ gtk_widget_get_ancestor (widget, GTK_TYPE_FILE_SELECTION);
+ const char *filename;
+ char *save_filename, *dir;
+ struct stat st;
+ int i;
+ GPtrArray *attachment_array;
+ CamelMimePart *part;
+ GConfClient *gconf;
+
+ gtk_widget_hide (GTK_WIDGET (dir_select));
+
+ /* Get the selected directory name */
+ filename = gtk_file_selection_get_filename (dir_select);
+ if (stat (filename, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ _("%s is not a valid directory name."), filename);
+
+ /* FIXME: this should be async */
+ gtk_dialog_run ((GtkDialog *) dialog);
+ gtk_widget_destroy (dialog);
+ gtk_widget_destroy (GTK_WIDGET (dir_select));
+ return;
+ } else {
+ dir = g_strdup (filename);
+ }
+
+ /* Now save the attachment one by one */
+ attachment_array = (GPtrArray *)user_data;
+ for (i = 0; i < attachment_array->len; i++) {
+ part = g_ptr_array_index (attachment_array, i);
+ save_filename = make_safe_filename (dir, part);
+ write_data_to_file (part, save_filename, FALSE);
+ g_free (save_filename);
+ }
+
+ /* preserve the pathname */
+ gconf = mail_config_get_gconf_client ();
+ gconf_client_set_string (gconf, "/apps/evolution/mail/save_dir", dir, NULL);
+ g_free (dir);
+
+ gtk_widget_destroy (GTK_WIDGET (dir_select));
+}
+
+static void
+save_all_parts (GPtrArray *attachment_array)
+{
+ GtkFileSelection *dir_select;
+ char *dir, *home, *dir2;
+ GConfClient *gconf;
+
+ g_return_if_fail (attachment_array != NULL);
+
+ home = getenv ("HOME");
+ gconf = mail_config_get_gconf_client ();
+ dir = gconf_client_get_string (gconf, "/apps/evolution/mail/save_dir", NULL);
+ dir = dir ? dir : (home ? g_strdup (home) : g_strdup (""));
+
+ /* Make sure dir2 has a '/' as its tail */
+ dir2 = g_strdup_printf ("%s/", dir);
+ g_free (dir);
+
+ dir_select = GTK_FILE_SELECTION (
+ gtk_file_selection_new (_("Select Directory for Attachments")));
+ gtk_file_selection_set_filename (dir_select, dir2);
+ gtk_widget_set_sensitive (dir_select->file_list, FALSE);
+ gtk_widget_hide (dir_select->selection_entry);
+ g_free (dir2);
+
+ g_signal_connect (dir_select->ok_button, "clicked",
+ G_CALLBACK (save_all_parts_cb), attachment_array);
+ g_signal_connect_swapped (dir_select->cancel_button,
+ "clicked",
+ G_CALLBACK (gtk_widget_destroy),
+ dir_select);
+
+ gtk_widget_show (GTK_WIDGET (dir_select));
+}
+
+static void
+save_all_cb (GtkWidget *widget, gpointer user_data)
+{
+ MailDisplay *md = g_object_get_data (user_data, "MailDisplay");
+ GPtrArray *attachment_array;
+
+ if (md == NULL) {
+ g_warning ("No MailDisplay!");
+ return;
+ }
+
+ attachment_array = g_datalist_get_data (md->data, "attachment_array");
+ save_all_parts (attachment_array);
+}
+
+static void
+inline_toggle(MailDisplay *md, CamelMimePart *part)
+{
+ g_return_if_fail(md != NULL);
+
+ mail_part_toggle_displayed (part, md);
+ mail_display_queue_redisplay (md);
+}
+
+static void
+inline_button_clicked(GtkWidget *widget, CamelMimePart *part)
+{
+ inline_toggle((MailDisplay *)g_object_get_data((GObject *)widget, "MailDisplay"), part);
+}
+
+static gboolean
+inline_button_press(GtkWidget *widget, GdkEventKey *event, CamelMimePart *part)
+{
+ if (event->keyval != GDK_Return)
+ return FALSE;
+
+ inline_toggle((MailDisplay *)g_object_get_data((GObject *)widget, "MailDisplay"), part);
+
+ return TRUE;
+}
+
+static void
+popup_menu_placement_callback(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
+{
+ GtkWidget *widget = (GtkWidget*) user_data;
+
+ gdk_window_get_origin (gtk_widget_get_parent_window (widget), x, y);
+ *x += widget->allocation.x + widget->allocation.width;
+ *y += widget->allocation.y;
+
+ return;
+}
+
+static gboolean
+pixmap_press (GtkWidget *widget, GdkEvent *event, gpointer user_data)
+{
+ EPopupMenu *menu;
+ GtkMenu *gtk_menu;
+ EPopupMenu save_item = E_POPUP_ITEM (N_("Save Attachment..."), G_CALLBACK (save_cb), 0);
+ EPopupMenu save_all_item = E_POPUP_ITEM (N_("Save all attachments..."), G_CALLBACK (save_all_cb), 0);
+ EPopupMenu view_item = E_POPUP_ITEM (N_("View Inline"), G_CALLBACK (inline_cb), 2);
+ EPopupMenu open_item = E_POPUP_ITEM (N_("Open in %s..."), G_CALLBACK (launch_cb), 1);
+ MailDisplay *md;
+ CamelMimePart *part;
+ MailMimeHandler *handler;
+ int mask = 0, i, nitems;
+ int current_item = 0;
+
+ if (event->type == GDK_BUTTON_PRESS) {
+#ifdef USE_OLD_DISPLAY_STYLE
+ if (event->button.button != 3) {
+ gtk_propagate_event (GTK_WIDGET (user_data),
+ (GdkEvent *)event);
+ return TRUE;
+ }
+#endif
+
+ if (event->button.button != 1 && event->button.button != 3) {
+ gtk_propagate_event (GTK_WIDGET (user_data),
+ (GdkEvent *)event);
+ return TRUE;
+ }
+ /* Stop the signal, since we don't want the button's class method to
+ mess up our popup. */
+ g_signal_stop_emission_by_name (widget, "button_press_event");
+ } else {
+ if (event->key.keyval != GDK_Return)
+ return FALSE;
+ }
+
+ part = g_object_get_data ((GObject *) widget, "CamelMimePart");
+ handler = mail_lookup_handler (g_object_get_data ((GObject *) widget, "mime_type"));
+
+ if (handler && handler->applications)
+ nitems = g_list_length (handler->applications) + 3;
+ else
+ nitems = 4;
+ menu = g_new0 (EPopupMenu, nitems + 1);
+
+ /* Save item */
+ memcpy (&menu[current_item], &save_item, sizeof (menu[current_item]));
+ menu[current_item].name = g_strdup (_(menu[current_item].name));
+ current_item++;
+
+ /* Save All item */
+ memcpy (&menu[current_item], &save_all_item, sizeof (menu[current_item]));
+ menu[current_item].name = g_strdup (_(menu[current_item].name));
+ current_item++;
+
+ /* Inline view item */
+ memcpy (&menu[current_item], &view_item, sizeof (menu[current_item]));
+ if (handler && handler->builtin) {
+ md = g_object_get_data ((GObject *) widget, "MailDisplay");
+
+ if (!mail_part_is_displayed_inline (part, md)) {
+ if (handler->component) {
+ Bonobo_ActivationProperty *prop;
+ char *name;
+
+ prop = bonobo_server_info_prop_find (handler->component, "name");
+ if (!prop) {
+ prop = bonobo_server_info_prop_find (handler->component,
+ "description");
+ }
+ if (prop && prop->v._d == Bonobo_ACTIVATION_P_STRING)
+ name = prop->v._u.value_string;
+ else
+ name = "bonobo";
+ menu[current_item].name = g_strdup_printf (_("View Inline (via %s)"), name);
+ } else
+ menu[current_item].name = g_strdup (_(menu[current_item].name));
+ } else
+ menu[current_item].name = g_strdup (_("Hide"));
+ } else {
+ menu[current_item].name = g_strdup (_(menu[current_item].name));
+ mask |= 2;
+ }
+ current_item++;
+
+ /* External views */
+ if (handler && handler->applications) {
+ GnomeVFSMimeApplication *app;
+ GList *apps;
+ int i;
+
+ apps = handler->applications;
+ for (i = current_item; i < nitems; i++, apps = apps->next) {
+ app = apps->data;
+ memcpy (&menu[i], &open_item, sizeof (menu[i]));
+ menu[i].name = g_strdup_printf (_(menu[i].name), app->name);
+ current_item++;
+ }
+ } else {
+ memcpy (&menu[current_item], &open_item, sizeof (menu[current_item]));
+ menu[current_item].name = g_strdup_printf (_(menu[current_item].name), _("External Viewer"));
+ mask |= 1;
+ }
+
+ gtk_menu = e_popup_menu_create (menu, mask, 0, widget);
+ e_auto_kill_popup_menu_on_selection_done (gtk_menu);
+
+ if (event->type == GDK_BUTTON_PRESS)
+ gtk_menu_popup (gtk_menu, NULL, NULL, NULL, (gpointer)widget, event->button.button, event->button.time);
+ else
+ gtk_menu_popup (gtk_menu, NULL, NULL, popup_menu_placement_callback, (gpointer)widget, 0, event->key.time);
+
+ for (i = 1; i < nitems; i++)
+ g_free (menu[i].name);
+ g_free (menu);
+
+ return TRUE;
+}
+
+static gboolean
+pixbuf_uncache (gpointer key)
+{
+ GdkPixbuf *pixbuf;
+
+ pixbuf = g_hash_table_lookup (thumbnail_cache, key);
+ g_object_unref (pixbuf);
+ g_hash_table_remove (thumbnail_cache, key);
+ g_free (key);
+ return FALSE;
+}
+
+static gint
+pixbuf_gen_idle (struct _PixbufLoader *pbl)
+{
+ GdkPixbuf *pixbuf, *mini;
+ gboolean error = FALSE;
+ char tmp[4096];
+ int len, width, height, ratio;
+ gpointer orig_key;
+
+ /* Get the pixbuf from the cache */
+ if (g_hash_table_lookup_extended (thumbnail_cache, pbl->cid,
+ &orig_key, (gpointer *)&mini)) {
+ width = gdk_pixbuf_get_width (mini);
+ height = gdk_pixbuf_get_height (mini);
+
+ gtk_image_set_from_pixbuf ((GtkImage *) pbl->pixmap, mini);
+ gtk_widget_set_size_request (pbl->pixmap, width, height);
+
+ /* Restart the cache-cleaning timer */
+ g_source_remove_by_user_data (orig_key);
+ g_timeout_add (5 * 60 * 1000, pixbuf_uncache, orig_key);
+
+ if (pbl->loader) {
+ gdk_pixbuf_loader_close (pbl->loader, NULL);
+ g_object_unref (pbl->loader);
+ camel_object_unref (pbl->mstream);
+ }
+
+ g_signal_handler_disconnect (pbl->eb, pbl->destroy_id);
+ g_free (pbl->type);
+ g_free (pbl->cid);
+ g_free (pbl);
+
+ return FALSE;
+ }
+
+ /* Not in cache, so get a pixbuf from the wrapper */
+
+ if (!GTK_IS_WIDGET (pbl->pixmap)) {
+ /* Widget has died */
+ if (pbl->mstream)
+ camel_object_unref (pbl->mstream);
+
+ if (pbl->loader) {
+ gdk_pixbuf_loader_close (pbl->loader, NULL);
+ g_object_unref (pbl->loader);
+ }
+
+ g_signal_handler_disconnect (pbl->eb, pbl->destroy_id);
+ g_free (pbl->type);
+ g_free (pbl->cid);
+ g_free (pbl);
+
+ return FALSE;
+ }
+
+ if (pbl->mstream) {
+ if (pbl->loader == NULL)
+ pbl->loader = gdk_pixbuf_loader_new ();
+
+ len = camel_stream_read (pbl->mstream, tmp, 4096);
+ if (len > 0) {
+ error = !gdk_pixbuf_loader_write (pbl->loader, tmp, len, NULL);
+ if (!error)
+ return TRUE;
+ } else if (!camel_stream_eos (pbl->mstream))
+ error = TRUE;
+ }
+
+ if (error || !pbl->mstream) {
+ if (pbl->type)
+ pixbuf = e_icon_for_mime_type (pbl->type, 24);
+ else
+ pixbuf = gdk_pixbuf_new_from_file (EVOLUTION_ICONSDIR "/pgp-signature-nokey.png", NULL);
+ } else
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (pbl->loader);
+
+ if (pixbuf == NULL) {
+ /* pixbuf is non-existant */
+ if (pbl->mstream)
+ camel_object_unref (pbl->mstream);
+
+ if (pbl->loader) {
+ gdk_pixbuf_loader_close (pbl->loader, NULL);
+ g_object_unref (pbl->loader);
+ }
+
+ g_signal_handler_disconnect (pbl->eb, pbl->destroy_id);
+ g_free (pbl->type);
+ g_free (pbl->cid);
+ g_free (pbl);
+
+ return FALSE;
+ }
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+
+ if (width >= height) {
+ if (width > 24) {
+ ratio = width / 24;
+ width = 24;
+ height /= ratio;
+ }
+ } else {
+ if (height > 24) {
+ ratio = height / 24;
+ height = 24;
+ width /= ratio;
+ }
+ }
+
+ mini = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR);
+ if (error || !pbl->mstream)
+ g_object_unref (pixbuf);
+
+ gtk_image_set_from_pixbuf ((GtkImage *) pbl->pixmap, mini);
+
+ /* Add the pixbuf to the cache */
+ g_hash_table_insert (thumbnail_cache, pbl->cid, mini);
+ g_timeout_add (5 * 60 * 1000, pixbuf_uncache, pbl->cid);
+
+ g_signal_handler_disconnect (pbl->eb, pbl->destroy_id);
+ if (pbl->loader) {
+ gdk_pixbuf_loader_close (pbl->loader, NULL);
+ g_object_unref (pbl->loader);
+ camel_object_unref (pbl->mstream);
+ }
+
+ g_free (pbl->type);
+ g_free (pbl);
+
+ return FALSE;
+}
+
+/* Stop the idle function and free the pbl structure
+ as the widget that the pixbuf was to be rendered to
+ has died on us. */
+static void
+embeddable_destroy_cb (GtkObject *embeddable, struct _PixbufLoader *pbl)
+{
+ g_idle_remove_by_data (pbl);
+ if (pbl->mstream)
+ camel_object_unref (pbl->mstream);
+
+ if (pbl->loader) {
+ gdk_pixbuf_loader_close (pbl->loader, NULL);
+ g_object_unref (pbl->loader);
+ }
+
+ g_free (pbl->type);
+ g_free (pbl->cid);
+ g_free (pbl);
+};
+
+static GtkWidget *
+get_embedded_for_component (const char *iid, MailDisplay *md)
+{
+ GtkWidget *embedded;
+ BonoboControlFrame *control_frame;
+ Bonobo_PropertyBag prop_bag;
+
+ /*
+ * First try a control.
+ */
+ embedded = bonobo_widget_new_control (iid, NULL);
+ if (embedded == NULL) {
+#warning "what about bonobo_widget_new_subdoc?"
+#if 0
+ /*
+ * No control, try an embeddable instead.
+ */
+ embedded = bonobo_widget_new_subdoc (iid, NULL);
+ if (embedded != NULL) {
+ /* FIXME: as of bonobo 0.18, there's an extra
+ * client_site dereference in the BonoboWidget
+ * destruction path that we have to balance out to
+ * prevent problems.
+ */
+ bonobo_object_ref (BONOBO_OBJECT (bonobo_widget_get_client_site (
+ BONOBO_WIDGET (embedded))));
+
+ return embedded;
+ }
+#endif
+ }
+
+ if (embedded == NULL)
+ return NULL;
+
+ control_frame = bonobo_widget_get_control_frame (BONOBO_WIDGET (embedded));
+
+ prop_bag = bonobo_control_frame_get_control_property_bag (control_frame, NULL);
+
+ if (prop_bag != CORBA_OBJECT_NIL) {
+ CORBA_Environment ev;
+ /*
+ * Now we can take care of business. Currently, the only control
+ * that needs something passed to it through a property bag is
+ * the iTip control, and it needs only the From email address,
+ * but perhaps in the future we can generalize this section of code
+ * to pass a bunch of useful things to all embedded controls.
+ */
+ const CamelInternetAddress *from;
+ char *from_address;
+
+ CORBA_exception_init (&ev);
+
+ from = camel_mime_message_get_from (md->current_message);
+ from_address = camel_address_encode ((CamelAddress *) from);
+ bonobo_property_bag_client_set_value_string (
+ prop_bag, "from_address",
+ from_address, &ev);
+ g_free (from_address);
+
+ Bonobo_Unknown_unref (prop_bag, &ev);
+ CORBA_exception_free (&ev);
+ }
+
+ return embedded;
+}
+
+static void *
+save_url (MailDisplay *md, const char *url)
+{
+ GHashTable *urls;
+ CamelMimePart *part;
+
+ urls = g_datalist_get_data (md->data, "part_urls");
+ g_return_val_if_fail (url != NULL, NULL);
+ g_return_val_if_fail (urls != NULL, NULL);
+
+ part = g_hash_table_lookup (urls, url);
+ if (part == NULL) {
+ CamelDataWrapper *wrapper;
+ CamelStream *stream = NULL;
+ const char *name;
+
+ /* See if it's some piece of cached data if it is then pretend it
+ * is a mime part so that we can use the mime part saving routines.
+ * It is gross but it keeps duplicated code to a minimum and helps
+ * out with ref counting and the like.
+ */
+ name = strrchr (url, '/');
+ name = name ? name : url;
+
+ if (fetch_cache) {
+ /* look in the soup cache */
+ stream = camel_data_cache_get(fetch_cache, FETCH_HTTP_CACHE, url, NULL);
+ } else {
+ GByteArray *ba = NULL;
+
+ urls = g_datalist_get_data (md->data, "data_urls");
+ g_return_val_if_fail (urls != NULL, NULL);
+
+ ba = g_hash_table_lookup (urls, url);
+ if (ba) {
+ /* we have to copy the data here since the ba may be long gone
+ * by the time the user actually saves the file
+ */
+ stream = camel_stream_mem_new_with_buffer (ba->data, ba->len);
+ }
+ }
+
+ if (stream) {
+ wrapper = camel_data_wrapper_new ();
+ camel_data_wrapper_construct_from_stream (wrapper, stream);
+ camel_object_unref (stream);
+ part = camel_mime_part_new ();
+ camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
+ camel_object_unref (wrapper);
+ camel_mime_part_set_filename (part, name);
+ }
+ } else {
+ camel_object_ref (part);
+ }
+
+ if (part) {
+ CamelDataWrapper *data;
+
+ g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
+
+ data = camel_medium_get_content_object ((CamelMedium *)part);
+ if (!mail_content_loaded (data, md, TRUE, NULL, NULL, NULL)) {
+ return NULL;
+ }
+
+ save_part (part);
+ camel_object_unref (part);
+ return NULL;
+ }
+
+ g_warning ("Data for url: \"%s\" not found", url);
+
+ return NULL;
+}
+
+static void
+drag_data_get_cb (GtkWidget *widget,
+ GdkDragContext *drag_context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time,
+ gpointer user_data)
+{
+ CamelMimePart *part = user_data;
+ const char *filename, *tmpdir;
+ char *uri_list;
+
+ switch (info) {
+ case DND_TARGET_TYPE_TEXT_URI_LIST:
+ /* Kludge around Nautilus requesting the same data many times */
+ uri_list = g_object_get_data ((GObject *) widget, "uri-list");
+ if (uri_list) {
+ gtk_selection_data_set (selection_data, selection_data->target, 8,
+ uri_list, strlen (uri_list));
+ return;
+ }
+
+ tmpdir = e_mkdtemp ("drag-n-drop-XXXXXX");
+ if (!tmpdir) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_RESPONSE_CLOSE,
+ _("Could not create temporary directory: %s"),
+ g_strerror (errno));
+
+ /* FIXME: this should be async */
+ gtk_dialog_run ((GtkDialog *) dialog);
+ gtk_widget_destroy (dialog);
+ }
+
+ filename = camel_mime_part_get_filename (part);
+ /* This is the default filename used for dnd temporary target of attachment */
+ if (!filename)
+ filename = _("Unknown");
+
+ uri_list = g_strdup_printf ("file://%s/%s", tmpdir, filename);
+
+ if (!write_data_to_file (part, uri_list + 7, TRUE)) {
+ g_free (uri_list);
+ return;
+ }
+
+ gtk_selection_data_set (selection_data, selection_data->target, 8,
+ uri_list, strlen (uri_list));
+
+ g_object_set_data_full ((GObject *) widget, "uri-list", uri_list, g_free);
+ break;
+ case DND_TARGET_TYPE_PART_MIME_TYPE:
+ if (header_content_type_is (((CamelDataWrapper *) part)->mime_type, "text", "*")) {
+ GByteArray *ba;
+
+ ba = mail_format_get_data_wrapper_text ((CamelDataWrapper *) part, NULL);
+ if (ba) {
+ gtk_selection_data_set (selection_data, selection_data->target, 8,
+ ba->data, ba->len);
+ g_byte_array_free (ba, TRUE);
+ }
+ } else {
+ CamelDataWrapper *wrapper;
+ CamelStreamMem *mem;
+
+ mem = (CamelStreamMem *) camel_stream_mem_new ();
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mem);
+
+ gtk_selection_data_set (selection_data, selection_data->target, 8,
+ mem->buffer->data, mem->buffer->len);
+
+ camel_object_unref (mem);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+drag_data_delete_cb (GtkWidget *widget,
+ GdkDragContext *drag_context,
+ gpointer user_data)
+{
+ char *uri_list;
+
+ uri_list = g_object_get_data ((GObject *) widget, "uri-list");
+ if (uri_list) {
+ unlink (uri_list + 7);
+ g_object_set_data ((GObject *) widget, "uri-list", NULL);
+ }
+}
+
+/* This is a wrapper function */
+void ptr_array_free_notify (gpointer array)
+{
+ g_ptr_array_free ((GPtrArray *) array, TRUE);
+}
+
+static gboolean
+do_attachment_header (GtkHTML *html, GtkHTMLEmbedded *eb,
+ CamelMimePart *part, MailDisplay *md)
+{
+ GtkWidget *button, *mainbox, *hbox, *arrow, *popup;
+ MailMimeHandler *handler;
+ struct _PixbufLoader *pbl;
+ GPtrArray *attachment_array;
+
+ pbl = g_new0 (struct _PixbufLoader, 1);
+ if (strncasecmp (eb->type, "image/", 6) == 0) {
+ CamelDataWrapper *content;
+
+ content = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ if (!camel_data_wrapper_is_offline (content)) {
+ pbl->mstream = camel_stream_mem_new ();
+ camel_data_wrapper_decode_to_stream (content, pbl->mstream);
+ camel_stream_reset (pbl->mstream);
+ }
+ }
+
+ pbl->type = g_strdup (eb->type);
+ pbl->cid = g_strdup (eb->classid + 6);
+ pbl->pixmap = gtk_image_new();
+ gtk_widget_set_size_request (pbl->pixmap, 24, 24);
+ pbl->eb = eb;
+ pbl->destroy_id = g_signal_connect (eb, "destroy", G_CALLBACK (embeddable_destroy_cb), pbl);
+
+ g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) pixbuf_gen_idle, pbl, NULL);
+
+ mainbox = gtk_hbox_new (FALSE, 0);
+
+ button = gtk_button_new ();
+ g_object_set_data ((GObject *) button, "MailDisplay", md);
+
+ handler = mail_lookup_handler (eb->type);
+ if (handler && handler->builtin) {
+ g_signal_connect (button, "clicked", G_CALLBACK (inline_button_clicked), part);
+ g_signal_connect (button, "key_press_event", G_CALLBACK (inline_button_press), part);
+ } else {
+ gtk_widget_set_sensitive (button, FALSE);
+ GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
+ }
+
+ /* Drag & Drop */
+ drag_types[DND_TARGET_TYPE_PART_MIME_TYPE].target = header_content_type_simple (((CamelDataWrapper *) part)->mime_type);
+ camel_strdown (drag_types[DND_TARGET_TYPE_PART_MIME_TYPE].target);
+
+ gtk_drag_source_set (button, GDK_BUTTON1_MASK,
+ drag_types, num_drag_types,
+ GDK_ACTION_COPY);
+ g_signal_connect (button, "drag-data-get", G_CALLBACK (drag_data_get_cb), part);
+ g_signal_connect (button, "drag-data-delete", G_CALLBACK (drag_data_delete_cb), part);
+
+ g_free (drag_types[DND_TARGET_TYPE_PART_MIME_TYPE].target);
+ drag_types[DND_TARGET_TYPE_PART_MIME_TYPE].target = NULL;
+
+ hbox = gtk_hbox_new (FALSE, 2);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
+
+ /* should this be a gtk_arrow? */
+ if (handler && mail_part_is_displayed_inline (part, md))
+ arrow = gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON);
+ else
+ arrow = gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON);
+ gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), pbl->pixmap, TRUE, TRUE, 0);
+ gtk_container_add (GTK_CONTAINER (button), hbox);
+
+ popup = gtk_button_new ();
+ gtk_container_add (GTK_CONTAINER (popup),
+ gtk_arrow_new (GTK_ARROW_DOWN,
+ GTK_SHADOW_ETCHED_IN));
+
+ g_object_set_data ((GObject *) popup, "MailDisplay", md);
+ g_object_set_data ((GObject *) popup, "CamelMimePart", part);
+ g_object_set_data_full ((GObject *) popup, "mime_type", g_strdup (eb->type), (GDestroyNotify) g_free);
+
+ /* Save attachment pointer in an array for "save all attachment" use */
+ attachment_array = g_datalist_get_data (md->data, "attachment_array");
+ if (!attachment_array) {
+ attachment_array = g_ptr_array_new ();
+ g_datalist_set_data_full (md->data, "attachment_array",
+ attachment_array, (GDestroyNotify) ptr_array_free_notify);
+ }
+ /* Since the attachment pointer might have been added to the array before,
+ remove it first anyway to avoide duplication */
+ g_ptr_array_remove (attachment_array, part);
+ g_ptr_array_add (attachment_array, part);
+
+
+ g_signal_connect (popup, "button_press_event", G_CALLBACK (pixmap_press), md->scroll);
+ g_signal_connect (popup, "key_press_event", G_CALLBACK (pixmap_press), md->scroll);
+
+ gtk_box_pack_start (GTK_BOX (mainbox), button, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (mainbox), popup, TRUE, TRUE, 0);
+ gtk_widget_show_all (mainbox);
+
+ gtk_container_add (GTK_CONTAINER (eb), mainbox);
+
+ return TRUE;
+}
+
+static gboolean
+do_external_viewer (GtkHTML *html, GtkHTMLEmbedded *eb,
+ CamelMimePart *part, MailDisplay *md)
+{
+ CamelDataWrapper *wrapper;
+ Bonobo_ServerInfo *component;
+ GtkWidget *embedded;
+ Bonobo_PersistStream persist;
+ CORBA_Environment ev;
+ CamelStreamMem *cstream;
+ BonoboStream *bstream;
+ MailMimeHandler *handler;
+
+ handler = mail_lookup_handler (eb->type);
+ if (!handler || !handler->is_bonobo)
+ return FALSE;
+
+ component = gnome_vfs_mime_get_default_component (eb->type);
+ if (!component)
+ return FALSE;
+
+ embedded = get_embedded_for_component (component->iid, md);
+ CORBA_free (component);
+ if (!embedded)
+ return FALSE;
+
+ persist = (Bonobo_PersistStream) Bonobo_Unknown_queryInterface (
+ bonobo_widget_get_objref (BONOBO_WIDGET (embedded)),
+ "IDL:Bonobo/PersistStream:1.0", NULL);
+
+ if (persist == CORBA_OBJECT_NIL) {
+ gtk_object_sink (GTK_OBJECT (embedded));
+ return FALSE;
+ }
+
+ /* Write the data to a CamelStreamMem... */
+ cstream = (CamelStreamMem *) camel_stream_mem_new ();
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *)cstream);
+
+ /* ...convert the CamelStreamMem to a BonoboStreamMem... */
+ bstream = bonobo_stream_mem_create (cstream->buffer->data, cstream->buffer->len, TRUE, FALSE);
+ camel_object_unref (cstream);
+
+ /* ...and hydrate the PersistStream from the BonoboStream. */
+ CORBA_exception_init (&ev);
+ Bonobo_PersistStream_load (persist,
+ bonobo_object_corba_objref (BONOBO_OBJECT (bstream)),
+ eb->type, &ev);
+ bonobo_object_unref (BONOBO_OBJECT (bstream));
+ Bonobo_Unknown_unref (persist, &ev);
+ CORBA_Object_release (persist, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ gtk_object_sink (GTK_OBJECT (embedded));
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+ CORBA_exception_free (&ev);
+
+ gtk_widget_show (embedded);
+ gtk_container_add (GTK_CONTAINER (eb), embedded);
+
+ return TRUE;
+}
+
+static gboolean
+do_signature (GtkHTML *html, GtkHTMLEmbedded *eb,
+ CamelMimePart *part, MailDisplay *md)
+{
+ GtkWidget *button;
+ struct _PixbufLoader *pbl;
+
+ pbl = g_new0 (struct _PixbufLoader, 1);
+ pbl->type = NULL;
+ pbl->cid = g_strdup (eb->classid);
+ pbl->pixmap = gtk_image_new ();
+ gtk_widget_set_size_request (pbl->pixmap, 24, 24);
+ pbl->eb = eb;
+ pbl->destroy_id = g_signal_connect (eb, "destroy", G_CALLBACK (embeddable_destroy_cb), pbl);
+
+ g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) pixbuf_gen_idle, pbl, NULL);
+
+ button = gtk_button_new ();
+ g_object_set_data ((GObject *) button, "MailDisplay", md);
+ g_signal_connect (button, "clicked", G_CALLBACK (inline_button_clicked), part);
+ g_signal_connect (button, "key_press_event", G_CALLBACK (inline_button_press), part);
+
+ gtk_container_add (GTK_CONTAINER (button), pbl->pixmap);
+ gtk_widget_show_all (button);
+ gtk_container_add (GTK_CONTAINER (eb), button);
+
+ return TRUE;
+}
+
+static gboolean
+on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data)
+{
+ MailDisplay *md = data;
+ GHashTable *urls;
+ CamelMimePart *part;
+
+ if (!eb->classid)
+ return FALSE;
+
+ urls = g_datalist_get_data (md->data, "part_urls");
+ if (!urls)
+ return FALSE;
+
+ if (!strncmp (eb->classid, "popup:", 6) && eb->type) {
+ part = g_hash_table_lookup (urls, eb->classid + 6);
+ if (!CAMEL_IS_MIME_PART (part))
+ return FALSE;
+ return do_attachment_header (html, eb, part, md);
+ } else if (!strncmp (eb->classid, "signature:", 10)) {
+ part = g_hash_table_lookup (urls, eb->classid);
+ if (!CAMEL_IS_MIME_PART (part))
+ return FALSE;
+ return do_signature (html, eb, part, md);
+ } else if (!strncmp (eb->classid, "cid:", 4) && eb->type) {
+ part = g_hash_table_lookup (urls, eb->classid);
+ if (!CAMEL_IS_MIME_PART (part))
+ return FALSE;
+ return do_external_viewer (html, eb, part, md);
+ }
+
+ return FALSE;
+}
+
+static void
+ebook_callback (EBook *book, const gchar *addr, ECard *card, gpointer data)
+{
+ MailDisplay *md = data;
+
+ if (card && md->current_message) {
+ const CamelInternetAddress *from = camel_mime_message_get_from (md->current_message);
+ const char *md_name = NULL, *md_addr = NULL;
+
+ /* We are extra anal, in case we are dealing with some sort of pathological message
+ w/o a From: header. */
+ if (from != NULL && camel_internet_address_get (from, 0, &md_name, &md_addr)) {
+ if (md_addr != NULL && !strcmp (addr, md_addr))
+ mail_display_load_images (md);
+ }
+ }
+}
+
+static void
+on_url_requested (GtkHTML *html, const char *url, GtkHTMLStream *handle,
+ gpointer user_data)
+{
+ MailDisplay *md = user_data;
+ GConfClient *gconf;
+ GHashTable *urls;
+ CamelMedium *medium;
+ GByteArray *ba;
+
+ gconf = mail_config_get_gconf_client ();
+
+ urls = g_datalist_get_data (md->data, "part_urls");
+ g_return_if_fail (urls != NULL);
+
+ /* See if it refers to a MIME part (cid: or http:) */
+ medium = g_hash_table_lookup (urls, url);
+ if (medium) {
+ CamelContentType *content_type;
+ CamelDataWrapper *wrapper;
+ CamelStream *html_stream;
+
+ g_return_if_fail (CAMEL_IS_MEDIUM (medium));
+
+ if (md->related)
+ g_hash_table_remove (md->related, medium);
+
+ wrapper = camel_medium_get_content_object (medium);
+ if (!mail_content_loaded (wrapper, md, FALSE, url, html, handle))
+ return;
+
+ content_type = camel_data_wrapper_get_mime_type_field (wrapper);
+
+ html_stream = mail_display_stream_new (html, handle);
+
+ if (header_content_type_is (content_type, "text", "*")) {
+ mail_format_data_wrapper_write_to_stream (wrapper, TRUE, md, html_stream);
+ } else {
+ camel_data_wrapper_decode_to_stream (wrapper, html_stream);
+ }
+
+ camel_object_unref (html_stream);
+
+ gtk_html_end (html, handle, GTK_HTML_STREAM_OK);
+ return;
+ }
+
+ urls = g_datalist_get_data (md->data, "data_urls");
+ g_return_if_fail (urls != NULL);
+
+ /* See if it's some piece of cached data */
+ ba = g_hash_table_lookup (urls, url);
+ if (ba) {
+ if (ba->len) {
+ gtk_html_write (html, handle, ba->data, ba->len);
+ /* printf ("-- begin --\n");
+ printf (ba->data);
+ printf ("-- end --\n"); */
+ }
+ gtk_html_end (html, handle, GTK_HTML_STREAM_OK);
+ return;
+ }
+
+ /* See if it's something we can load. */
+ if (strncmp (url, "http:", 5) == 0 || strncmp (url, "https:", 6) == 0) {
+ int http_mode;
+
+ http_mode = gconf_client_get_int (gconf, "/apps/evolution/mail/display/load_http_images", NULL);
+ if (http_mode == MAIL_CONFIG_HTTP_ALWAYS ||
+ g_datalist_get_data (md->data, "load_images")) {
+ fetch_remote (md, url, html, handle);
+ } else if (http_mode == MAIL_CONFIG_HTTP_SOMETIMES &&
+ !g_datalist_get_data (md->data, "checking_from")) {
+ const CamelInternetAddress *from;
+ const char *name, *addr;
+
+ from = camel_mime_message_get_from (md->current_message);
+ g_datalist_set_data (md->data, "checking_from", GINT_TO_POINTER (1));
+
+ /* Make sure we aren't deal w/ some sort of a
+ pathological message w/o a From: header */
+ if (from != NULL && camel_internet_address_get (from, 0, &name, &addr))
+ e_book_query_address_default (addr, ebook_callback, md);
+ else
+ gtk_html_end (html, handle, GTK_HTML_STREAM_ERROR);
+ }
+ }
+}
+
+/* for processing asynchronous url fetch cancels */
+static struct _mail_msg_op fetch_fake_op = {
+ NULL, NULL, NULL, NULL,
+};
+
+static gboolean
+fetch_cancelled (GIOChannel *source, GIOCondition cond, void *user_data)
+{
+ fetch_cancel ((MailDisplay *) user_data);
+
+ return FALSE;
+}
+
+static void
+fetch_next (MailDisplay *md)
+{
+ struct _remote_data *rd;
+ struct _MailDisplayPrivate *p = md->priv;
+ SoupMessage *msg;
+ SoupContext *ctx;
+
+ /* if we're called and no more work to do, clean up, otherwise, setup */
+ if (e_dlist_empty(&p->fetch_active) && e_dlist_empty(&p->fetch_queue)) {
+ if (p->fetch_msg) {
+ p->fetch_total = 0;
+ mail_disable_stop();
+ camel_operation_end(p->fetch_msg->cancel);
+ camel_operation_unregister(p->fetch_msg->cancel);
+ mail_msg_free(p->fetch_msg);
+ p->fetch_msg = NULL;
+ g_source_remove(p->fetch_cancel_watch);
+ g_io_channel_unref(p->fetch_cancel_channel);
+ }
+ } else {
+ if (p->fetch_msg == NULL) {
+ p->fetch_total_done = 0;
+ p->fetch_msg = mail_msg_new(&fetch_fake_op, NULL, sizeof(*p->fetch_msg));
+ camel_operation_register(p->fetch_msg->cancel);
+ camel_operation_start(p->fetch_msg->cancel, _("Downloading images"));
+ p->fetch_cancel_channel = g_io_channel_unix_new(camel_operation_cancel_fd(p->fetch_msg->cancel));
+ p->fetch_cancel_watch = g_io_add_watch(p->fetch_cancel_channel, G_IO_IN, fetch_cancelled, md);
+ mail_enable_stop();
+ }
+ }
+
+ while (e_dlist_length(&p->fetch_active) < FETCH_MAX_CONNECTIONS
+ && (rd = (struct _remote_data *)e_dlist_remhead(&p->fetch_queue))) {
+
+ ctx = soup_context_get(rd->uri);
+ rd->msg = msg = soup_message_new(ctx, SOUP_METHOD_GET);
+
+ if (ctx)
+ soup_context_unref(ctx);
+
+ soup_message_set_flags(msg, SOUP_MESSAGE_OVERWRITE_CHUNKS);
+ soup_message_add_handler(msg, SOUP_HANDLER_BODY_CHUNK, fetch_data, rd);
+ e_dlist_addtail(&p->fetch_active, (EDListNode *)rd);
+ soup_message_queue(msg, fetch_done, rd);
+ }
+}
+
+static void fetch_remote(MailDisplay *md, const char *uri, GtkHTML *html, GtkHTMLStream *stream)
+{
+ struct _remote_data *rd;
+ CamelStream *cstream = NULL;
+
+ if (fetch_cache) {
+ cstream = camel_data_cache_get(fetch_cache, FETCH_HTTP_CACHE, uri, NULL);
+ if (cstream) {
+ char buf[1024];
+ ssize_t len;
+
+ /* need to verify header? */
+
+ while (!camel_stream_eos(cstream)) {
+ len = camel_stream_read(cstream, buf, 1024);
+ if (len > 0) {
+ gtk_html_write(html, stream, buf, len);
+ } else if (len < 0) {
+ gtk_html_end(html, stream, GTK_HTML_STREAM_ERROR);
+ camel_object_unref(cstream);
+ return;
+ }
+ }
+ gtk_html_end(html, stream, GTK_HTML_STREAM_OK);
+ camel_object_unref(cstream);
+ return;
+ }
+ cstream = camel_data_cache_add(fetch_cache, FETCH_HTTP_CACHE, uri, NULL);
+ }
+
+ rd = g_malloc0(sizeof(*rd));
+ rd->md = md; /* dont ref */
+ rd->uri = g_strdup(uri);
+ rd->html = html;
+ g_object_ref(html);
+ rd->stream = stream;
+ rd->cstream = cstream;
+
+ md->priv->fetch_total++;
+ e_dlist_addtail(&md->priv->fetch_queue, (EDListNode *)rd);
+
+ fetch_next(md);
+}
+
+static void fetch_data(SoupMessage *req, void *data)
+{
+ struct _remote_data *rd = data, *wd;
+ struct _MailDisplayPrivate *p = rd->md->priv;
+ int count;
+ double complete;
+
+ /* we could just hook into the header function for this, but i'm lazy today */
+ if (rd->total == 0) {
+ const char *cl = soup_message_get_header(req->response_headers, "content-length");
+ if (cl)
+ rd->total = strtoul(cl, 0, 10);
+ else
+ rd->total = 0;
+ }
+ rd->length += req->response.length;
+
+ gtk_html_write(rd->html, rd->stream, req->response.body, req->response.length);
+
+ /* copy to cache, clear cache if we get a cache failure */
+ if (rd->cstream) {
+ if (camel_stream_write(rd->cstream, req->response.body, req->response.length) == -1) {
+ camel_data_cache_remove(fetch_cache, FETCH_HTTP_CACHE, rd->uri, NULL);
+ camel_object_unref(rd->cstream);
+ rd->cstream = NULL;
+ }
+ }
+
+ /* update based on total active + finished totals */
+ complete = 0.0;
+ wd = (struct _remote_data *)p->fetch_active.head;
+ count = e_dlist_length(&p->fetch_active);
+ while (wd->next) {
+ if (wd->total)
+ complete += (double)wd->length / wd->total / count;
+ wd = wd->next;
+ }
+
+ d(printf("%s: %f total %f (%d,%d)\n", rd->uri, complete, (p->fetch_total_done + complete ) * 100.0 / p->fetch_total, p->fetch_total, p->fetch_total_done));
+
+ camel_operation_progress(p->fetch_msg->cancel, (p->fetch_total_done + complete ) * 100.0 / p->fetch_total);
+}
+
+static void fetch_free(struct _remote_data *rd)
+{
+ g_object_unref(rd->html);
+ if (rd->cstream)
+ camel_object_unref(rd->cstream);
+ g_free(rd->uri);
+ g_free(rd);
+}
+
+static void fetch_done(SoupMessage *req, void *data)
+{
+ struct _remote_data *rd = data;
+ MailDisplay *md = rd->md;
+
+ if (SOUP_MESSAGE_IS_ERROR(req)) {
+ d(printf("Loading '%s' failed!\n", rd->uri));
+ gtk_html_end(rd->html, rd->stream, GTK_HTML_STREAM_ERROR);
+ if (fetch_cache)
+ camel_data_cache_remove(fetch_cache, FETCH_HTTP_CACHE, rd->uri, NULL);
+ } else {
+ d(printf("Loading '%s' complete!\n", rd->uri));
+ gtk_html_end(rd->html, rd->stream, GTK_HTML_STREAM_OK);
+ }
+
+ e_dlist_remove((EDListNode *)rd);
+ fetch_free(rd);
+ md->priv->fetch_total_done++;
+
+ fetch_next(md);
+}
+
+static void fetch_cancel(MailDisplay *md)
+{
+ struct _remote_data *rd;
+
+ /* first, clean up all the ones we haven't finished yet */
+ while ((rd = (struct _remote_data *)e_dlist_remhead(&md->priv->fetch_queue))) {
+ gtk_html_end(rd->html, rd->stream, GTK_HTML_STREAM_ERROR);
+ if (fetch_cache)
+ camel_data_cache_remove(fetch_cache, FETCH_HTTP_CACHE, rd->uri, NULL);
+ fetch_free(rd);
+ }
+
+ /* cancel the rest, cancellation will free it/etc */
+ while (!e_dlist_empty(&md->priv->fetch_active)) {
+ rd = (struct _remote_data *)md->priv->fetch_active.head;
+ soup_message_cancel(rd->msg);
+ }
+}
+
+struct _load_content_msg {
+ struct _mail_msg msg;
+
+ MailDisplay *display;
+ GtkHTML *html;
+
+ GtkHTMLStream *handle;
+ int redisplay_counter;
+ char *url;
+ CamelMimeMessage *message;
+ void (*callback)(MailDisplay *, gpointer);
+ gpointer data;
+};
+
+static char *
+load_content_desc (struct _mail_msg *mm, int done)
+{
+ return g_strdup (_("Loading message content"));
+}
+
+static void
+load_content_load (struct _mail_msg *mm)
+{
+ struct _load_content_msg *m = (struct _load_content_msg *)mm;
+
+ m->callback (m->display, m->data);
+}
+
+static gboolean
+try_part_urls (struct _load_content_msg *m)
+{
+ GHashTable *urls;
+ CamelMedium *medium;
+
+ urls = g_datalist_get_data (m->display->data, "part_urls");
+ g_return_val_if_fail (urls != NULL, FALSE);
+
+ /* See if it refers to a MIME part (cid: or http:) */
+ medium = g_hash_table_lookup (urls, m->url);
+ if (medium) {
+ CamelDataWrapper *data;
+ CamelStream *html_stream;
+
+ g_return_val_if_fail (CAMEL_IS_MEDIUM (medium), FALSE);
+
+ data = camel_medium_get_content_object (medium);
+ if (!mail_content_loaded (data, m->display, FALSE, m->url, m->html, m->handle)) {
+ g_warning ("This code should not be reached\n");
+ return TRUE;
+ }
+
+ html_stream = mail_display_stream_new (m->html, m->handle);
+ camel_data_wrapper_decode_to_stream (data, html_stream);
+ camel_object_unref (html_stream);
+
+ gtk_html_end (m->html, m->handle, GTK_HTML_STREAM_OK);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+try_data_urls (struct _load_content_msg *m)
+{
+ GHashTable *urls;
+ GByteArray *ba;
+
+ urls = g_datalist_get_data (m->display->data, "data_urls");
+ ba = g_hash_table_lookup (urls, m->url);
+
+ if (ba) {
+ if (ba->len)
+ gtk_html_write (m->html, m->handle, ba->data, ba->len);
+ gtk_html_end (m->html, m->handle, GTK_HTML_STREAM_OK);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+load_content_loaded (struct _mail_msg *mm)
+{
+ struct _load_content_msg *m = (struct _load_content_msg *)mm;
+
+ if (m->display->destroyed)
+ return;
+
+ if (m->display->current_message == m->message) {
+ if (m->handle) {
+ if (m->redisplay_counter == m->display->redisplay_counter) {
+ if (!try_part_urls (m) && !try_data_urls (m))
+ gtk_html_end (m->html, m->handle, GTK_HTML_STREAM_ERROR);
+ }
+ } else {
+ mail_display_redisplay (m->display, FALSE);
+ }
+ }
+}
+
+static void
+load_content_free (struct _mail_msg *mm)
+{
+ struct _load_content_msg *m = (struct _load_content_msg *)mm;
+
+ g_free (m->url);
+ g_object_unref (m->html);
+ g_object_unref (m->display);
+ camel_object_unref (m->message);
+}
+
+static struct _mail_msg_op load_content_op = {
+ load_content_desc,
+ load_content_load,
+ load_content_loaded,
+ load_content_free,
+};
+
+static void
+stream_write_or_redisplay_when_loaded (MailDisplay *md,
+ GtkHTML *html,
+ gconstpointer key,
+ const gchar *url,
+ void (*callback)(MailDisplay *, gpointer),
+ GtkHTMLStream *handle,
+ gpointer data)
+{
+ struct _load_content_msg *m;
+ GHashTable *loading;
+
+ if (md->destroyed)
+ return;
+
+ loading = g_datalist_get_data (md->data, "loading");
+ if (loading) {
+ if (g_hash_table_lookup (loading, key))
+ return;
+ } else {
+ loading = g_hash_table_new (NULL, NULL);
+ g_datalist_set_data_full (md->data, "loading", loading,
+ (GDestroyNotify) g_hash_table_destroy);
+ }
+ g_hash_table_insert (loading, (gpointer) key, GINT_TO_POINTER (1));
+
+ m = mail_msg_new (&load_content_op, NULL, sizeof (*m));
+ m->display = md;
+ g_object_ref((m->display));
+ m->html = html;
+ g_object_ref((html));
+ m->handle = handle;
+ m->url = g_strdup (url);
+ m->redisplay_counter = md->redisplay_counter;
+ m->message = md->current_message;
+ camel_object_ref (m->message);
+ m->callback = callback;
+ m->data = data;
+
+ e_thread_put (mail_thread_queued, (EMsg *)m);
+ return;
+}
+
+void
+mail_display_stream_write_when_loaded (MailDisplay *md,
+ gconstpointer key,
+ const char *url,
+ void (*callback)(MailDisplay *, gpointer),
+ GtkHTML *html,
+ GtkHTMLStream *handle,
+ gpointer data)
+{
+ stream_write_or_redisplay_when_loaded (md, html, key, url, callback, handle, data);
+}
+
+void
+mail_display_redisplay_when_loaded (MailDisplay *md,
+ gconstpointer key,
+ void (*callback)(MailDisplay *, gpointer),
+ GtkHTML *html,
+ gpointer data)
+{
+ stream_write_or_redisplay_when_loaded (md, html, key, NULL, callback, NULL, data);
+}
+
+void
+mail_text_write (MailDisplayStream *stream, MailDisplay *md, CamelMimePart *part,
+ int idx, gboolean printing, const char *text)
+{
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilter *html_filter;
+ GConfClient *gconf;
+ guint32 flags, rgb;
+ GdkColor colour;
+ char *buf;
+
+ gconf = mail_config_get_gconf_client ();
+
+ flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
+
+ if (!printing)
+ flags |= CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
+
+ if (!printing && gconf_client_get_bool (gconf, "/apps/evolution/mail/display/mark_citations", NULL))
+ flags |= CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+
+ buf = gconf_client_get_string (gconf, "/apps/evolution/mail/display/citation_colour", NULL);
+ gdk_color_parse (buf ? buf : "#737373", &colour);
+ g_free (buf);
+
+ rgb = ((colour.red & 0xff00) << 8) | (colour.green & 0xff00) | ((colour.blue & 0xff00) >> 8);
+ html_filter = camel_mime_filter_tohtml_new (flags, rgb);
+ filtered_stream = camel_stream_filter_new_with_stream ((CamelStream *) stream);
+ camel_stream_filter_add (filtered_stream, html_filter);
+ camel_object_unref (html_filter);
+
+ camel_stream_write ((CamelStream *) stream, "<tt>\n", 5);
+ camel_stream_write ((CamelStream *) filtered_stream, text, strlen (text));
+ camel_stream_flush ((CamelStream *) filtered_stream);
+ camel_stream_write ((CamelStream *) stream, "</tt>\n", 6);
+ camel_object_unref (filtered_stream);
+
+#if 0
+ /* this was the old way of doing it, I don't understand why we need iframes... */
+ GByteArray *ba;
+ char *xed, *iframe;
+ char *btt = "<tt>\n";
+ char *ett = "</tt>\n";
+ char *htmltext;
+ guint32 flags;
+
+ flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
+
+ if (!printing)
+ flags |= CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
+
+ if (!printing && mail_config_get_citation_highlight ())
+ flags |= CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+
+ htmltext = camel_text_to_html (text, flags, mail_config_get_citation_color ());
+
+ ba = g_byte_array_new ();
+ g_byte_array_append (ba, (const guint8 *) btt, strlen (btt) + 1);
+ g_byte_array_append (ba, (const guint8 *) htmltext, strlen (htmltext) + 1);
+ g_byte_array_append (ba, (const guint8 *) ett, strlen (ett) + 1);
+ g_free (htmltext);
+
+ xed = g_strdup_printf ("x-evolution-data:%p-%d", part, idx);
+ iframe = g_strdup_printf ("<iframe src=\"%s\" frameborder=0 scrolling=no>could not get %s</iframe>", xed, xed);
+ mail_display_add_url (md, "data_urls", xed, ba);
+ camel_stream_write ((CamelStream *) stream, iframe, strlen (iframe));
+ g_free (iframe);
+#endif
+}
+
+void
+mail_error_printf (MailDisplayStream *stream, const char *format, ...)
+{
+ /* FIXME: it'd be nice if camel-stream had a vprintf method... */
+ char *buf, *htmltext;
+ va_list ap;
+
+ va_start (ap, format);
+ buf = g_strdup_vprintf (format, ap);
+ va_end (ap);
+
+ htmltext = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+ g_free (buf);
+
+ camel_stream_printf ((CamelStream *) stream, "<em><font color=red>");
+ camel_stream_write ((CamelStream *) stream, htmltext, strlen (htmltext));
+ camel_stream_printf ((CamelStream *) stream, "</font></em>");
+
+ g_free (htmltext);
+}
+
+
+#define COLOR_IS_LIGHT(r, g, b) ((r + g + b) > (128 * 3))
+
+#define HTML_HEADER "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n" \
+ "<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\">\n</head>\n"
+
+void
+mail_display_render (MailDisplay *md, GtkHTML *html, gboolean reset_scroll)
+{
+ const char *flag, *completed;
+ GtkHTMLStream *html_stream;
+ MailDisplayStream *stream;
+
+ g_return_if_fail (IS_MAIL_DISPLAY (md));
+ g_return_if_fail (GTK_IS_HTML (html));
+
+ if (!md->html) {
+ /* we've been destroyed */
+ return;
+ }
+
+ html_stream = gtk_html_begin (html);
+ if (!reset_scroll) {
+ /* This is a hack until there's a clean way to do this. */
+ GTK_HTML (md->html)->engine->newPage = FALSE;
+ }
+
+ gtk_html_stream_write (html_stream, HTML_HEADER, sizeof (HTML_HEADER) - 1);
+
+ if (md->current_message && md->display_style == MAIL_CONFIG_DISPLAY_SOURCE)
+ gtk_html_stream_write (html_stream, "<body>\n", 7);
+ else
+ gtk_html_stream_write (html_stream, "<body marginwidth=0 marginheight=0>\n", 36);
+
+ flag = md->info ? camel_tag_get (&md->info->user_tags, "follow-up") : NULL;
+ completed = md->info ? camel_tag_get (&md->info->user_tags, "completed-on") : NULL;
+ if ((flag && *flag) && !(completed && *completed)) {
+ const char *due_by, *overdue = "";
+ char bgcolor[7], fontcolor[7];
+ time_t target_date, now;
+ GtkStyle *style = NULL;
+ char due_date[256];
+ struct tm due;
+ int offset;
+
+ /* my favorite thing to do... muck around with colors so we respect people's stupid themes. */
+ /* FIXME: this is also in mail-format.c */
+ style = gtk_widget_get_style (GTK_WIDGET (html));
+ if (style && !md->printing) {
+ int state = GTK_WIDGET_STATE (GTK_WIDGET (html));
+ gushort r, g, b;
+
+ r = style->base[state].red / 256;
+ g = style->base[state].green / 256;
+ b = style->base[state].blue / 256;
+
+ if (COLOR_IS_LIGHT (r, g, b)) {
+ r *= 1.0;
+ g *= 0.97;
+ b *= 0.75;
+ } else {
+ r = 255 - (1.0 * (255 - r));
+ g = 255 - (0.97 * (255 - g));
+ b = 255 - (0.75 * (255 - b));
+ }
+
+ sprintf (bgcolor, "%.2X%.2X%.2X", r, g, b);
+
+ r = style->text[state].red / 256;
+ g = style->text[state].green / 256;
+ b = style->text[state].blue / 256;
+
+ sprintf (fontcolor, "%.2X%.2X%.2X", r, g, b);
+ } else {
+ strcpy (bgcolor, "EEEEEE");
+ strcpy (fontcolor, "000000");
+ }
+
+ due_by = camel_tag_get (&md->info->user_tags, "due-by");
+ if (due_by && *due_by) {
+ target_date = header_decode_date (due_by, &offset);
+ now = time (NULL);
+ if (now >= target_date)
+ overdue = _("Overdue:");
+
+ localtime_r (&target_date, &due);
+
+ e_utf8_strftime_fix_am_pm (due_date, sizeof (due_date), _("by %B %d, %Y, %l:%M %p"), &due);
+ } else {
+ due_date[0] = '\0';
+ }
+
+ gtk_html_stream_printf (html_stream, "<font color=\"#%s\">"
+ "<table width=\"100%%\" cellpadding=0 cellspacing=0><tr><td colspan=3 height=10></td></tr>"
+ "<tr><td width=10></td><td>"
+ "<table cellspacing=1 cellpadding=1 bgcolor=\"#000000\" width=\"100%%\"><tr><td>"
+ "<table cellspacing=0 bgcolor=\"#%s\" cellpadding=2 cellspacing=2 width=\"100%%\">"
+ "<tr><td align=\"left\" width=20><img src=\"%s\" align=\"middle\"></td>"
+ "<td>%s%s%s%s %s</td></table></td></tr></table>"
+ "</td><td width=10></td></tr></table></font>", fontcolor, bgcolor,
+ mail_display_get_url_for_icon (md, EVOLUTION_IMAGES "/flag-for-followup-16.png"),
+ overdue ? "<b>" : "", overdue, overdue ? "</b>&nbsp;" : "",
+ flag, due_date);
+ }
+
+ if (md->current_message) {
+ stream = (MailDisplayStream *) mail_display_stream_new (html, html_stream);
+
+ if (md->display_style == MAIL_CONFIG_DISPLAY_SOURCE)
+ mail_format_raw_message (md->current_message, md, stream);
+ else
+ mail_format_mime_message (md->current_message, md, stream);
+
+ camel_object_unref (stream);
+ }
+
+ gtk_html_stream_write (html_stream, "</body></html>\n", 15);
+ gtk_html_end (html, html_stream, GTK_HTML_STREAM_OK);
+}
+
+/**
+ * mail_display_redisplay:
+ * @mail_display: the mail display object
+ * @reset_scroll: specifies whether or not to reset current scroll
+ *
+ * Force a redraw of the message display.
+ **/
+void
+mail_display_redisplay (MailDisplay *md, gboolean reset_scroll)
+{
+ if (md->destroyed)
+ return;
+
+ /* we're in effect stealing the queued redisplay */
+ if (md->idle_id) {
+ g_source_remove(md->idle_id);
+ md->idle_id = 0;
+ }
+
+ fetch_cancel(md);
+
+ md->last_active = NULL;
+ md->redisplay_counter++;
+ /* printf ("md %p redisplay %d\n", md, md->redisplay_counter); */
+
+ mail_display_render (md, md->html, reset_scroll);
+}
+
+
+/**
+ * mail_display_set_message:
+ * @mail_display: the mail display object
+ * @medium: the input camel medium, or %NULL
+ * @folder: CamelFolder
+ * @info: message info
+ *
+ * Makes the mail_display object show the contents of the medium
+ * param.
+ **/
+void
+mail_display_set_message (MailDisplay *md, CamelMedium *medium, CamelFolder *folder, CamelMessageInfo *info)
+{
+ /* For the moment, we deal only with CamelMimeMessage, but in
+ * the future, we should be able to deal with any medium.
+ */
+ if (md->destroyed
+ || (medium && !CAMEL_IS_MIME_MESSAGE (medium)))
+ return;
+
+ /* Clean up from previous message. */
+ if (md->current_message) {
+ fetch_cancel (md);
+ camel_object_unref (md->current_message);
+ g_datalist_clear (md->data);
+ }
+
+ if (medium) {
+ camel_object_ref (medium);
+ md->current_message = (CamelMimeMessage *) medium;
+ } else
+ md->current_message = NULL;
+
+ if (md->folder && md->info) {
+ camel_folder_free_message_info (md->folder, md->info);
+ camel_object_unref (md->folder);
+ }
+
+ if (folder && info) {
+ md->info = info;
+ md->folder = folder;
+ camel_object_ref (folder);
+ camel_folder_ref_message_info (folder, info);
+ } else {
+ md->info = NULL;
+ md->folder = NULL;
+ }
+
+ g_datalist_init (md->data);
+ mail_display_redisplay (md, TRUE);
+}
+
+/**
+ * mail_display_set_charset:
+ * @mail_display: the mail display object
+ * @charset: charset or %NULL
+ *
+ * Makes the mail_display object show the contents of the medium
+ * param.
+ **/
+void
+mail_display_set_charset (MailDisplay *mail_display, const char *charset)
+{
+ g_free (mail_display->charset);
+ mail_display->charset = g_strdup (charset);
+
+ mail_display_queue_redisplay (mail_display);
+}
+
+/**
+ * mail_display_load_images:
+ * @md: the mail display object
+ *
+ * Load all HTTP images in the current message
+ **/
+void
+mail_display_load_images (MailDisplay *md)
+{
+ g_datalist_set_data (md->data, "load_images", GINT_TO_POINTER (1));
+ mail_display_redisplay (md, FALSE);
+}
+
+/*----------------------------------------------------------------------*
+ * Standard Gtk+ Class functions
+ *----------------------------------------------------------------------*/
+
+static void
+mail_display_init (GObject *object)
+{
+ MailDisplay *mail_display = MAIL_DISPLAY (object);
+ GConfClient *gconf;
+ int style;
+
+ mail_display->scroll = NULL;
+ mail_display->html = NULL;
+ mail_display->redisplay_counter = 0;
+ mail_display->last_active = NULL;
+ mail_display->idle_id = 0;
+ mail_display->selection = NULL;
+ mail_display->charset = NULL;
+ mail_display->current_message = NULL;
+ mail_display->folder = NULL;
+ mail_display->info = NULL;
+ mail_display->data = NULL;
+
+ mail_display->invisible = gtk_invisible_new ();
+ g_object_ref (mail_display->invisible);
+ gtk_object_sink ((GtkObject *) mail_display->invisible);
+
+ gconf = mail_config_get_gconf_client ();
+ style = gconf_client_get_int (gconf, "/apps/evolution/mail/format/message_display_style", NULL);
+ mail_display->display_style = style;
+
+ mail_display->printing = FALSE;
+
+ mail_display->priv = g_malloc0(sizeof(*mail_display->priv));
+ e_dlist_init(&mail_display->priv->fetch_active);
+ e_dlist_init(&mail_display->priv->fetch_queue);
+}
+
+static void
+mail_display_destroy (GtkObject *object)
+{
+ MailDisplay *mail_display = MAIL_DISPLAY (object);
+
+ if (mail_display->html) {
+ g_object_unref (mail_display->html);
+ mail_display->html = NULL;
+ }
+
+ if (mail_display->current_message) {
+ camel_object_unref (mail_display->current_message);
+ g_datalist_clear (mail_display->data);
+ fetch_cancel(mail_display);
+ mail_display->current_message = NULL;
+ }
+
+ g_free (mail_display->charset);
+ mail_display->charset = NULL;
+ g_free (mail_display->selection);
+ mail_display->selection = NULL;
+
+ if (mail_display->folder) {
+ if (mail_display->info)
+ camel_folder_free_message_info (mail_display->folder, mail_display->info);
+ camel_object_unref (mail_display->folder);
+ mail_display->folder = NULL;
+ }
+
+ g_free (mail_display->data);
+ mail_display->data = NULL;
+
+ if (mail_display->idle_id) {
+ g_source_remove (mail_display->idle_id);
+ mail_display->idle_id = 0;
+ }
+
+ if (mail_display->invisible) {
+ g_object_unref (mail_display->invisible);
+ mail_display->invisible = NULL;
+ }
+
+ if (mail_display->priv && mail_display->priv->display_notify_id) {
+ GConfClient *gconf = mail_config_get_gconf_client ();
+ gconf_client_notify_remove (gconf, mail_display->priv->display_notify_id);
+ mail_display->priv->display_notify_id = 0;
+ }
+
+ g_free (mail_display->priv);
+ mail_display->priv = NULL;
+
+ mail_display->destroyed = TRUE;
+
+ mail_display_parent_class->destroy (object);
+}
+
+static void
+invisible_selection_get_callback (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time,
+ void *data)
+{
+ MailDisplay *display;
+
+ display = MAIL_DISPLAY (data);
+
+ if (!display->selection)
+ return;
+
+ g_assert (info == 1);
+
+ gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING, 8,
+ display->selection, strlen (display->selection));
+}
+
+static gint
+invisible_selection_clear_event_callback (GtkWidget *widget,
+ GdkEventSelection *event,
+ void *data)
+{
+ MailDisplay *display;
+
+ display = MAIL_DISPLAY (data);
+
+ g_free (display->selection);
+ display->selection = NULL;
+
+ return TRUE;
+}
+
+static void
+mail_display_class_init (GtkObjectClass *object_class)
+{
+ object_class->destroy = mail_display_destroy;
+
+ if (mail_display_parent_class == NULL) {
+ const char *base_directory = mail_component_peek_base_directory (mail_component_peek ());
+ char *path;
+
+ path = g_alloca (strlen (base_directory) + 16);
+ sprintf (path, "%s/cache", base_directory);
+
+ /* cache expiry - 2 hour access, 1 day max */
+ fetch_cache = camel_data_cache_new(path, 0, NULL);
+ camel_data_cache_set_expire_age(fetch_cache, 24*60*60);
+ camel_data_cache_set_expire_access(fetch_cache, 2*60*60);
+
+ mail_display_parent_class = g_type_class_ref (PARENT_TYPE);
+ thumbnail_cache = g_hash_table_new (g_str_hash, g_str_equal);
+ }
+}
+
+static void
+link_open_in_browser (GtkWidget *w, MailDisplay *mail_display)
+{
+ if (!mail_display->html->pointer_url)
+ return;
+
+ on_link_clicked (mail_display->html, mail_display->html->pointer_url,
+ mail_display);
+}
+
+#if 0
+static void
+link_save_as (GtkWidget *w, MailDisplay *mail_display)
+{
+ g_print ("FIXME save %s\n", mail_display->html->pointer_url);
+}
+#endif
+
+static void
+link_copy_location (GtkWidget *w, MailDisplay *mail_display)
+{
+ GdkAtom clipboard_atom;
+
+ g_free (mail_display->selection);
+ mail_display->selection = g_strdup (mail_display->html->pointer_url);
+
+ clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
+ if (clipboard_atom == GDK_NONE)
+ return; /* failed */
+
+ /* We don't check the return values of the following since there is not
+ * much we can do if we cannot assert the selection.
+ */
+
+ gtk_selection_owner_set (GTK_WIDGET (mail_display->invisible),
+ GDK_SELECTION_PRIMARY,
+ GDK_CURRENT_TIME);
+ gtk_selection_owner_set (GTK_WIDGET (mail_display->invisible),
+ clipboard_atom,
+ GDK_CURRENT_TIME);
+}
+
+static void
+image_save_as (GtkWidget *w, MailDisplay *mail_display)
+{
+ const char *src;
+
+ src = g_object_get_data ((GObject *) mail_display, "current_src_uri");
+
+ save_url (mail_display, src);
+}
+
+enum {
+ /*
+ * This is used to mask the link specific menu items.
+ */
+ MASK_URL = 1,
+
+ /*
+ * This is used to mask src specific menu items.
+ */
+ MASK_SRC = 2
+};
+
+#define SEPARATOR { "", NULL, (NULL), NULL, 0 }
+#define TERMINATOR { NULL, NULL, (NULL), NULL, 0 }
+
+static EPopupMenu link_menu [] = {
+ E_POPUP_ITEM (N_("Open Link in Browser"), G_CALLBACK (link_open_in_browser), MASK_URL),
+ E_POPUP_ITEM (N_("Copy Link Location"), G_CALLBACK (link_copy_location), MASK_URL),
+#if 0
+ E_POPUP_ITEM (N_("Save Link as (FIXME)"), G_CALLBACK (link_save_as), MASK_URL),
+#endif
+ E_POPUP_ITEM (N_("Save Image as..."), G_CALLBACK (image_save_as), MASK_SRC),
+
+ TERMINATOR
+};
+
+
+/*
+ * Create a window and popup our widget, with reasonable semantics for the popup
+ * disappearing, etc.
+ */
+
+typedef struct _PopupInfo PopupInfo;
+struct _PopupInfo {
+ GtkWidget *w;
+ GtkWidget *win;
+ guint destroy_timeout;
+ guint widget_destroy_handle;
+ Bonobo_Listener listener;
+ gboolean hidden;
+};
+
+/* Aiieee! Global Data! */
+static GtkWidget *the_popup = NULL;
+
+static void
+popup_window_destroy_cb (PopupInfo *pop, GObject *deadbeef)
+{
+ the_popup = NULL;
+
+ if (pop->destroy_timeout != 0)
+ g_source_remove(pop->destroy_timeout);
+
+ bonobo_event_source_client_remove_listener (bonobo_widget_get_objref (BONOBO_WIDGET (pop->w)),
+ pop->listener,
+ NULL);
+ CORBA_Object_release (pop->listener, NULL);
+ g_object_unref(pop->w);
+ g_free (pop);
+}
+
+static int
+popup_timeout_cb (gpointer user_data)
+{
+ PopupInfo *pop = (PopupInfo *) user_data;
+
+ pop->destroy_timeout = 0;
+ gtk_widget_destroy (pop->win);
+
+ return 0;
+}
+
+static int
+popup_enter_cb (GtkWidget *w, GdkEventCrossing *ev, gpointer user_data)
+{
+ PopupInfo *pop = (PopupInfo *) user_data;
+
+ if (pop->destroy_timeout)
+ g_source_remove (pop->destroy_timeout);
+ pop->destroy_timeout = 0;
+
+ return 0;
+}
+
+static int
+popup_leave_cb (GtkWidget *w, GdkEventCrossing *ev, gpointer user_data)
+{
+ PopupInfo *pop = (PopupInfo *) user_data;
+
+ if (pop->destroy_timeout)
+ g_source_remove (pop->destroy_timeout);
+
+ if (!pop->hidden)
+ pop->destroy_timeout = g_timeout_add (500, popup_timeout_cb, pop);
+
+ return 0;
+}
+
+static void
+popup_realize_cb (GtkWidget *widget, gpointer user_data)
+{
+ PopupInfo *pop = (PopupInfo *) user_data;
+
+ gtk_widget_add_events (pop->win, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+
+ if (pop->destroy_timeout == 0) {
+ if (!pop->hidden) {
+ pop->destroy_timeout = g_timeout_add (5000, popup_timeout_cb, pop);
+ } else {
+ pop->destroy_timeout = 0;
+ }
+ }
+}
+
+static void
+popup_size_allocate_cb (GtkWidget *widget, GtkAllocation *alloc, gpointer user_data)
+{
+ gtk_window_set_position (GTK_WINDOW (widget), GTK_WIN_POS_MOUSE);
+}
+
+static PopupInfo *
+make_popup_window (GtkWidget *w)
+{
+ PopupInfo *pop = g_new0 (PopupInfo, 1);
+ GtkWidget *fr;
+
+ /* Only allow for one popup at a time. Ugly. */
+ if (the_popup)
+ gtk_widget_destroy (the_popup);
+
+ pop->w = w;
+ g_object_ref(w);
+ the_popup = pop->win = gtk_window_new (GTK_WINDOW_POPUP);
+ fr = gtk_frame_new (NULL);
+
+ gtk_container_add (GTK_CONTAINER (pop->win), fr);
+ gtk_container_add (GTK_CONTAINER (fr), w);
+
+ gtk_window_set_resizable (GTK_WINDOW (pop->win), FALSE);
+
+ g_signal_connect (pop->win, "enter_notify_event", G_CALLBACK (popup_enter_cb), pop);
+ g_signal_connect (pop->win, "leave_notify_event", G_CALLBACK (popup_leave_cb), pop);
+ g_signal_connect_after (pop->win, "realize", G_CALLBACK (popup_realize_cb), pop);
+ g_signal_connect (pop->win, "size_allocate", G_CALLBACK (popup_size_allocate_cb), pop);
+
+ g_object_weak_ref ((GObject *) pop->win, (GWeakNotify) popup_window_destroy_cb, pop);
+
+ gtk_widget_show (w);
+ gtk_widget_show (fr);
+ gtk_widget_show (pop->win);
+
+ return pop;
+}
+
+static void
+listener_cb (BonoboListener *listener,
+ char *event_name,
+ CORBA_any *any,
+ CORBA_Environment *ev,
+ gpointer user_data)
+{
+ PopupInfo *pop;
+ char *type;
+
+ pop = user_data;
+
+ if (pop->destroy_timeout)
+ g_source_remove (pop->destroy_timeout);
+ pop->destroy_timeout = 0;
+
+ type = bonobo_event_subtype (event_name);
+
+ if (!strcmp (type, "Destroy")) {
+ gtk_widget_destroy (GTK_WIDGET (pop->win));
+ } else if (!strcmp (type, "Hide")) {
+ pop->hidden = TRUE;
+ gtk_widget_hide (GTK_WIDGET (pop->win));
+ }
+
+ g_free (type);
+}
+
+static int
+html_button_press_event (GtkWidget *widget, GdkEventButton *event, MailDisplay *mail_display)
+{
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ if (event->type == GDK_BUTTON_PRESS) {
+ if (event->button == 3) {
+ HTMLEngine *e;
+ HTMLPoint *point;
+ GtkWidget *popup_thing;
+
+ e = GTK_HTML (widget)->engine;
+ point = html_engine_get_point_at (e, event->x, event->y, FALSE);
+
+ if (point) {
+ const char *url, *src;
+
+ url = html_object_get_url (point->object);
+ src = html_object_get_src (point->object);
+
+ if (url && !strncasecmp (url, "mailto:", 7)) {
+ PopupInfo *pop;
+ char *url_decoded;
+
+ url_decoded = gtk_html_get_url_object_relative (GTK_HTML (widget),
+ point->object,
+ url);
+ camel_url_decode (url_decoded);
+
+ popup_thing = bonobo_widget_new_control ("OAFIID:GNOME_Evolution_Addressbook_AddressPopup",
+ CORBA_OBJECT_NIL);
+
+ bonobo_widget_set_property (BONOBO_WIDGET (popup_thing),
+ "email", TC_CORBA_string, url_decoded+7,
+ NULL);
+ g_free (url_decoded);
+
+ pop = make_popup_window (popup_thing);
+
+ pop->listener = bonobo_event_source_client_add_listener_full(
+ bonobo_widget_get_objref (BONOBO_WIDGET (popup_thing)),
+ g_cclosure_new (G_CALLBACK (listener_cb), pop, NULL),
+ NULL, NULL);
+ } else if (url || src) {
+ int hide_mask = 0;
+
+ if (!url)
+ hide_mask |= MASK_URL;
+
+ if (!src)
+ hide_mask |= MASK_SRC;
+
+ g_free (g_object_get_data ((GObject *) mail_display, "current_src_uri"));
+ g_object_set_data ((GObject *) mail_display, "current_src_uri",
+ gtk_html_get_url_object_relative (GTK_HTML (widget),
+ point->object,
+ src));
+
+ e_popup_menu_run (link_menu, (GdkEvent *) event, 0, hide_mask, mail_display);
+ }
+
+ html_point_destroy (point);
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static inline void
+set_underline (HTMLEngine *e, HTMLObject *o, gboolean underline)
+{
+ HTMLText *text = HTML_TEXT (o);
+
+ html_text_set_font_style (text, e, underline
+ ? html_text_get_font_style (text) | GTK_HTML_FONT_STYLE_UNDERLINE
+ : html_text_get_font_style (text) & ~GTK_HTML_FONT_STYLE_UNDERLINE);
+ html_engine_queue_draw (e, o);
+}
+
+static void
+update_active (GtkWidget *widget, gint x, gint y, MailDisplay *mail_display)
+{
+ HTMLEngine *e;
+ HTMLPoint *point;
+ const gchar *email;
+
+ e = GTK_HTML (widget)->engine;
+
+ point = html_engine_get_point_at (e, x, y, FALSE);
+ if (mail_display->last_active && (!point || mail_display->last_active != point->object)) {
+ set_underline (e, HTML_OBJECT (mail_display->last_active), FALSE);
+ mail_display->last_active = NULL;
+ }
+ if (point) {
+ email = (const gchar *) html_object_get_data (point->object, "email");
+ if (email && html_object_is_text (point->object)) {
+ set_underline (e, point->object, TRUE);
+ mail_display->last_active = point->object;
+ }
+ html_point_destroy (point);
+ }
+}
+
+static int
+html_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event, MailDisplay *mail_display)
+{
+ update_active (widget, event->x, event->y, mail_display);
+
+ return FALSE;
+}
+
+static int
+html_motion_notify_event (GtkWidget *widget, GdkEventMotion *event, MailDisplay *mail_display)
+{
+ int x, y;
+
+ g_return_val_if_fail (widget != NULL, 0);
+ g_return_val_if_fail (GTK_IS_HTML (widget), 0);
+ g_return_val_if_fail (event != NULL, 0);
+
+ if (event->is_hint)
+ gdk_window_get_pointer (GTK_LAYOUT (widget)->bin_window, &x, &y, NULL);
+ else {
+ x = event->x;
+ y = event->y;
+ }
+
+ update_active (widget, x, y, mail_display);
+
+ return FALSE;
+}
+
+static void
+html_iframe_created (GtkWidget *w, GtkHTML *iframe, MailDisplay *mail_display)
+{
+ g_signal_connect (iframe, "button_press_event",
+ G_CALLBACK (html_button_press_event), mail_display);
+ g_signal_connect (iframe, "motion_notify_event",
+ G_CALLBACK (html_motion_notify_event), mail_display);
+ g_signal_connect (iframe, "enter_notify_event",
+ G_CALLBACK (html_enter_notify_event), mail_display);
+}
+
+static GNOME_Evolution_ShellView
+retrieve_shell_view_interface_from_control (BonoboControl *control)
+{
+ Bonobo_ControlFrame control_frame;
+ GNOME_Evolution_ShellView shell_view_interface;
+ CORBA_Environment ev;
+
+ control_frame = bonobo_control_get_control_frame (control, NULL);
+
+ if (control_frame == NULL)
+ return CORBA_OBJECT_NIL;
+
+ CORBA_exception_init (&ev);
+ shell_view_interface = Bonobo_Unknown_queryInterface (control_frame,
+ "IDL:GNOME/Evolution/ShellView:1.0",
+ &ev);
+
+ if (BONOBO_EX (&ev))
+ shell_view_interface = CORBA_OBJECT_NIL;
+
+ CORBA_exception_free (&ev);
+
+ return shell_view_interface;
+}
+
+static void
+set_status_message (const char *message, int busy)
+{
+ EList *controls;
+ EIterator *it;
+
+ controls = folder_browser_factory_get_control_list ();
+ for (it = e_list_get_iterator (controls); e_iterator_is_valid (it); e_iterator_next (it)) {
+ BonoboControl *control;
+ GNOME_Evolution_ShellView shell_view_interface;
+ CORBA_Environment ev;
+
+ control = BONOBO_CONTROL (e_iterator_get (it));
+
+ shell_view_interface = retrieve_shell_view_interface_from_control (control);
+
+ CORBA_exception_init (&ev);
+
+ if (shell_view_interface != CORBA_OBJECT_NIL) {
+ if (message != NULL)
+ GNOME_Evolution_ShellView_setMessage (shell_view_interface,
+ message[0] ? message: "",
+ busy,
+ &ev);
+ }
+
+ CORBA_exception_free (&ev);
+
+ bonobo_object_release_unref (shell_view_interface, NULL);
+
+ /* yeah we only set the first one. Why? Because it seems to leave
+ random ones lying around otherwise. Shrug. */
+ break;
+ }
+
+ g_object_unref (it);
+}
+
+/* For now show every url but possibly limit it to showing only http:
+ or ftp: urls */
+static void
+html_on_url (GtkHTML *html, const char *url, MailDisplay *mail_display)
+{
+ static char *previous_url = NULL;
+
+ /* This all looks silly but yes, this is the proper way to mix
+ GtkHTML's on_url with BonoboUIComponent statusbar */
+ if (!url || (previous_url && (strcmp (url, previous_url) != 0)))
+ set_status_message ("", FALSE);
+ if (url) {
+ set_status_message (url, FALSE);
+ g_free (previous_url);
+ previous_url = g_strdup (url);
+ }
+}
+
+/* If if a gconf setting for the mail display has changed redisplay to pick up the changes */
+static void
+display_notify (GConfClient *gconf, guint cnxn_id, GConfEntry *entry, gpointer data)
+{
+ MailDisplay *md = data;
+ gchar *tkey;
+
+ g_return_if_fail (entry != NULL);
+ g_return_if_fail (gconf_entry_get_key (entry) != NULL);
+ g_return_if_fail (gconf_entry_get_value (entry) != NULL);
+
+ tkey = strrchr (entry->key, '/');
+
+ g_return_if_fail (tkey != NULL);
+
+ if (!strcmp (tkey, "/animate_images")) {
+ gtk_html_set_animate (md->html, gconf_value_get_bool (gconf_entry_get_value(entry)));
+ } else if (!strcmp (tkey, "/citation_color")
+ || !strcmp (tkey, "/mark_citations")) {
+ mail_display_queue_redisplay (md);
+ } else if (!strcmp (tkey, "/caret_mode")) {
+ gtk_html_set_caret_mode(md->html, gconf_value_get_bool (gconf_entry_get_value(entry)));
+ }
+}
+
+GtkWidget *
+mail_display_new (void)
+{
+ MailDisplay *mail_display = g_object_new (mail_display_get_type (), NULL);
+ GtkWidget *scroll, *html;
+ GdkAtom clipboard_atom;
+ HTMLTokenizer *tok;
+ GConfClient *gconf;
+
+ gtk_box_set_homogeneous (GTK_BOX (mail_display), FALSE);
+ gtk_widget_show (GTK_WIDGET (mail_display));
+
+ scroll = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
+ gtk_box_pack_start_defaults (GTK_BOX (mail_display), scroll);
+ gtk_widget_show (scroll);
+
+ html = gtk_html_new ();
+ tok = e_searching_tokenizer_new ();
+ html_engine_set_tokenizer (GTK_HTML (html)->engine, tok);
+ g_object_unref (tok);
+
+ mail_display_initialize_gtkhtml (mail_display, GTK_HTML (html));
+
+ gtk_container_add (GTK_CONTAINER (scroll), html);
+ gtk_widget_show (GTK_WIDGET (html));
+
+ g_signal_connect (mail_display->invisible, "selection_get",
+ G_CALLBACK (invisible_selection_get_callback), mail_display);
+ g_signal_connect (mail_display->invisible, "selection_clear_event",
+ G_CALLBACK (invisible_selection_clear_event_callback), mail_display);
+
+ gtk_selection_add_target (mail_display->invisible,
+ GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING, 1);
+
+ clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
+ if (clipboard_atom != GDK_NONE)
+ gtk_selection_add_target (mail_display->invisible,
+ clipboard_atom, GDK_SELECTION_TYPE_STRING, 1);
+
+ gconf = mail_config_get_gconf_client ();
+ gtk_html_set_animate (GTK_HTML (html), gconf_client_get_bool (gconf, "/apps/evolution/mail/display/animate_images", NULL));
+ gtk_html_set_caret_mode (GTK_HTML (html), gconf_client_get_bool (gconf, "/apps/evolution/mail/display/caret_mode", NULL));
+
+ gconf_client_add_dir (gconf, "/apps/evolution/mail/display",GCONF_CLIENT_PRELOAD_NONE, NULL);
+ mail_display->priv->display_notify_id = gconf_client_notify_add (gconf, "/apps/evolution/mail/display",
+ display_notify, mail_display, NULL, NULL);
+
+ mail_display->scroll = GTK_SCROLLED_WINDOW (scroll);
+ mail_display->html = GTK_HTML (html);
+ g_object_ref (mail_display->html);
+ mail_display->last_active = NULL;
+ mail_display->data = g_new0 (GData *, 1);
+ g_datalist_init (mail_display->data);
+
+ return GTK_WIDGET (mail_display);
+}
+
+void
+mail_display_initialize_gtkhtml (MailDisplay *mail_display, GtkHTML *html)
+{
+ gtk_html_set_default_content_type (GTK_HTML (html), "text/html; charset=utf-8");
+
+ gtk_html_set_editable (GTK_HTML (html), FALSE);
+
+ g_signal_connect (html, "url_requested",
+ G_CALLBACK (on_url_requested),
+ mail_display);
+ g_signal_connect (html, "object_requested",
+ G_CALLBACK (on_object_requested),
+ mail_display);
+ g_signal_connect (html, "link_clicked",
+ G_CALLBACK (on_link_clicked),
+ mail_display);
+ g_signal_connect (html, "button_press_event",
+ G_CALLBACK (html_button_press_event), mail_display);
+ g_signal_connect (html, "motion_notify_event",
+ G_CALLBACK (html_motion_notify_event), mail_display);
+ g_signal_connect (html, "enter_notify_event",
+ G_CALLBACK (html_enter_notify_event), mail_display);
+ g_signal_connect (html, "iframe_created",
+ G_CALLBACK (html_iframe_created), mail_display);
+ g_signal_connect (html, "on_url",
+ G_CALLBACK (html_on_url), mail_display);
+}
+
+static void
+free_url (gpointer key, gpointer value, gpointer data)
+{
+ g_free (key);
+ if (data)
+ g_byte_array_free (value, TRUE);
+}
+
+static void
+free_data_urls (gpointer urls)
+{
+ g_hash_table_foreach (urls, free_url, GINT_TO_POINTER (1));
+ g_hash_table_destroy (urls);
+}
+
+char *
+mail_display_add_url (MailDisplay *md, const char *kind, char *url, gpointer data)
+{
+ GHashTable *urls;
+ gpointer old_key, old_value;
+
+ urls = g_datalist_get_data (md->data, kind);
+ if (!urls) {
+ urls = g_hash_table_new (g_str_hash, g_str_equal);
+ g_datalist_set_data_full (md->data, "data_urls", urls,
+ free_data_urls);
+ }
+
+ if (g_hash_table_lookup_extended (urls, url, &old_key, &old_value)) {
+ g_free (url);
+ url = old_key;
+ }
+
+ g_hash_table_insert (urls, url, data);
+
+ return url;
+}
+
+const char *
+mail_display_get_url_for_icon (MailDisplay *md, const char *icon_name)
+{
+ char *icon_path, buf[1024], *url;
+ int fd, nread;
+ GByteArray *ba;
+
+ /* FIXME: cache */
+
+ if (*icon_name == '/')
+ icon_path = g_strdup (icon_name);
+ else {
+ icon_path = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_PIXMAP,
+ icon_name, TRUE, NULL);
+ if (!icon_path)
+ return "file:///dev/null";
+ }
+
+ fd = open (icon_path, O_RDONLY);
+ g_free (icon_path);
+ if (fd == -1)
+ return "file:///dev/null";
+
+ ba = g_byte_array_new ();
+ while (1) {
+ nread = read (fd, buf, sizeof (buf));
+ if (nread < 1)
+ break;
+ g_byte_array_append (ba, buf, nread);
+ }
+ close (fd);
+
+ url = g_strdup_printf ("x-evolution-data:%p", ba);
+
+ return mail_display_add_url (md, "data_urls", url, ba);
+}
+
+
+struct _location_url_stack {
+ struct _location_url_stack *parent;
+ CamelURL *url;
+};
+
+void
+mail_display_push_content_location (MailDisplay *md, const char *location)
+{
+ struct _location_url_stack *node;
+ CamelURL *url;
+
+ url = camel_url_new (location, NULL);
+ node = g_new (struct _location_url_stack, 1);
+ node->parent = md->urls;
+ node->url = url;
+ md->urls = node;
+}
+
+CamelURL *
+mail_display_get_content_location (MailDisplay *md)
+{
+ return md->urls ? md->urls->url : NULL;
+}
+
+void
+mail_display_pop_content_location (MailDisplay *md)
+{
+ struct _location_url_stack *node;
+
+ if (!md->urls) {
+ g_warning ("content-location stack underflow!");
+ return;
+ }
+
+ node = md->urls;
+ md->urls = node->parent;
+
+ if (node->url)
+ camel_url_free (node->url);
+
+ g_free (node);
+}
+
+E_MAKE_TYPE (mail_display, "MailDisplay", MailDisplay, mail_display_class_init, mail_display_init, PARENT_TYPE);
diff --git a/mail/mail-display.h b/mail/mail-display.h
new file mode 100644
index 0000000000..fe95c95490
--- /dev/null
+++ b/mail/mail-display.h
@@ -0,0 +1,137 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * 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 2 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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef _MAIL_DISPLAY_H_
+#define _MAIL_DISPLAY_H_
+
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtkhtml/gtkhtml.h>
+#include <gtkhtml/gtkhtml-stream.h>
+
+#include <camel/camel-stream.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-medium.h>
+#include <camel/camel-folder.h>
+
+#include "mail-types.h"
+#include "mail-config.h" /*display_style*/
+#include "mail-display-stream.h"
+
+#define MAIL_DISPLAY_TYPE (mail_display_get_type ())
+#define MAIL_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MAIL_DISPLAY_TYPE, MailDisplay))
+#define MAIL_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), MAIL_DISPLAY_TYPE, MailDisplayClass))
+#define IS_MAIL_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MAIL_DISPLAY_TYPE))
+#define IS_MAIL_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MAIL_DISPLAY_TYPE))
+
+struct _MailDisplay {
+ GtkVBox parent;
+
+ struct _MailDisplayPrivate *priv;
+
+ GtkScrolledWindow *scroll;
+ GtkHTML *html;
+ /* GtkHTMLStream *stream; */
+ gint redisplay_counter;
+ gpointer last_active;
+ guint idle_id;
+
+ char *charset;
+
+ char *selection;
+
+ CamelMimeMessage *current_message;
+ CamelMessageInfo *info;
+ CamelFolder *folder;
+ GData **data;
+
+ /* stack of Content-Location URLs used for combining with a
+ relative URL Content-Location on a leaf part in order to
+ construct the full URL */
+ struct _location_url_stack *urls;
+
+ GHashTable *related; /* related parts not displayed yet */
+
+ /* Sigh. This shouldn't be needed. I haven't figured out why it is
+ though. */
+ GtkWidget *invisible;
+
+ MailConfigDisplayStyle display_style;
+
+ guint printing : 1;
+ guint destroyed: 1;
+};
+
+typedef struct {
+ GtkVBoxClass parent_class;
+} MailDisplayClass;
+
+GtkType mail_display_get_type (void);
+GtkWidget * mail_display_new (void);
+
+void mail_display_initialize_gtkhtml (MailDisplay *mail_display, GtkHTML *html);
+
+void mail_display_queue_redisplay (MailDisplay *mail_display);
+void mail_display_render (MailDisplay *mail_display, GtkHTML *html, gboolean reset_scroll);
+void mail_display_redisplay (MailDisplay *mail_display, gboolean reset_scroll);
+void mail_display_redisplay_when_loaded (MailDisplay *md,
+ gconstpointer key,
+ void (*callback)(MailDisplay *, gpointer),
+ GtkHTML *html,
+ gpointer data);
+void mail_display_stream_write_when_loaded (MailDisplay *md,
+ gconstpointer key,
+ const gchar *url,
+ void (*callback)(MailDisplay *, gpointer),
+ GtkHTML *html,
+ GtkHTMLStream *handle,
+ gpointer data);
+
+void mail_display_set_message (MailDisplay *mail_display,
+ CamelMedium *medium,
+ CamelFolder *folder,
+ CamelMessageInfo *info);
+
+void mail_display_set_charset (MailDisplay *mail_display,
+ const char *charset);
+
+void mail_display_load_images (MailDisplay *mail_display);
+
+void mail_text_write (MailDisplayStream *stream,
+ MailDisplay *md,
+ CamelMimePart *part,
+ gint idx,
+ gboolean printing,
+ const char *text);
+void mail_error_printf (MailDisplayStream *stream,
+ const char *format, ...);
+
+char *mail_display_add_url (MailDisplay *md, const char *kind, char *url, gpointer data);
+
+const char *mail_display_get_url_for_icon (MailDisplay *md, const char *icon_name);
+
+void mail_display_push_content_location (MailDisplay *md, const char *location);
+CamelURL *mail_display_get_content_location (MailDisplay *md);
+void mail_display_pop_content_location (MailDisplay *md);
+
+#endif /* _MAIL_DISPLAY_H_ */
diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c
index c22d3011b0..3d4eb96d53 100644
--- a/mail/mail-folder-cache.c
+++ b/mail/mail-folder-cache.c
@@ -98,9 +98,7 @@ struct _store_info {
CamelStore *store; /* the store for these folders */
- /* only 1 should be set */
- EvolutionStorage *storage;
- GNOME_Evolution_Storage corba_storage;
+ EStorage *storage;
/* Outstanding folderinfo requests */
EDList folderinfo_updates;
@@ -109,7 +107,7 @@ struct _store_info {
static void folder_changed(CamelObject *o, gpointer event_data, gpointer user_data);
static void folder_renamed(CamelObject *o, gpointer event_data, gpointer user_data);
static void folder_finalised(CamelObject *o, gpointer event_data, gpointer user_data);
-
+static void message_changed (CamelObject *o, gpointer event_data, gpointer user_data);
static guint ping_id = 0;
static gboolean ping_cb (gpointer user_data);
@@ -188,9 +186,7 @@ real_flush_updates(void *o, void *event_data, void *data)
{
struct _folder_update *up;
struct _store_info *si;
- EvolutionStorage *storage;
- GNOME_Evolution_Storage corba_storage;
- CORBA_Environment ev;
+ EStorage *storage;
time_t now;
LOCK(info_lock);
@@ -199,11 +195,9 @@ real_flush_updates(void *o, void *event_data, void *data)
if (si) {
storage = si->storage;
if (storage)
- bonobo_object_ref((BonoboObject *)storage);
- corba_storage = si->corba_storage;
+ g_object_ref (storage);
} else {
storage = NULL;
- corba_storage = CORBA_OBJECT_NIL;
}
UNLOCK(info_lock);
@@ -214,7 +208,7 @@ real_flush_updates(void *o, void *event_data, void *data)
mail_filter_delete_uri(up->store, up->uri);
mail_config_uri_deleted(CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(up->store))->compare_folder_name, up->uri);
if (up->unsub)
- evolution_storage_removed_folder (storage, up->path);
+ e_storage_removed_folder (storage, up->path);
} else
mail_vfolder_add_uri(up->store, up->uri, TRUE);
} else {
@@ -222,7 +216,7 @@ real_flush_updates(void *o, void *event_data, void *data)
if (up->oldpath) {
if (storage != NULL) {
d(printf("Removing old folder (rename?) '%s'\n", up->oldpath));
- evolution_storage_removed_folder(storage, up->oldpath);
+ e_storage_removed_folder(storage, up->oldpath);
}
/* ELSE? Shell supposed to handle the local snot case */
}
@@ -237,24 +231,28 @@ real_flush_updates(void *o, void *event_data, void *data)
}
if (up->name == NULL) {
- if (storage != NULL) {
- d(printf("Updating existing folder: %s (%d unread)\n", up->path, up->unread));
- evolution_storage_update_folder(storage, up->path, up->unread);
- } else if (corba_storage != CORBA_OBJECT_NIL) {
- d(printf("Updating existing (local) folder: %s (%d unread)\n", up->path, up->unread));
- CORBA_exception_init(&ev);
- GNOME_Evolution_Storage_updateFolder(corba_storage, up->path, up->unread, &ev);
- CORBA_exception_free(&ev);
+ EFolder *folder = e_storage_get_folder (storage, up->path);
+
+ if (folder != NULL) {
+ d(printf("updating unread count to '%s' to %d\n", up->path, up->unread));
+ e_folder_set_unread_count (folder, up->unread);
+ } else {
+ g_warning ("No folder at %s ?!", up->path);
}
} else if (storage != NULL) {
char *type = (strncmp(up->uri, "vtrash:", 7)==0)?"vtrash":"mail";
-
+ EFolder *new_folder = e_folder_new (up->name, type, NULL);
+
d(printf("Adding new folder: %s\n", up->path));
- evolution_storage_new_folder(storage,
- up->path, up->name, type, up->uri, up->name, NULL,
- up->unread,
- CAMEL_IS_DISCO_STORE(up->store)
- && camel_disco_store_can_work_offline((CamelDiscoStore *)up->store), 0);
+
+ e_folder_set_physical_uri (new_folder, up->uri);
+ e_folder_set_unread_count (new_folder, up->unread);
+ if (CAMEL_IS_DISCO_STORE(up->store) && camel_disco_store_can_work_offline((CamelDiscoStore *)up->store))
+ e_folder_set_can_sync_offline (new_folder, TRUE);
+ else
+ e_folder_set_can_sync_offline (new_folder, FALSE);
+
+ e_storage_new_folder(storage, up->path, new_folder);
}
if (!up->olduri && up->add)
@@ -279,9 +277,9 @@ real_flush_updates(void *o, void *event_data, void *data)
notify_idle_id = g_idle_add_full (G_PRIORITY_LOW, notify_idle_cb, NULL, NULL);
free_update(up);
-
- if (storage)
- bonobo_object_unref((BonoboObject *)storage);
+
+ if (storage != NULL)
+ g_object_unref (storage);
LOCK(info_lock);
}
@@ -307,7 +305,7 @@ unset_folder_info(struct _folder_info *mfi, int delete, int unsub)
CamelFolder *folder = mfi->folder;
camel_object_unhook_event(folder, "folder_changed", folder_changed, mfi);
- camel_object_unhook_event(folder, "message_changed", folder_changed, mfi);
+ camel_object_unhook_event(folder, "message_changed", message_changed, mfi);
camel_object_unhook_event(folder, "renamed", folder_renamed, mfi);
camel_object_unhook_event(folder, "finalize", folder_finalised, mfi);
}
@@ -907,17 +905,18 @@ store_online_cb (CamelStore *store, void *data)
}
void
-mail_note_store(CamelStore *store, CamelOperation *op, EvolutionStorage *storage, GNOME_Evolution_Storage corba_storage,
+mail_note_store(CamelStore *store, CamelOperation *op, EStorage *storage,
void (*done)(CamelStore *store, CamelFolderInfo *info, void *data), void *data)
{
struct _store_info *si;
struct _update_data *ud;
const char *buf;
guint timeout;
+
+ g_return_if_fail (storage == NULL || E_IS_STORAGE (storage));
g_assert(CAMEL_IS_STORE(store));
g_assert(pthread_self() == mail_gui_thread);
- g_assert(storage == NULL || corba_storage == CORBA_OBJECT_NIL);
LOCK(info_lock);
@@ -942,8 +941,7 @@ mail_note_store(CamelStore *store, CamelOperation *op, EvolutionStorage *storage
CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->compare_folder_name);
si->storage = storage;
if (storage != NULL)
- bonobo_object_ref((BonoboObject *)storage);
- si->corba_storage = corba_storage;
+ g_object_ref (storage);
si->store = store;
camel_object_ref((CamelObject *)store);
g_hash_table_insert(stores, store, si);
diff --git a/mail/mail-folder-cache.h b/mail/mail-folder-cache.h
index 3d612d7d6b..b9f8f44dfb 100644
--- a/mail/mail-folder-cache.h
+++ b/mail/mail-folder-cache.h
@@ -25,14 +25,15 @@
#ifndef _MAIL_FOLDER_CACHE_H
#define _MAIL_FOLDER_CACHE_H
-#include <shell/evolution-storage.h>
+#include "e-storage.h"
/* Add a store whose folders should appear in the shell
The folders are scanned from the store, and/or added at
runtime via the folder_created event */
void
-mail_note_store(CamelStore *store, CamelOperation *op, EvolutionStorage *storage, GNOME_Evolution_Storage corba_storage,
- void (*done)(CamelStore *store, CamelFolderInfo *info, void *data), void *data);
+mail_note_store(CamelStore *store, CamelOperation *op, EStorage *storage,
+ void (*done) (CamelStore *store, CamelFolderInfo *info, void *data),
+ void *data);
/* de-note a store */
void mail_note_store_remove(CamelStore *store);
@@ -41,7 +42,7 @@ void mail_note_store_remove(CamelStore *store);
The folder must have already been created on the store (which has already been noted)
before the folder can be opened
*/
-void mail_note_folder(struct _CamelFolder *folder);
+void mail_note_folder(CamelFolder *folder);
/* Returns true if a folder is available (yet), and also sets *folderp (if supplied)
to a (referenced) copy of the folder if it has already been opened */
diff --git a/mail/mail-font-prefs.c b/mail/mail-font-prefs.c
new file mode 100644
index 0000000000..0d26f1ccbd
--- /dev/null
+++ b/mail/mail-font-prefs.c
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Larry Ewing <lewing@ximian.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * 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 2 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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <gtkhtml/gtkhtml-propmanager.h>
+
+#include "mail-font-prefs.h"
+
+static GtkVBoxClass *parent_class = NULL;
+
+GtkWidget *
+mail_font_prefs_new (void)
+{
+ MailFontPrefs *new;
+
+ new = MAIL_FONT_PREFS (g_object_new (mail_font_prefs_get_type ()), NULL);
+
+ return GTK_WIDGET (new);
+}
+
+void
+mail_font_prefs_apply (MailFontPrefs *prefs)
+{
+ gtk_html_propmanager_apply (prefs->pman);
+}
+
+static void
+font_prefs_changed (GtkHTMLPropmanager *pman, MailFontPrefs *prefs)
+{
+ if (prefs->control)
+ evolution_config_control_changed (prefs->control);
+}
+
+static void
+mail_font_prefs_destroy (GtkObject *object)
+{
+ MailFontPrefs *prefs = (MailFontPrefs *) object;
+
+ if (prefs->pman) {
+ g_object_unref(prefs->pman);
+ g_object_unref(prefs->gui);
+ prefs->pman = NULL;
+ }
+
+ if (GTK_OBJECT_CLASS (parent_class)->finalize)
+ (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+static void
+mail_font_prefs_init (MailFontPrefs *prefs)
+{
+ GtkWidget *toplevel;
+ GladeXML *gui;
+
+ gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", "font_tab", NULL);
+ prefs->gui = gui;
+
+ prefs->pman = GTK_HTML_PROPMANAGER (gtk_html_propmanager_new (NULL));
+ gtk_html_propmanager_set_gui (prefs->pman, gui, NULL);
+ g_object_ref(prefs->pman);
+ gtk_object_sink (GTK_OBJECT (prefs->pman));
+
+ g_signal_connect(prefs->pman, "changed", font_prefs_changed, prefs);
+
+ /* get our toplevel widget */
+ toplevel = glade_xml_get_widget (gui, "toplevel");
+
+ /* reparent */
+ g_object_ref (toplevel);
+ gtk_container_remove (GTK_CONTAINER (toplevel->parent), toplevel);
+ gtk_container_add (GTK_CONTAINER (prefs), toplevel);
+ g_object_unref (toplevel);
+}
+
+static void
+mail_font_prefs_class_init (MailFontPrefsClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *) klass;
+ parent_class = g_type_class_ref(gtk_vbox_get_type ());
+
+ object_class->destroy = mail_font_prefs_destroy;
+}
+
+GtkType
+mail_font_prefs_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo type_info = {
+ sizeof (MailFontPrefsClass),
+ NULL, NULL,
+ (GClassInitFunc) mail_font_prefs_class_init,
+ NULL, NULL,
+ sizeof (MailFontPrefs),
+ 0,
+ (GInstanceInitFunc) mail_font_prefs_init,
+ };
+
+ type = g_type_register_static (gtk_vbox_get_type (), "MailFontPrefs", &type_info, 0);
+ }
+
+ return type;
+}
+
+
diff --git a/mail/mail-font-prefs.h b/mail/mail-font-prefs.h
new file mode 100644
index 0000000000..14a1d20b40
--- /dev/null
+++ b/mail/mail-font-prefs.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * 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 2 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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+#ifndef __MAIL_FONT_PREFS_H__
+#define __MAIL_FONT_PREFS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif
+
+#include <gtk/gtk.h>
+#include <gtkhtml/gtkhtml-propmanager.h>
+
+#include <shell/Evolution.h>
+#include "evolution-config-control.h"
+
+#define MAIL_FONT_PREFS_TYPE (mail_font_prefs_get_type())
+#define MAIL_FONT_PREFS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MAIL_FONT_PREFS_TYPE, MailFontPrefs))
+#define MAIL_FONT_PREFS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), MAIL_FONT_PREFS_TYPE, MailFontPrefsClass))
+#define IS_MAIL_FONT_PREFS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MAIL_FONT_PREFS_TYPE))
+#define IS_MAIL_FONT_PREFS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MAIL_FONT_PREFS_TYPE))
+
+typedef struct _MailFontPrefs MailFontPrefs;
+typedef struct _MailFontPrefsClass MailFontPrefsClass;
+
+struct _MailFontPrefs {
+ GtkVBox parent_object;
+
+ GtkHTMLPropmanager *pman;
+ GladeXML *gui;
+ EvolutionConfigControl *control;
+};
+
+struct _MailFontPrefsClass {
+ GtkVBoxClass parent_object;
+};
+
+GtkType mail_font_prefs_get_type (void);
+GtkWidget * mail_font_prefs_new (void);
+void mail_font_prefs_apply (MailFontPrefs *prefs);
+
+#define MAIL_FONT_PREFS_CONTROL_ID "OAFIID:GNOME_Evolution_Mail_FontPrefs_ConfigControl"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __MAIL_FONT_PREFS_H__ */
diff --git a/mail/mail-format.c b/mail/mail-format.c
new file mode 100644
index 0000000000..92428af592
--- /dev/null
+++ b/mail/mail-format.c
@@ -0,0 +1,2131 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Dan Winship <danw@ximian.com>
+ * Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2000-2003 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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>
+#endif
+
+#include <string.h> /* for strstr */
+#include <ctype.h>
+#include <fcntl.h>
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <libgnome/gnome-util.h>
+#include <libgnomevfs/gnome-vfs-mime-handlers.h>
+#include <shell/e-setup.h>
+
+#include <gal/util/e-iconv.h>
+
+#include <camel/camel-mime-utils.h>
+#include <camel/camel-stream-null.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-multipart-signed.h>
+#include <camel/camel-mime-filter-enriched.h>
+#include <camel/camel-mime-filter-tohtml.h>
+#include <camel/camel-mime-filter-windows.h>
+
+#include <e-util/e-trie.h>
+#include <e-util/e-time-utils.h>
+
+#include "mail.h"
+#include "mail-tools.h"
+#include "mail-display.h"
+#include "mail-format.h"
+#include "mail-mt.h"
+#include "mail-crypto.h"
+
+
+#define STANDARD_ISSUE_TABLE_OPEN "<table cellspacing=0 cellpadding=10 width=\"100%\">"
+
+
+static gboolean handle_text_plain (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_text_enriched (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_text_html (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_image (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_multipart_mixed (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_multipart_related (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_multipart_alternative (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_multipart_appledouble (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_multipart_encrypted (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_multipart_signed (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_message_rfc822 (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+static gboolean handle_message_external_body (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+
+static gboolean handle_via_bonobo (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+
+/* writes the header info for a mime message into an html stream */
+static void write_headers (MailDisplayStream *stream, MailDisplay *md, CamelMimeMessage *message);
+
+/* dispatch html printing via mimetype */
+static gboolean format_mime_part (CamelMimePart *part, MailDisplay *md, MailDisplayStream *stream);
+
+static void
+free_url (gpointer key, gpointer value, gpointer data)
+{
+ g_free (key);
+ if (data)
+ g_byte_array_free (value, TRUE);
+}
+
+static void
+free_part_urls (gpointer urls)
+{
+ g_hash_table_foreach (urls, free_url, NULL);
+ g_hash_table_destroy (urls);
+}
+
+static void
+free_data_urls (gpointer urls)
+{
+ g_hash_table_foreach (urls, free_url, GINT_TO_POINTER (1));
+ g_hash_table_destroy (urls);
+}
+
+/**
+ * mail_format_mime_message:
+ * @mime_message: the input mime message
+ * @md: the MailDisplay to render into
+ *
+ * Writes a CamelMimeMessage out into a MailDisplay
+ **/
+void
+mail_format_mime_message (CamelMimeMessage *mime_message, MailDisplay *md,
+ MailDisplayStream *stream)
+{
+ GHashTable *hash;
+
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (mime_message));
+
+ hash = g_datalist_get_data (md->data, "part_urls");
+ if (!hash) {
+ hash = g_hash_table_new (g_str_hash, g_str_equal);
+ g_datalist_set_data_full (md->data, "part_urls", hash,
+ free_part_urls);
+ }
+ hash = g_datalist_get_data (md->data, "data_urls");
+ if (!hash) {
+ hash = g_hash_table_new (g_str_hash, g_str_equal);
+ g_datalist_set_data_full (md->data, "data_urls", hash,
+ free_data_urls);
+ }
+
+ hash = g_datalist_get_data (md->data, "attachment_states");
+ if (!hash) {
+ hash = g_hash_table_new (NULL, NULL);
+ g_datalist_set_data_full (md->data, "attachment_states", hash,
+ (GDestroyNotify) g_hash_table_destroy);
+ }
+ hash = g_datalist_get_data (md->data, "fake_parts");
+ if (!hash) {
+ hash = g_hash_table_new (NULL, NULL);
+ g_datalist_set_data_full (md->data, "fake_parts", hash,
+ (GDestroyNotify) g_hash_table_destroy);
+ }
+
+ write_headers (stream, md, mime_message);
+ format_mime_part (CAMEL_MIME_PART (mime_message), md, stream);
+}
+
+
+/**
+ * mail_format_raw_message:
+ * @mime_message: the input mime message
+ * @md: the MailDisplay to render into
+ *
+ * Writes a CamelMimeMessage source out into a MailDisplay
+ **/
+void
+mail_format_raw_message (CamelMimeMessage *mime_message, MailDisplay *md,
+ MailDisplayStream *stream)
+{
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilter *html_filter;
+ CamelDataWrapper *wrapper;
+ guint32 flags;
+
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (mime_message));
+
+ wrapper = CAMEL_DATA_WRAPPER (mime_message);
+ if (!mail_content_loaded (wrapper, md, TRUE, NULL, md->html, NULL))
+ return;
+
+ filtered_stream = camel_stream_filter_new_with_stream ((CamelStream *) stream);
+
+ flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
+ CAMEL_MIME_FILTER_TOHTML_ESCAPE_8BIT;
+ html_filter = camel_mime_filter_tohtml_new (flags, 0);
+ camel_stream_filter_add (filtered_stream, html_filter);
+ camel_object_unref (html_filter);
+
+ camel_stream_write_string ((CamelStream *) stream, STANDARD_ISSUE_TABLE_OPEN "<tr><td><tt>");
+
+ mail_format_data_wrapper_write_to_stream (wrapper, FALSE, md, (CamelStream *) filtered_stream);
+ camel_object_unref (filtered_stream);
+
+ camel_stream_write_string ((CamelStream *) stream, "</tt></td></tr></table>");
+}
+
+static const char *
+get_cid (CamelMimePart *part, MailDisplay *md)
+{
+ static int fake_cid_counter = 0;
+ char *cid;
+
+ /* If we have a real Content-ID, use it. If we don't,
+ * make a (syntactically invalid, unique) fake one.
+ */
+ if (camel_mime_part_get_content_id (part)) {
+ cid = g_strdup_printf ("cid:%s", camel_mime_part_get_content_id (part));
+ } else
+ cid = g_strdup_printf ("cid:@@@%d", fake_cid_counter++);
+
+ return mail_display_add_url (md, "part_urls", cid, part);
+}
+
+static const char *
+get_location (CamelMimePart *part, MailDisplay *md)
+{
+ CamelURL *base;
+ const char *loc;
+ char *location;
+
+ base = mail_display_get_content_location (md);
+
+ loc = camel_mime_part_get_content_location (part);
+ if (!loc) {
+ if (!base)
+ return NULL;
+
+ location = camel_url_to_string (base, 0);
+ return mail_display_add_url (md, "part_urls", location, part);
+ }
+
+ /* kludge: If the multipart/related does not have a
+ Content-Location header and the HTML part doesn't contain a
+ Content-Location header either, then we will end up
+ generating a invalid unique identifier in the form of
+ "cid:@@@%d" for use in GtkHTML's iframe src url. This means
+ that when GtkHTML requests a relative URL, it will request
+ "cid:/%s" */
+ mail_display_add_url (md, "part_urls", g_strdup_printf ("cid:/%s", loc), part);
+
+ if (!strchr (loc, ':') && base) {
+ CamelURL *url;
+
+ mail_display_add_url (md, "part_urls", g_strdup (loc), part);
+
+ url = camel_url_new_with_base (base, loc);
+ location = camel_url_to_string (url, 0);
+ camel_url_free (url);
+ } else {
+ location = g_strdup (loc);
+ }
+
+ return mail_display_add_url (md, "part_urls", location, part);
+}
+
+
+static GHashTable *mime_handler_table, *mime_function_table;
+
+static void
+setup_mime_tables (void)
+{
+ mime_handler_table = g_hash_table_new (g_str_hash, g_str_equal);
+ mime_function_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_insert (mime_function_table, "text/plain",
+ handle_text_plain);
+ g_hash_table_insert (mime_function_table, "text/richtext",
+ handle_text_enriched);
+ g_hash_table_insert (mime_function_table, "text/enriched",
+ handle_text_enriched);
+ g_hash_table_insert (mime_function_table, "text/html",
+ handle_text_html);
+
+ g_hash_table_insert (mime_function_table, "image/gif",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/jpeg",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/png",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/x-png",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/tiff",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/x-bmp",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/bmp",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/x-cmu-raster",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/x-ico",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/x-portable-anymap",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/x-portable-bitmap",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/x-portable-graymap",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/x-portable-pixmap",
+ handle_image);
+ g_hash_table_insert (mime_function_table, "image/x-xpixmap",
+ handle_image);
+
+ g_hash_table_insert (mime_function_table, "message/rfc822",
+ handle_message_rfc822);
+ g_hash_table_insert (mime_function_table, "message/news",
+ handle_message_rfc822);
+ g_hash_table_insert (mime_function_table, "message/external-body",
+ handle_message_external_body);
+
+ g_hash_table_insert (mime_function_table, "multipart/alternative",
+ handle_multipart_alternative);
+ g_hash_table_insert (mime_function_table, "multipart/related",
+ handle_multipart_related);
+ g_hash_table_insert (mime_function_table, "multipart/mixed",
+ handle_multipart_mixed);
+ g_hash_table_insert (mime_function_table, "multipart/appledouble",
+ handle_multipart_appledouble);
+ g_hash_table_insert (mime_function_table, "multipart/encrypted",
+ handle_multipart_encrypted);
+ g_hash_table_insert (mime_function_table, "multipart/signed",
+ handle_multipart_signed);
+
+ /* RFC 2046 says unrecognized text subtypes can be treated
+ * as text/plain (as long as you recognize the character set),
+ * and unrecognized multipart subtypes as multipart/mixed. */
+ g_hash_table_insert (mime_function_table, "text/*",
+ handle_text_plain);
+ g_hash_table_insert (mime_function_table, "multipart/*",
+ handle_multipart_mixed);
+}
+
+static gboolean
+component_supports (Bonobo_ServerInfo *component, const char *mime_type)
+{
+ Bonobo_ActivationProperty *prop;
+ CORBA_sequence_CORBA_string stringv;
+ int i;
+
+ prop = bonobo_server_info_prop_find (component, "repo_ids");
+ if (!prop || prop->v._d != Bonobo_ACTIVATION_P_STRINGV)
+ return FALSE;
+
+ stringv = prop->v._u.value_stringv;
+ for (i = 0; i < stringv._length; i++) {
+ if (!strcasecmp ("IDL:Bonobo/PersistStream:1.0", stringv._buffer[i]))
+ break;
+ }
+
+ /* got to end of list with no persist stream? */
+
+ if (i >= stringv._length)
+ return FALSE;
+
+ prop = bonobo_server_info_prop_find (component,
+ "bonobo:supported_mime_types");
+ if (!prop || prop->v._d != Bonobo_ACTIVATION_P_STRINGV)
+ return FALSE;
+
+ stringv = prop->v._u.value_stringv;
+ for (i = 0; i < stringv._length; i++) {
+ if (!strcasecmp (mime_type, stringv._buffer[i]))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+mime_type_uses_evolution_component (const char *mime_type)
+{
+ return (!strcmp (mime_type, "text/x-vcard") || !strcmp (mime_type, "text/calendar"));
+}
+
+static gboolean
+mime_type_can_use_component (const char *mime_type)
+{
+ const char **mime_types;
+ int i;
+
+ mime_types = mail_config_get_allowable_mime_types ();
+ for (i = 0; mime_types[i]; i++) {
+ if (!strcmp (mime_types[i], mime_type))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * mail_lookup_handler:
+ * @mime_type: a MIME type
+ *
+ * Looks up the MIME type in its own tables and GNOME-VFS's and returns
+ * a MailMimeHandler structure detailing the component, application,
+ * and built-in handlers (if any) for that MIME type. (If the component
+ * is non-%NULL, the built-in handler will always be handle_via_bonobo().)
+ * The MailMimeHandler's @generic field is set if the match was for the
+ * MIME supertype rather than the exact type.
+ *
+ * Return value: a MailMimeHandler (which should not be freed), or %NULL
+ * if no handlers are available.
+ **/
+MailMimeHandler *
+mail_lookup_handler (const char *mime_type)
+{
+ MailMimeHandler *handler;
+ char *mime_type_main;
+ const char *p;
+ GList *components, *iter;
+
+ if (mime_handler_table == NULL)
+ setup_mime_tables ();
+
+ /* See if we've already found it. */
+ handler = g_hash_table_lookup (mime_handler_table, mime_type);
+ if (handler)
+ return handler;
+
+ /* Special case MIME type: application/octet-stream
+ * The point of this type is that there isn't a handler.
+ */
+ if (strcmp (mime_type, "application/octet-stream") == 0)
+ return NULL;
+
+ /* No. Create a new one and look up application and full type
+ * handler. If we find a builtin, create the handler and
+ * register it.
+ */
+ handler = g_new0 (MailMimeHandler, 1);
+ handler->applications =
+ gnome_vfs_mime_get_short_list_applications (mime_type);
+ handler->builtin =
+ g_hash_table_lookup (mime_function_table, mime_type);
+
+ if (handler->builtin) {
+ handler->generic = FALSE;
+ handler->is_bonobo = FALSE;
+ goto reg;
+ }
+
+ /* only allow using a bonobo component if it is an evo-component or the user has
+ * specified that we can use a bonobo-component by setting the gconf key */
+ if (mime_type_uses_evolution_component (mime_type) || mime_type_can_use_component (mime_type)) {
+ /* Try for the first matching component. (we don't use get_short_list_comps
+ * as that will return NULL if the oaf files don't have the short_list properties
+ * defined). */
+ components = gnome_vfs_mime_get_all_components (mime_type);
+ for (iter = components; iter; iter = iter->next) {
+ if (component_supports (iter->data, mime_type)) {
+ handler->generic = FALSE;
+ handler->is_bonobo = TRUE;
+ handler->builtin = handle_via_bonobo;
+ handler->component = Bonobo_ServerInfo_duplicate (iter->data);
+ gnome_vfs_mime_component_list_free (components);
+ goto reg;
+ }
+ }
+
+ gnome_vfs_mime_component_list_free (components);
+ }
+
+ /* Try for a generic builtin match. */
+ p = strchr (mime_type, '/');
+ if (p == NULL)
+ p = mime_type + strlen (mime_type);
+ mime_type_main = g_alloca ((p - mime_type) + 3);
+ memcpy (mime_type_main, mime_type, p - mime_type);
+ memcpy (mime_type_main + (p - mime_type), "/*", 3);
+
+ handler->builtin = g_hash_table_lookup (mime_function_table,
+ mime_type_main);
+
+ if (handler->builtin) {
+ handler->generic = TRUE;
+ handler->is_bonobo = FALSE;
+ if (handler->component) {
+ CORBA_free (handler->component);
+ handler->component = NULL;
+ }
+ goto reg;
+ }
+
+ /* Try for a generic component match. */
+ if (handler->component) {
+ handler->generic = TRUE;
+ handler->is_bonobo = TRUE;
+ handler->builtin = handle_via_bonobo;
+ goto reg;
+ }
+
+ /* If we at least got an application list, use that. */
+ if (handler->applications) {
+ handler->generic = TRUE;
+ handler->is_bonobo = FALSE;
+ goto reg;
+ }
+
+ /* Nada. */
+ g_free (handler);
+ return NULL;
+
+ reg:
+ g_hash_table_insert (mime_handler_table, g_strdup (mime_type), handler);
+
+ return handler;
+}
+
+/* An "anonymous" MIME part is one that we shouldn't call attention
+ * to the existence of, but simply display.
+ */
+static gboolean
+is_anonymous (CamelMimePart *part, const char *mime_type)
+{
+ /* FIXME: should use CamelContentType stuff */
+ if (!strncasecmp (mime_type, "multipart/", 10) ||
+ !strncasecmp (mime_type, "message/", 8))
+ return TRUE;
+
+ if (!strncasecmp (mime_type, "text/", 5) &&
+ !camel_mime_part_get_filename (part))
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * mail_part_is_inline:
+ * @part: a CamelMimePart
+ *
+ * Return value: whether or not the part should/will be displayed inline.
+ **/
+gboolean
+mail_part_is_inline (CamelMimePart *part)
+{
+ const char *disposition;
+ CamelContentType *content_type;
+ gboolean anon;
+ char *type;
+
+ /* If it has an explicit disposition, return that. */
+ disposition = camel_mime_part_get_disposition (part);
+ if (disposition)
+ return strcasecmp (disposition, "inline") == 0;
+
+ /* Certain types should default to inline. FIXME: this should
+ * be customizable.
+ */
+ content_type = camel_mime_part_get_content_type (part);
+ if (!header_content_type_is (content_type, "message", "*"))
+ return TRUE;
+
+ /* Otherwise, display it inline if it's "anonymous", and
+ * as an attachment otherwise.
+ */
+ type = header_content_type_simple (content_type);
+ anon = is_anonymous (part, type);
+ g_free (type);
+
+ return anon;
+}
+
+enum inline_states {
+ I_VALID = (1 << 0),
+ I_ACTUALLY = (1 << 1),
+ I_DISPLAYED = (1 << 2)
+};
+
+static int
+get_inline_flags (CamelMimePart *part, MailDisplay *md)
+{
+ GHashTable *asht;
+ int val;
+
+ /* check if we already know. */
+
+ asht = g_datalist_get_data (md->data, "attachment_states");
+ val = GPOINTER_TO_INT (g_hash_table_lookup (asht, part));
+ if (val)
+ return val;
+
+ /* ok, we don't know. Figure it out. */
+
+ if (mail_part_is_inline (part))
+ val = (I_VALID | I_ACTUALLY | I_DISPLAYED);
+ else
+ val = (I_VALID);
+
+ g_hash_table_insert (asht, part, GINT_TO_POINTER (val));
+
+ return val;
+}
+
+gboolean
+mail_part_is_displayed_inline (CamelMimePart *part, MailDisplay *md)
+{
+ return (gboolean) (get_inline_flags (part, md) & I_DISPLAYED);
+}
+
+void
+mail_part_toggle_displayed (CamelMimePart *part, MailDisplay *md)
+{
+ GHashTable *asht = g_datalist_get_data (md->data, "attachment_states");
+ gpointer ostate, opart;
+ int state;
+
+ if (g_hash_table_lookup_extended (asht, part, &opart, &ostate)) {
+ g_hash_table_remove (asht, part);
+
+ state = GPOINTER_TO_INT (ostate);
+
+ if (state & I_DISPLAYED)
+ state &= ~I_DISPLAYED;
+ else
+ state |= I_DISPLAYED;
+ } else {
+ state = I_VALID | I_DISPLAYED;
+ }
+
+ g_hash_table_insert (asht, part, GINT_TO_POINTER (state));
+}
+
+static void
+mail_part_set_default_displayed_inline (CamelMimePart *part, MailDisplay *md,
+ gboolean displayed)
+{
+ GHashTable *asht = g_datalist_get_data (md->data, "attachment_states");
+ int state;
+
+ if (g_hash_table_lookup (asht, part))
+ return;
+
+ state = I_VALID | (displayed ? I_DISPLAYED : 0);
+ g_hash_table_insert (asht, part, GINT_TO_POINTER (state));
+}
+
+static void
+attachment_header (CamelMimePart *part, const char *mime_type, MailDisplay *md,
+ MailDisplayStream *stream)
+{
+ char *htmlinfo;
+ const char *info;
+
+ /* Start the table, create the pop-up object. */
+ camel_stream_write_string ((CamelStream *) stream, "<table cellspacing=0 cellpadding=0><tr><td>"
+ "<table width=10 cellspacing=0 cellpadding=0>"
+ "<tr><td></td></tr></table></td>");
+
+ if (!md->printing) {
+ camel_stream_printf ((CamelStream *) stream, "<td><object classid=\"popup:%s\""
+ "type=\"%s\"></object></td>", get_cid (part, md), mime_type);
+ }
+
+ camel_stream_write_string ((CamelStream *) stream, "<td><table width=3 cellspacing=0 cellpadding=0>"
+ "<tr><td></td></tr></table></td><td><font size=-1>");
+
+ /* Write the MIME type */
+ info = gnome_vfs_mime_get_description (mime_type);
+ htmlinfo = camel_text_to_html (info ? info : mime_type, 0, 0);
+ camel_stream_printf ((CamelStream *) stream, _("%s attachment"), htmlinfo);
+ g_free (htmlinfo);
+
+ /* Write the name, if we have it. */
+ info = camel_mime_part_get_filename (part);
+ if (info) {
+ htmlinfo = camel_text_to_html (info, 0, 0);
+ camel_stream_printf ((CamelStream *) stream, " (%s)", htmlinfo);
+ g_free (htmlinfo);
+ }
+
+ /* Write a description, if we have one. */
+ info = camel_mime_part_get_description (part);
+ if (info) {
+ htmlinfo = camel_text_to_html (info, md->printing ? 0 : CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+ camel_stream_printf ((CamelStream *) stream, ", \"%s\"", htmlinfo);
+ g_free (htmlinfo);
+ }
+
+ camel_stream_write_string ((CamelStream *) stream, "</font></td></tr><tr><td height=10>"
+ "<table cellspacing=0 cellpadding=0><tr><td height=10>"
+ "<a name=\"glue\"></td></tr></table></td></tr></table>\n");
+}
+
+static gboolean
+format_mime_part (CamelMimePart *part, MailDisplay *md,
+ MailDisplayStream *stream)
+{
+ CamelDataWrapper *wrapper;
+ MailMimeHandler *handler;
+ gboolean output;
+ int inline_flags;
+ char *mime_type;
+
+ /* Record URLs associated with this part */
+ get_cid (part, md);
+ get_location (part, md);
+
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+
+ if (CAMEL_IS_MULTIPART (wrapper) &&
+ camel_multipart_get_number (CAMEL_MULTIPART (wrapper)) == 0) {
+ mail_error_printf (stream, "\n%s\n", _("Could not parse MIME message. Displaying as source."));
+ if (mail_content_loaded (wrapper, md, TRUE, NULL, md->html, NULL))
+ handle_text_plain (part, "text/plain", md, stream);
+ return TRUE;
+ }
+
+ mime_type = camel_data_wrapper_get_mime_type (wrapper);
+ camel_strdown (mime_type);
+
+ handler = mail_lookup_handler (mime_type);
+ if (!handler) {
+ char *id_type;
+
+ /* Special case MIME types that we know that we can't
+ * display but are some kind of plain text to prevent
+ * evil infinite recursion.
+ */
+
+ if (!strcmp (mime_type, "application/mac-binhex40")) {
+ handler = NULL;
+ } else if (!strcmp (mime_type, "application/octet-stream")) {
+ /* only sniff application/octet-stream parts */
+ id_type = mail_identify_mime_part (part, md);
+ if (id_type) {
+ g_free (mime_type);
+ mime_type = id_type;
+ handler = mail_lookup_handler (id_type);
+ }
+ }
+ }
+
+ inline_flags = get_inline_flags (part, md);
+
+ /* No header for anonymous inline parts. */
+ if (!((inline_flags & I_ACTUALLY) && is_anonymous (part, mime_type)))
+ attachment_header (part, mime_type, md, stream);
+
+ if (handler && handler->builtin && inline_flags & I_DISPLAYED &&
+ mail_content_loaded (wrapper, md, TRUE, NULL, md->html, NULL))
+ output = (*handler->builtin) (part, mime_type, md, stream);
+ else
+ output = TRUE;
+
+ g_free (mime_type);
+ return output;
+}
+
+/* flags for write_field_to_stream */
+enum {
+ WRITE_BOLD=1,
+ WRITE_NOCOLUMNS=2,
+};
+
+static void
+write_field_row_begin (MailDisplayStream *stream, const char *name, int flags)
+{
+ gboolean bold = (flags & WRITE_BOLD);
+ gboolean nocolumns = (flags & WRITE_NOCOLUMNS);
+
+ if (nocolumns) {
+ camel_stream_printf ((CamelStream *) stream, "<tr><td>%s%s:%s ",
+ bold ? "<b>" : "", name, bold ? "</b>" : "");
+ } else {
+ camel_stream_printf ((CamelStream *) stream,
+ "<tr><%s align=\"right\" valign=\"top\">%s:"
+ "<b>&nbsp;</%s><td>", bold ? "th" : "td",
+ name, bold ? "th" : "td");
+ }
+}
+
+static void
+write_date (MailDisplayStream *stream, CamelMimeMessage *message, int flags)
+{
+ const char *datestr;
+
+ datestr = camel_medium_get_header (CAMEL_MEDIUM (message), "Date");
+
+ if (datestr) {
+ int msg_offset;
+ time_t msg_date;
+ struct tm local;
+ int local_tz;
+
+ msg_date = header_decode_date(datestr, &msg_offset);
+ e_localtime_with_offset(msg_date, &local, &local_tz);
+
+ write_field_row_begin(stream, _("Date"), flags);
+ camel_stream_printf((CamelStream *)stream, "%s", datestr);
+
+ /* Convert message offset to minutes (e.g. -0400 --> -240) */
+ msg_offset = ((msg_offset / 100) * 60) + (msg_offset % 100);
+ /* Turn into offset from localtime, not UTC */
+ msg_offset -= local_tz / 60;
+
+ if (msg_offset) {
+ /* Message timezone different from local. Show both */
+ char buf[30];
+
+ msg_offset += (local.tm_hour * 60) + local.tm_min;
+
+ if (msg_offset >= (24 * 60) || msg_offset < 0) {
+ /* Timezone conversion crossed midnight. Show day */
+ /* translators: strftime format for local time equivalent in Date header display */
+ e_utf8_strftime(buf, 29, _("<I> (%a, %R %Z)</I>"), &local);
+ } else {
+ e_utf8_strftime(buf, 29, _("<I> (%R %Z)</I>"), &local);
+ }
+
+ /* I doubt any locales put '%' in time representation
+ but just in case... */
+ camel_stream_printf((CamelStream *)stream, "%s", buf);
+ }
+
+ camel_stream_printf ((CamelStream *) stream, "</td> </tr>");
+ }
+}
+
+static void
+write_text_header (MailDisplayStream *stream, const char *name, const char *value, int flags)
+{
+ char *encoded;
+
+ if (value && *value)
+ encoded = camel_text_to_html (value, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+ else
+ encoded = "";
+
+ write_field_row_begin (stream, name, flags);
+
+ camel_stream_printf ((CamelStream *) stream, "%s</td></tr>", encoded);
+
+ if (value && *value)
+ g_free (encoded);
+}
+
+static void
+write_address (MailDisplay *md, MailDisplayStream *stream,
+ const CamelInternetAddress *addr, const char *field_name, int flags)
+{
+ const char *name, *email;
+ int i;
+
+ if (addr == NULL || !camel_internet_address_get (addr, 0, NULL, NULL))
+ return;
+
+ write_field_row_begin (stream, field_name, flags);
+
+ i = 0;
+ while (camel_internet_address_get (addr, i, &name, &email)) {
+ CamelInternetAddress *subaddr;
+ char *addr_txt, *addr_url;
+ gboolean have_name = name && *name;
+ gboolean have_email = email && *email;
+ char *name_disp = NULL;
+ char *email_disp = NULL;
+
+ subaddr = camel_internet_address_new ();
+ camel_internet_address_add (subaddr, name, email);
+ addr_txt = camel_address_format (CAMEL_ADDRESS (subaddr));
+ addr_url = camel_url_encode (addr_txt, NULL);
+ camel_object_unref (subaddr);
+
+ if (have_name) {
+ name_disp = camel_text_to_html (name, 0, 0);
+ }
+
+ if (have_email) {
+ email_disp = camel_text_to_html (email, 0, 0);
+ }
+
+ if (i)
+ camel_stream_write_string ((CamelStream *) stream, ", ");
+
+ if (have_email || have_name) {
+ if (!have_email)
+ email_disp = g_strdup ("???");
+
+ if (have_name) {
+ if (md->printing) {
+ camel_stream_printf ((CamelStream *) stream,
+ "%s &lt;%s&gt;", name_disp, email_disp);
+ } else {
+ camel_stream_printf ((CamelStream *) stream,
+ "%s &lt;<a href=\"mailto:%s\">%s</a>&gt;",
+ name_disp, addr_url, email_disp);
+ }
+ } else {
+ if (md->printing) {
+ camel_stream_write_string ((CamelStream *) stream, email_disp);
+ } else {
+ camel_stream_printf ((CamelStream *) stream,
+ "<a href=\"mailto:%s\">%s</a>",
+ addr_url, email_disp);
+ }
+ }
+ } else {
+ camel_stream_printf ((CamelStream *) stream, "<i>%s</i>", _("Bad Address"));
+ }
+
+ g_free (name_disp);
+ g_free (email_disp);
+ g_free (addr_txt);
+ g_free (addr_url);
+
+ i++;
+ }
+
+ camel_stream_write_string ((CamelStream *) stream, "</td></tr>");
+}
+
+/* order of these must match write_header code */
+static char *default_headers[] = {
+ "From", "Reply-To", "To", "Cc", "Bcc", "Subject", "Date",
+};
+
+/* return index of header in default_headers array */
+static int
+default_header_index (const char *name)
+{
+ int i;
+
+ for (i = 0; i < sizeof (default_headers) / sizeof (default_headers[0]); i++)
+ if (!strcasecmp (name, default_headers[i]))
+ return i;
+
+ return -1;
+}
+
+/* index is index of header in default_headers array */
+static void
+write_default_header (CamelMimeMessage *message, MailDisplay *md,
+ MailDisplayStream *stream,
+ int index, int flags)
+{
+ switch (index) {
+ case 0:
+ write_address (md, stream,
+ camel_mime_message_get_from (message), _("From"), flags | WRITE_BOLD);
+ break;
+ case 1:
+ write_address (md, stream,
+ camel_mime_message_get_reply_to (message), _("Reply-To"), flags | WRITE_BOLD);
+ break;
+ case 2:
+ write_address (md, stream,
+ camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO),
+ _("To"), flags | WRITE_BOLD);
+ break;
+ case 3:
+ write_address (md, stream,
+ camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC),
+ _("Cc"), flags | WRITE_BOLD);
+ break;
+ case 4:
+ write_address (md, stream,
+ camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_BCC),
+ _("Bcc"), flags | WRITE_BOLD);
+ break;
+ case 5:
+ write_text_header (stream, _("Subject"), camel_mime_message_get_subject (message),
+ flags | WRITE_BOLD);
+ break;
+ case 6:
+ write_date (stream, message, flags | WRITE_BOLD);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+write_xmailer_header (CamelMimeMessage *message, MailDisplay *md,
+ MailDisplayStream *stream, int xmask)
+{
+ const char *xmailer, *evolution;
+
+ xmailer = camel_medium_get_header (CAMEL_MEDIUM (message), "X-Mailer");
+ if (!xmailer) {
+ xmailer = camel_medium_get_header (CAMEL_MEDIUM (message), "User-Agent");
+ if (!xmailer)
+ return FALSE;
+ }
+ while (isspace ((unsigned char)*xmailer))
+ xmailer++;
+
+ evolution = strstr (xmailer, "Evolution");
+ if ((xmask & MAIL_CONFIG_XMAILER_OTHER) ||
+ (evolution && (xmask & MAIL_CONFIG_XMAILER_EVO)))
+ write_text_header (stream, _("Mailer"), xmailer, WRITE_BOLD);
+
+ return evolution != NULL && (xmask & MAIL_CONFIG_XMAILER_RUPERT_APPROVED);
+}
+
+#define COLOR_IS_LIGHT(r, g, b) ((r + g + b) > (128 * 3))
+
+static void
+write_headers (MailDisplayStream *stream, MailDisplay *md, CamelMimeMessage *message)
+{
+ gboolean full = (md->display_style == MAIL_CONFIG_DISPLAY_FULL_HEADERS);
+ char bgcolor[7], fontcolor[7];
+ GtkStyle *style = NULL;
+ gboolean evo_icon = FALSE;
+ GConfClient *gconf;
+ int xmask, i;
+
+ gconf = mail_config_get_gconf_client ();
+ xmask = gconf_client_get_int (gconf, "/apps/evolution/mail/display/xmailer_mask", NULL);
+
+ /* My favorite thing to do... muck around with colors so we respect people's stupid themes.
+ However, we only do this if we are rendering to the screen -- we ignore the theme
+ when we are printing. */
+ style = gtk_widget_get_style (GTK_WIDGET (md->html));
+ if (style && !md->printing) {
+ int state = GTK_WIDGET_STATE (GTK_WIDGET (md->html));
+ gushort r, g, b;
+
+ r = style->base[state].red / 256;
+ g = style->base[state].green / 256;
+ b = style->base[state].blue / 256;
+
+ if (COLOR_IS_LIGHT (r, g, b)) {
+ r *= 0.92;
+ g *= 0.92;
+ b *= 0.92;
+ } else {
+ r = 255 - (0.92 * (255 - r));
+ g = 255 - (0.92 * (255 - g));
+ b = 255 - (0.92 * (255 - b));
+ }
+
+ sprintf (bgcolor, "%.2X%.2X%.2X", r, g, b);
+
+ r = style->text[state].red / 256;
+ g = style->text[state].green / 256;
+ b = style->text[state].blue / 256;
+
+ sprintf (fontcolor, "%.2X%.2X%.2X", r, g, b);
+ } else {
+ strcpy (bgcolor, "EEEEEE");
+ strcpy (fontcolor, "000000");
+ }
+
+ camel_stream_write_string ((CamelStream *) stream,
+ "<table width=\"100%\" cellpadding=0 cellspacing=0>");
+
+ /* Top margin */
+ camel_stream_write_string ((CamelStream *) stream, "<tr><td colspan=3 height=10>"
+ "<table cellpadding=0 cellspacing=0><tr><td height=10>"
+ "<a name=\"glue\"></td></tr></table></td></tr>");
+
+ /* Left margin */
+ camel_stream_write_string ((CamelStream *) stream, "<tr><td><table width=10 "
+ "cellpadding=0 cellspacing=0><tr><td></td></tr></table></td>");
+
+ /* Black border */
+ camel_stream_write_string ((CamelStream *) stream, "<td width=\"100%\"><table bgcolor=\"#000000\" "
+ "width=\"100%\" cellspacing=0 cellpadding=1>");
+
+ /* Main header box */
+ camel_stream_printf ((CamelStream *) stream, "<tr><td><table bgcolor=\"#%s\" width=\"100%%\" "
+ "cellpadding=0 cellspacing=0>"
+ /* Internal header table */
+ "<tr valign=top><td><table><font color=\"#%s\">\n",
+ bgcolor, fontcolor);
+
+ if (full) {
+ struct _header_raw *header;
+ const char *charset;
+ CamelContentType *ct;
+ char *value;
+
+ ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (message));
+ charset = header_content_type_param (ct, "charset");
+ charset = e_iconv_charset_name (charset);
+
+ header = CAMEL_MIME_PART (message)->headers;
+ while (header) {
+ i = default_header_index (header->name);
+ if (i == -1) {
+ value = header_decode_string (header->value, charset);
+ write_text_header (stream, header->name, value, WRITE_NOCOLUMNS);
+ g_free (value);
+ } else
+ write_default_header (message, md, stream, i, WRITE_NOCOLUMNS);
+ header = header->next;
+ }
+ } else {
+ for (i = 0; i < sizeof (default_headers) / sizeof (default_headers[0]); i++)
+ write_default_header (message, md, stream, i, 0);
+ if (xmask != MAIL_CONFIG_XMAILER_NONE)
+ evo_icon = write_xmailer_header (message, md, stream, xmask);
+ }
+
+ /* Close off the internal header table */
+ camel_stream_write_string ((CamelStream *) stream, "</font></table></td>");
+
+ if (!md->printing && evo_icon) {
+ camel_stream_printf ((CamelStream *) stream, "<td align=right><table><tr><td width=16>"
+ "<img src=\"%s\"></td></tr></table></td>",
+ mail_display_get_url_for_icon (md, EVOLUTION_ICONSDIR "/monkey-16.png"));
+ }
+
+ camel_stream_write_string ((CamelStream *) stream,
+ /* Main header box */
+ "</tr></table>"
+ /* Black border */
+ "</td></tr></table></td>"
+ /* Right margin */
+ "<td><table width=10 cellpadding=0 cellspacing=0>"
+ "<tr><td></td></tr></table></td>"
+ "</tr></table>\n");
+}
+
+static void
+load_offline_content (MailDisplay *md, gpointer data)
+{
+ CamelDataWrapper *wrapper = data;
+ CamelStream *stream;
+
+ stream = camel_stream_null_new ();
+ camel_data_wrapper_write_to_stream (wrapper, stream);
+ camel_object_unref (stream);
+ camel_object_unref (wrapper);
+}
+
+gboolean
+mail_content_loaded (CamelDataWrapper *wrapper, MailDisplay *md, gboolean redisplay, const char *url,
+ GtkHTML *html, GtkHTMLStream *stream)
+{
+ if (!camel_data_wrapper_is_offline (wrapper))
+ return TRUE;
+
+ camel_object_ref (wrapper);
+ if (redisplay) {
+ mail_display_redisplay_when_loaded (md, wrapper, load_offline_content,
+ html, wrapper);
+ } else {
+ mail_display_stream_write_when_loaded (md, wrapper, url, load_offline_content,
+ html, stream, wrapper);
+ }
+
+ return FALSE;
+}
+
+
+ssize_t
+mail_format_data_wrapper_write_to_stream (CamelDataWrapper *wrapper, gboolean decode, MailDisplay *mail_display, CamelStream *stream)
+{
+ CamelStreamFilter *filter_stream;
+ CamelMimeFilterCharset *filter;
+ CamelContentType *content_type;
+ GConfClient *gconf;
+ ssize_t nwritten;
+ char *charset;
+
+ gconf = mail_config_get_gconf_client ();
+
+ content_type = camel_data_wrapper_get_mime_type_field (wrapper);
+
+ /* find out the charset the user wants to override to */
+ if (mail_display && mail_display->charset) {
+ /* user override charset */
+ charset = g_strdup (mail_display->charset);
+ } else if (content_type && (charset = (char *) header_content_type_param (content_type, "charset"))) {
+ /* try to use the charset declared in the Content-Type header */
+ if (!strncasecmp (charset, "iso-8859-", 9)) {
+ /* Since a few Windows mailers like to claim they sent
+ * out iso-8859-# encoded text when they really sent
+ * out windows-cp125#, do some simple sanity checking
+ * before we move on... */
+ CamelMimeFilterWindows *windows;
+ CamelStream *null;
+
+ null = camel_stream_null_new ();
+ filter_stream = camel_stream_filter_new_with_stream (null);
+ camel_object_unref (null);
+
+ windows = (CamelMimeFilterWindows *) camel_mime_filter_windows_new (charset);
+ camel_stream_filter_add (filter_stream, (CamelMimeFilter *) windows);
+
+ if (decode)
+ camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) filter_stream);
+ else
+ camel_data_wrapper_write_to_stream (wrapper, (CamelStream *) filter_stream);
+ camel_stream_flush ((CamelStream *) filter_stream);
+ camel_object_unref (filter_stream);
+
+ charset = g_strdup (camel_mime_filter_windows_real_charset (windows));
+ camel_object_unref (windows);
+ } else {
+ charset = g_strdup (charset);
+ }
+ } else {
+ /* default to user's locale charset? */
+ charset = gconf_client_get_string (gconf, "/apps/evolution/mail/format/charset", NULL);
+ }
+
+ filter_stream = camel_stream_filter_new_with_stream (stream);
+
+ if ((filter = camel_mime_filter_charset_new_convert (charset, "UTF-8"))) {
+ camel_stream_filter_add (filter_stream, (CamelMimeFilter *) filter);
+ camel_object_unref (filter);
+ }
+
+ g_free (charset);
+
+ if (decode)
+ nwritten = camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) filter_stream);
+ else
+ nwritten = camel_data_wrapper_write_to_stream (wrapper, (CamelStream *) filter_stream);
+ camel_stream_flush ((CamelStream *) filter_stream);
+ camel_object_unref (filter_stream);
+
+ return nwritten;
+}
+
+/* Return the contents of a data wrapper, or %NULL if it contains only
+ * whitespace.
+ */
+GByteArray *
+mail_format_get_data_wrapper_text (CamelDataWrapper *wrapper, MailDisplay *mail_display)
+{
+ CamelStream *memstream;
+ GByteArray *ba;
+ char *text, *end;
+
+ memstream = camel_stream_mem_new ();
+ ba = g_byte_array_new ();
+ camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (memstream), ba);
+
+ mail_format_data_wrapper_write_to_stream (wrapper, TRUE, mail_display, memstream);
+ camel_object_unref (memstream);
+
+ for (text = ba->data, end = text + ba->len; text < end; text++) {
+ if (!isspace ((unsigned char) *text))
+ break;
+ }
+
+ if (text >= end) {
+ g_byte_array_free (ba, TRUE);
+ return NULL;
+ }
+
+ return ba;
+}
+
+static void
+write_hr (MailDisplayStream *stream)
+{
+ camel_stream_write_string ((CamelStream *) stream, STANDARD_ISSUE_TABLE_OPEN
+ "<tr><td width=\"100%\"><hr noshadow size=1>"
+ "</td></tr></table>\n");
+}
+
+/*----------------------------------------------------------------------*
+ * Mime handling functions
+ *----------------------------------------------------------------------*/
+
+static gboolean
+handle_text_plain (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilter *html_filter;
+ CamelDataWrapper *wrapper;
+ CamelContentType *type;
+ const char *format;
+ GConfClient *gconf;
+ guint32 flags, rgb = 0;
+ GdkColor colour;
+ char *buf;
+
+ gconf = mail_config_get_gconf_client ();
+
+ flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
+ if (!md->printing) {
+ flags |= CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
+ if (gconf_client_get_bool (gconf, "/apps/evolution/mail/display/mark_citations", NULL)) {
+ flags |= CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+
+ buf = gconf_client_get_string (gconf, "/apps/evolution/mail/display/citation_colour", NULL);
+ gdk_color_parse (buf ? buf : "#737373", &colour);
+ g_free (buf);
+
+ rgb = ((colour.red & 0xff00) << 8) | (colour.green & 0xff00) | ((colour.blue & 0xff00) >> 8);
+ }
+ }
+
+ /* Check for RFC 2646 flowed text. */
+ type = camel_mime_part_get_content_type (part);
+ if (header_content_type_is (type, "text", "plain")) {
+ format = header_content_type_param (type, "format");
+
+ if (format && !strcasecmp (format, "flowed"))
+ flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;
+ }
+
+ html_filter = camel_mime_filter_tohtml_new (flags, rgb);
+ filtered_stream = camel_stream_filter_new_with_stream ((CamelStream *) stream);
+ camel_stream_filter_add (filtered_stream, html_filter);
+ camel_object_unref (html_filter);
+
+ camel_stream_write_string ((CamelStream *) stream, STANDARD_ISSUE_TABLE_OPEN "<tr><td><tt>\n");
+
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ mail_format_data_wrapper_write_to_stream (wrapper, TRUE, md, (CamelStream *) filtered_stream);
+
+ camel_stream_write_string ((CamelStream *) stream, "</tt></td></tr></table>\n");
+
+ camel_object_unref (filtered_stream);
+
+ return TRUE;
+}
+
+/* text/enriched (RFC 1896) or text/richtext (included in RFC 1341) */
+static gboolean
+handle_text_enriched (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilter *enriched;
+ CamelDataWrapper *wrapper;
+ guint32 flags = 0;
+
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+
+ if (!strcasecmp (mime_type, "text/richtext")) {
+ flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT;
+ camel_stream_write_string ((CamelStream *) stream, "\n<!-- text/richtext -->\n");
+ } else {
+ camel_stream_write_string ((CamelStream *) stream, "\n<!-- text/enriched -->\n");
+ }
+
+ enriched = camel_mime_filter_enriched_new (flags);
+ filtered_stream = camel_stream_filter_new_with_stream ((CamelStream *) stream);
+ camel_stream_filter_add (filtered_stream, enriched);
+ camel_object_unref (enriched);
+
+ camel_stream_write_string ((CamelStream *) stream, STANDARD_ISSUE_TABLE_OPEN "<tr><td><tt>\n");
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ mail_format_data_wrapper_write_to_stream (wrapper, TRUE, md, (CamelStream *) filtered_stream);
+
+ camel_stream_write_string ((CamelStream *) stream, "</tt></td></tr></table>\n");
+ camel_object_unref (filtered_stream);
+
+ return TRUE;
+}
+
+static gboolean
+handle_text_html (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ const char *location, *base;
+
+ camel_stream_write_string ((CamelStream *) stream, "\n<!-- text/html -->\n");
+
+ if ((base = camel_medium_get_header (CAMEL_MEDIUM (part), "Content-Base"))) {
+ char *base_url;
+ size_t len;
+
+ len = strlen (base);
+
+ if (*base == '"' && *(base + len - 1) == '"') {
+ len -= 2;
+ base_url = g_alloca (len + 1);
+ memcpy (base_url, base + 1, len);
+ base_url[len] = '\0';
+ base = base_url;
+ }
+
+ gtk_html_set_base (md->html, base);
+ }
+
+ location = get_location (part, md);
+ if (!location)
+ location = get_cid (part, md);
+
+ camel_stream_printf ((CamelStream *) stream, "<iframe src=\"%s\" frameborder=0 "
+ "scrolling=no>could not get %s</iframe>", location, location);
+
+ return TRUE;
+}
+
+static gboolean
+handle_image (CamelMimePart *part, const char *mime_type, MailDisplay *md, MailDisplayStream *stream)
+{
+ camel_stream_printf ((CamelStream *) stream, "<img hspace=10 vspace=10 src=\"%s\">",
+ get_cid (part, md));
+ return TRUE;
+}
+
+static gboolean
+handle_multipart_mixed (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ CamelDataWrapper *wrapper =
+ camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ CamelMultipart *mp;
+ int i, nparts;
+ gboolean output = FALSE;
+
+ if (!CAMEL_IS_MULTIPART (wrapper)) {
+ mail_error_printf (stream, "\n%s\n", _("Could not parse MIME message. Displaying as source."));
+ if (mail_content_loaded (wrapper, md, TRUE, NULL, md->html, NULL))
+ handle_text_plain (part, "text/plain", md, stream);
+ return TRUE;
+ }
+
+ mp = CAMEL_MULTIPART (wrapper);
+
+ nparts = camel_multipart_get_number (mp);
+ for (i = 0; i < nparts; i++) {
+ if (i != 0 && output)
+ write_hr (stream);
+
+ part = camel_multipart_get_part (mp, i);
+
+ output = format_mime_part (part, md, stream);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+handle_multipart_encrypted (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ CamelMultipartEncrypted *mpe;
+ CamelMimePart *mime_part;
+ CamelCipherContext *cipher;
+ CamelDataWrapper *wrapper;
+ const char *protocol;
+ CamelException ex;
+ gboolean handled;
+
+ /* Currently we only handle RFC2015-style PGP encryption. */
+ protocol = header_content_type_param (((CamelDataWrapper *) part)->mime_type, "protocol");
+ if (!protocol || strcmp (protocol, "application/pgp-encrypted") != 0)
+ return handle_multipart_mixed (part, mime_type, md, stream);
+
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+
+ mpe = CAMEL_MULTIPART_ENCRYPTED (wrapper);
+
+ camel_exception_init (&ex);
+ cipher = camel_gpg_context_new (session);
+ mime_part = camel_multipart_encrypted_decrypt (mpe, cipher, &ex);
+ camel_object_unref (cipher);
+
+ if (camel_exception_is_set (&ex)) {
+ mail_error_printf (stream, "\n%s\n", camel_exception_get_description (&ex));
+ camel_exception_clear (&ex);
+ return TRUE;
+ }
+
+ handled = format_mime_part (mime_part, md, stream);
+ camel_object_unref (mime_part);
+
+ return handled;
+}
+
+static gboolean
+handle_multipart_signed (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ CamelMimePart *subpart;
+ CamelDataWrapper *wrapper;
+ CamelMultipartSigned *mps;
+ gboolean output = FALSE;
+
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+
+ if (!CAMEL_IS_MULTIPART_SIGNED (wrapper)) {
+ mail_error_printf (stream, "\n%s\n", _("Could not parse MIME message. Displaying as source."));
+ if (mail_content_loaded (wrapper, md, TRUE, NULL, md->html, NULL))
+ handle_text_plain (part, "text/plain", md, stream);
+ return TRUE;
+ }
+
+ mps = CAMEL_MULTIPART_SIGNED (wrapper);
+
+ /* if subpart & signature is null, what do we do? just write it out raw?
+ multipart_signed will, if it cannot parse properly, put everything in the first part
+ this includes: more or less than 2 parts */
+
+ /* output the content */
+ subpart = camel_multipart_get_part ((CamelMultipart *) mps, CAMEL_MULTIPART_SIGNED_CONTENT);
+ if (subpart == NULL)
+ return FALSE;
+
+ output = format_mime_part (subpart, md, stream);
+
+ /* now handle the signature */
+ subpart = camel_multipart_get_part ((CamelMultipart *) mps, CAMEL_MULTIPART_SIGNED_SIGNATURE);
+ if (subpart == NULL)
+ return FALSE;
+
+ mail_part_set_default_displayed_inline (subpart, md, FALSE);
+
+ if (!mail_part_is_displayed_inline (subpart, md) && !md->printing) {
+ char *url;
+
+ /* Write out the click-for-info object */
+ url = g_strdup_printf ("signature:%p/%lu", subpart,
+ (unsigned long)time (NULL));
+ camel_stream_printf ((CamelStream *) stream,
+ "<br><table cellspacing=0 cellpadding=0>"
+ "<tr><td><table width=10 cellspacing=0 cellpadding=0>"
+ "<tr><td></td></tr></table></td>"
+ "<td><object classid=\"%s\"></object></td>"
+ "<td><table width=3 cellspacing=0 cellpadding=0>"
+ "<tr><td></td></tr></table></td>"
+ "<td><font size=-1>", url);
+ mail_display_add_url (md, "part_urls", url, subpart);
+
+ camel_stream_write_string ((CamelStream *) stream,
+ _("This message is digitally signed. "
+ "Click the lock icon for more information."));
+
+ camel_stream_write_string ((CamelStream *) stream, "</font></td></tr><tr><td height=10>"
+ "<table cellspacing=0 cellpadding=0><tr>"
+ "<td height=10><a name=\"glue\"></td></tr>"
+ "</table></td></tr></table>\n");
+ } else {
+ CamelCipherValidity *valid = NULL;
+ CamelException ex;
+ const char *message = NULL;
+ gboolean good = FALSE;
+ CamelCipherContext *cipher;
+
+ /* Write out the verification results */
+ /* TODO: use the right context for the right message ... */
+ camel_exception_init (&ex);
+ cipher = camel_gpg_context_new (session);
+ if (cipher) {
+ valid = camel_multipart_signed_verify (mps, cipher, &ex);
+ camel_object_unref (cipher);
+ if (valid) {
+ good = camel_cipher_validity_get_valid (valid);
+ message = camel_cipher_validity_get_description (valid);
+ } else {
+ message = camel_exception_get_description (&ex);
+ }
+ } else {
+ message = _("Could not create a PGP verfication context");
+ }
+
+ if (good) {
+ camel_stream_printf ((CamelStream *) stream, "<table><tr valign=top><td>"
+ "<img src=\"%s\"></td><td>%s<br><br>",
+ mail_display_get_url_for_icon (md, EVOLUTION_ICONSDIR
+ "/pgp-signature-ok.png"),
+ _("This message is digitally signed and "
+ "has been found to be authentic."));
+ } else {
+ camel_stream_printf ((CamelStream *) stream, "<table><tr valign=top><td>"
+ "<img src=\"%s\"></td><td>%s<br><br>",
+ mail_display_get_url_for_icon (md, EVOLUTION_ICONSDIR
+ "/pgp-signature-bad.png"),
+ _("This message is digitally signed but can "
+ "not be proven to be authentic."));
+ }
+
+ if (message) {
+ camel_stream_printf ((CamelStream *) stream, "<font size=-1%s>", good ||
+ md->printing ? "" : " color=red");
+ mail_text_write (stream, md, part, 0, md->printing, message);
+ camel_stream_write_string ((CamelStream *) stream, "</font>");
+ }
+
+ camel_stream_write_string ((CamelStream *) stream, "</td></tr></table>");
+ camel_exception_clear (&ex);
+ camel_cipher_validity_free (valid);
+ }
+
+ return TRUE;
+}
+
+/* As seen in RFC 2387! */
+static gboolean
+handle_multipart_related (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ CamelDataWrapper *wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ CamelMultipart *mp;
+ CamelMimePart *body_part, *display_part = NULL;
+ CamelContentType *content_type;
+ const char *location, *start;
+ int i, nparts;
+ GHashTable *related_save;
+ int ret;
+
+ if (!CAMEL_IS_MULTIPART (wrapper)) {
+ mail_error_printf (stream, "\n%s\n", _("Could not parse MIME message. Displaying as source."));
+ if (mail_content_loaded (wrapper, md, TRUE, NULL, md->html, NULL))
+ handle_text_plain (part, "text/plain", md, stream);
+ return TRUE;
+ }
+
+ mp = CAMEL_MULTIPART (wrapper);
+ nparts = camel_multipart_get_number (mp);
+
+ content_type = camel_mime_part_get_content_type (part);
+ start = header_content_type_param (content_type, "start");
+ if (start) {
+ int len;
+
+ /* The "start" parameter includes <>s, which Content-Id
+ * does not.
+ */
+ len = strlen (start) - 2;
+
+ for (i = 0; i < nparts; i++) {
+ const char *cid;
+
+ body_part = camel_multipart_get_part (mp, i);
+ cid = camel_mime_part_get_content_id (body_part);
+
+ if (cid && !strncmp (cid, start + 1, len) && strlen (cid) == len) {
+ display_part = body_part;
+ break;
+ }
+ }
+ } else {
+ /* No start parameter, so it defaults to the first part. */
+ display_part = camel_multipart_get_part (mp, 0);
+ }
+
+ if (!display_part) {
+ /* Oops. Hrmph. */
+ return handle_multipart_mixed (part, mime_type, md, stream);
+ }
+
+ /* setup a 'stack' of related parts */
+ related_save = md->related;
+ md->related = g_hash_table_new(NULL, NULL);
+
+ location = camel_mime_part_get_content_location (part);
+ if (location)
+ mail_display_push_content_location (md, location);
+
+ /* Record the Content-ID/Content-Location of any non-displayed parts. */
+ for (i = 0; i < nparts; i++) {
+ body_part = camel_multipart_get_part (mp, i);
+ if (body_part == display_part)
+ continue;
+
+ get_cid (body_part, md);
+ get_location (body_part, md);
+ g_hash_table_insert (md->related, body_part, body_part);
+ }
+
+ /* Now, display the displayed part. */
+ ret = format_mime_part (display_part, md, stream);
+
+ /* FIXME: flush html stream via gtkhtml_stream_flush which doens't exist yet ... */
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ /* Now check for related parts which didn't display, display them as attachments */
+ for (i = 0; i < nparts; i++) {
+ body_part = camel_multipart_get_part (mp, i);
+ if (body_part == display_part)
+ continue;
+
+ if (g_hash_table_lookup (md->related, body_part)) {
+ if (ret)
+ write_hr (stream);
+ ret |= format_mime_part (body_part, md, stream);
+ }
+ }
+
+ g_hash_table_destroy (md->related);
+ md->related = related_save;
+
+ if (location)
+ mail_display_pop_content_location (md);
+
+ return ret;
+}
+
+/* RFC 2046 says "display the last part that you are able to display". */
+static CamelMimePart *
+find_preferred_alternative (CamelMultipart *multipart, gboolean want_plain)
+{
+ int i, nparts;
+ CamelMimePart *preferred_part = NULL;
+ MailMimeHandler *handler;
+
+ nparts = camel_multipart_get_number (multipart);
+ for (i = 0; i < nparts; i++) {
+ CamelMimePart *part = camel_multipart_get_part (multipart, i);
+ CamelContentType *type = camel_mime_part_get_content_type (part);
+ char *mime_type = header_content_type_simple (type);
+
+ camel_strdown (mime_type);
+ if (want_plain && !strcmp (mime_type, "text/plain"))
+ return part;
+ handler = mail_lookup_handler (mime_type);
+ if (handler && (!preferred_part || !handler->generic))
+ preferred_part = part;
+ g_free (mime_type);
+ }
+
+ return preferred_part;
+}
+
+static gboolean
+handle_multipart_alternative (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ CamelDataWrapper *wrapper =
+ camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ CamelMultipart *multipart;
+ CamelMimePart *mime_part;
+
+ if (!CAMEL_IS_MULTIPART (wrapper)) {
+ mail_error_printf (stream, "\n%s\n", _("Could not parse MIME message. Displaying as source."));
+ if (mail_content_loaded (wrapper, md, TRUE, NULL, md->html, NULL))
+ handle_text_plain (part, "text/plain", md, stream);
+ return TRUE;
+ }
+
+ multipart = CAMEL_MULTIPART (wrapper);
+
+ mime_part = find_preferred_alternative (multipart, FALSE);
+ if (mime_part)
+ return format_mime_part (mime_part, md, stream);
+ else
+ return handle_multipart_mixed (part, mime_type, md, stream);
+}
+
+/* RFC 1740 */
+static gboolean
+handle_multipart_appledouble (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ CamelDataWrapper *wrapper =
+ camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ CamelMultipart *multipart;
+
+ if (!CAMEL_IS_MULTIPART (wrapper)) {
+ mail_error_printf (stream, "\n%s\n", _("Could not parse MIME message. Displaying as source."));
+ if (mail_content_loaded (wrapper, md, TRUE, NULL, md->html, NULL))
+ handle_text_plain (part, "text/plain", md, stream);
+ return TRUE;
+ }
+
+ multipart = CAMEL_MULTIPART (wrapper);
+
+ /* The first part is application/applefile and is not useful
+ * to us. The second part _may_ be displayable data. Most
+ * likely it's application/octet-stream though.
+ */
+ part = camel_multipart_get_part (multipart, 1);
+ return format_mime_part (part, md, stream);
+}
+
+static gboolean
+handle_message_rfc822 (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ CamelDataWrapper *wrapper =
+ camel_medium_get_content_object (CAMEL_MEDIUM (part));
+
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (wrapper), FALSE);
+
+ camel_stream_write_string ((CamelStream *) stream, "<blockquote>");
+ mail_format_mime_message (CAMEL_MIME_MESSAGE (wrapper), md, stream);
+ camel_stream_write_string ((CamelStream *) stream, "</blockquote>");
+
+ return TRUE;
+}
+
+static gboolean
+handle_message_external_body (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ CamelContentType *type;
+ const char *access_type;
+ char *url = NULL, *desc = NULL;
+
+ type = camel_mime_part_get_content_type (part);
+ access_type = header_content_type_param (type, "access-type");
+ if (!access_type)
+ goto fallback;
+
+ if (!strcasecmp (access_type, "ftp") ||
+ !strcasecmp (access_type, "anon-ftp")) {
+ const char *name, *site, *dir, *mode, *ftype;
+ char *path;
+
+ name = header_content_type_param (type, "name");
+ site = header_content_type_param (type, "site");
+ if (name == NULL || site == NULL)
+ goto fallback;
+ dir = header_content_type_param (type, "directory");
+ mode = header_content_type_param (type, "mode");
+
+ /* Generate the path. */
+ if (dir) {
+ const char *p = dir + strlen (dir);
+
+ path = g_strdup_printf ("%s%s%s%s",
+ *dir == '/' ? "" : "/",
+ dir,
+ *p == '/' ? "" : "/",
+ name);
+ } else {
+ path = g_strdup_printf ("%s%s",
+ *name == '/' ? "" : "/",
+ name);
+ }
+
+ if (mode && *mode == 'A')
+ ftype = ";type=A";
+ else if (mode && *mode == 'I')
+ ftype = ";type=I";
+ else
+ ftype = "";
+
+ url = g_strdup_printf ("ftp://%s%s%s", site, path, ftype);
+ g_free (path);
+ desc = g_strdup_printf (_("Pointer to FTP site (%s)"), url);
+ } else if (!g_ascii_strcasecmp (access_type, "local-file")) {
+ const char *name, *site;
+
+ name = header_content_type_param (type, "name");
+ if (name == NULL)
+ goto fallback;
+ site = header_content_type_param (type, "site");
+
+ url = g_strdup_printf ("file://%s%s", *name == '/' ? "" : "/", name);
+ if (site) {
+ desc = g_strdup_printf(_("Pointer to local file (%s) "
+ "valid at site \"%s\""), name, site);
+ } else {
+ desc = g_strdup_printf(_("Pointer to local file (%s)"), name);
+ }
+ } else if (!strcasecmp (access_type, "URL")) {
+ const char *urlparam;
+ char *s, *d;
+
+ /* RFC 2017 */
+
+ urlparam = header_content_type_param (type, "url");
+ if (urlparam == NULL)
+ goto fallback;
+
+ /* For obscure MIMEy reasons, the URL may be split into
+ * multiple words, and needs to be rejoined. (The URL
+ * must have any real whitespace %-encoded, so we just
+ * get rid of all of it.
+ */
+ url = g_strdup (urlparam);
+ s = d = url;
+
+ while (*s) {
+ if (!isspace ((unsigned char)*s))
+ *d++ = *s;
+ s++;
+ }
+ *d = *s;
+
+ desc = g_strdup_printf (_("Pointer to remote data (%s)"), url);
+ }
+
+ fallback:
+ if (!desc) {
+ if (access_type)
+ desc = g_strdup_printf (_("Pointer to unknown external data (\"%s\" type)"), access_type);
+ else
+ desc = g_strdup (_("Malformed external-body part."));
+ }
+
+#if 0 /* FIXME */
+ handle_mystery (part, md, url, "gnome-globe.png", desc,
+ url ? "open it in a browser" : NULL);
+#endif
+
+ g_free (desc);
+ g_free (url);
+
+ return TRUE;
+}
+
+static gboolean
+handle_via_bonobo (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream)
+{
+ if (!md->printing) {
+ camel_stream_printf ((CamelStream *) stream,
+ "<object classid=\"%s\" type=\"%s\"></object>",
+ get_cid (part, md), mime_type);
+ }
+
+ return TRUE;
+}
+
+/**
+ * mail_get_message_rfc822:
+ * @message: the message
+ * @want_plain: whether the caller prefers plain to html
+ * @cite: whether or not to cite the message text
+ *
+ * See mail_get_message_body() below for more details.
+ *
+ * Return value: an HTML string representing the text parts of @message.
+ **/
+static char *
+mail_get_message_rfc822 (CamelMimeMessage *message, gboolean want_plain, gboolean cite)
+{
+ CamelDataWrapper *contents;
+ GString *retval;
+ const CamelInternetAddress *cia;
+ char *text, *citation, *buf, *html;
+ time_t date_val;
+ int offset;
+
+ contents = camel_medium_get_content_object (CAMEL_MEDIUM (message));
+ text = mail_get_message_body (contents, want_plain, cite);
+ if (!text)
+ text = g_strdup ("");
+ citation = cite ? "&gt; " : "";
+ retval = g_string_new (NULL);
+
+ /* Kludge: if text starts with "<PRE>", wrap it around the
+ * headers too so we won't get a blank line between them for the
+ * <P> to <PRE> switch.
+ */
+ if (!strncasecmp (text, "<pre>", 5))
+ g_string_append_printf (retval, "<PRE>");
+
+ /* create credits */
+ cia = camel_mime_message_get_from (message);
+ buf = camel_address_format (CAMEL_ADDRESS (cia));
+ if (buf) {
+ html = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL, 0);
+ g_string_append_printf (retval, "%s<b>From:</b> %s<br>",
+ citation, html);
+ g_free (html);
+ g_free (buf);
+ }
+
+ cia = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO);
+ buf = camel_address_format (CAMEL_ADDRESS (cia));
+ if (buf) {
+ html = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL, 0);
+ g_string_append_printf (retval, "%s<b>To:</b> %s<br>",
+ citation, html);
+ g_free (html);
+ g_free (buf);
+ }
+
+ cia = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC);
+ buf = camel_address_format (CAMEL_ADDRESS (cia));
+ if (buf) {
+ html = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL, 0);
+ g_string_append_printf (retval, "%s<b>Cc:</b> %s<br>",
+ citation, html);
+ g_free (html);
+ g_free (buf);
+ }
+
+ buf = (char *) camel_mime_message_get_subject (message);
+ if (buf) {
+ html = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+ g_string_append_printf (retval, "%s<b>Subject:</b> %s<br>",
+ citation, html);
+ g_free (html);
+ }
+
+ date_val = camel_mime_message_get_date (message, &offset);
+ buf = header_format_date (date_val, offset);
+ html = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL, 0);
+ g_string_append_printf (retval, "%s<b>Date:</b> %s<br>", citation, html);
+ g_free (html);
+ g_free (buf);
+
+ if (!strncasecmp (text, "<pre>", 5))
+ g_string_append_printf (retval, "%s<br>%s", citation, text + 5);
+ else
+ g_string_append_printf (retval, "%s<br>%s", citation, text);
+ g_free (text);
+
+ buf = retval->str;
+ g_string_free (retval, FALSE);
+
+ return buf;
+}
+
+/**
+ * mail_get_message_body:
+ * @data: the message or mime part content
+ * @want_plain: whether the caller prefers plain to html
+ * @cite: whether or not to cite the message text
+ *
+ * This creates an HTML string representing @data. If @want_plain is %TRUE,
+ * it will be an HTML string that looks like a text/plain representation
+ * of @data (but it will still be HTML).
+ *
+ * If @cite is %TRUE, the message will be cited as a reply, using "> "s.
+ *
+ * Return value: the HTML string, which the caller must free, or
+ * %NULL if @data doesn't include any data which should be forwarded or
+ * replied to.
+ **/
+char *
+mail_get_message_body (CamelDataWrapper *data, gboolean want_plain, gboolean cite)
+{
+ char *subtext, *old, *div, *text = NULL;
+ CamelContentType *mime_type;
+ CamelCipherContext *cipher;
+ GByteArray *bytes = NULL;
+ CamelMimePart *subpart;
+ CamelMultipart *mp;
+ int i, nparts;
+
+ mime_type = camel_data_wrapper_get_mime_type_field (data);
+
+ /* If it is message/rfc822 or message/news, extract the
+ * important headers and recursively process the body.
+ */
+ if (header_content_type_is (mime_type, "message", "rfc822") ||
+ header_content_type_is (mime_type, "message", "news"))
+ return mail_get_message_rfc822 (CAMEL_MIME_MESSAGE (data), want_plain, cite);
+
+ /* If it's a vcard or icalendar, ignore it. */
+ if (header_content_type_is (mime_type, "text", "x-vcard") ||
+ header_content_type_is (mime_type, "text", "calendar"))
+ return NULL;
+
+ /* Get the body data for other text/ or message/ types */
+ if (header_content_type_is (mime_type, "text", "*") ||
+ header_content_type_is (mime_type, "message", "*")) {
+ bytes = mail_format_get_data_wrapper_text (data, NULL);
+
+ if (bytes) {
+ g_byte_array_append (bytes, "", 1);
+ text = bytes->data;
+ g_byte_array_free (bytes, FALSE);
+ }
+
+ if (text && !header_content_type_is(mime_type, "text", "html")) {
+ char *html;
+
+ if (header_content_type_is(mime_type, "text", "richtext"))
+ html = camel_enriched_to_html(text, CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT);
+ else if (header_content_type_is(mime_type, "text", "enriched"))
+ html = camel_enriched_to_html(text, 0);
+ else
+ html = camel_text_to_html (text, CAMEL_MIME_FILTER_TOHTML_PRE |
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
+ (cite ? CAMEL_MIME_FILTER_TOHTML_CITE : 0), 0);
+ g_free(text);
+ text = html;
+ }
+ return text;
+ }
+
+ /* If it's not message and it's not text, and it's not
+ * multipart, we don't want to deal with it.
+ */
+ if (!header_content_type_is (mime_type, "multipart", "*"))
+ return NULL;
+
+ mp = CAMEL_MULTIPART (data);
+
+ if (CAMEL_IS_MULTIPART_ENCRYPTED (mp)) {
+ cipher = camel_gpg_context_new (session);
+ subpart = camel_multipart_encrypted_decrypt (CAMEL_MULTIPART_ENCRYPTED (mp),
+ cipher, NULL);
+ if (!subpart)
+ return NULL;
+
+ data = camel_medium_get_content_object (CAMEL_MEDIUM (subpart));
+ return mail_get_message_body (data, want_plain, cite);
+ } else if (header_content_type_is (mime_type, "multipart", "alternative")) {
+ /* Pick our favorite alternative and reply to it. */
+
+ subpart = find_preferred_alternative (mp, want_plain);
+ if (!subpart)
+ return NULL;
+
+ data = camel_medium_get_content_object (CAMEL_MEDIUM (subpart));
+ return mail_get_message_body (data, want_plain, cite);
+ }
+
+ /* Otherwise, concatenate all the parts that we can. */
+ if (want_plain) {
+ if (cite)
+ div = "<br>\n&gt; ----<br>\n&gt; <br>\n";
+ else
+ div = "<br>\n----<br>\n<br>\n";
+ } else
+ div = "<br><hr><br>";
+
+ nparts = camel_multipart_get_number (mp);
+ for (i = 0; i < nparts; i++) {
+ subpart = camel_multipart_get_part (mp, i);
+
+ /* only add to the body contents if it is marked as "inline" */
+ if (!mail_part_is_inline (subpart))
+ continue;
+
+ data = camel_medium_get_content_object (CAMEL_MEDIUM (subpart));
+ subtext = mail_get_message_body (data, want_plain, cite);
+ if (!subtext)
+ continue;
+
+ if (text) {
+ old = text;
+ text = g_strdup_printf ("%s%s%s", old, div, subtext);
+ g_free (subtext);
+ g_free (old);
+ } else
+ text = subtext;
+ }
+
+ return text;
+}
diff --git a/mail/mail-format.h b/mail/mail-format.h
new file mode 100644
index 0000000000..e39148ca83
--- /dev/null
+++ b/mail/mail-format.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2003 Ximian, Inc. (www.ximian.com)
+ *
+ * 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 2 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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __MAIL_FORMAT_H__
+#define __MAIL_FORMAT_H__
+
+#include <camel/camel.h>
+#include <gtkhtml/gtkhtml.h>
+
+#include "mail-display.h"
+#include "mail-display-stream.h"
+
+GByteArray *mail_format_get_data_wrapper_text (CamelDataWrapper *data,
+ MailDisplay *mail_display);
+
+ssize_t mail_format_data_wrapper_write_to_stream (CamelDataWrapper *wrapper,
+ gboolean decode,
+ MailDisplay *mail_display,
+ CamelStream *stream);
+
+void mail_format_mime_message (CamelMimeMessage *mime_message,
+ MailDisplay *md, MailDisplayStream *stream);
+void mail_format_raw_message (CamelMimeMessage *mime_message,
+ MailDisplay *md, MailDisplayStream *stream);
+
+gboolean mail_content_loaded (CamelDataWrapper *wrapper,
+ MailDisplay *display,
+ gboolean redisplay,
+ const char *url,
+ GtkHTML *html,
+ GtkHTMLStream *handle);
+
+typedef gboolean (*MailMimeHandlerFn) (CamelMimePart *part, const char *mime_type,
+ MailDisplay *md, MailDisplayStream *stream);
+typedef struct {
+ Bonobo_ServerInfo *component;
+ GList *applications;
+ MailMimeHandlerFn builtin;
+ guint generic : 1;
+ guint is_bonobo : 1;
+} MailMimeHandler;
+
+MailMimeHandler *mail_lookup_handler (const char *mime_type);
+
+gboolean mail_part_is_inline (CamelMimePart *part);
+gboolean mail_part_is_displayed_inline (CamelMimePart *part, MailDisplay *md);
+void mail_part_toggle_displayed (CamelMimePart *part, MailDisplay *md);
+
+char *mail_get_message_body (CamelDataWrapper *data, gboolean want_plain, gboolean cite);
+
+#endif /* __MAIL_FORMAT_H__ */
diff --git a/mail/mail-identify.c b/mail/mail-identify.c
new file mode 100644
index 0000000000..2e3f517145
--- /dev/null
+++ b/mail/mail-identify.c
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * Author :
+ * Dan Winship <danw@ximian.com>
+ *
+ * Copyright 2000, Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-mime.h>
+#include <libgnomevfs/gnome-vfs-mime-utils.h>
+#include "mail.h"
+
+static const char *identify_by_magic (CamelDataWrapper *data, MailDisplay *md);
+
+/**
+ * mail_identify_mime_part:
+ * @part: a CamelMimePart
+ * @md: the MailDisplay @part is being shown in
+ *
+ * Try to identify the MIME type of the data in @part (which presumably
+ * doesn't have a useful Content-Type).
+ *
+ * Return value: the MIME type, which the caller must free, or %NULL
+ * if it could not be identified.
+ **/
+char *
+mail_identify_mime_part (CamelMimePart *part, MailDisplay *md)
+{
+ const char *filename, *name_type = NULL, *magic_type = NULL;
+ CamelDataWrapper *data;
+
+ filename = camel_mime_part_get_filename (part);
+ if (filename) {
+ /* GNOME-VFS will misidentify TNEF attachments as MPEG */
+ if (!strcmp (filename, "winmail.dat"))
+ return g_strdup ("application/vnd.ms-tnef");
+
+ name_type = gnome_vfs_mime_type_from_name (filename);
+ }
+
+ data = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+ if (!camel_data_wrapper_is_offline (data))
+ magic_type = identify_by_magic (data, md);
+
+ if (magic_type && name_type) {
+ /* If GNOME-VFS doesn't recognize the data by magic, but it
+ * contains English words, it will call it text/plain. If the
+ * filename-based check came up with something different, use
+ * that instead.
+ */
+ if (!strcmp (magic_type, "text/plain"))
+ return g_strdup (name_type);
+
+ /* If if returns "application/octet-stream" try to
+ * do better with the filename check.
+ */
+ if (!strcmp (magic_type, "application/octet-stream"))
+ return g_strdup (name_type);
+ }
+
+ /* If the MIME part data was online, and the magic check
+ * returned something, use that, since it's more reliable.
+ */
+ if (magic_type)
+ return g_strdup (magic_type);
+
+ /* Otherwise try guessing based on the filename */
+ if (name_type)
+ return g_strdup (name_type);
+
+ /* Another possibility to try is the x-mac-type / x-mac-creator
+ * parameter to Content-Type used by some Mac email clients. That
+ * would require a Mac type to mime type conversion table.
+ */
+
+#if 0
+ /* If the data part is offline, then we didn't try magic
+ * before, so force it to be loaded so we can try again later.
+ * FIXME: In a perfect world, we would not load the content
+ * just to identify the MIME type.
+ */
+ /* This is disabled as it just frustrates users more than it helps,
+ see discussion in bug #11778 */
+ if (camel_data_wrapper_is_offline (data))
+ mail_content_loaded (data, md, TRUE, NULL, NULL, NULL);
+#endif
+
+ return NULL;
+}
+
+static const char *
+identify_by_magic (CamelDataWrapper *data, MailDisplay *md)
+{
+ CamelStreamMem *memstream;
+ const char *type;
+
+ memstream = (CamelStreamMem *)camel_stream_mem_new();
+ if (camel_data_wrapper_write_to_stream (data, (CamelStream *)memstream) > 0)
+ type = gnome_vfs_get_mime_type_for_data(memstream->buffer->data, memstream->buffer->len);
+ else
+ type = NULL;
+ camel_object_unref(memstream);
+
+ return type;
+}
diff --git a/mail/mail-importer.c b/mail/mail-importer.c
index 193726aa1e..a915c04668 100644
--- a/mail/mail-importer.c
+++ b/mail/mail-importer.c
@@ -36,12 +36,12 @@
#include <camel/camel-exception.h>
#include <e-util/e-path.h>
+#include "mail-component.h"
#include "mail-importer.h"
#include "mail-local.h"
#include "mail.h"
static GList *importer_modules = NULL;
-extern char *evolution_dir;
static GNOME_Evolution_Storage local_storage = NULL;
void mail_importer_uninit (void);
@@ -95,7 +95,8 @@ mail_importer_make_local_folder(const char *folderpath)
} else {
struct _create_data data = { GNOME_Evolution_Storage_GENERIC_ERROR, FALSE };
- tmp = g_strdup_printf("file://%s/local", evolution_dir);
+ tmp = g_strdup_printf("file://%s/local",
+ mail_component_peek_base_directory (mail_component_peek ()));
uri = e_path_to_physical(tmp, folderpath);
g_free(tmp);
tmp = strrchr(uri, '/');
diff --git a/mail/mail-local.c b/mail/mail-local.c
index 0ec4f5a8e9..565e028432 100644
--- a/mail/mail-local.c
+++ b/mail/mail-local.c
@@ -533,10 +533,11 @@ mlf_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args)
/* CamelObject args */
case CAMEL_OBJECT_ARG_DESCRIPTION:
if (mlf->description == NULL) {
+ const char *base_directory = mail_component_peek_base_directory (mail_component_peek ());
int pathlen;
/* string to describe a local folder as the location of a message */
- pathlen = strlen(evolution_dir) + strlen("local") + 1;
+ pathlen = strlen(base_directory) + strlen("local") + 1;
if (strlen(folder->full_name) > pathlen)
mlf->description = g_strdup_printf(_("Local folders/%s"), folder->full_name+pathlen);
else
diff --git a/mail/mail-mt.c b/mail/mail-mt.c
index 603e55dd50..cb75fe93bf 100644
--- a/mail/mail-mt.c
+++ b/mail/mail-mt.c
@@ -28,8 +28,6 @@
#include "mail-session.h"
#include "mail-mt.h"
-#include "component-factory.h"
-
/*#define MALLOC_CHECK*/
#define LOG_OPS
#define LOG_LOCKS
@@ -911,10 +909,11 @@ static void do_op_status(struct _mail_msg *mm)
what = msg->ops->describe_msg (msg, FALSE);
else
what = _("Working");
-
+
+ /* EPFIXME: redo activity client stuff. */
if (global_shell_client) {
activity = evolution_activity_client_new (global_shell_client,
- COMPONENT_ID,
+ "evolution-mail",
progress_icon, what, TRUE,
&display);
} else {
diff --git a/mail/mail-offline-handler.c b/mail/mail-offline-handler.c
index ccaff703f5..ce0bcf729f 100644
--- a/mail/mail-offline-handler.c
+++ b/mail/mail-offline-handler.c
@@ -27,9 +27,10 @@
#endif
#include "mail-offline-handler.h"
-#include "mail.h"
+#include "mail-component.h"
#include "mail-ops.h"
#include "mail-folder-cache.h"
+#include "mail.h"
#include <gtk/gtkmain.h>
@@ -77,10 +78,10 @@ create_connection_list (void)
list = GNOME_Evolution_ConnectionList__alloc ();
list->_length = 0;
- list->_maximum = mail_storages_count ();
+ list->_maximum = mail_component_get_storage_count (mail_component_peek ());
list->_buffer = CORBA_sequence_GNOME_Evolution_Connection_allocbuf (list->_maximum);
- mail_storages_foreach (add_connection, list);
+ mail_component_storages_foreach (mail_component_peek (), add_connection, list);
return list;
}
@@ -260,7 +261,7 @@ impl_goOffline (PortableServer_Servant servant,
/* FIXME: If send/receive active, wait for it to finish */
- mail_storages_foreach (storage_go_offline, progress_listener);
+ mail_component_storages_foreach (mail_component_peek (), storage_go_offline, progress_listener);
}
static void
@@ -270,8 +271,7 @@ storage_go_online (gpointer key, gpointer value, gpointer data)
if (service_is_relevant (CAMEL_SERVICE (store), FALSE)) {
mail_store_set_offline (store, FALSE, NULL, NULL);
- mail_note_store (store, NULL, NULL, CORBA_OBJECT_NIL,
- NULL, NULL);
+ mail_note_store (store, NULL, NULL, NULL, NULL);
}
}
@@ -288,7 +288,7 @@ impl_goOnline (PortableServer_Servant servant,
/* Enable auto-mail-checking */
camel_session_set_online (session, TRUE);
- mail_storages_foreach (storage_go_online, NULL);
+ mail_component_storages_foreach (mail_component_peek (), storage_go_online, NULL);
}
/* GObject methods. */
diff --git a/mail/mail-ops.c b/mail/mail-ops.c
index 65cc8676c1..8d3711ff4e 100644
--- a/mail/mail-ops.c
+++ b/mail/mail-ops.c
@@ -38,6 +38,7 @@
#include <camel/camel-vtrash-folder.h>
#include <camel/camel-vee-store.h>
#include "mail.h"
+#include "mail-component.h"
#include "mail-tools.h"
#include "mail-ops.h"
#include "mail-vfolder.h"
@@ -229,7 +230,8 @@ uid_cachename_hack (CamelStore *store)
url->host);
e_filename_make_safe (encoded_url);
- filename = g_strdup_printf ("%s/mail/pop3/cache-%s", evolution_dir, encoded_url);
+ filename = g_strdup_printf ("%s/mail/pop3/cache-%s",
+ mail_component_peek_base_directory (mail_component_peek ()), encoded_url);
/* lame hack, but we can't expect user's to actually migrate
their cache files - brain power requirements are too
@@ -238,7 +240,9 @@ uid_cachename_hack (CamelStore *store)
/* This is either the first time the user has checked
mail with this POP provider or else their cache
file is in the old location... */
- old_location = g_strdup_printf ("%s/config/cache-%s", evolution_dir, encoded_url);
+ old_location = g_strdup_printf ("%s/config/cache-%s",
+ mail_component_peek_base_directory (mail_component_peek ()),
+ encoded_url);
if (stat (old_location, &st) == -1) {
/* old location doesn't exist either so use the new location */
g_free (old_location);
diff --git a/mail/mail-search.c b/mail/mail-search.c
new file mode 100644
index 0000000000..424ccee991
--- /dev/null
+++ b/mail/mail-search.c
@@ -0,0 +1,403 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jon Trowbridge <trow@ximian.com>
+ *
+ * Copyright 2001-2003 Ximian, Inc. (www.ximian.com)
+ *
+ * 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 2 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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "mail-search.h"
+#include "e-searching-tokenizer.h"
+#include <gtkhtml/gtkhtml-search.h>
+#include <gtkhtml/htmlengine.h>
+#include <libgnomeui/gnome-window-icon.h>
+#include <gdk/gdkkeysyms.h>
+
+
+static ESearchingTokenizer *mail_search_tokenizer (MailSearch *ms);
+static void mail_search_redisplay_message (MailSearch *ms);
+
+
+static GtkObjectClass *parent_class = NULL;
+
+
+static void
+mail_search_finalise (GObject *obj)
+{
+ MailSearch *ms = MAIL_SEARCH (obj);
+
+ g_free (ms->last_search);
+ g_object_weak_unref ((GObject *) ms->mail, (GWeakNotify) gtk_widget_destroy, ms);
+ g_object_unref (ms->mail);
+
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+mail_search_destroy (GtkObject *obj)
+{
+ MailSearch *ms = (MailSearch *) obj;
+ ESearchingTokenizer *st = mail_search_tokenizer (ms);
+
+ if (ms->begin_handler) {
+ g_signal_handler_disconnect (ms->mail->html->engine->ht, ms->begin_handler);
+ ms->begin_handler = 0;
+ g_signal_handler_disconnect (ms->mail->html->engine->ht, ms->match_handler);
+ ms->match_handler = 0;
+
+ e_searching_tokenizer_set_primary_search_string (st, NULL);
+ mail_search_redisplay_message (ms);
+ }
+
+ GTK_OBJECT_CLASS (parent_class)->destroy (obj);
+}
+
+static void
+mail_search_class_init (MailSearchClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+ GtkObjectClass *gtk_object_class = (GtkObjectClass *) klass;
+
+ parent_class = (GtkObjectClass *) g_type_class_ref (GTK_TYPE_DIALOG);
+
+ object_class->finalize = mail_search_finalise;
+
+ gtk_object_class->destroy = mail_search_destroy;
+}
+
+static void
+mail_search_init (MailSearch *ms)
+{
+
+}
+
+GtkType
+mail_search_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo info = {
+ sizeof (MailSearchClass),
+ NULL, NULL,
+ (GClassInitFunc) mail_search_class_init,
+ NULL, NULL,
+ sizeof (MailSearch),
+ 0,
+ (GInstanceInitFunc) mail_search_init,
+ };
+
+ type = g_type_register_static (GTK_TYPE_DIALOG, "MailSearch", &info, 0);
+ }
+
+ return type;
+}
+
+/*
+ * Convenience
+ */
+
+static ESearchingTokenizer *
+mail_search_tokenizer (MailSearch *ms)
+{
+ return E_SEARCHING_TOKENIZER (ms->mail->html->engine->ht);
+}
+
+static void
+mail_search_redisplay_message (MailSearch *ms)
+{
+ mail_display_redisplay (ms->mail, FALSE);
+}
+
+static void
+mail_search_set_subject (MailSearch *ms, const char *subject)
+{
+ char *utf8_subject = NULL;
+
+ if (subject && *subject) {
+ utf8_subject = g_strdup (subject);
+
+ if (g_utf8_validate (utf8_subject, -1, NULL)) {
+#define ARBITRARY_CUTOFF 40
+ if (g_utf8_strlen (utf8_subject, -1) > ARBITRARY_CUTOFF + 3) {
+ char *p = g_utf8_offset_to_pointer (utf8_subject, ARBITRARY_CUTOFF);
+
+ strcpy (p, "...");
+ }
+ } else {
+ /* If the subject contains bad utf8, don't show anything in the frame label. */
+ g_free (utf8_subject);
+ utf8_subject = NULL;
+ }
+ } else {
+ utf8_subject = g_strdup (_("(Untitled Message)"));
+ }
+
+ gtk_frame_set_label (GTK_FRAME (ms->msg_frame), utf8_subject);
+
+ g_free (utf8_subject);
+}
+
+/*
+ * Construct Objects
+ */
+
+static void
+toggled_case_cb (GtkToggleButton *b, MailSearch *ms)
+{
+ ms->case_sensitive = gtk_toggle_button_get_active (b);
+
+ e_searching_tokenizer_set_primary_case_sensitivity (mail_search_tokenizer (ms),
+ ms->case_sensitive);
+ mail_search_redisplay_message (ms);
+
+}
+
+#if 0
+static void
+toggled_fwd_cb (GtkToggleButton *b, MailSearch *ms)
+{
+ ms->search_forward = gtk_toggle_button_get_active (b);
+ gtk_html_engine_search_set_forward (ms->mail->html, ms->search_forward);
+}
+#endif
+
+static void
+dialog_response_cb (GtkWidget *widget, int button, MailSearch *ms)
+{
+ ESearchingTokenizer *st = mail_search_tokenizer (ms);
+
+ if (button == GTK_RESPONSE_ACCEPT) {
+ char *search_text;
+
+ search_text = gtk_editable_get_chars (GTK_EDITABLE (ms->entry), 0, -1);
+ g_strstrip (search_text);
+
+ if (search_text && *search_text) {
+ if (ms->last_search && !strcmp (ms->last_search, search_text)) {
+
+ if (!gtk_html_engine_search_next (ms->mail->html)) {
+ g_free (ms->last_search);
+ ms->last_search = NULL;
+ }
+ } else {
+ g_free (ms->last_search);
+ ms->last_search = NULL;
+
+ e_searching_tokenizer_set_primary_search_string (st, search_text);
+ e_searching_tokenizer_set_primary_case_sensitivity (st, ms->case_sensitive);
+
+ mail_search_redisplay_message (ms);
+
+ if (gtk_html_engine_search (ms->mail->html, search_text,
+ ms->case_sensitive, ms->search_forward,
+ FALSE)) {
+ ms->last_search = g_strdup (search_text);
+ }
+ }
+ }
+
+ g_free (search_text);
+ } else if (button == GTK_RESPONSE_CLOSE) {
+ gtk_widget_destroy (widget);
+ }
+}
+
+static void
+begin_cb (ESearchingTokenizer *st, char *foo, MailSearch *ms)
+{
+ const char *subject;
+
+ if (ms && ms->mail && ms->mail->current_message) {
+ subject = ms->mail->current_message->subject;
+
+ if (subject == NULL)
+ subject = _("Untitled Message");
+ } else {
+ subject = _("Empty Message");
+ }
+
+ gtk_label_set_text (GTK_LABEL (ms->count_label), "0");
+ mail_search_set_subject (ms, subject);
+}
+
+static void
+match_cb (ESearchingTokenizer *st, MailSearch *ms)
+{
+ char buf[16];
+
+ g_snprintf (buf, 16, "%d", e_searching_tokenizer_match_count (st));
+ gtk_label_set_text (GTK_LABEL (ms->count_label), buf);
+}
+
+static void
+entry_run_search (GtkWidget *w, MailSearch *ms)
+{
+ /* run search when enter pressed on widget */
+ gtk_dialog_response ((GtkDialog *) ms, GTK_RESPONSE_ACCEPT);
+}
+
+void
+mail_search_construct (MailSearch *ms, MailDisplay *mail)
+{
+ GtkWidget *find_hbox;
+ GtkWidget *matches_hbox;
+ GtkWidget *toggles_hbox;
+ GtkWidget *frame_vbox;
+ GtkWidget *entry;
+ GtkWidget *count_label;
+ GtkWidget *case_check;
+#if 0
+ GtkWidget *fwd_check;
+#endif
+ GtkWidget *button;
+ GtkWidget *msg_hbox;
+ GtkWidget *msg_frame;
+ GtkAccelGroup *accel_group;
+
+ g_return_if_fail (ms != NULL && IS_MAIL_SEARCH (ms));
+ g_return_if_fail (mail != NULL && IS_MAIL_DISPLAY (mail));
+
+ /* Basic set-up */
+
+ ms->mail = mail;
+ g_object_ref (mail);
+
+ gtk_window_set_title ((GtkWindow *) ms, _("Find in Message"));
+
+ button = gtk_dialog_add_button ((GtkDialog *) ms, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+ gtk_dialog_set_default_response ((GtkDialog *) ms, GTK_RESPONSE_ACCEPT);
+ accel_group = gtk_accel_group_new ();
+ gtk_window_add_accel_group (GTK_WINDOW (ms), accel_group);
+ gtk_widget_add_accelerator (button, "activate", accel_group, GDK_Escape, 0, GTK_ACCEL_LOCKED);
+
+ gtk_dialog_add_button ((GtkDialog *) ms, GTK_STOCK_FIND, GTK_RESPONSE_ACCEPT);
+
+ ms->search_forward = TRUE;
+ ms->case_sensitive = FALSE;
+
+ ms->begin_handler = g_signal_connect (ms->mail->html->engine->ht, "begin",
+ G_CALLBACK (begin_cb), ms);
+ ms->match_handler = g_signal_connect (ms->mail->html->engine->ht, "match",
+ G_CALLBACK (match_cb), ms);
+
+ /* Construct the dialog contents. */
+
+ msg_hbox = gtk_hbox_new (FALSE, 3);
+ find_hbox = gtk_hbox_new (FALSE, 3);
+ matches_hbox = gtk_hbox_new (FALSE, 3);
+ toggles_hbox = gtk_hbox_new (FALSE, 3);
+ frame_vbox = gtk_vbox_new (FALSE, 3);
+ gtk_container_set_border_width ((GtkContainer *) frame_vbox, 3);
+
+ entry = gtk_entry_new ();
+ count_label = gtk_label_new ("0");
+
+ msg_frame = gtk_frame_new (NULL);
+ gtk_container_set_border_width ((GtkContainer *) msg_frame, 6);
+
+ case_check = gtk_check_button_new_with_label (_("Case Sensitive"));
+#if 0
+ fwd_check = gtk_check_button_new_with_label (_("Search Forward"));
+#endif
+
+ ms->entry = entry;
+ ms->count_label = count_label;
+
+ ms->msg_frame = msg_frame;
+
+ if (mail->current_message->subject && *mail->current_message->subject)
+ mail_search_set_subject (ms, mail->current_message->subject);
+ else
+ mail_search_set_subject (ms, NULL);
+
+#if 0
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fwd_check), ms->search_forward);
+#endif
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (case_check), ms->case_sensitive);
+
+ gtk_box_pack_start (GTK_BOX (msg_hbox), GTK_WIDGET (msg_frame), TRUE, TRUE, 0);
+
+ gtk_box_pack_start (GTK_BOX (find_hbox), gtk_label_new (_("Find:")), FALSE, FALSE, 3);
+ gtk_box_pack_start (GTK_BOX (find_hbox), entry, TRUE, TRUE, 3);
+
+ gtk_box_pack_start (GTK_BOX (matches_hbox), gtk_hbox_new (FALSE, 0), TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (matches_hbox), gtk_label_new (_("Matches:")), FALSE, FALSE, 3);
+ gtk_box_pack_start (GTK_BOX (matches_hbox), count_label, FALSE, FALSE, 3);
+ gtk_box_pack_start (GTK_BOX (matches_hbox), gtk_hbox_new (FALSE, 0), TRUE, TRUE, 0);
+
+ gtk_box_pack_start (GTK_BOX (toggles_hbox), case_check, FALSE, FALSE, 3);
+
+ /*
+ * Disabling the forward/backward search button because there are problems with it
+ * (related to how gtkhtml handles searches), the GUI freeze is upon us, and I
+ * don't know if they'll get resolved for 1.0. Hopefully getting this fixed can
+ * be a 1.1 item.
+ */
+
+#if 0
+ gtk_box_pack_start (GTK_BOX (toggles_hbox), fwd_check, FALSE, FALSE, 3);
+#endif
+
+ gtk_box_pack_start (GTK_BOX (frame_vbox), find_hbox, FALSE, FALSE, 3);
+ gtk_box_pack_start (GTK_BOX (frame_vbox), matches_hbox, FALSE, FALSE, 3);
+ gtk_box_pack_start (GTK_BOX (frame_vbox), toggles_hbox, FALSE, FALSE, 3);
+
+ gtk_container_add (GTK_CONTAINER (msg_frame), GTK_WIDGET (frame_vbox));
+
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ms)->vbox), msg_hbox, TRUE, TRUE, 0);
+
+ gtk_widget_grab_focus (entry); /* Give focus to entry by default */
+ g_signal_connect (entry, "activate", G_CALLBACK (entry_run_search), ms);
+ gnome_window_icon_set_from_file (GTK_WINDOW (ms), EVOLUTION_ICONSDIR "/find-message.xpm");
+
+ gtk_widget_show_all (msg_hbox);
+ gtk_widget_show_all (find_hbox);
+ gtk_widget_show_all (matches_hbox);
+ gtk_widget_show_all (toggles_hbox);
+
+ /* Hook up signals */
+
+ g_signal_connect (case_check, "toggled", G_CALLBACK (toggled_case_cb), ms);
+#if 0
+ g_signal_connect (fwd_check, "toggled", G_CALLBACK (toggled_fwd_cb), ms);
+#endif
+ g_signal_connect (ms, "response", G_CALLBACK (dialog_response_cb), ms);
+
+ g_object_weak_ref ((GObject *) ms->mail, (GWeakNotify) gtk_widget_destroy, ms);
+}
+
+GtkWidget *
+mail_search_new (MailDisplay *mail)
+{
+ GtkWidget *widget;
+
+ g_return_val_if_fail (IS_MAIL_DISPLAY (mail), NULL);
+
+ widget = g_object_new (mail_search_get_type (), NULL);
+ mail_search_construct (MAIL_SEARCH (widget), mail);
+
+ return widget;
+}
+
diff --git a/mail/mail-search.h b/mail/mail-search.h
new file mode 100644
index 0000000000..cbcf563636
--- /dev/null
+++ b/mail/mail-search.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jon Trowbridge <trow@ximian.com>
+ *
+ * Copyright 2001-2003 Ximian, Inc. (www.ximian.com)
+ *
+ * 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 2 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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef _MAIL_SEARCH_H_
+#define _MAIL_SEARCH_H_
+
+#ifdef _cplusplus
+extern "C" {
+#pragma }
+#endif /* _cplusplus */
+
+#include <gtk/gtkdialog.h>
+#include "mail-display.h"
+
+#define MAIL_SEARCH_TYPE (mail_search_get_type ())
+#define MAIL_SEARCH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MAIL_SEARCH_TYPE, MailSearch))
+#define MAIL_SEARCH_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), MAIL_SEARCH_TYPE, MailSearch))
+#define IS_MAIL_SEARCH(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MAIL_SEARCH_TYPE))
+#define IS_MAIL_SEARCH_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MAIL_SEARCH_TYPE))
+
+typedef struct _MailSearch MailSearch;
+typedef struct _MailSearchClass MailSearchClass;
+
+struct _MailSearch {
+ GtkDialog parent;
+
+ MailDisplay *mail;
+
+ GtkWidget *entry;
+ GtkWidget *msg_frame;
+ GtkWidget *count_label;
+
+ gboolean search_forward, case_sensitive;
+ char *last_search;
+
+ guint begin_handler;
+ guint match_handler;
+};
+
+struct _MailSearchClass {
+ GtkDialogClass parent_class;
+
+};
+
+GtkType mail_search_get_type (void);
+
+void mail_search_construct (MailSearch *, MailDisplay *);
+GtkWidget *mail_search_new (MailDisplay *);
+
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* _MAIL_SEARCH_H_ */
diff --git a/mail/mail-send-recv.c b/mail/mail-send-recv.c
index 0ba9ae3179..6d70fe5047 100644
--- a/mail/mail-send-recv.c
+++ b/mail/mail-send-recv.c
@@ -46,6 +46,7 @@
#include "mail.h"
#include "mail-mt.h"
+#include "mail-component.h"
#include "mail-config.h"
#include "mail-session.h"
#include "mail-tools.h"
@@ -167,7 +168,7 @@ static void free_send_info(void *key, struct _send_info *info, void *data)
g_free(info->uri);
camel_operation_unref(info->cancel);
if (info->timeout_id != 0)
- gtk_timeout_remove(info->timeout_id);
+ g_source_remove(info->timeout_id);
g_free(info->what);
g_free(info);
}
@@ -207,7 +208,7 @@ static void hide_send_info(void *key, struct _send_info *info, void *data)
info->status = NULL;
if (info->timeout_id != 0) {
- gtk_timeout_remove (info->timeout_id);
+ g_source_remove (info->timeout_id);
info->timeout_id = 0;
}
}
@@ -366,7 +367,7 @@ build_dialogue (EAccountList *accounts, CamelFolder *outbox, const char *destina
info->keep = source->keep_on_server;
info->cancel = camel_operation_new (operation_status, info);
info->state = SEND_ACTIVE;
- info->timeout_id = gtk_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);
+ info->timeout_id = g_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);
g_hash_table_insert (data->active, info->uri, info);
list = g_list_prepend (list, info);
@@ -375,7 +376,7 @@ build_dialogue (EAccountList *accounts, CamelFolder *outbox, const char *destina
e_iterator_next (iter);
continue;
} else if (info->timeout_id == 0)
- info->timeout_id = gtk_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);
+ info->timeout_id = g_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);
recv_icon = gtk_image_new_from_file (EVOLUTION_BUTTONSDIR "/receive-24.png");
@@ -423,12 +424,12 @@ build_dialogue (EAccountList *accounts, CamelFolder *outbox, const char *destina
info->keep = FALSE;
info->cancel = camel_operation_new (operation_status, info);
info->state = SEND_ACTIVE;
- info->timeout_id = gtk_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);
+ info->timeout_id = g_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);
g_hash_table_insert (data->active, SEND_URI_KEY, info);
list = g_list_prepend (list, info);
} else if (info->timeout_id == 0)
- info->timeout_id = gtk_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);
+ info->timeout_id = g_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);
send_icon = gtk_image_new_from_file (EVOLUTION_BUTTONSDIR "/send-24.png");
@@ -663,10 +664,10 @@ receive_update_got_store (char *uri, CamelStore *store, void *data)
struct _send_info *info = data;
if (store) {
- EvolutionStorage *storage = mail_lookup_storage (store);
+ EStorage *storage = mail_component_lookup_storage (mail_component_peek (), store);
if (storage) {
- mail_note_store(store, info->cancel, storage, CORBA_OBJECT_NIL, receive_update_done, info);
+ mail_note_store(store, info->cancel, storage, receive_update_done, info);
/*bonobo_object_unref (BONOBO_OBJECT (storage));*/
} else {
/* If we get here, store must be an external
@@ -770,7 +771,7 @@ static void auto_clean_set(void *key, struct _auto_data *info, GHashTable *set)
{
d(printf("removing auto-check for %s %p\n", info->uri, info));
g_hash_table_remove(set, info->uri);
- gtk_timeout_remove(info->timeout_id);
+ g_source_remove(info->timeout_id);
g_free(info->uri);
g_free(info);
}
@@ -811,15 +812,15 @@ mail_autoreceive_setup (void)
info->keep = source->keep_on_server;
if (info->period != source->auto_check_time*60) {
info->period = source->auto_check_time*60;
- gtk_timeout_remove(info->timeout_id);
- info->timeout_id = gtk_timeout_add(info->period*1000, auto_timeout, info);
+ g_source_remove(info->timeout_id);
+ info->timeout_id = g_timeout_add(info->period*1000, auto_timeout, info);
}
} else {
info = g_malloc0(sizeof(*info));
info->uri = g_strdup(source->url);
info->keep = source->keep_on_server;
info->period = source->auto_check_time*60;
- info->timeout_id = gtk_timeout_add(info->period*1000, auto_timeout, info);
+ info->timeout_id = g_timeout_add(info->period*1000, auto_timeout, info);
g_hash_table_insert(auto_active, info->uri, info);
/* If we do this at startup, it can cause the logon dialogue to be hidden,
so lets not */
diff --git a/mail/mail-session.c b/mail/mail-session.c
index 65b537246b..1c41007c53 100644
--- a/mail/mail-session.c
+++ b/mail/mail-session.c
@@ -40,6 +40,7 @@
#include "filter/filter-context.h"
#include "filter/filter-filter.h"
#include "mail.h"
+#include "mail-component.h"
#include "mail-config.h"
#include "mail-session.h"
#include "mail-tools.h"
@@ -593,7 +594,7 @@ main_get_filter_driver (CamelSession *session, const char *type, CamelException
gconf = mail_config_get_gconf_client ();
- user = g_strdup_printf ("%s/filters.xml", evolution_dir);
+ user = g_strdup_printf ("%s/filters.xml", mail_component_peek_base_directory (mail_component_peek ()));
system = EVOLUTION_PRIVDATADIR "/filtertypes.xml";
fc = (RuleContext *) filter_context_new ();
rule_context_load (fc, system, user);
@@ -743,16 +744,16 @@ mail_session_forget_password (const char *key)
}
void
-mail_session_init (void)
+mail_session_init (const char *base_directory)
{
char *camel_dir;
-
- if (camel_init (evolution_dir, TRUE) != 0)
+
+ if (camel_init (base_directory, TRUE) != 0)
exit (0);
session = CAMEL_SESSION (camel_object_new (MAIL_SESSION_TYPE));
- camel_dir = g_strdup_printf ("%s/mail", evolution_dir);
+ camel_dir = g_strdup_printf ("%s/mail", base_directory);
camel_session_construct (session, camel_dir);
/* The shell will tell us to go online. */
diff --git a/mail/mail-session.h b/mail/mail-session.h
index 72a2757fc4..2a7559964c 100644
--- a/mail/mail-session.h
+++ b/mail/mail-session.h
@@ -32,7 +32,7 @@ extern "C" {
#pragma }
#endif /* __cplusplus */
-void mail_session_init (void);
+void mail_session_init (const char *base_directory);
gboolean mail_session_get_interactive (void);
void mail_session_set_interactive (gboolean interactive);
char *mail_session_request_dialog (const char *prompt, gboolean secret,
diff --git a/mail/mail-signature-editor.c b/mail/mail-signature-editor.c
index 0c1907b3bb..570a0157c4 100644
--- a/mail/mail-signature-editor.c
+++ b/mail/mail-signature-editor.c
@@ -395,11 +395,11 @@ mail_signature_editor (MailConfigSignature *sig, GtkWindow *parent, gboolean is_
EVOLUTION_UIDIR "/evolution-signature-editor.xml",
"evolution-signature-editor", NULL);
- editor->control = bonobo_widget_new_control ("OAFIID:GNOME_GtkHTML_Editor:3.0",
+ editor->control = bonobo_widget_new_control ("OAFIID:GNOME_GtkHTML_Editor:3.1",
bonobo_ui_component_get_container (component));
if (editor->control == NULL) {
- g_warning ("Cannot get 'OAFIID:GNOME_GtkHTML_Editor:3.0'.");
+ g_warning ("Cannot get 'OAFIID:GNOME_GtkHTML_Editor:3.1'.");
destroy_editor (editor);
return;
diff --git a/mail/mail-summary.c b/mail/mail-summary.c
index 978347bb43..903c03ea4e 100644
--- a/mail/mail-summary.c
+++ b/mail/mail-summary.c
@@ -72,7 +72,6 @@ typedef struct {
static int queue_len = 0;
-extern char *evolution_dir;
extern EvolutionStorage *vfolder_storage;
#define MAIN_READER main_compipe[0]
@@ -295,7 +294,7 @@ generate_folder_summaries (MailSummary *summary)
CamelException *ex;
int i;
- user = g_strdup_printf ("%s/vfolders.xml", evolution_dir);
+ user = g_strdup_printf ("%s/vfolders.xml", mail_component_peek_base_directory (mail_component_peek ()));
system = EVOLUTION_PRIVDATADIR "/vfoldertypes.xml";
context = vfolder_context_new ();
diff --git a/mail/mail-tools.c b/mail/mail-tools.c
index 99fd749d78..e5fbeed05f 100644
--- a/mail/mail-tools.c
+++ b/mail/mail-tools.c
@@ -46,6 +46,7 @@
#include "e-util/e-meta.h"
#include "mail.h" /*session*/
+#include "mail-component.h"
#include "mail-config.h"
#include "mail-vfolder.h"
#include "mail-tools.h"
@@ -62,7 +63,8 @@ mail_tool_get_local_inbox (CamelException *ex)
CamelFolder *folder;
char *url;
- url = g_strdup_printf("file://%s/local/Inbox", evolution_dir);
+ url = g_strdup_printf("file://%s/local/Inbox",
+ mail_component_peek_base_directory (mail_component_peek ()));
folder = mail_tool_uri_to_folder (url, 0, ex);
g_free (url);
@@ -120,7 +122,9 @@ mail_tool_get_local_movemail_path (const unsigned char *uri)
if (strchr ("/:;=|%&#!*^()\\, ", *c) || !isprint ((int) *c))
*c = '_';
- path = g_strdup_printf ("%s/local/Inbox/movemail.%s", evolution_dir, safe_uri);
+ path = g_strdup_printf ("%s/local/Inbox/movemail.%s",
+ mail_component_peek_base_directory (mail_component_peek ()),
+ safe_uri);
g_free (safe_uri);
return path;
@@ -318,7 +322,7 @@ mail_tool_uri_to_folder (const char *uri, guint32 flags, CamelException *ex)
store = camel_session_get_store (session, uri + offset, ex);
if (store) {
const char *name;
-
+
/* if we have a fragment, then the path is actually used by the store,
so the fragment is the path to the folder instead */
if (url->fragment) {
@@ -412,6 +416,7 @@ mail_tools_folder_to_url (CamelFolder *folder)
static char *meta_data_key(const char *uri, char **pathp)
{
+ const char *base_directory = mail_component_peek_base_directory (mail_component_peek ());
CamelURL *url;
GString *path;
const char *key;
@@ -421,12 +426,12 @@ static char *meta_data_key(const char *uri, char **pathp)
if (url == NULL) {
g_warning("Trying to retrieve meta-data for unparsable uri: %s", uri);
- *pathp = g_build_path(evolution_dir, "meta/unknown", NULL);
+ *pathp = g_build_path(base_directory, "meta/unknown", NULL);
return g_strdup("folder");
}
- path = g_string_new(evolution_dir);
+ path = g_string_new(base_directory);
g_string_append_printf(path, "/meta/%s/", url->protocol);
if (url->host && url->host[0]) {
diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c
index 001a0ae57e..b27aea30f7 100644
--- a/mail/mail-vfolder.c
+++ b/mail/mail-vfolder.c
@@ -32,6 +32,8 @@
#include "evolution-storage.h"
#include "evolution-shell-component.h"
+#include "folder-browser.h"
+#include "mail-component.h"
#include "mail-vfolder.h"
#include "mail-tools.h"
#include "mail-autofilter.h"
@@ -64,7 +66,6 @@ static GHashTable *vfolder_hash;
extern EvolutionShellClient *global_shell_client;
/* more globals ... */
-extern char *evolution_dir;
extern CamelSession *session;
static void rule_changed(FilterRule *rule, CamelFolder *folder);
@@ -471,7 +472,8 @@ mail_vfolder_delete_uri(CamelStore *store, const char *uri)
g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
gtk_widget_show (dialog);
- user = g_strdup_printf ("%s/vfolders.xml", evolution_dir);
+ user = g_strdup_printf ("%s/vfolders.xml",
+ mail_component_peek_base_directory (mail_component_peek ()));
rule_context_save ((RuleContext *) context, user);
g_free (user);
}
@@ -526,7 +528,7 @@ mail_vfolder_rename_uri(CamelStore *store, const char *from, const char *to)
char *user;
d(printf("Vfolders updated from renamed folder\n"));
- user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
+ user = g_strdup_printf("%s/vfolders.xml", mail_component_peek_base_directory (mail_component_peek ()));
rule_context_save((RuleContext *)context, user);
g_free(user);
}
@@ -646,7 +648,10 @@ static void context_rule_removed(RuleContext *ctx, FilterRule *rule)
/* TODO: remove from folder info cache? */
path = g_strdup_printf("/%s", rule->name);
- evolution_storage_removed_folder(mail_lookup_storage(vfolder_store), path);
+
+ /* EPFIXME This leaks, the original code was broken too. */
+ e_storage_removed_folder (mail_component_lookup_storage (mail_component_peek (), vfolder_store), path);
+
g_free(path);
LOCK();
@@ -697,7 +702,7 @@ store_folder_deleted(CamelObject *o, void *event_data, void *data)
g_object_unref(rule);
g_signal_connect(context, "rule_removed", G_CALLBACK(context_rule_removed), context);
- user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
+ user = g_strdup_printf("%s/vfolders.xml", mail_component_peek_base_directory (mail_component_peek ()));
rule_context_save((RuleContext *)context, user);
g_free(user);
} else {
@@ -738,7 +743,7 @@ store_folder_renamed(CamelObject *o, void *event_data, void *data)
filter_rule_set_name(rule, info->new->full_name);
g_signal_connect(rule, "changed", G_CALLBACK(rule_changed), folder);
- user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
+ user = g_strdup_printf("%s/vfolders.xml", mail_component_peek_base_directory (mail_component_peek ()));
rule_context_save((RuleContext *)context, user);
g_free(user);
@@ -750,7 +755,7 @@ store_folder_renamed(CamelObject *o, void *event_data, void *data)
}
void
-vfolder_load_storage(GNOME_Evolution_Shell shell)
+vfolder_load_storage(void)
{
char *user, *storeuri;
FilterRule *rule;
@@ -758,7 +763,7 @@ vfolder_load_storage(GNOME_Evolution_Shell shell)
vfolder_hash = g_hash_table_new(g_str_hash, g_str_equal);
/* first, create the vfolder store, and set it up */
- storeuri = g_strdup_printf("vfolder:%s/vfolder", evolution_dir);
+ storeuri = g_strdup_printf("vfolder:%s/vfolder", mail_component_peek_base_directory (mail_component_peek ()));
vfolder_store = camel_session_get_store(session, storeuri, NULL);
if (vfolder_store == NULL) {
g_warning("Cannot open vfolder store - no vfolders available");
@@ -773,10 +778,10 @@ vfolder_load_storage(GNOME_Evolution_Shell shell)
(CamelObjectEventHookFunc)store_folder_renamed, NULL);
d(printf("got store '%s' = %p\n", storeuri, vfolder_store));
- mail_load_storage_by_uri(shell, storeuri, _("VFolders"));
+ mail_component_load_storage_by_uri(mail_component_peek (), storeuri, _("VFolders"));
/* load our rules */
- user = g_strdup_printf ("%s/vfolders.xml", evolution_dir);
+ user = g_strdup_printf ("%s/vfolders.xml", mail_component_peek_base_directory (mail_component_peek ()));
context = vfolder_context_new ();
if (rule_context_load ((RuleContext *)context,
EVOLUTION_PRIVDATADIR "/vfoldertypes.xml", user) != 0) {
@@ -806,8 +811,7 @@ vfolder_editor_response (GtkWidget *dialog, int button, void *data)
{
char *user;
- user = alloca(strlen(evolution_dir)+16);
- sprintf(user, "%s/vfolders.xml", evolution_dir);
+ user = g_strdup_printf ("%s/vfolders.xml", mail_component_peek_base_directory (mail_component_peek ()));
switch(button) {
case GTK_RESPONSE_ACCEPT:
@@ -820,6 +824,8 @@ vfolder_editor_response (GtkWidget *dialog, int button, void *data)
vfolder_editor = NULL;
gtk_widget_destroy(dialog);
+
+ g_free (user);
}
void
@@ -846,7 +852,7 @@ edit_rule_response(GtkWidget *w, int button, void *data)
FilterRule *orig = g_object_get_data (G_OBJECT (w), "orig");
filter_rule_copy(orig, rule);
- user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
+ user = g_strdup_printf("%s/vfolders.xml", mail_component_peek_base_directory (mail_component_peek ()));
rule_context_save((RuleContext *)context, user);
g_free(user);
}
@@ -877,7 +883,7 @@ vfolder_edit_rule(const char *uri)
GTK_STOCK_OK,
GTK_RESPONSE_OK,
NULL);
- gtk_container_set_border_width ((GtkContainer *) gd, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (gd), 6);
gtk_box_set_spacing ((GtkBox *) gd->vbox, 6);
gtk_dialog_set_default_response(gd, GTK_RESPONSE_OK);
g_object_set(gd, "allow_shrink", FALSE, "allow_grow", TRUE, NULL);
@@ -925,7 +931,7 @@ new_rule_clicked(GtkWidget *w, int button, void *data)
g_object_ref(rule);
rule_context_add_rule((RuleContext *)context, rule);
- user = g_strdup_printf("%s/vfolders.xml", evolution_dir);
+ user = g_strdup_printf("%s/vfolders.xml", mail_component_peek_base_directory (mail_component_peek ()));
rule_context_save((RuleContext *)context, user);
g_free(user);
}
@@ -971,7 +977,7 @@ vfolder_gui_add_rule(VfolderRule *rule)
GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response(gd, GTK_RESPONSE_OK);
- gtk_container_set_border_width ((GtkContainer *) gd, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (gd), 6);
gtk_box_set_spacing ((GtkBox *) gd->vbox, 6);
g_object_set(gd, "allow_shrink", FALSE, "allow_grow", TRUE, NULL);
gtk_window_set_default_size (GTK_WINDOW (gd), 500, 500);
diff --git a/mail/mail-vfolder.h b/mail/mail-vfolder.h
index 955b358c30..50c0dc5d93 100644
--- a/mail/mail-vfolder.h
+++ b/mail/mail-vfolder.h
@@ -11,7 +11,7 @@
#include "filter/vfolder-rule.h"
#include "filter/filter-part.h"
-void vfolder_load_storage(GNOME_Evolution_Shell shell);
+void vfolder_load_storage(void);
void vfolder_edit (void);
void vfolder_edit_rule(const char *name);
diff --git a/mail/mail.h b/mail/mail.h
index 81832cd2a5..86ca868f5f 100644
--- a/mail/mail.h
+++ b/mail/mail.h
@@ -31,23 +31,7 @@
#include "mail-session.h"
#include "mail-types.h"
-extern char *evolution_dir;
-
/* mail-identify */
char *mail_identify_mime_part (CamelMimePart *part, MailDisplay *md);
-
-/* component factory for lack of a better place */
-void mail_add_storage (CamelStore *store, const char *name, const char *uri);
-void mail_load_storage_by_uri (GNOME_Evolution_Shell shell, const char *uri, const char *name);
-/*takes a GSList of MailConfigServices */
-void mail_load_storages (GNOME_Evolution_Shell shell, EAccountList *sources);
-
-void mail_hash_storage (CamelService *store, EvolutionStorage *storage);
-EvolutionStorage *mail_lookup_storage (CamelStore *store);
-void mail_remove_storage_by_uri (const char *uri);
-void mail_remove_storage (CamelStore *store);
-void mail_storages_foreach (GHFunc func, gpointer data);
-int mail_storages_count (void);
-
gboolean evolution_folder_info_factory_init (void);
diff --git a/mail/main.c b/mail/main.c
deleted file mode 100644
index b5192a9f5c..0000000000
--- a/mail/main.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * main.c: The core of the mail component
- *
- * Author:
- * Miguel de Icaza (miguel@ximian.com)
- *
- * (C) 2000 Ximian, Inc.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <signal.h>
-
-#include <libgnome/gnome-sound.h>
-#include <bonobo/bonobo-main.h>
-#include <bonobo-activation/bonobo-activation-init.h>
-#include <glade/glade.h>
-#include <libgnomevfs/gnome-vfs.h>
-
-#include <gconf/gconf.h>
-
-#include <gal/widgets/e-gui-utils.h>
-#include <gal/widgets/e-cursors.h>
-
-#include "e-util/e-passwords.h"
-#include "e-util/e-proxy.h"
-
-#include "component-factory.h"
-#include "composer/evolution-composer.h"
-#include "mail.h"
-#include "mail-mt.h"
-
-/*#define DO_MCHECK*/
-
-#ifdef DO_MCHECK
-static int blowup(int status)
-{
- switch(status) {
- case 1:
- printf("Double free failure\n");
- break;
- case 2:
- printf("Memory clobbered before block\n");
- break;
- case 3:
- printf("Memory clobbered after block\n");
- break;
- }
- abort();
- return status;
-}
-#endif
-
-/* The GNOME SEGV handler will lose if it's not run from the main Gtk
- * thread. So if we crash in another thread, redirect the signal.
- */
-static void (*gnome_segv_handler) (int);
-
-static GStaticMutex segv_mutex = G_STATIC_MUTEX_INIT;
-
-static void
-segv_redirect (int sig)
-{
- if (pthread_self () == mail_gui_thread)
- gnome_segv_handler (sig);
- else {
- pthread_kill (mail_gui_thread, sig);
- /* We can't return from the signal handler or the
- * thread may SEGV again. But we can't pthread_exit,
- * because then the thread may get cleaned up before
- * bug-buddy can get a stack trace. So we block by
- * trying to lock a mutex we know is already locked.
- */
- g_static_mutex_lock (&segv_mutex);
- }
-}
-
-int
-main (int argc, char *argv [])
-{
- CORBA_ORB orb;
- struct sigaction sa, osa;
-
- /* used to make elfence work */
- free(malloc (10));
-#ifdef DO_MCHECK
- /*mtrace();*/
- mcheck(blowup);
-#endif
- bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR);
- textdomain (GETTEXT_PACKAGE);
-
- g_thread_init (NULL);
-
- gnome_init_with_popt_table ("evolution-mail-component", VERSION,
- argc, argv, bonobo_activation_popt_options, 0, NULL);
-
- sigaction (SIGSEGV, NULL, &osa);
- if (osa.sa_handler != SIG_DFL) {
- sa.sa_flags = 0;
- sigemptyset (&sa.sa_mask);
- sa.sa_handler = segv_redirect;
- sigaction (SIGSEGV, &sa, NULL);
- sigaction (SIGBUS, &sa, NULL);
- sigaction (SIGFPE, &sa, NULL);
-
- sa.sa_handler = SIG_IGN;
- sigaction (SIGXFSZ, &sa, NULL);
- gnome_segv_handler = osa.sa_handler;
- g_static_mutex_lock (&segv_mutex);
- }
-
- if (!bonobo_init (&argc, argv)) {
- g_error ("Mail component could not initialize Bonobo.\n"
- "If there was a warning message about the "
- "RootPOA, it probably means\nyou compiled "
- "Bonobo against GOAD instead of Bonobo Activation.");
- }
-
- gconf_init (argc, argv, NULL);
-
- glade_init ();
-
- gnome_vfs_init ();
-
- e_cursors_init ();
-
- e_proxy_init ();
-
- mail_config_init ();
- mail_msg_init ();
-
- gnome_sound_init ("localhost");
-
- component_factory_init ();
- evolution_composer_factory_init (composer_send_cb, composer_save_draft_cb);
-
- if (gdk_threads_mutex) {
- g_mutex_free (gdk_threads_mutex);
- gdk_threads_mutex = NULL;
- }
-
- g_print ("Evolution Mail ready and running.\n");
-
- GDK_THREADS_ENTER ();
- bonobo_main ();
-
- mail_msg_cleanup();
-
- GDK_THREADS_LEAVE ();
-
- mail_config_write_on_exit ();
-
- e_passwords_shutdown ();
-
- gnome_sound_shutdown ();
-
- return 0;
-}
diff --git a/mail/message-browser.c b/mail/message-browser.c
new file mode 100644
index 0000000000..e8e6ee0ef2
--- /dev/null
+++ b/mail/message-browser.c
@@ -0,0 +1,402 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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>
+#endif
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include <gal/util/e-util.h>
+
+#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-ui-component.h>
+#include <bonobo/bonobo-ui-container.h>
+#include <bonobo/bonobo-ui-util.h>
+
+#include "message-browser.h"
+
+#include "mail.h"
+#include "mail-callbacks.h"
+#include "mail-tools.h"
+#include "message-list.h"
+#include "mail-ops.h"
+#include "mail-vfolder.h"
+#include "mail-autofilter.h"
+#include "mail-mt.h"
+
+#include "mail-local.h"
+#include "mail-config.h"
+
+#include "folder-browser-ui.h"
+
+#define d(x)
+
+#define MINIMUM_WIDTH 600
+#define MINIMUM_HEIGHT 400
+
+#define PARENT_TYPE BONOBO_TYPE_WINDOW
+
+/* Size of the window last time it was changed. */
+static GtkAllocation last_allocation = { 0, 0 };
+
+static BonoboWindowClass *message_browser_parent_class;
+
+static void
+message_browser_destroy (GtkObject *object)
+{
+ MessageBrowser *message_browser;
+
+ message_browser = MESSAGE_BROWSER (object);
+
+ if (message_browser->ml_built_id) {
+ g_signal_handler_disconnect (message_browser->fb->message_list, message_browser->ml_built_id);
+ message_browser->ml_built_id = 0;
+ }
+
+ if (message_browser->loaded_id) {
+ g_signal_handler_disconnect (message_browser->fb, message_browser->loaded_id);
+ message_browser->loaded_id = 0;
+ }
+
+ if (message_browser->fb) {
+ g_object_unref (message_browser->fb);
+ message_browser->fb = NULL;
+ }
+
+ if (GTK_OBJECT_CLASS (message_browser_parent_class)->destroy)
+ (GTK_OBJECT_CLASS (message_browser_parent_class)->destroy) (object);
+}
+
+static void
+message_browser_class_init (GObjectClass *object_class)
+{
+ ((GtkObjectClass *)object_class)->destroy = message_browser_destroy;
+
+ message_browser_parent_class = g_type_class_ref (PARENT_TYPE);
+}
+
+static void
+message_browser_init (GtkObject *object)
+{
+
+}
+
+static void
+transfer_msg_done (gboolean ok, void *data)
+{
+ MessageBrowser *mb = data;
+
+ gtk_widget_destroy ((GtkWidget *) mb);
+
+ g_object_unref (mb);
+}
+
+static void
+transfer_msg (MessageBrowser *mb, int del)
+{
+ const char *allowed_types[] = { "mail/*", "vtrash", NULL };
+ extern EvolutionShellClient *global_shell_client;
+ GNOME_Evolution_Folder *folder;
+ static char *last_uri = NULL;
+ GPtrArray *uids;
+ char *desc;
+
+/* if (GTK_OBJECT_DESTROYED(mb))
+ return;*/
+
+ if (last_uri == NULL)
+ last_uri = g_strdup ("");
+
+ if (del)
+ desc = _("Move message(s) to");
+ else
+ desc = _("Copy message(s) to");
+
+ evolution_shell_client_user_select_folder (global_shell_client,
+ GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (mb))),
+ desc, last_uri, allowed_types, &folder);
+ if (!folder)
+ return;
+
+ if (strcmp (last_uri, folder->evolutionUri) != 0) {
+ g_free (last_uri);
+ last_uri = g_strdup (folder->evolutionUri);
+ }
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (mb->fb->message_list, enumerate_msg, uids);
+
+ if (del) {
+ g_object_ref (mb);
+ mail_transfer_messages (mb->fb->folder, uids, del,
+ folder->physicalUri, 0, transfer_msg_done, mb);
+ } else {
+ mail_transfer_messages (mb->fb->folder, uids, del,
+ folder->physicalUri, 0, NULL, NULL);
+ }
+
+ CORBA_free (folder);
+}
+
+
+/* UI callbacks */
+
+static void
+message_browser_close (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ gtk_widget_destroy (GTK_WIDGET (user_data));
+}
+
+static void
+message_browser_move (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ transfer_msg (user_data, TRUE);
+}
+
+static void
+message_browser_copy (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ transfer_msg (user_data, FALSE);
+}
+
+static void
+message_browser_delete (BonoboUIComponent *uih, void *user_data, const char *path)
+{
+ MessageBrowser *mb = user_data;
+ GPtrArray *uids;
+ int i;
+
+ uids = g_ptr_array_new ();
+ message_list_foreach (mb->fb->message_list, enumerate_msg, uids);
+ camel_folder_freeze (mb->fb->folder);
+ for (i = 0; i < uids->len; i++) {
+ camel_folder_set_message_flags (mb->fb->folder, uids->pdata[i],
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN,
+ CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN);
+ g_free (uids->pdata[i]);
+ }
+
+ camel_folder_thaw (mb->fb->folder);
+
+ g_ptr_array_free (uids, TRUE);
+
+ gtk_widget_destroy ((GtkWidget *) mb);
+}
+
+static BonoboUIVerb
+browser_verbs [] = {
+ BONOBO_UI_UNSAFE_VERB ("MessageBrowserClose", message_browser_close),
+ BONOBO_UI_UNSAFE_VERB ("MessageMove", message_browser_move),
+ BONOBO_UI_UNSAFE_VERB ("MessageCopy", message_browser_copy),
+ BONOBO_UI_UNSAFE_VERB ("MessageDelete", message_browser_delete),
+ BONOBO_UI_VERB_END
+};
+
+/* FB message loading hookups */
+
+static void
+message_browser_message_loaded (FolderBrowser *fb, const char *uid, MessageBrowser *mb)
+{
+ CamelMimeMessage *message;
+ char *subject = NULL;
+ char *title;
+
+ folder_browser_ui_message_loaded(fb);
+
+ message = fb->mail_display->current_message;
+
+ if (message)
+ subject = (char *) camel_mime_message_get_subject (message);
+
+ if (subject == NULL)
+ subject = _("(No subject)");
+
+ title = g_strdup_printf (_("%s - Message"), subject);
+
+ gtk_window_set_title (GTK_WINDOW (mb), title);
+
+ g_free (title);
+}
+
+static void
+message_browser_message_list_built (MessageList *ml, MessageBrowser *mb)
+{
+ const char *uid = g_object_get_data (G_OBJECT (mb), "uid");
+
+ g_signal_handler_disconnect (ml, mb->ml_built_id);
+ mb->ml_built_id = 0;
+
+ message_list_select_uid (ml, uid);
+}
+
+static void
+message_browser_folder_loaded (FolderBrowser *fb, const char *uri, MessageBrowser *mb)
+{
+ g_signal_handler_disconnect (fb, mb->loaded_id);
+ mb->loaded_id = 0;
+
+ mb->ml_built_id = g_signal_connect (fb->message_list, "message_list_built",
+ G_CALLBACK (message_browser_message_list_built), mb);
+}
+
+static void
+message_browser_size_allocate_cb (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ last_allocation = *allocation;
+}
+
+/* Construction */
+
+static void
+set_default_size (GtkWidget *widget)
+{
+ int width, height;
+
+ width = MAX (MINIMUM_WIDTH, last_allocation.width);
+ height = MAX (MINIMUM_HEIGHT, last_allocation.height);
+
+ gtk_window_set_default_size (GTK_WINDOW (widget), width, height);
+}
+
+static void
+set_bonobo_ui (GtkWidget *widget, FolderBrowser *fb)
+{
+ BonoboUIContainer *uicont;
+ BonoboUIComponent *uic;
+ CORBA_Environment ev;
+
+ uicont = bonobo_window_get_ui_container (BONOBO_WINDOW (widget));
+
+ uic = bonobo_ui_component_new_default ();
+ bonobo_ui_component_set_container (uic, BONOBO_OBJREF (uicont), NULL);
+ folder_browser_set_ui_component (fb, uic);
+
+ /* Load our UI */
+
+ /*bonobo_ui_component_freeze (uic, NULL);*/
+ bonobo_ui_util_set_ui (uic, PREFIX,
+ EVOLUTION_UIDIR "/evolution-mail-messagedisplay.xml",
+ "evolution-mail", NULL);
+
+ /* Load the appropriate UI stuff from the folder browser */
+
+ folder_browser_ui_add_message (fb);
+
+ /* We just opened the message! We don't need to open it again. */
+
+ CORBA_exception_init (&ev);
+ /* remove the broken menus and toolbar items */
+ bonobo_ui_component_rm (uic, "/menu/File/FileOps/MessageOpen", &ev);
+ bonobo_ui_component_rm (uic, "/menu/Actions/ComponentActionsPlaceholder/MailMessageActions/GoTo", &ev);
+ bonobo_ui_component_rm (uic, "/menu/Tools", &ev);
+ bonobo_ui_component_rm (uic, "/Toolbar/MailNextButtons", &ev);
+ CORBA_exception_free (&ev);
+
+ /* Hack around the move/copy/delete commands api's */
+ bonobo_ui_component_remove_listener (uic, "MessageCopy");
+ bonobo_ui_component_remove_listener (uic, "MessageMove");
+ bonobo_ui_component_remove_listener (uic, "MessageDelete");
+
+ /* Add the Close & Move/Copy/Delete items */
+
+ bonobo_ui_component_add_verb_list_with_data (uic, browser_verbs, widget);
+
+ /* Done */
+
+ /*bonobo_ui_component_thaw (uic, NULL);*/
+}
+
+static int
+on_key_press (GtkWidget *widget, GdkEventKey *key, gpointer data)
+{
+ MessageBrowser *mb = data;
+
+ if (key->state & GDK_CONTROL_MASK)
+ return FALSE;
+
+ switch (key->keyval) {
+ case GDK_Delete:
+ case GDK_KP_Delete:
+ message_browser_delete (NULL, mb, NULL);
+ return TRUE;
+ case GDK_Escape:
+ message_browser_close (NULL, mb, NULL);
+ return TRUE;
+ default:
+ }
+
+ return FALSE;
+}
+
+GtkWidget *
+message_browser_new (const char *uri, const char *uid)
+{
+ GtkWidget *vbox;
+ MessageBrowser *new;
+ FolderBrowser *fb;
+
+ new = g_object_new (MESSAGE_BROWSER_TYPE, "title", "Ximian Evolution", NULL);
+
+ g_object_set_data_full (G_OBJECT (new), "uid", g_strdup (uid), g_free);
+
+ fb = FOLDER_BROWSER (folder_browser_new (uri));
+ g_object_ref (fb);
+ gtk_object_sink ((GtkObject *) fb);
+
+ new->fb = fb;
+
+ set_bonobo_ui (GTK_WIDGET (new), fb);
+
+ /* some evil hackery action... */
+ vbox = gtk_vbox_new (TRUE, 0);
+ gtk_widget_ref (GTK_WIDGET (fb->mail_display));
+ gtk_widget_reparent (GTK_WIDGET (fb->mail_display), vbox);
+ /* Note: normally we'd unref the fb->mail_display now, except
+ that if we do then our refcounts will not be in
+ harmony... both the fb *and* the message-browser need to
+ own a ref on the mail_display. */
+ gtk_widget_show (GTK_WIDGET (fb->mail_display));
+ gtk_widget_show (vbox);
+
+ g_signal_connect (new, "size-allocate", G_CALLBACK (message_browser_size_allocate_cb), NULL);
+
+ bonobo_window_set_contents (BONOBO_WINDOW (new), vbox);
+ gtk_widget_grab_focus (GTK_WIDGET (MAIL_DISPLAY (fb->mail_display)->html));
+
+ set_default_size (GTK_WIDGET (new));
+
+ /* more evil hackery... */
+ new->loaded_id = g_signal_connect (fb, "folder_loaded", G_CALLBACK (message_browser_folder_loaded), new);
+ g_signal_connect (fb, "message_loaded", G_CALLBACK (message_browser_message_loaded), new);
+
+ g_signal_connect (new, "key_press_event", G_CALLBACK (on_key_press), new);
+
+ return GTK_WIDGET (new);
+}
+
+/* Fin */
+
+E_MAKE_TYPE (message_browser, "MessageBrowser", MessageBrowser, message_browser_class_init,
+ message_browser_init, PARENT_TYPE);
diff --git a/mail/message-browser.h b/mail/message-browser.h
new file mode 100644
index 0000000000..a02b13ef06
--- /dev/null
+++ b/mail/message-browser.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 _MESSAGE_BROWSER_H_
+#define _MESSAGE_BROWSER_H_
+
+#include <gnome.h>
+#include <bonobo/bonobo-window.h>
+
+#include <camel/camel-folder.h>
+#include "folder-browser.h"
+#include "mail-display.h"
+#include "mail-types.h"
+
+#define MESSAGE_BROWSER_TYPE (message_browser_get_type ())
+#define MESSAGE_BROWSER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MESSAGE_BROWSER_TYPE, MessageBrowser))
+#define MESSAGE_BROWSER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), MESSAGE_BROWSER_TYPE, MessageBrowserClass))
+#define IS_MESSAGE_BROWSER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MESSAGE_BROWSER_TYPE))
+#define IS_MESSAGE_BROWSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MESSAGE_BROWSER_TYPE))
+
+struct _MessageBrowser {
+ BonoboWindow parent;
+
+ /*
+ * The current URI being displayed by the MessageBrowser
+ */
+ FolderBrowser *fb;
+ gulong ml_built_id;
+ gulong loaded_id;
+};
+
+
+typedef struct {
+ BonoboWindowClass parent_class;
+
+} MessageBrowserClass;
+
+GtkType message_browser_get_type (void);
+
+GtkWidget *message_browser_new (const char *uri,
+ const char *uid);
+
+#endif /* _MESSAGE_BROWSER_H_ */
+
diff --git a/mail/subscribe-dialog.c b/mail/subscribe-dialog.c
new file mode 100644
index 0000000000..a1c18ff870
--- /dev/null
+++ b/mail/subscribe-dialog.c
@@ -0,0 +1,1669 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* subscribe-dialog.c: Subscribe dialog */
+/*
+ * Authors: Chris Toshok <toshok@ximian.com>
+ * Peter Williams <peterw@ximian.com>
+ *
+ * Copyright 2000 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+/* This doens't do what it's supposed to do ...
+ I think etree changed so it just fills out the whole tree always anyway */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gal/util/e-util.h>
+
+#include <gal/e-table/e-cell-toggle.h>
+#include <gal/e-table/e-cell-text.h>
+#include <gal/e-table/e-cell-tree.h>
+
+#include <gal/e-table/e-tree-scrolled.h>
+#include <gal/e-table/e-tree-memory-callbacks.h>
+#include <gal/e-table/e-tree.h>
+
+#include <pthread.h>
+
+#include "evolution-shell-component-utils.h"
+#include "mail.h"
+#include "mail-component.h"
+#include "mail-tools.h"
+#include "mail-ops.h"
+#include "mail-mt.h"
+#include "mail-folder-cache.h"
+#include "camel/camel-exception.h"
+#include "camel/camel-store.h"
+#include "camel/camel-session.h"
+#include "subscribe-dialog.h"
+
+#include "art/empty.xpm"
+#include "art/mark.xpm"
+
+#define d(x)
+
+/* Things to test.
+ * - Feature
+ * + How to check that it works.
+ *
+ * - Proper stores displayed
+ * + Skip stores that don't support subscriptions
+ * + Skip disabled stores
+ * - Changing subscription status
+ * + Select single folder, double-click row -> toggled
+ * + Select multiple folders, press subscribe -> all selected folders end up subscribed
+ * - (un)Subscribing from/to already (un)subscribed folder
+ * + Check that no IMAP command is sent
+ * - Switching views between stores
+ * + Proper tree shown
+ * - No crashes when buttons are pressed with "No store" screen
+ * + obvious
+ * - Restoring filter settings when view switched
+ * + Enter search, change view, change back -> filter checked and search entry set
+ * + Clear search, change view, change back -> "all" checked
+ * - Cancelling in middle of get_store
+ * + Enter invalid hostname, open dialog, click Close
+ * - Cancelling in middle if listing
+ * + Open large directory, click Close
+ * - Cancelling in middle of subscription op
+ * + How to test?
+ * - Test with both IMAP and NNTP
+ * + obvious
+ * - Verify that refresh view works
+ * + obvious
+ * - No unnecessary tree rebuilds
+ * + Show All folders, change filter with empty search -> no tree rebuild
+ * + Converse
+ * - No out of date tree
+ * + Show All Folders, change to filter with a search -> tree rebuild
+ * - Tree construction logic (mostly IMAP-specific terminology)
+ * + Tree is created progressively
+ * + No wasted LIST responses
+ * + No extraneous LIST commands
+ * + Specifying "folder names begin with" works
+ * + Always show folders below IMAP namespace (no escaping the namespace)
+ * + Don't allow subscription to NoSelect folders
+ * + IMAP accounts always show INBOX
+ * - Shell interactions
+ * + Folders are properly created / delete from folder tree when subscribed / unsubscribed
+ * + Folders with spaces in names / 8bit chars
+ * + Toplevel as well as subfolders
+ * + Mail Folder Cache doesn't complain
+ * - No ETable wackiness
+ * + Verify columns cannot be DnD'd
+ * + Alphabetical order always
+ * - UI cleanliness
+ * + Keybindings work
+ * + Some widget has focus by default
+ * + Escape / enter work
+ * + Close button works
+ */
+
+/* FIXME: we should disable/enable the subscribe/unsubscribe buttons as
+ * appropriate when only a single folder is selected. We need a
+ * mechanism to learn when the selected folder's subscription status
+ * changes, so when the user double-clicks it (eg) the buttons can
+ * (de)sensitize appropriately. See Ximian bug #7673.
+ */
+
+/*#define NEED_TOGGLE_SELECTION*/
+
+typedef struct _FolderETree FolderETree;
+typedef struct _FolderETreeClass FolderETreeClass;
+
+typedef void (*FolderETreeActivityCallback) (int level, gpointer user_data);
+
+struct _FolderETree {
+ ETreeMemory parent;
+ ETreePath root;
+
+ GHashTable *scan_ops;
+ GHashTable *subscribe_ops;
+
+ GHashTable *node_full_name;
+
+ CamelStore *store;
+ EStorage *e_storage;
+ char *service_name;
+
+ FolderETreeActivityCallback activity_cb;
+ gpointer activity_data;
+ int activity_level;
+};
+
+struct _FolderETreeClass {
+ ETreeMemoryClass parent;
+};
+
+static GtkObjectClass *folder_etree_parent_class = NULL;
+
+typedef struct _FolderETreeExtras FolderETreeExtras;
+typedef struct _FolderETreeExtrasClass FolderETreeExtrasClass;
+
+enum {
+ FOLDER_COL_SUBSCRIBED,
+ FOLDER_COL_NAME,
+ FOLDER_COL_LAST
+};
+
+struct _FolderETreeExtras {
+ ETableExtras parent;
+ GdkPixbuf *toggles[2];
+};
+
+struct _FolderETreeExtrasClass {
+ ETableExtrasClass parent;
+};
+
+static GtkObjectClass *ftree_extras_parent_class = NULL;
+
+/* util */
+
+static void
+recursive_add_folder (EStorage *storage, const char *path, const char *name, const char *url)
+{
+ EFolder *folder;
+ char *parent, *pname, *p;
+
+ p = strrchr (path, '/');
+ if (p && p != path) {
+ parent = g_strndup (path, p - path);
+ if (! e_storage_get_folder (storage, parent)) {
+ p = strrchr (parent, '/');
+ if (p)
+ pname = g_strdup (p + 1);
+ else
+ pname = g_strdup ("");
+ recursive_add_folder (storage, parent, pname, "");
+ g_free (pname);
+ }
+ g_free (parent);
+ }
+
+ folder = e_folder_new (name, "mail", NULL);
+ e_folder_set_physical_uri (folder, url);
+ e_folder_set_can_sync_offline (folder, TRUE);
+
+ e_storage_new_folder (storage, path, folder);
+}
+
+/* ** Get one level of folderinfo ****************************************** */
+
+typedef void (*SubscribeShortFolderinfoFunc) (CamelStore *store, char *prefix, CamelFolderInfo *info, gpointer data);
+
+int subscribe_get_short_folderinfo (FolderETree *ftree, const char *prefix,
+ SubscribeShortFolderinfoFunc func, gpointer user_data);
+
+struct _get_short_folderinfo_msg {
+ struct _mail_msg msg;
+
+ char *prefix;
+
+ FolderETree *ftree;
+ CamelFolderInfo *info;
+
+ SubscribeShortFolderinfoFunc func;
+ gpointer user_data;
+};
+
+static char *
+get_short_folderinfo_desc (struct _mail_msg *mm, int done)
+{
+ struct _get_short_folderinfo_msg *m = (struct _get_short_folderinfo_msg *) mm;
+ char *ret, *name;
+
+ name = camel_service_get_name (CAMEL_SERVICE (m->ftree->store), TRUE);
+
+ if (m->prefix)
+ ret = g_strdup_printf (_("Scanning folders under %s on \"%s\""), m->prefix, name);
+ else
+ ret = g_strdup_printf (_("Scanning root-level folders on \"%s\""), name);
+
+ g_free (name);
+ return ret;
+}
+
+static void
+get_short_folderinfo_get (struct _mail_msg *mm)
+{
+ struct _get_short_folderinfo_msg *m = (struct _get_short_folderinfo_msg *) mm;
+
+ m->info = camel_store_get_folder_info (m->ftree->store, m->prefix, CAMEL_STORE_FOLDER_INFO_FAST, &mm->ex);
+
+ d(printf("%d: getted folderinfo '%s'\n", mm->seq, m->prefix));
+}
+
+static void
+get_short_folderinfo_got (struct _mail_msg *mm)
+{
+ struct _get_short_folderinfo_msg *m = (struct _get_short_folderinfo_msg *) mm;
+
+ d(printf("%d: got folderinfo '%s'\n", mm->seq, m->prefix));
+
+ if (camel_exception_is_set (&mm->ex) && camel_exception_get_id(&mm->ex) != CAMEL_EXCEPTION_USER_CANCEL) {
+ g_warning ("Error getting folder info from store at %s: %s",
+ camel_service_get_url (CAMEL_SERVICE (m->ftree->store)),
+ camel_exception_get_description (&mm->ex));
+ }
+
+ if (m->func)
+ m->func (m->ftree->store, m->prefix, m->info, m->user_data);
+}
+
+static void
+get_short_folderinfo_free (struct _mail_msg *mm)
+{
+ struct _get_short_folderinfo_msg *m = (struct _get_short_folderinfo_msg *) mm;
+
+ camel_store_free_folder_info (m->ftree->store, m->info);
+ g_object_unref((m->ftree));
+
+ g_free (m->prefix); /* may be NULL but that's ok */
+}
+
+static struct _mail_msg_op get_short_folderinfo_op = {
+ get_short_folderinfo_desc,
+ get_short_folderinfo_get,
+ get_short_folderinfo_got,
+ get_short_folderinfo_free,
+};
+
+int
+subscribe_get_short_folderinfo (FolderETree *ftree,
+ const char *prefix,
+ SubscribeShortFolderinfoFunc func,
+ gpointer user_data)
+{
+ struct _get_short_folderinfo_msg *m;
+ int id;
+
+ m = mail_msg_new (&get_short_folderinfo_op, NULL, sizeof(*m));
+
+ m->ftree = ftree;
+ g_object_ref((ftree));
+ m->prefix = g_strdup (prefix);
+ m->func = func;
+ m->user_data = user_data;
+
+ d(printf("%d: get folderinfo '%s'\n", m->msg.seq, m->prefix));
+
+ id = m->msg.seq;
+ e_thread_put (mail_thread_queued, (EMsg *)m);
+ return id;
+}
+
+/* ** Subscribe folder operation **************************************** */
+
+typedef void (*SubscribeFolderCallback) (const char *, const char *, gboolean, gboolean, gpointer);
+
+struct _subscribe_msg {
+ struct _mail_msg msg;
+
+ CamelStore *store;
+ gboolean subscribe;
+ char *full_name;
+ char *name;
+
+ SubscribeFolderCallback cb;
+ gpointer cb_data;
+};
+
+static char *
+subscribe_folder_desc (struct _mail_msg *mm, int done)
+{
+ struct _subscribe_msg *m = (struct _subscribe_msg *) mm;
+
+ if (m->subscribe)
+ return g_strdup_printf (_("Subscribing to folder \"%s\""), m->name);
+ else
+ return g_strdup_printf (_("Unsubscribing to folder \"%s\""), m->name);
+}
+
+static void
+subscribe_folder_subscribe (struct _mail_msg *mm)
+{
+ struct _subscribe_msg *m = (struct _subscribe_msg *) mm;
+
+ if (m->subscribe)
+ camel_store_subscribe_folder (m->store, m->full_name, &mm->ex);
+ else
+ camel_store_unsubscribe_folder (m->store, m->full_name, &mm->ex);
+}
+
+static void
+subscribe_folder_subscribed (struct _mail_msg *mm)
+{
+ struct _subscribe_msg *m = (struct _subscribe_msg *) mm;
+
+ if (m->cb)
+ (m->cb) (m->full_name, m->name, m->subscribe,
+ !camel_exception_is_set (&mm->ex), m->cb_data);
+}
+
+static void
+subscribe_folder_free (struct _mail_msg *mm)
+{
+ struct _subscribe_msg *m = (struct _subscribe_msg *) mm;
+
+ g_free (m->name);
+ g_free (m->full_name);
+
+ camel_object_unref (m->store);
+}
+
+static struct _mail_msg_op subscribe_folder_op = {
+ subscribe_folder_desc,
+ subscribe_folder_subscribe,
+ subscribe_folder_subscribed,
+ subscribe_folder_free,
+};
+
+static int
+subscribe_do_subscribe_folder (CamelStore *store, const char *full_name, const char *name,
+ gboolean subscribe, SubscribeFolderCallback cb, gpointer cb_data)
+{
+ struct _subscribe_msg *m;
+ int id;
+
+ g_return_val_if_fail (CAMEL_IS_STORE (store), 0);
+ g_return_val_if_fail (full_name, 0);
+
+ m = mail_msg_new (&subscribe_folder_op, NULL, sizeof(*m));
+ m->store = store;
+ m->subscribe = subscribe;
+ m->name = g_strdup (name);
+ m->full_name = g_strdup (full_name);
+ m->cb = cb;
+ m->cb_data = cb_data;
+
+ camel_object_ref(store);
+
+ id = m->msg.seq;
+ e_thread_put (mail_thread_queued, (EMsg *)m);
+ return id;
+}
+
+/* ** FolderETree Extras *************************************************** */
+
+static void
+fete_finalise (GObject *object)
+{
+ FolderETreeExtras *extras = (FolderETreeExtras *) object;
+
+ g_object_unref (extras->toggles[0]);
+ g_object_unref (extras->toggles[1]);
+
+ ((GObjectClass *)ftree_extras_parent_class)->finalize (object);
+}
+
+static void
+fete_class_init (GObjectClass *object_class)
+{
+ object_class->finalize = fete_finalise;
+
+ ftree_extras_parent_class = g_type_class_ref (E_TABLE_EXTRAS_TYPE);
+}
+
+static void
+fete_init (GtkObject *object)
+{
+ FolderETreeExtras *extras = (FolderETreeExtras *) object;
+ ECell *cell;
+ ECell *text_cell;
+
+ /* text column */
+
+ cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
+ text_cell = cell;
+ g_object_set (G_OBJECT (cell),
+ "bold_column", FOLDER_COL_SUBSCRIBED,
+ NULL);
+ e_table_extras_add_cell (E_TABLE_EXTRAS (extras), "cell_text", cell);
+
+ /* toggle column */
+
+ extras->toggles[0] = gdk_pixbuf_new_from_xpm_data ((const char **)empty_xpm);
+ extras->toggles[1] = gdk_pixbuf_new_from_xpm_data ((const char **)mark_xpm);
+ cell = e_cell_toggle_new (0, 2, extras->toggles);
+ e_table_extras_add_cell (E_TABLE_EXTRAS (extras), "cell_toggle", cell);
+
+ /* tree cell */
+
+ cell = e_cell_tree_new (NULL, NULL, TRUE, text_cell);
+ e_table_extras_add_cell (E_TABLE_EXTRAS (extras), "cell_tree", cell);
+
+ /* misc */
+
+ e_table_extras_add_pixbuf (E_TABLE_EXTRAS (extras), "subscribed-image", extras->toggles[1]);
+}
+
+/* naughty! */
+static
+E_MAKE_TYPE (fete, "FolderETreeExtras", FolderETreeExtras, fete_class_init, fete_init, E_TABLE_EXTRAS_TYPE);
+
+/* ** Global Extras ******************************************************** */
+
+static FolderETreeExtras *global_extras = NULL;
+
+static void
+global_extras_destroyed (void *user_data, GObject *obj)
+{
+ global_extras = NULL;
+}
+
+static ETableExtras *
+subscribe_get_global_extras (void)
+{
+ if (global_extras == NULL) {
+ global_extras = g_object_new (fete_get_type(), NULL);
+ /*g_object_ref(global_extras);
+ gtk_object_sink((GtkObject *)global_extras);*/
+ g_object_weak_ref(G_OBJECT(global_extras), global_extras_destroyed, NULL);
+ } else {
+ g_object_ref(global_extras);
+ }
+
+ return E_TABLE_EXTRAS (global_extras);
+}
+
+/* ** Folder Tree Node ***************************************************** */
+
+typedef struct _ftree_node ftree_node;
+
+struct _ftree_node {
+ guint8 flags;
+ char *cache;
+ int uri_offset;
+ int full_name_offset;
+
+ /* format: {name}{\0}{uri}{\0}{full_name}{\0}
+ * (No braces). */
+ char data[1];
+};
+
+#define FTREE_NODE_GOT_CHILDREN (1 << 0)
+#define FTREE_NODE_SUBSCRIBABLE (1 << 1)
+#define FTREE_NODE_SUBSCRIBED (1 << 2)
+#define FTREE_NODE_ROOT (1 << 3)
+
+static ftree_node *
+ftree_node_new_root (void)
+{
+ ftree_node *node;
+
+ node = g_malloc (sizeof (ftree_node));
+ node->flags = FTREE_NODE_ROOT;
+ node->uri_offset = 0;
+ node->full_name_offset = 0;
+ node->data[0] = '\0';
+
+ return node;
+}
+
+static ftree_node *
+ftree_node_new (CamelStore *store, CamelFolderInfo *fi)
+{
+ ftree_node *node;
+ int uri_offset, full_name_offset;
+ size_t size;
+
+ uri_offset = strlen (fi->name) + 1;
+ full_name_offset = uri_offset + strlen (fi->url) + 1;
+ size = full_name_offset + strlen (fi->full_name);
+
+ /* - 1 for sizeof(node.data) but +1 for terminating \0 */
+ node = g_malloc (sizeof (*node) + size);
+
+ node->cache = NULL;
+
+ node->flags = FTREE_NODE_SUBSCRIBABLE;
+
+ /* subscribed? */
+
+ if (camel_store_folder_subscribed (store, fi->full_name))
+ node->flags |= FTREE_NODE_SUBSCRIBED;
+
+ /* Copy strings */
+
+ node->uri_offset = uri_offset;
+ node->full_name_offset = full_name_offset;
+
+ strcpy (node->data, fi->name);
+ strcpy (node->data + uri_offset, fi->url);
+ strcpy (node->data + full_name_offset, fi->full_name);
+
+ /* Done */
+
+ return node;
+}
+
+#define ftree_node_subscribable(node) ( ((ftree_node *) (node))->flags & FTREE_NODE_SUBSCRIBABLE )
+#define ftree_node_subscribed(node) ( ((ftree_node *) (node))->flags & FTREE_NODE_SUBSCRIBED )
+#define ftree_node_get_name(node) ( ((ftree_node *) (node))->data )
+#define ftree_node_get_full_name(node) ( ((ftree_node *) (node))->data + ((ftree_node *) (node))->full_name_offset )
+#define ftree_node_get_uri(node) ( ((ftree_node *) (node))->data + ((ftree_node *) (node))->uri_offset )
+
+/* ** Folder Tree Model **************************************************** */
+
+/* A subscribe or scan operation */
+
+typedef struct _ftree_op_data ftree_op_data;
+
+struct _ftree_op_data {
+ FolderETree *ftree;
+ ETreePath path;
+ ftree_node *data;
+ int handle;
+};
+
+
+/* ETreeModel functions */
+
+static int
+fe_column_count (ETreeModel *etm)
+{
+ return FOLDER_COL_LAST;
+}
+
+static void *
+fe_duplicate_value (ETreeModel *etm, int col, const void *val)
+{
+ return g_strdup (val);
+}
+
+static void
+fe_free_value (ETreeModel *etm, int col, void *val)
+{
+ g_free (val);
+}
+
+static void*
+fe_init_value (ETreeModel *etm, int col)
+{
+ return g_strdup ("");
+}
+
+static gboolean
+fe_value_is_empty (ETreeModel *etm, int col, const void *val)
+{
+ return !(val && *(char *)val);
+}
+
+static char *
+fe_value_to_string (ETreeModel *etm, int col, const void *val)
+{
+ return g_strdup (val);
+}
+
+static GdkPixbuf *
+fe_icon_at (ETreeModel *etree, ETreePath path)
+{
+ return NULL; /* XXX no icons for now */
+}
+
+static gpointer
+fe_root_value_at (FolderETree *ftree, int col)
+{
+ switch (col) {
+ case FOLDER_COL_NAME:
+ return ftree->service_name;
+ case FOLDER_COL_SUBSCRIBED:
+ return GINT_TO_POINTER (0);
+ default:
+ printf ("Oh no, unimplemented column %d in subscribe dialog\n", col);
+ }
+
+ return NULL;
+}
+
+static gpointer
+fe_real_value_at (FolderETree *ftree, int col, gpointer data)
+{
+ switch (col) {
+ case FOLDER_COL_NAME:
+ return ftree_node_get_name (data);
+ case FOLDER_COL_SUBSCRIBED:
+ if (ftree_node_subscribed (data))
+ return GINT_TO_POINTER (1);
+ return GINT_TO_POINTER (0);
+ default:
+ printf ("Oh no, unimplemented column %d in subscribe dialog\n", col);
+ }
+
+ return NULL;
+}
+
+static void *
+fe_value_at (ETreeModel *etree, ETreePath path, int col)
+{
+ FolderETree *ftree = (FolderETree *) etree;
+ gpointer node_data;
+
+ if (path == ftree->root)
+ return fe_root_value_at (ftree, col);
+
+ node_data = e_tree_memory_node_get_data (E_TREE_MEMORY (etree), path);
+ return fe_real_value_at (ftree, col, node_data);
+}
+
+static void
+fe_set_value_at (ETreeModel *etree, ETreePath path, int col, const void *val)
+{
+ /* nothing */
+}
+
+static gboolean
+fe_return_false (void)
+{
+ return FALSE;
+}
+
+static gint
+fe_sort_folder (ETreeMemory *etmm, ETreePath left, ETreePath right, gpointer user_data)
+{
+ ftree_node *n_left, *n_right;
+
+ n_left = e_tree_memory_node_get_data (etmm, left);
+ n_right = e_tree_memory_node_get_data (etmm, right);
+
+ /* if in utf8 locale ? */
+ return strcasecmp (ftree_node_get_name (n_left), ftree_node_get_name (n_right));
+}
+
+
+static void fe_check_for_children (FolderETree *ftree, ETreePath path);
+
+/* scanning */
+static void
+fe_got_children (CamelStore *store, char *prefix, CamelFolderInfo *info, gpointer data)
+{
+ ftree_op_data *closure = (ftree_op_data *) data;
+
+ if (!info) /* cancelled */
+ goto done;
+
+ /* also cancelled, but camel returned data, might leak */
+ if (closure->handle == -1)
+ goto done;
+
+ if (!prefix)
+ prefix = "";
+
+ for ( ; info; info = info->sibling) {
+ ETreePath child_path;
+ ftree_node *node;
+
+ if (g_hash_table_lookup(closure->ftree->node_full_name, info->full_name))
+ continue;
+
+ node = ftree_node_new (store, info);
+ child_path = e_tree_memory_node_insert (E_TREE_MEMORY (closure->ftree),
+ closure->path,
+ 0,
+ node);
+ g_hash_table_insert(closure->ftree->node_full_name, ftree_node_get_full_name(node), child_path);
+
+ if (!(info->flags & CAMEL_FOLDER_NOINFERIORS))
+ fe_check_for_children (closure->ftree, child_path);
+ }
+
+ /* FIXME: this needs to be added back to sort the tree */
+ e_tree_memory_sort_node (E_TREE_MEMORY (closure->ftree),
+ closure->path,
+ fe_sort_folder,
+ NULL);
+
+ if (closure->data)
+ closure->data->flags |= FTREE_NODE_GOT_CHILDREN;
+
+ g_hash_table_remove (closure->ftree->scan_ops, closure->path);
+
+done:
+ /* finish off the activity of this task */
+ /* hack, we know activity_data is an object */
+ closure->ftree->activity_level--;
+ (closure->ftree->activity_cb) (closure->ftree->activity_level, closure->ftree->activity_data);
+ g_object_unref(closure->ftree->activity_data);
+
+ g_free (closure);
+}
+
+static void
+fe_check_for_children (FolderETree *ftree, ETreePath path)
+{
+ ftree_op_data *closure;
+ ftree_node *node;
+ char *prefix;
+
+ node = e_tree_memory_node_get_data (E_TREE_MEMORY (ftree), path);
+
+ /* have we already gotten these children? */
+ if (node->flags & FTREE_NODE_GOT_CHILDREN)
+ return;
+
+ /* or we're loading them right now? */
+ if (g_hash_table_lookup (ftree->scan_ops, path))
+ return;
+
+ /* figure out our search prefix */
+ if (path == ftree->root)
+ prefix = "";
+ else
+ prefix = ftree_node_get_full_name (node);
+
+ closure = g_new (ftree_op_data, 1);
+ closure->ftree = ftree;
+ closure->path = path;
+ closure->data = node;
+ closure->handle = -1;
+
+ g_hash_table_insert (ftree->scan_ops, path, closure);
+
+ /* hack, we know this is an object ... infact the subscribe dialog */
+ g_object_ref(ftree->activity_data);
+ ftree->activity_level++;
+ (ftree->activity_cb) (ftree->activity_level, ftree->activity_data);
+
+ /* FIXME. Tiny race possiblity I guess. */
+ closure->handle = subscribe_get_short_folderinfo (ftree, prefix, fe_got_children, closure);
+}
+
+static void
+fe_create_root_node (FolderETree *ftree)
+{
+ ftree_node *node;
+
+ node = ftree_node_new_root ();
+ ftree->root = e_tree_memory_node_insert (E_TREE_MEMORY(ftree), NULL, 0, node);
+ fe_check_for_children (ftree, ftree->root);
+}
+
+static ETreePath
+fe_get_first_child (ETreeModel *model, ETreePath path)
+{
+ ETreePath child_path;
+
+ child_path = E_TREE_MODEL_CLASS (folder_etree_parent_class)->get_first_child (model, path);
+ if (child_path)
+ fe_check_for_children ((FolderETree *) model, child_path);
+ else
+ fe_check_for_children ((FolderETree *) model, path);
+ return child_path;
+}
+
+/* subscribing */
+static void
+fe_done_subscribing (const char *full_name, const char *name, gboolean subscribe, gboolean success, gpointer user_data)
+{
+ ftree_op_data *closure = (ftree_op_data *) user_data;
+
+ if (success && closure->handle != -1) {
+ char *path;
+
+ path = g_strdup_printf ("/%s", full_name);
+
+ if (subscribe) {
+ closure->data->flags |= FTREE_NODE_SUBSCRIBED;
+ recursive_add_folder (closure->ftree->e_storage,
+ path, name,
+ ftree_node_get_uri (closure->data));
+ } else {
+ closure->data->flags &= ~FTREE_NODE_SUBSCRIBED;
+
+ /* FIXME: recursively remove folder as well? Possible? */
+ }
+
+ g_free (path);
+ e_tree_model_node_data_changed (E_TREE_MODEL (closure->ftree), closure->path);
+ }
+
+ if (closure->handle != -1)
+ g_hash_table_remove (closure->ftree->subscribe_ops, closure->path);
+
+ g_free (closure);
+}
+
+/* cleanup */
+
+static gboolean
+fe_cancel_op_foreach (gpointer key, gpointer value, gpointer user_data)
+{
+ /*FolderETree *ftree = (FolderETree *) user_data;*/
+ ftree_op_data *closure = (ftree_op_data *) value;
+
+ if (closure->handle != -1) {
+ d(printf("%d: cancel get messageinfo\n", closure->handle));
+ mail_msg_cancel (closure->handle);
+ }
+
+ closure->handle = -1;
+
+ return TRUE;
+}
+
+static void
+fe_kill_current_tree (FolderETree *ftree)
+{
+ g_hash_table_foreach_remove (ftree->scan_ops, fe_cancel_op_foreach, ftree);
+ g_assert (g_hash_table_size (ftree->scan_ops) == 0);
+}
+
+static void
+fe_finalise (GObject *obj)
+{
+ FolderETree *ftree = (FolderETree *) (obj);
+
+ d(printf("fe finalise!?\n"));
+
+ fe_kill_current_tree (ftree);
+
+ g_hash_table_foreach_remove (ftree->subscribe_ops, fe_cancel_op_foreach, ftree);
+
+ g_hash_table_destroy (ftree->scan_ops);
+ g_hash_table_destroy (ftree->subscribe_ops);
+ g_hash_table_destroy(ftree->node_full_name);
+
+ camel_object_unref (ftree->store);
+ g_object_unref (ftree->e_storage);
+
+ g_free (ftree->service_name);
+
+ ((GObjectClass *)folder_etree_parent_class)->finalize(obj);
+}
+
+typedef gboolean (*bool_func_1) (ETreeModel *, ETreePath, int);
+typedef gboolean (*bool_func_2) (ETreeModel *);
+
+static void
+folder_etree_class_init (GObjectClass *klass)
+{
+ ETreeModelClass *etree_model_class = E_TREE_MODEL_CLASS (klass);
+
+ folder_etree_parent_class = g_type_class_ref (E_TREE_MEMORY_TYPE);
+
+ klass->finalize = fe_finalise;
+
+ etree_model_class->value_at = fe_value_at;
+ etree_model_class->set_value_at = fe_set_value_at;
+ etree_model_class->column_count = fe_column_count;
+ etree_model_class->duplicate_value = fe_duplicate_value;
+ etree_model_class->free_value = fe_free_value;
+ etree_model_class->initialize_value = fe_init_value;
+ etree_model_class->value_is_empty = fe_value_is_empty;
+ etree_model_class->value_to_string = fe_value_to_string;
+ etree_model_class->icon_at = fe_icon_at;
+ etree_model_class->is_editable = (bool_func_1) fe_return_false;
+ etree_model_class->has_save_id = (bool_func_2) fe_return_false;
+ etree_model_class->has_get_node_by_id = (bool_func_2) fe_return_false;
+ etree_model_class->get_first_child = fe_get_first_child;
+}
+
+static void
+folder_etree_init (GtkObject *object)
+{
+ FolderETree *ftree = (FolderETree *) object;
+
+ e_tree_memory_set_node_destroy_func (E_TREE_MEMORY (ftree), (GFunc) g_free, ftree);
+
+ ftree->scan_ops = g_hash_table_new (g_direct_hash, g_direct_equal);
+ ftree->subscribe_ops = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ ftree->activity_level = 0;
+ ftree->node_full_name = g_hash_table_new(g_str_hash, g_str_equal);
+}
+
+static FolderETree *
+folder_etree_construct (FolderETree *ftree,
+ CamelStore *store,
+ FolderETreeActivityCallback activity_cb,
+ gpointer activity_data)
+{
+ e_tree_memory_construct (E_TREE_MEMORY (ftree));
+
+ ftree->store = store;
+ camel_object_ref (store);
+
+ ftree->service_name = camel_service_get_name (CAMEL_SERVICE (store), FALSE);
+
+ ftree->e_storage = mail_component_lookup_storage (mail_component_peek (), store); /* this gives us a ref */
+
+ ftree->activity_cb = activity_cb;
+ ftree->activity_data = activity_data;
+
+ fe_create_root_node (ftree);
+
+ return ftree;
+}
+
+static
+E_MAKE_TYPE (folder_etree, "FolderETree", FolderETree, folder_etree_class_init, folder_etree_init, E_TREE_MEMORY_TYPE);
+
+/* public */
+
+static FolderETree *
+folder_etree_new (CamelStore *store,
+ FolderETreeActivityCallback activity_cb,
+ gpointer activity_data)
+{
+ FolderETree *ftree;
+
+ ftree = g_object_new (folder_etree_get_type(), NULL);
+ ftree = folder_etree_construct (ftree, store, activity_cb, activity_data);
+ return ftree;
+}
+
+static void
+folder_etree_clear_tree (FolderETree *ftree)
+{
+ e_tree_memory_freeze (E_TREE_MEMORY (ftree));
+ e_tree_memory_node_remove (E_TREE_MEMORY (ftree), ftree->root);
+ fe_create_root_node (ftree);
+ g_hash_table_destroy(ftree->node_full_name);
+ ftree->node_full_name = g_hash_table_new(g_str_hash, g_str_equal);
+ e_tree_memory_thaw (E_TREE_MEMORY (ftree));
+}
+
+static int
+folder_etree_path_set_subscription (FolderETree *ftree, ETreePath path, gboolean subscribe)
+{
+ ftree_op_data *closure;
+ ftree_node *node;
+
+ /* already in progress? */
+
+ if (g_hash_table_lookup (ftree->subscribe_ops, path))
+ return 0;
+
+ /* noselect? */
+
+ node = e_tree_memory_node_get_data (E_TREE_MEMORY (ftree), path);
+
+ if (!ftree_node_subscribable (node))
+ return -1;
+
+ /* noop? */
+
+ /* uh, this should be a not XOR or something */
+ if ((ftree_node_subscribed (node) && subscribe) ||
+ (!ftree_node_subscribed (node) && !subscribe))
+ return 0;
+
+ closure = g_new (ftree_op_data, 1);
+ closure->ftree = ftree;
+ closure->path = path;
+ closure->data = node;
+ closure->handle = -1;
+
+ g_hash_table_insert (ftree->subscribe_ops, path, closure);
+
+ closure->handle = subscribe_do_subscribe_folder (ftree->store,
+ ftree_node_get_full_name (node),
+ ftree_node_get_name (node),
+ subscribe,
+ fe_done_subscribing,
+ closure);
+ return 0;
+}
+
+static int
+folder_etree_path_toggle_subscription (FolderETree *ftree, ETreePath path)
+{
+ ftree_node *node = e_tree_memory_node_get_data (E_TREE_MEMORY (ftree), path);
+
+ if (ftree_node_subscribed (node))
+ return folder_etree_path_set_subscription (ftree, path, FALSE);
+ else
+ return folder_etree_path_set_subscription (ftree, path, TRUE);
+}
+
+static void
+folder_etree_cancel_all(FolderETree *ftree)
+{
+ g_hash_table_foreach_remove (ftree->scan_ops, fe_cancel_op_foreach, ftree);
+ g_hash_table_foreach_remove (ftree->subscribe_ops, fe_cancel_op_foreach, ftree);
+}
+
+/* ** StoreData ************************************************************ */
+
+typedef struct _StoreData StoreData;
+
+typedef void (*StoreDataStoreFunc) (StoreData *, CamelStore *, gpointer);
+
+struct _StoreData {
+ int refcount;
+ char *uri;
+
+ FolderETree *ftree;
+ CamelStore *store;
+
+ int request_id;
+
+ GtkWidget *widget;
+ StoreDataStoreFunc store_func;
+ gpointer store_data;
+};
+
+static StoreData *
+store_data_new (const char *uri)
+{
+ StoreData *sd;
+
+ sd = g_new0 (StoreData, 1);
+ sd->refcount = 1;
+ sd->uri = g_strdup (uri);
+
+ return sd;
+}
+
+static void
+store_data_free (StoreData *sd)
+{
+ d(printf("store data free?\n"));
+
+ if (sd->request_id)
+ mail_msg_cancel (sd->request_id);
+
+ if (sd->ftree) {
+ folder_etree_cancel_all(sd->ftree);
+ g_object_unref(sd->ftree);
+ }
+
+ if (sd->store)
+ camel_object_unref (sd->store);
+
+ g_free (sd->uri);
+ g_free (sd);
+}
+
+static void
+store_data_ref (StoreData *sd)
+{
+ sd->refcount++;
+}
+
+static void
+store_data_unref (StoreData *sd)
+{
+ if (sd->refcount <= 1) {
+ store_data_free (sd);
+ } else {
+ sd->refcount--;
+ }
+}
+
+static void
+sd_got_store (char *uri, CamelStore *store, gpointer user_data)
+{
+ StoreData *sd = (StoreData *) user_data;
+
+ sd->store = store;
+
+ if (store) /* we can have exceptions getting the store... server is down, eg */
+ camel_object_ref (sd->store);
+
+ /* uh, so we might have a problem if this operation is cancelled. Unsure. */
+ sd->request_id = 0;
+
+ if (sd->store_func)
+ (sd->store_func) (sd, sd->store, sd->store_data);
+
+ store_data_unref (sd);
+}
+
+static void
+store_data_async_get_store (StoreData *sd, StoreDataStoreFunc func, gpointer user_data)
+{
+ if (sd->request_id) {
+ d(printf ("Already loading store, nooping\n"));
+ return;
+ }
+
+ if (sd->store) {
+ /* um, is this the best behavior? */
+ func (sd, sd->store, user_data);
+ return;
+ }
+
+ sd->store_func = func;
+ sd->store_data = user_data;
+ store_data_ref (sd);
+ sd->request_id = mail_get_store (sd->uri, NULL, sd_got_store, sd);
+}
+
+static void
+store_data_cancel_get_store (StoreData *sd)
+{
+ g_return_if_fail (sd->request_id);
+
+ mail_msg_cancel (sd->request_id);
+ sd->request_id = 0;
+}
+
+static void
+sd_toggle_cb (ETree *tree, int row, ETreePath path, int col, GdkEvent *event, gpointer user_data)
+{
+ StoreData *sd = (StoreData *) user_data;
+
+ folder_etree_path_toggle_subscription (sd->ftree, path);
+}
+
+static GtkWidget *
+store_data_get_widget (StoreData *sd,
+ FolderETreeActivityCallback activity_cb,
+ gpointer activity_data)
+{
+ GtkWidget *tree;
+
+ if (!sd->store) {
+ d(printf ("store data can't get widget before getting store.\n"));
+ return NULL;
+ }
+
+ if (sd->widget)
+ return sd->widget;
+
+ sd->ftree = folder_etree_new (sd->store, activity_cb, activity_data);
+
+ /* You annoy me, etree! */
+ tree = gtk_widget_new (E_TREE_SCROLLED_TYPE,
+ "hadjustment", NULL,
+ "vadjustment", NULL,
+ NULL);
+
+ tree = (GtkWidget *) e_tree_scrolled_construct_from_spec_file (E_TREE_SCROLLED (tree),
+ E_TREE_MODEL (sd->ftree),
+ subscribe_get_global_extras (),
+ EVOLUTION_ETSPECDIR "/subscribe-dialog.etspec",
+ NULL);
+ e_tree_root_node_set_visible (e_tree_scrolled_get_tree(E_TREE_SCROLLED(tree)), TRUE);
+ g_signal_connect(e_tree_scrolled_get_tree(E_TREE_SCROLLED (tree)),
+ "double_click", G_CALLBACK (sd_toggle_cb), sd);
+
+ g_object_unref(global_extras);
+
+ sd->widget = tree;
+
+ return sd->widget;
+}
+
+typedef struct _selection_closure {
+ StoreData *sd;
+ enum { SET, CLEAR, TOGGLE } mode;
+} selection_closure;
+
+static void
+sd_subscribe_folder_foreach (int model_row, gpointer closure)
+{
+ selection_closure *sc = (selection_closure *) closure;
+ StoreData *sd = sc->sd;
+ ETree *tree = e_tree_scrolled_get_tree(E_TREE_SCROLLED(sd->widget));
+ ETreePath path = e_tree_node_at_row (tree, model_row);
+
+ /* ignore results */
+ switch (sc->mode) {
+ case SET:
+ folder_etree_path_set_subscription (sd->ftree, path, TRUE);
+ break;
+ case CLEAR:
+ folder_etree_path_set_subscription (sd->ftree, path, FALSE);
+ break;
+ case TOGGLE:
+ folder_etree_path_toggle_subscription (sd->ftree, path);
+ break;
+ }
+}
+
+static void
+store_data_selection_set_subscription (StoreData *sd, gboolean subscribe)
+{
+ selection_closure sc;
+ ETree *tree;
+
+ sc.sd = sd;
+ if (subscribe)
+ sc.mode = SET;
+ else
+ sc.mode = CLEAR;
+
+ tree = e_tree_scrolled_get_tree (E_TREE_SCROLLED (sd->widget));
+ e_tree_selected_row_foreach (tree, sd_subscribe_folder_foreach, &sc);
+}
+
+#ifdef NEED_TOGGLE_SELECTION
+static void
+store_data_selection_toggle_subscription (StoreData *sd)
+{
+ selection_closure sc;
+ ETree *tree;
+
+ sc.sd = sd;
+ sc.mode = TOGGLE;
+
+ tree = e_tree_scrolled_get_tree (E_TREE_SCROLLED (sd->widget));
+ e_tree_selected_row_foreach (tree, sd_subscribe_folder_foreach, &sc);
+}
+#endif
+
+static gboolean
+store_data_mid_request (StoreData *sd)
+{
+ return (gboolean) sd->request_id;
+}
+
+/* ** yaay, SubscribeDialog ******************************************************* */
+
+#define PARENT_TYPE (gtk_object_get_type ())
+
+#ifdef JUST_FOR_TRANSLATORS
+static char *str = N_("Folder");
+#endif
+
+#define STORE_DATA_KEY "store-data"
+
+struct _SubscribeDialogPrivate {
+ GladeXML *xml;
+ GList *store_list;
+
+ StoreData *current_store;
+ GtkWidget *current_widget;
+
+ GtkWidget *default_widget;
+ GtkWidget *none_item;
+ GtkWidget *search_entry;
+ GtkWidget *hbox;
+ GtkWidget *filter_radio, *all_radio;
+ GtkWidget *sub_button, *unsub_button, *refresh_button, *close_button;
+ GtkWidget *progress;
+
+ int cancel; /* have we been cancelled? */
+ guint activity_timeout_id;
+};
+
+static GtkObjectClass *subscribe_dialog_parent_class;
+
+static void
+sc_refresh_pressed (GtkWidget *widget, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+
+ if (sc->priv->current_store)
+ folder_etree_clear_tree (sc->priv->current_store->ftree);
+}
+
+static void
+sc_close_pressed (GtkWidget *widget, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+
+ /* order important here */
+ gtk_object_destroy (GTK_OBJECT (sc));
+ gtk_widget_destroy (GTK_WIDGET (sc->app));
+}
+
+static void
+sc_subscribe_pressed (GtkWidget *widget, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ StoreData *store = sc->priv->current_store;
+
+ if (!store)
+ return;
+
+ store_data_selection_set_subscription (store, TRUE);
+}
+
+static void
+sc_unsubscribe_pressed (GtkWidget *widget, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ StoreData *store = sc->priv->current_store;
+
+ if (!store)
+ return;
+
+ store_data_selection_set_subscription (store, FALSE);
+}
+
+static void
+kill_default_view (SubscribeDialog *sc)
+{
+ gtk_widget_hide (sc->priv->none_item);
+
+ gtk_widget_set_sensitive (sc->priv->sub_button, TRUE);
+ gtk_widget_set_sensitive (sc->priv->unsub_button, TRUE);
+ gtk_widget_set_sensitive (sc->priv->refresh_button, TRUE);
+}
+
+static void
+sc_selection_changed (GtkObject *obj, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ gboolean sensitive;
+
+ if (e_selection_model_selected_count (E_SELECTION_MODEL (obj)))
+ sensitive = TRUE;
+ else
+ sensitive = FALSE;
+
+ gtk_widget_set_sensitive (sc->priv->sub_button, sensitive);
+ gtk_widget_set_sensitive (sc->priv->unsub_button, sensitive);
+}
+
+static gboolean
+sc_activity_timeout (SubscribeDialog *sc)
+{
+ gtk_progress_bar_pulse(GTK_PROGRESS_BAR(sc->priv->progress));
+
+ return TRUE;
+}
+
+static void
+sc_activity_cb (int level, SubscribeDialog *sc)
+{
+ g_assert (pthread_self() == mail_gui_thread);
+
+ if (sc->priv->cancel)
+ return;
+
+ if (level) {
+ if (sc->priv->activity_timeout_id)
+ return;
+
+ sc->priv->activity_timeout_id = g_timeout_add(50, (GSourceFunc)sc_activity_timeout, sc);
+ gtk_widget_show(sc->priv->progress);
+ } else {
+ if (sc->priv->activity_timeout_id) {
+ g_source_remove (sc->priv->activity_timeout_id);
+ sc->priv->activity_timeout_id = 0;
+ }
+
+ gtk_widget_hide(sc->priv->progress);
+ }
+}
+
+static void
+menu_item_selected (GtkMenuItem *item, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+ StoreData *sd = g_object_get_data (G_OBJECT (item), STORE_DATA_KEY);
+
+ g_return_if_fail (sd);
+
+ if (sd->widget == NULL) {
+ GtkWidget *widget;
+ ESelectionModel *esm;
+ ETree *tree;
+
+ widget = store_data_get_widget (sd, (FolderETreeActivityCallback) sc_activity_cb, sc);
+ gtk_box_pack_start (GTK_BOX (sc->priv->hbox), widget, TRUE, TRUE, 0);
+
+ tree = e_tree_scrolled_get_tree (E_TREE_SCROLLED (widget));
+ esm = e_tree_get_selection_model (tree);
+ g_signal_connect(esm, "selection_changed", G_CALLBACK(sc_selection_changed), sc);
+ sc_selection_changed ((GtkObject *)esm, sc);
+ }
+
+ if (sc->priv->current_widget == sc->priv->default_widget)
+ kill_default_view (sc);
+
+ gtk_widget_hide (sc->priv->current_widget);
+ gtk_widget_show (sd->widget);
+ sc->priv->current_widget = sd->widget;
+ sc->priv->current_store = sd;
+}
+
+static void
+dummy_item_selected (GtkMenuItem *item, gpointer user_data)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (user_data);
+
+ gtk_widget_hide (sc->priv->current_widget);
+ gtk_widget_show (sc->priv->default_widget);
+ sc->priv->current_widget = sc->priv->default_widget;
+ sc->priv->current_store = NULL;
+
+ gtk_entry_set_text (GTK_ENTRY (sc->priv->search_entry), "");
+}
+
+/* wonderful */
+
+static void
+got_sd_store (StoreData *sd, CamelStore *store, gpointer data)
+{
+ if (store && camel_store_supports_subscriptions (store))
+ gtk_widget_show (GTK_WIDGET (data));
+}
+
+/* FIXME: if there aren't any stores that are subscribable, the option
+ * menu will only have the "No server selected" item and the user will
+ * be confused. */
+
+static void
+populate_store_list (SubscribeDialog *sc)
+{
+ EAccountList *accounts;
+ EAccount *account;
+ EIterator *iter;
+ GtkWidget *menu;
+ GtkWidget *omenu;
+ GList *l;
+
+ accounts = mail_config_get_accounts ();
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ StoreData *sd;
+
+ account = (EAccount *) e_iterator_get (iter);
+
+ if (account->enabled && account->source->url) {
+ sd = store_data_new (account->source->url);
+ sc->priv->store_list = g_list_prepend (sc->priv->store_list, sd);
+ }
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ menu = gtk_menu_new ();
+
+ for (l = sc->priv->store_list; l; l = l->next) {
+ GtkWidget *item;
+ CamelURL *url;
+ char *string;
+
+ url = camel_url_new (((StoreData *) l->data)->uri, NULL);
+ string = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (url);
+ item = gtk_menu_item_new_with_label (string);
+ store_data_async_get_store (l->data, got_sd_store, item);
+ g_object_set_data (G_OBJECT (item), STORE_DATA_KEY, l->data);
+ g_signal_connect (item, "activate", G_CALLBACK (menu_item_selected), sc);
+ g_free (string);
+
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+ }
+
+ sc->priv->none_item = gtk_menu_item_new_with_label (_("No server has been selected"));
+ g_signal_connect (sc->priv->none_item, "activate", G_CALLBACK (dummy_item_selected), sc);
+ gtk_widget_show (sc->priv->none_item);
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), sc->priv->none_item);
+
+ gtk_widget_show (menu);
+
+ omenu = glade_xml_get_widget (sc->priv->xml, "store_menu");
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
+}
+
+static void
+subscribe_dialog_finalise (GObject *object)
+{
+ SubscribeDialog *sc;
+ GList *iter;
+
+ sc = SUBSCRIBE_DIALOG (object);
+
+ if (sc->priv->store_list) {
+ for (iter = sc->priv->store_list; iter; iter = iter->next) {
+ StoreData *data = iter->data;
+ store_data_unref (data);
+ }
+
+ g_list_free (sc->priv->store_list);
+ sc->priv->store_list = NULL;
+ }
+
+ g_free (sc->priv);
+ sc->priv = NULL;
+
+ ((GObjectClass *)subscribe_dialog_parent_class)->finalize (object);
+}
+
+static void
+subscribe_dialog_destroy (GtkObject *object)
+{
+ SubscribeDialog *sc;
+ GList *iter;
+
+ sc = SUBSCRIBE_DIALOG (object);
+
+ d(printf("subscribe_dialog_destroy\n"));
+
+ if (!sc->priv->cancel) {
+ sc->priv->cancel = 1;
+
+ if (sc->priv->activity_timeout_id) {
+ g_source_remove (sc->priv->activity_timeout_id);
+ sc->priv->activity_timeout_id = 0;
+ }
+
+ if (sc->priv->store_list) {
+ for (iter = sc->priv->store_list; iter; iter = iter->next) {
+ StoreData *data = iter->data;
+
+ if (store_data_mid_request (data))
+ store_data_cancel_get_store (data);
+
+ if (data->ftree)
+ folder_etree_cancel_all(data->ftree);
+
+ data->store_func = NULL;
+ }
+ }
+
+ if (sc->priv->xml) {
+ g_object_unref(sc->priv->xml);
+ sc->priv->xml = NULL;
+ }
+ }
+
+ subscribe_dialog_parent_class->destroy (object);
+}
+
+static void
+subscribe_dialog_class_init (GtkObjectClass *object_class)
+{
+ object_class->destroy = subscribe_dialog_destroy;
+ ((GObjectClass *)object_class)->finalize = subscribe_dialog_finalise;
+
+ subscribe_dialog_parent_class = g_type_class_ref (PARENT_TYPE);
+}
+
+static void
+subscribe_dialog_init (GtkObject *object)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (object);
+
+ sc->priv = g_new0 (SubscribeDialogPrivate, 1);
+}
+
+static GtkWidget *
+sc_create_default_widget (void)
+{
+ GtkWidget *label;
+ GtkWidget *viewport;
+
+ label = gtk_label_new (_("Please select a server."));
+ gtk_widget_show (label);
+
+ viewport = gtk_viewport_new (NULL, NULL);
+ gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (viewport), label);
+
+ return viewport;
+}
+
+static void
+subscribe_dialog_construct (GtkObject *object)
+{
+ SubscribeDialog *sc = SUBSCRIBE_DIALOG (object);
+
+ /* Load the XML */
+ /* "app2" */
+ sc->priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/subscribe-dialog.glade", "subscribe_dialog", NULL);
+
+ sc->app = glade_xml_get_widget (sc->priv->xml, "subscribe_dialog");
+ sc->priv->hbox = glade_xml_get_widget (sc->priv->xml, "tree_box");
+ sc->priv->close_button = glade_xml_get_widget (sc->priv->xml, "close_button");
+ sc->priv->sub_button = glade_xml_get_widget (sc->priv->xml, "subscribe_button");
+ sc->priv->unsub_button = glade_xml_get_widget (sc->priv->xml, "unsubscribe_button");
+ sc->priv->refresh_button = glade_xml_get_widget (sc->priv->xml, "refresh_button");
+ sc->priv->progress = glade_xml_get_widget(sc->priv->xml, "progress_bar");
+
+ /* create default view */
+ sc->priv->default_widget = sc_create_default_widget();
+ sc->priv->current_widget = sc->priv->default_widget;
+ gtk_box_pack_start (GTK_BOX (sc->priv->hbox), sc->priv->default_widget, TRUE, TRUE, 0);
+ gtk_widget_show (sc->priv->default_widget);
+
+ gtk_widget_set_sensitive (sc->priv->sub_button, FALSE);
+ gtk_widget_set_sensitive (sc->priv->unsub_button, FALSE);
+ gtk_widget_set_sensitive (sc->priv->refresh_button, FALSE);
+
+ /* hook up some signals */
+ g_signal_connect(sc->priv->close_button, "clicked", G_CALLBACK(sc_close_pressed), sc);
+ g_signal_connect(sc->priv->sub_button, "clicked", G_CALLBACK(sc_subscribe_pressed), sc);
+ g_signal_connect(sc->priv->unsub_button, "clicked", G_CALLBACK(sc_unsubscribe_pressed), sc);
+ g_signal_connect(sc->priv->refresh_button, "clicked", G_CALLBACK(sc_refresh_pressed), sc);
+
+ /* progress */
+ gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(sc->priv->progress), 0.1);
+ gtk_widget_hide(sc->priv->progress);
+
+ /* reasonable starting point */
+ gtk_window_set_default_size((GtkWindow *)sc->app, 350, 400);
+
+ /* Get the list of stores */
+ populate_store_list (sc);
+}
+
+GtkObject *
+subscribe_dialog_new (void)
+{
+ SubscribeDialog *subscribe_dialog;
+
+ subscribe_dialog = g_object_new (SUBSCRIBE_DIALOG_TYPE, NULL);
+ subscribe_dialog_construct (GTK_OBJECT (subscribe_dialog));
+
+ return GTK_OBJECT (subscribe_dialog);
+}
+
+E_MAKE_TYPE (subscribe_dialog, "SubscribeDialog", SubscribeDialog, subscribe_dialog_class_init, subscribe_dialog_init, PARENT_TYPE);
diff --git a/mail/subscribe-dialog.etspec b/mail/subscribe-dialog.etspec
new file mode 100644
index 0000000000..1f5decbb36
--- /dev/null
+++ b/mail/subscribe-dialog.etspec
@@ -0,0 +1,9 @@
+<ETableSpecification cursor-mode="line" no-headers="true">
+ <ETableColumn model_col="0" pixbuf="subscribed-image" expansion="0.0" minimum_width="16" resizable="false" cell="cell_toggle" compare="integer"/>
+ <ETableColumn model_col="1" _title="Folder" expansion="1.0" minimum_width="20" resizable="true" cell="cell_tree" compare="string"/>
+ <ETableState>
+ <column source="0"/>
+ <column source="1"/>
+ <grouping></grouping>
+ </ETableState>
+</ETableSpecification>
diff --git a/mail/subscribe-dialog.h b/mail/subscribe-dialog.h
new file mode 100644
index 0000000000..c2e6b3d46f
--- /dev/null
+++ b/mail/subscribe-dialog.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Chris Toshok <toshok@ximian.com>
+ * Peter Williams <peterw@ximian.com>
+ *
+ * Copyright 2000 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 _SUBSCRIBE_DIALOG_H_
+#define _SUBSCRIBE_DIALOG_H_
+
+#include <gtk/gtktable.h>
+#include <bonobo/bonobo-control.h>
+#include <bonobo/bonobo-property-bag.h>
+#include <gal/e-table/e-tree-model.h>
+#include <gal/e-table/e-table-model.h>
+#include "shell/evolution-storage.h"
+#include "mail-types.h"
+#include "camel/camel-store.h"
+
+#define SUBSCRIBE_DIALOG_TYPE (subscribe_dialog_get_type ())
+#define SUBSCRIBE_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SUBSCRIBE_DIALOG_TYPE, SubscribeDialog))
+#define SUBSCRIBE_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SUBSCRIBE_DIALOG_TYPE, SubscribeDialogClass))
+#define IS_SUBSCRIBE_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SUBSCRIBE_DIALOG_TYPE))
+#define IS_SUBSCRIBE_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SUBSCRIBE_DIALOG_TYPE))
+
+typedef struct _SubscribeDialogPrivate SubscribeDialogPrivate;
+
+struct _SubscribeDialog {
+ GtkObject parent;
+
+ GtkWidget *app;
+ SubscribeDialogPrivate *priv;
+};
+
+typedef struct {
+ GtkObjectClass parent_class;
+} SubscribeDialogClass;
+
+GtkType subscribe_dialog_get_type (void);
+GtkObject *subscribe_dialog_new (void);
+
+/* helper macro */
+#define subscribe_dialog_show(dialog) gtk_widget_show (SUBSCRIBE_DIALOG (dialog)->app)
+
+#endif /* _SUBSCRIBE_DIALOG_H_ */
diff --git a/mail/upgrade-mailer.c b/mail/upgrade-mailer.c
new file mode 100644
index 0000000000..130194ca6a
--- /dev/null
+++ b/mail/upgrade-mailer.c
@@ -0,0 +1,1169 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
+ *
+ * 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 2 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 Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <bonobo.h>
+#include <bonobo-conf/bonobo-config-database.h>
+#include <gal/util/e-xml-utils.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include <camel/camel-file-utils.h>
+
+struct _storeinfo {
+ char *base_url;
+ char *namespace;
+ char *encoded_namespace;
+ char dir_sep;
+ GPtrArray *folders;
+};
+
+
+
+static char
+find_dir_sep (const char *lsub_response)
+{
+ register const unsigned char *inptr;
+ const unsigned char *inend;
+
+ inptr = (const unsigned char *) lsub_response;
+ inend = inptr + strlen (inptr);
+
+ if (strncmp (inptr, "* LSUB (", 8))
+ return '\0';
+
+ inptr += 8;
+ while (inptr < inend && *inptr != ')')
+ inptr++;
+
+ if (inptr >= inend)
+ return '\0';
+
+ inptr++;
+ while (inptr < inend && isspace ((int) *inptr))
+ inptr++;
+
+ if (inptr >= inend)
+ return '\0';
+
+ if (*inptr == '\"')
+ inptr++;
+
+ return inptr < inend ? *inptr : '\0';
+}
+
+static void
+si_free (struct _storeinfo *si)
+{
+ int i;
+
+ g_free (si->base_url);
+ g_free (si->namespace);
+ g_free (si->encoded_namespace);
+ if (si->folders) {
+ for (i = 0; i < si->folders->len; i++)
+ g_free (si->folders->pdata[i]);
+ g_ptr_array_free (si->folders, TRUE);
+ }
+ g_free (si);
+}
+
+static unsigned char tohex[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+static char *
+hex_encode (const char *in, size_t len)
+{
+ const unsigned char *inend = in + len;
+ unsigned char *inptr, *outptr;
+ char *outbuf;
+
+ outptr = outbuf = g_malloc ((len * 3) + 1);
+
+ inptr = (unsigned char *) in;
+ while (inptr < inend) {
+ if (*inptr > 127 || isspace ((int) *inptr)) {
+ *outptr++ = '%';
+ *outptr++ = tohex[(*inptr >> 4) & 0xf];
+ *outptr++ = tohex[*inptr & 0xf];
+ inptr++;
+ } else
+ *outptr++ = *inptr++;
+ }
+
+ *outptr = '\0';
+
+ return outbuf;
+}
+
+#define HEXVAL(c) (isdigit (c) ? (c) - '0' : tolower (c) - 'a' + 10)
+
+static char *
+hex_decode (const char *in, size_t len)
+{
+ const unsigned char *inend = in + len;
+ unsigned char *inptr, *outptr;
+ char *outbuf;
+
+ outptr = outbuf = g_malloc (len + 1);
+
+ inptr = (unsigned char *) in;
+ while (inptr < inend) {
+ if (*inptr == '%') {
+ if (isxdigit ((int) inptr[1]) && isxdigit ((int) inptr[2])) {
+ *outptr++ = HEXVAL (inptr[1]) * 16 + HEXVAL (inptr[2]);
+ inptr += 3;
+ } else
+ *outptr++ = *inptr++;
+ } else
+ *outptr++ = *inptr++;
+ }
+
+ *outptr = '\0';
+
+ return outbuf;
+}
+
+static char *
+parse_lsub (const char *lsub, char *dir_sep)
+{
+ const unsigned char *inptr = (const unsigned char *) lsub;
+ const unsigned char *inend;
+ int inlen, quoted = 0;
+
+ inend = inptr + strlen (inptr);
+ if (strncmp (inptr, "* LSUB (", 8))
+ return NULL;
+
+ inptr += 8;
+ while (inptr < inend && *inptr != ')')
+ inptr++;
+
+ if (inptr >= inend)
+ return NULL;
+
+ inptr++;
+ while (inptr < inend && isspace ((int) *inptr))
+ inptr++;
+
+ if (inptr >= inend)
+ return NULL;
+
+ /* skip over the dir sep */
+ if (*inptr == '\"')
+ inptr++;
+
+ *dir_sep = (char) *inptr++;
+ if (*inptr == '\"')
+ inptr++;
+
+ if (inptr >= inend)
+ return NULL;
+
+ while (inptr < inend && isspace ((int) *inptr))
+ inptr++;
+
+ if (inptr >= inend)
+ return NULL;
+
+ if (*inptr == '\"') {
+ inptr++;
+ quoted = 1;
+ } else
+ quoted = 0;
+
+ inlen = strlen (inptr) - quoted;
+
+ return g_strndup (inptr, inlen);
+}
+
+static void
+cache_upgrade (struct _storeinfo *si, const char *folder_name)
+{
+ const char *old_folder_name = folder_name;
+ char *oldpath, *newpath, *p;
+ struct dirent *dent;
+ DIR *dir = NULL;
+
+ if (si->namespace && strcmp ("INBOX", folder_name)) {
+ if (!strncmp (old_folder_name, si->namespace, strlen (si->namespace))) {
+ old_folder_name += strlen (si->namespace);
+ if (*old_folder_name == si->dir_sep)
+ old_folder_name++;
+ }
+ }
+
+ oldpath = g_strdup_printf ("%s/evolution/mail/imap/%s/%s", getenv ("HOME"),
+ si->base_url + 7, old_folder_name);
+
+ newpath = g_strdup_printf ("%s/evolution/mail/imap/%s/folders/%s",
+ getenv ("HOME"), si->base_url + 7, folder_name);
+
+ if (!strcmp (folder_name, "folders"))
+ goto special_case_folders;
+
+ if (si->dir_sep != '/') {
+ p = newpath + strlen (newpath) - strlen (folder_name) - 1;
+ while (*p) {
+ if (*p == si->dir_sep)
+ *p = '/';
+ p++;
+ }
+ }
+
+ /* make sure all parent directories exist */
+ if ((p = strrchr (newpath, '/'))) {
+ *p = '\0';
+ camel_mkdir (newpath, 0755);
+ *p = '/';
+ }
+
+ if (rename (oldpath, newpath) == -1) {
+ fprintf (stderr, "Failed to upgrade cache for imap folder %s/%s: %s\n",
+ si->base_url, folder_name, g_strerror (errno));
+ }
+
+ g_free (oldpath);
+ g_free (newpath);
+
+ return;
+
+ special_case_folders:
+
+ /* the user had a toplevel folder named "folders" */
+ if (camel_mkdir (newpath, 0755) == -1) {
+ /* we don't bother to check EEXIST because well, if
+ folders/folders exists then we're pretty much
+ fucked */
+ goto exception;
+ }
+
+ if (!(dir = opendir (oldpath)))
+ goto exception;
+
+ while ((dent = readdir (dir))) {
+ char *old_path, *new_path;
+
+ if (!strcmp (dent->d_name, ".") || !strcmp (dent->d_name, ".."))
+ continue;
+
+ old_path = g_strdup_printf ("%s/%s", oldpath, dent->d_name);
+ new_path = g_strdup_printf ("%s/%s", newpath, dent->d_name);
+
+ /* make sure all parent directories exist */
+ if ((p = strrchr (new_path, '/'))) {
+ *p = '\0';
+ camel_mkdir (new_path, 0755);
+ *p = '/';
+ }
+
+ if (rename (old_path, new_path) == -1) {
+ g_free (old_path);
+ g_free (new_path);
+ goto exception;
+ }
+
+ g_free (old_path);
+ g_free (new_path);
+ }
+
+ closedir (dir);
+
+ g_free (oldpath);
+ g_free (newpath);
+
+ return;
+
+ exception:
+
+ fprintf (stderr, "Failed to upgrade cache for imap folder %s/%s: %s\n",
+ si->base_url, folder_name, g_strerror (errno));
+
+ if (dir)
+ closedir (dir);
+
+ g_free (oldpath);
+ g_free (newpath);
+}
+
+static int
+foldercmp (const void *f1, const void *f2)
+{
+ const char **folder1 = (const char **) f1;
+ const char **folder2 = (const char **) f2;
+
+ return strcmp (*folder1, *folder2);
+}
+
+static void
+cache_upgrade_and_free (gpointer key, gpointer val, gpointer user_data)
+{
+ struct _storeinfo *si = val;
+ GPtrArray *folders;
+ char *path = NULL;
+ char dir_sep;
+ int i;
+
+ if (si->folders) {
+ path = g_strdup_printf ("%s/evolution/mail/imap/%s/folders",
+ getenv ("HOME"), si->base_url + 7);
+
+ if (mkdir (path, 0755) == -1 && errno != EEXIST) {
+ fprintf (stderr, "Failed to create directory %s: %s", path, g_strerror (errno));
+ goto exception;
+ }
+
+ g_free (path);
+ folders = g_ptr_array_new ();
+ for (i = 0; i < si->folders->len; i++) {
+ if ((path = parse_lsub (si->folders->pdata[i], &dir_sep))) {
+ g_ptr_array_add (folders, path);
+ }
+ }
+
+ /* sort the folders so that parents get created before
+ their children */
+ qsort (folders->pdata, folders->len, sizeof (void *), foldercmp);
+
+ for (i = 0; i < folders->len; i++) {
+ cache_upgrade (si, folders->pdata[i]);
+ g_free (folders->pdata[i]);
+ }
+ }
+
+ si_free (si);
+
+ return;
+
+ exception:
+
+ fprintf (stderr, "Could not upgrade imap cache for %s: %s\n",
+ si->base_url + 7, g_strerror (errno));
+
+ g_free (path);
+
+ si_free (si);
+}
+
+static char *
+get_base_url (const char *protocol, const char *uri)
+{
+ unsigned char *base_url, *p;
+
+ p = (unsigned char *) uri + strlen (protocol) + 1;
+ if (!strncmp (p, "//", 2))
+ p += 2;
+
+ base_url = p;
+ p = strchr (p, '/');
+ base_url = g_strdup_printf ("%s://%.*s", protocol, p ? (int) (p - base_url) : (int) strlen (base_url), base_url);
+
+ return base_url;
+}
+
+static char *
+imap_namespace (const char *uri)
+{
+ unsigned char *name, *p;
+
+ if ((name = strstr (uri, ";namespace=\"")) == NULL)
+ return NULL;
+
+ name += strlen (";namespace=\"");
+ p = name;
+ while (*p && *p != '\"')
+ p++;
+
+ return g_strndup (name, p - name);
+}
+
+static char *
+find_folder (GPtrArray *folders, const char *folder, char *dir_sep)
+{
+ const unsigned char *inptr, *inend;
+ int inlen, len, diff, i;
+ int quoted;
+
+ len = strlen (folder);
+
+ for (i = 0; i < folders->len; i++) {
+ inptr = folders->pdata[i];
+ inend = inptr + strlen (inptr);
+ if (strncmp (inptr, "* LSUB (", 8))
+ continue;
+
+ inptr += 8;
+ while (inptr < inend && *inptr != ')')
+ inptr++;
+
+ if (inptr >= inend)
+ continue;
+
+ inptr++;
+ while (inptr < inend && isspace ((int) *inptr))
+ inptr++;
+
+ if (inptr >= inend)
+ continue;
+
+ /* skip over the dir sep */
+ if (*inptr == '\"')
+ inptr++;
+
+ *dir_sep = *inptr++;
+ if (*inptr == '\"')
+ inptr++;
+
+ if (inptr >= inend)
+ continue;
+
+ while (inptr < inend && isspace ((int) *inptr))
+ inptr++;
+
+ if (inptr >= inend)
+ continue;
+
+ if (*inptr == '\"') {
+ inptr++;
+ quoted = 1;
+ } else
+ quoted = 0;
+
+ inlen = strlen (inptr) - quoted;
+ if (len > inlen)
+ continue;
+
+ diff = inlen - len;
+ if (!strncmp (inptr + diff, folder, len))
+ return hex_encode (inptr, inlen);
+ }
+
+ *dir_sep = '\0';
+
+ return NULL;
+}
+
+static char *
+imap_url_upgrade (GHashTable *imap_sources, const char *uri)
+{
+ struct _storeinfo *si;
+ unsigned char *base_url, *folder, *p, *new = NULL;
+ char dir_sep;
+
+ base_url = get_base_url ("imap", uri);
+
+ fprintf (stderr, "checking for %s... ", base_url);
+ if (!(si = g_hash_table_lookup (imap_sources, base_url))) {
+ fprintf (stderr, "not found.\n");
+ g_warning ("Unknown imap account: %s", base_url);
+ g_free (base_url);
+ return NULL;
+ }
+
+ fprintf (stderr, "found.\n");
+ p = (unsigned char *) uri + strlen (base_url) + 1;
+ if (!strcmp (p, "INBOX")) {
+ new = g_strdup_printf ("%s/INBOX", base_url);
+ g_free (base_url);
+ return new;
+ }
+
+ p = hex_decode (p, strlen (p));
+
+ fprintf (stderr, "checking for folder %s on %s... ", p, base_url);
+ folder = si->folders ? find_folder (si->folders, p, &dir_sep) : NULL;
+ if (folder == NULL) {
+ fprintf (stderr, "not found.\n");
+ folder = p;
+ if (si->namespace) {
+ if (!si->dir_sep) {
+ fprintf (stderr, "checking for directory separator in namespace param... ");
+ if (*si->namespace == '/') {
+ dir_sep = '/';
+ } else {
+ p = si->namespace;
+ while (*p && !ispunct ((int) *p))
+ p++;
+
+ dir_sep = (char) *p;
+ }
+ } else {
+ dir_sep = si->dir_sep;
+ }
+
+ if (dir_sep) {
+ fprintf (stderr, "found: '%c'\n", dir_sep);
+ p = folder;
+ folder = hex_encode (folder, strlen (folder));
+ new = g_strdup_printf ("%s/%s%c%s", base_url, si->encoded_namespace, dir_sep, folder);
+ g_free (folder);
+ folder = p;
+
+ p = new + strlen (base_url) + 1;
+ while (*p) {
+ if (*p == dir_sep)
+ *p = '/';
+ p++;
+ }
+ } else {
+ fprintf (stderr, "not found.");
+ g_warning ("Cannot update settings for imap folder %s: unknown directory separator", uri);
+ }
+ } else {
+ g_warning ("Cannot update settings for imap folder %s: unknown namespace", uri);
+ }
+
+ g_free (base_url);
+ g_free (folder);
+
+ return new;
+ } else
+ g_free (p);
+
+ fprintf (stderr, "found.\n");
+ new = g_strdup_printf ("%s/%s", base_url, folder);
+ g_free (folder);
+
+ if (!si->dir_sep)
+ si->dir_sep = dir_sep;
+
+ if (dir_sep) {
+ p = new + strlen (base_url) + 1;
+ while (*p) {
+ if (*p == dir_sep)
+ *p = '/';
+ p++;
+ }
+ }
+
+ g_free (base_url);
+
+ return new;
+}
+
+static char *
+exchange_url_upgrade (const char *uri)
+{
+ unsigned char *base_url, *folder;
+ char *url;
+
+ base_url = get_base_url ("exchange", uri);
+ folder = (unsigned char *) uri + strlen (base_url) + 1;
+
+ if (strncmp (folder, "exchange/", 9))
+ return g_strdup (uri);
+
+ folder += 9;
+ while (*folder && *folder != '/')
+ folder++;
+ if (*folder == '/')
+ folder++;
+
+ folder = hex_decode (folder, strlen (folder));
+ url = g_strdup_printf ("%s/personal/%s", base_url, folder);
+ g_free (base_url);
+ g_free (folder);
+
+ return url;
+}
+
+static int
+mailer_upgrade_account_info (Bonobo_ConfigDatabase db, const char *key, int num, GHashTable *imap_sources)
+{
+ char *path, *uri, *new;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ path = g_strdup_printf ("/Mail/Accounts/account_%s_folder_uri_%d", key, i);
+ uri = bonobo_config_get_string (db, path, NULL);
+ if (uri) {
+ if (!strncmp (uri, "imap:", 5)) {
+ new = imap_url_upgrade (imap_sources, uri);
+ if (new) {
+ bonobo_config_set_string (db, path, new, NULL);
+ g_free (new);
+ }
+ } else if (!strncmp (uri, "exchange:", 9)) {
+ new = exchange_url_upgrade (uri);
+ bonobo_config_set_string (db, path, new, NULL);
+ g_free (new);
+ }
+ }
+
+ g_free (uri);
+ g_free (path);
+ }
+
+ return 0;
+}
+
+static int
+mailer_upgrade_xml_file (GHashTable *imap_sources, const char *filename)
+{
+ unsigned char *buffer, *inptr, *start, *uri, *new;
+ ssize_t nread = 0, nwritten, n;
+ gboolean url_need_upgrade;
+ struct stat st;
+ size_t len;
+ char *bak;
+ int fd;
+
+ bak = g_strdup_printf ("%s.bak-1.0", filename);
+ if (stat (bak, &st) != -1) {
+ /* seems we have already converted this file? */
+ fprintf (stderr, "\n%s already exists, assuming %s has already been upgraded\n", bak, filename);
+ g_free (bak);
+ return 0;
+ }
+
+ if (stat (filename, &st) == -1 || (fd = open (filename, O_RDONLY)) == -1) {
+ /* file doesn't exist? I guess nothing to upgrade here */
+ fprintf (stderr, "\nCould not open %s: %s\n", filename, strerror (errno));
+ g_free (bak);
+ return 0;
+ }
+
+ start = buffer = g_malloc (st.st_size + 1);
+ do {
+ do {
+ n = read (fd, buffer + nread, st.st_size - nread);
+ } while (n == -1 && errno == EINTR);
+
+ if (n > 0)
+ nread += n;
+ } while (n != -1 && nread < st.st_size);
+ buffer[nread] = '\0';
+
+ if (nread < st.st_size) {
+ /* failed to load the entire file? */
+ fprintf (stderr, "\nFailed to load %s: %s\n", filename, strerror (errno));
+ g_free (buffer);
+ g_free (bak);
+ close (fd);
+ return -1;
+ }
+
+ close (fd);
+
+ inptr = buffer;
+ url_need_upgrade = FALSE;
+ do {
+ inptr = strstr (inptr, "uri=\"");
+ if (inptr) {
+ inptr += 5;
+ url_need_upgrade = !strncmp (inptr, "imap:", 5) || !strncmp (inptr, "exchange:", 9);
+ }
+ } while (inptr && !url_need_upgrade);
+
+ if (inptr == NULL) {
+ /* no imap urls in this xml file, so no need to "upgrade" it */
+ fprintf (stdout, "\nNo updates required for %s\n", filename);
+ g_free (buffer);
+ g_free (bak);
+ return 0;
+ }
+
+ if (rename (filename, bak) == -1) {
+ /* failed to backup xml file */
+ fprintf (stderr, "\nFailed to create backup file %s: %s\n", bak, strerror (errno));
+ g_free (buffer);
+ g_free (bak);
+ return -1;
+ }
+
+ if ((fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) {
+ /* failed to create new xml file */
+ fprintf (stderr, "\nFailed to create new %s: %s\n", filename, strerror (errno));
+ rename (bak, filename);
+ g_free (buffer);
+ g_free (bak);
+ return -1;
+ }
+
+ while (inptr != NULL) {
+ len = inptr - start;
+ nwritten = 0;
+ do {
+ do {
+ n = write (fd, start + nwritten, len - nwritten);
+ } while (n == -1 && errno == EINTR);
+
+ if (n > 0)
+ nwritten += n;
+ } while (n != -1 && nwritten < len);
+
+ if (nwritten < len)
+ goto exception;
+
+ start = inptr;
+ while (*start && *start != '"')
+ start++;
+
+ uri = g_strndup (inptr, start - inptr);
+ if (!strncmp (uri, "imap:", 5)) {
+ if ((new = imap_url_upgrade (imap_sources, uri)) == NULL) {
+ new = uri;
+ uri = NULL;
+ }
+ } else if (!strncmp (uri, "exchange:", 9)) {
+ new = exchange_url_upgrade (uri);
+ } else {
+ new = uri;
+ uri = NULL;
+ }
+ g_free (uri);
+
+ nwritten = 0;
+ len = strlen (new);
+ do {
+ do {
+ n = write (fd, new + nwritten, len - nwritten);
+ } while (n == -1 && errno == EINTR);
+
+ if (n > 0)
+ nwritten += n;
+ } while (n != -1 && nwritten < len);
+
+ g_free (new);
+
+ if (nwritten < len)
+ goto exception;
+
+ inptr = start;
+ url_need_upgrade = FALSE;
+ do {
+ inptr = strstr (inptr, "uri=\"");
+ if (inptr) {
+ inptr += 5;
+ url_need_upgrade = !strncmp (inptr, "imap:", 5) || !strncmp (inptr, "exchange:", 9);
+ }
+ } while (inptr && !url_need_upgrade);
+ }
+
+ nwritten = 0;
+ len = strlen (start);
+ do {
+ do {
+ n = write (fd, start + nwritten, len - nwritten);
+ } while (n == -1 && errno == EINTR);
+
+ if (n > 0)
+ nwritten += n;
+ } while (n != -1 && nwritten < len);
+
+ if (nwritten < len)
+ goto exception;
+
+ if (fsync (fd) == -1)
+ goto exception;
+
+ close (fd);
+ g_free (buffer);
+
+ fprintf (stdout, "\nSuccessfully upgraded %s\nPrevious settings saved in %s\n\n", filename, bak);
+
+ g_free (bak);
+
+ return 0;
+
+ exception:
+
+ fprintf (stderr, "\nFailed to save updated settings to %s: %s\n\n", filename, strerror (errno));
+
+ close (fd);
+ g_free (buffer);
+ unlink (filename);
+ rename (bak, filename);
+ g_free (bak);
+
+ return -1;
+}
+
+static char *
+shortcuts_upgrade_uri (GHashTable *accounts, GHashTable *imap_sources, const char *account, const char *folder)
+{
+ char *url, *name, *decoded, *new = NULL;
+ struct _storeinfo *si;
+ int type;
+
+ type = GPOINTER_TO_INT ((si = g_hash_table_lookup (accounts, account)));
+ if (type == 1) {
+ /* exchange */
+ decoded = hex_decode (folder, strlen (folder));
+ name = g_strdup_printf ("personal/%s", decoded);
+ g_free (decoded);
+
+ return name;
+ } else {
+ /* imap */
+ url = g_strdup_printf ("%s/%s", si->base_url, folder);
+ new = imap_url_upgrade (imap_sources, url);
+ g_free (url);
+
+ if (new) {
+ name = new + strlen (si->base_url) + 1;
+ name = hex_decode (name, strlen (name));
+ g_free (new);
+
+ return name;
+ }
+ }
+
+ return NULL;
+}
+
+static int
+shortcuts_upgrade_xml_file (GHashTable *accounts, GHashTable *imap_sources, const char *filename)
+{
+ char *bak, *uri, *account, *folder, *new, *new_uri, *type;
+ struct stat st;
+ xmlDoc *doc;
+ xmlNode *group, *item;
+ int account_len;
+ gboolean changed = FALSE;
+
+ bak = g_strdup_printf ("%s.bak-1.0", filename);
+ if (stat (bak, &st) != -1) {
+ /* seems we have already converted this file? */
+ fprintf (stderr, "\n%s already exists, assuming %s has already been upgraded\n", bak, filename);
+ g_free (bak);
+ return 0;
+ }
+
+ if (stat (filename, &st) == -1) {
+ /* file doesn't exist? I guess nothing to upgrade here */
+ fprintf (stderr, "\nCould not open %s: %s\n", filename, strerror (errno));
+ g_free (bak);
+ return 0;
+ }
+
+ doc = xmlParseFile (filename);
+ if (!doc || !doc->xmlRootNode) {
+ /* failed to load/parse the file? */
+ fprintf (stderr, "\nFailed to load %s\n", filename);
+ g_free (bak);
+ return -1;
+ }
+
+ for (group = doc->xmlRootNode->xmlChildrenNode; group; group = group->next) {
+ for (item = group->xmlChildrenNode; item; item = item->next) {
+ /* Fix IMAP/Exchange URIs */
+ uri = xmlNodeGetContent (item);
+ if (!strncmp (uri, "evolution:/", 11)) {
+ if (!strcmp (uri, "evolution:/local/Inbox")) {
+ xmlNodeSetContent (item, "default:mail");
+ changed = TRUE;
+ } else if (!strcmp (uri, "evolution:/local/Calendar")) {
+ xmlNodeSetContent (item, "default:calendar");
+ changed = TRUE;
+ } else if (!strcmp (uri, "evolution:/local/Contacts")) {
+ xmlNodeSetContent (item, "default:contacts");
+ changed = TRUE;
+ } else if (!strcmp (uri, "evolution:/local/Tasks")) {
+ xmlNodeSetContent (item, "default:tasks");
+ changed = TRUE;
+ } else {
+ account_len = strcspn (uri + 11, "/");
+ account = g_strndup (uri + 11, account_len);
+ if (g_hash_table_lookup (accounts, account)) {
+ folder = uri + 11 + account_len;
+ if (*folder)
+ folder++;
+ new = shortcuts_upgrade_uri (accounts, imap_sources, account, folder);
+ new_uri = g_strdup_printf ("evolution:/%s/%s", account, new);
+ xmlNodeSetContent (item, new_uri);
+ changed = TRUE;
+ g_free (new_uri);
+ }
+ g_free (account);
+ }
+ }
+ xmlFree (uri);
+
+ /* Fix LDAP shortcuts */
+ type = xmlGetProp (item, "type");
+ if (type) {
+ if (!strcmp (type, "ldap-contacts")) {
+ xmlSetProp (item, "type", "contacts/ldap");
+ changed = TRUE;
+ }
+ xmlFree (type);
+ }
+ }
+ }
+
+ if (!changed) {
+ fprintf (stdout, "\nNo updates required for %s\n", filename);
+ xmlFreeDoc (doc);
+ g_free (bak);
+ return 0;
+ }
+
+ if (rename (filename, bak) == -1) {
+ /* failed to backup xml file */
+ fprintf (stderr, "\nFailed to create backup file %s: %s\n", bak, strerror (errno));
+ xmlFreeDoc (doc);
+ g_free (bak);
+ return -1;
+ }
+
+ if (e_xml_save_file (filename, doc) == -1) {
+ fprintf (stderr, "\nFailed to save updated settings to %s: %s\n\n", filename, strerror (errno));
+ xmlFreeDoc (doc);
+ unlink (filename);
+ rename (bak, filename);
+ g_free (bak);
+ return -1;
+ }
+
+ fprintf (stdout, "\nSuccessfully upgraded %s\nPrevious settings saved in %s\n\n", filename, bak);
+
+ xmlFreeDoc (doc);
+ g_free (bak);
+
+ return 0;
+}
+
+
+static int
+mailer_upgrade (Bonobo_ConfigDatabase db)
+{
+ GHashTable *imap_sources, *accounts;
+ char *path, *uri;
+ char *account, *transport;
+ int num, i;
+
+ if ((num = bonobo_config_get_long_with_default (db, "/Mail/Accounts/num", 0, NULL)) == 0) {
+ /* nothing to upgrade */
+ return 0;
+ }
+
+ accounts = g_hash_table_new (g_str_hash, g_str_equal);
+ imap_sources = g_hash_table_new (g_str_hash, g_str_equal);
+ for (i = 0; i < num; i++) {
+ struct _storeinfo *si;
+ struct stat st;
+ char *string;
+ guint32 tmp;
+ FILE *fp;
+ int j;
+
+ path = g_strdup_printf ("/Mail/Accounts/source_url_%d", i);
+ uri = bonobo_config_get_string (db, path, NULL);
+ g_free (path);
+ if (uri && !strncmp (uri, "imap:", 5)) {
+ path = g_strdup_printf ("/Mail/Accounts/account_name_%d", i);
+ account = bonobo_config_get_string (db, path, NULL);
+ g_free (path);
+
+ si = g_new (struct _storeinfo, 1);
+ si->base_url = get_base_url ("imap", uri);
+ si->namespace = imap_namespace (uri);
+ si->encoded_namespace = NULL;
+ si->dir_sep = '\0';
+ si->folders = NULL;
+
+ path = si->base_url + 7;
+
+ path = g_strdup_printf ("%s/evolution/mail/imap/%s/storeinfo", getenv ("HOME"), path);
+ if (stat (path, &st) != -1 && (fp = fopen (path, "r")) != NULL) {
+ camel_file_util_decode_uint32 (fp, &tmp);
+ camel_file_util_decode_uint32 (fp, &tmp);
+
+ j = 0;
+ si->folders = g_ptr_array_new ();
+ while (camel_file_util_decode_string (fp, &string) != -1) {
+ if (j++ > 0) {
+ g_ptr_array_add (si->folders, string);
+ } else {
+ if (!si->namespace)
+ si->namespace = string;
+ else
+ g_free (string);
+
+ camel_file_util_decode_uint32 (fp, &tmp);
+ si->dir_sep = (char) tmp & 0xff;
+ }
+ }
+
+ fclose (fp);
+ }
+ g_free (path);
+
+ if (si->folders && si->folders->len > 0)
+ si->dir_sep = find_dir_sep (si->folders->pdata[0]);
+
+ if (si->namespace) {
+ /* strip trailing dir_sep from namespace if it's there */
+ j = strlen (si->namespace) - 1;
+ if (si->namespace[j] == si->dir_sep)
+ si->namespace[j] = '\0';
+
+ /* set the encoded version of the namespace */
+ si->encoded_namespace = g_strdup (si->namespace);
+ for (j = 0; j < strlen (si->encoded_namespace); j++) {
+ if (si->encoded_namespace[j] == '/')
+ si->encoded_namespace[j] = '.';
+ }
+ }
+
+ g_hash_table_insert (imap_sources, si->base_url, si);
+
+ if (account)
+ g_hash_table_insert (accounts, account, si);
+ } else if (uri && !strncmp (uri, "exchange:", 9)) {
+ /* Upgrade transport uri */
+ path = g_strdup_printf ("/Mail/Accounts/transport_url_%d", i);
+ transport = bonobo_config_get_string (db, path, NULL);
+ if (transport && !strncmp (transport, "exchanget:", 10))
+ bonobo_config_set_string (db, path, uri, NULL);
+ g_free (transport);
+ g_free (path);
+
+ path = g_strdup_printf ("/Mail/Accounts/account_name_%d", i);
+ account = bonobo_config_get_string (db, path, NULL);
+ g_free (path);
+
+ if (account)
+ g_hash_table_insert (accounts, account, GINT_TO_POINTER (1));
+ }
+
+ g_free (uri);
+ }
+
+ if (g_hash_table_size (accounts) == 0) {
+ /* user doesn't have any imap/exchange accounts - nothing to upgrade */
+ g_hash_table_destroy (imap_sources);
+ return 0;
+ }
+
+ /* upgrade user's account info (bug #29135) */
+ mailer_upgrade_account_info (db, "drafts", num, imap_sources);
+ mailer_upgrade_account_info (db, "sent", num, imap_sources);
+
+ /* upgrade user's filters/vfolders (bug #24451) */
+ path = g_strdup_printf ("%s/evolution/filters.xml", getenv ("HOME"));
+ mailer_upgrade_xml_file (imap_sources, path);
+ g_free (path);
+
+ path = g_strdup_printf ("%s/evolution/vfolders.xml", getenv ("HOME"));
+ mailer_upgrade_xml_file (imap_sources, path);
+ g_free (path);
+
+ /* upgrade user's shortcuts (there's no bug # for this one) */
+ path = g_strdup_printf ("%s/evolution/shortcuts.xml", getenv ("HOME"));
+ shortcuts_upgrade_xml_file (accounts, imap_sources, path);
+ g_free (path);
+
+ g_hash_table_foreach (imap_sources, cache_upgrade_and_free, NULL);
+ g_hash_table_destroy (imap_sources);
+#if 0
+ path = g_strdup_printf ("%s/evolution/mail/imap", getenv ("HOME"));
+ bak = g_strdup_printf ("%s.bak-1.0", path);
+
+ if (rename (path, bak) == -1)
+ fprintf (stderr, "\nFailed to backup Evolution 1.0's IMAP cache: %s\n", strerror (errno));
+
+ g_free (path);
+ g_free (bak);
+#endif
+
+ return 0;
+}
+
+static Bonobo_ConfigDatabase
+get_config_db (void)
+{
+ Bonobo_ConfigDatabase db;
+ CORBA_Environment ev;
+
+ CORBA_exception_init (&ev);
+
+ db = bonobo_get_object ("wombat:", "Bonobo/ConfigDatabase", &ev);
+ if (BONOBO_EX (&ev) || db == CORBA_OBJECT_NIL) {
+ fprintf (stderr, "get_config_db(): Could not get the config database object '%s'",
+ bonobo_exception_get_text (&ev));
+ db = CORBA_OBJECT_NIL;
+ }
+
+ CORBA_exception_free (&ev);
+
+ return db;
+}
+
+static int
+upgrade (void)
+{
+ Bonobo_ConfigDatabase db;
+ CORBA_Environment ev;
+
+ if ((db = get_config_db ()) == CORBA_OBJECT_NIL)
+ g_error ("Could not get config db");
+
+ mailer_upgrade (db);
+
+ CORBA_exception_init (&ev);
+ Bonobo_ConfigDatabase_sync (db, &ev);
+
+ gtk_main_quit ();
+
+ return FALSE;
+}
+
+int main (int argc, char **argv)
+{
+ CORBA_ORB orb;
+
+ gnome_init ("evolution-upgrade", "1.0", argc, argv);
+
+ if ((orb = oaf_init (argc, argv)) == NULL)
+ g_error ("Cannot init oaf");
+
+ if (bonobo_init (orb, CORBA_OBJECT_NIL, CORBA_OBJECT_NIL) == FALSE)
+ g_error ("Cannot init bonobo");
+
+ gtk_idle_add ((GtkFunction) upgrade, NULL);
+
+ bonobo_main ();
+
+ return 0;
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9a4b6048ef..0df0336bbe 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -92,6 +92,7 @@ calendar/gui/dialogs/event-editor.c
calendar/gui/dialogs/event-page.c
calendar/gui/dialogs/event-page.glade
calendar/gui/dialogs/meeting-page.c
+calendar/gui/dialogs/meeting-page.etspec
calendar/gui/dialogs/meeting-page.glade
calendar/gui/dialogs/recur-comp.c
calendar/gui/dialogs/recurrence-page.c
@@ -118,6 +119,7 @@ calendar/gui/e-day-view-time-item.c
calendar/gui/e-day-view-top-item.c
calendar/gui/e-itip-control.c
calendar/gui/e-itip-control.glade
+calendar/gui/e-meeting-model.c
calendar/gui/e-meeting-time-sel.c
calendar/gui/e-meeting-time-sel.etspec
calendar/gui/e-meeting-time-sel-item.c
@@ -260,7 +262,10 @@ importers/evolution-gnomecard-importer.c
importers/netscape-importer.c
importers/pine-importer.c
mail/component-factory.c
+mail/folder-browser.c
mail/folder-browser-factory.c
+mail/folder-browser.h
+mail/folder-browser-ui.c
mail/folder-info.c
mail/GNOME_Evolution_Mail.server.in.in
mail/importers/elm-importer.c
@@ -275,27 +280,35 @@ mail/local-config.glade
mail/mail-account-editor.c
mail/mail-account-gui.c
mail/mail-accounts.c
+mail/mail-accounts.etspec
mail/mail-autofilter.c
+mail/mail-callbacks.c
mail/mail-composer-prefs.c
mail/mail-config.c
mail/mail-config-druid.c
mail/mail-config.glade
mail/mail-crypto.c
+mail/mail-display.c
mail/mail-folder-cache.c
+mail/mail-format.c
mail/mail-local.c
mail/mail-mt.c
mail/mail-ops.c
mail/mail-preferences.c
+mail/mail-search.c
mail/mail-send-recv.c
mail/mail-session.c
mail/mail-signature-editor.c
mail/mail-tools.c
mail/mail-vfolder.c
+mail/message-browser.c
mail/message-list.c
mail/message-list.etspec
mail/message-tag-editor.c
mail/message-tag-followup.c
mail/message-tags.glade
+mail/subscribe-dialog.c
+mail/subscribe-dialog.etspec
mail/subscribe-dialog.glade
my-evolution/component-factory.c
my-evolution/e-summary.c
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 886ae0f72c..d645236d05 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -3,6 +3,7 @@ addressbook/gui/widgets/test-minicard-view.c
addressbook/tools/evolution-addressbook-export-list-cards.c
addressbook/tools/evolution-addressbook-export-list-folders.c
addressbook/tools/evolution-addressbook-export.c
+camel/camel-pkcs7-context.c
camel/providers/nntp/camel-nntp-auth.c
camel/providers/nntp/camel-nntp-folder.c
camel/providers/nntp/camel-nntp-grouplist.c
diff --git a/po/am.po b/po/am.po
index 1d1bae1758..3c360a5599 100644
--- a/po/am.po
+++ b/po/am.po
@@ -7,201 +7,72 @@
msgid ""
msgstr ""
"Project-Id-Version: evolution 1.0\n"
-"POT-Creation-Date: 2003-10-15 23:45+0200\n"
+"POT-Creation-Date: 2003-06-25 13:24-0400\n"
"PO-Revision-Date: 2003-02-07 17:46+EDT\n"
"Last-Translator: Ge'ez Frontier Foundation <locales@geez.org>\n"
"Language-Team: Amharic <locales@geez.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Report-Msgid-Bugs-To: \n"
-#: addressbook/backend/ebook/e-card.c:1306
+#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in.h:1
+msgid "Evolution LDIF importer"
+msgstr ""
+
+#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in.h:2
+msgid "LDAP Data Interchange Format (.ldif)"
+msgstr ""
+
+#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in.h:1
+msgid "Evolution VCard Importer"
+msgstr ""
+
+#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in.h:2
+msgid "Evolution VCard importer"
+msgstr ""
+
+#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in.h:3
+msgid "VCard (.vcf, .gcrd)"
+msgstr ""
+
#: addressbook/backend/ebook/e-card-simple.c:60
+#: addressbook/backend/ebook/e-card.c:1306
#: addressbook/gui/widgets/e-addressbook-view.etspec.h:15
msgid "File As"
msgstr ""
-#: addressbook/backend/ebook/e-card.c:1313
-#: addressbook/gui/contact-editor/fullname.glade.h:4
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:17
-msgid "Full Name"
-msgstr "ሙሉ ስም"
-
-#: addressbook/backend/ebook/e-card.c:1320
#: addressbook/backend/ebook/e-card-simple.c:61
-#: addressbook/gui/component/select-names/e-select-names.etspec.h:1
+#: addressbook/backend/ebook/e-card.c:1320
#: addressbook/gui/component/select-names/e-select-names-section.etspec.h:1
+#: addressbook/gui/component/select-names/e-select-names.etspec.h:1
#: addressbook/gui/contact-editor/e-contact-editor-fullname.c:89
#: my-evolution/e-summary-table.c:59
msgid "Name"
msgstr "ስም"
-#: addressbook/backend/ebook/e-card.c:1326
-#: addressbook/gui/contact-editor/e-contact-editor-address.c:96
-msgid "Address"
-msgstr "አድራሻ"
-
-#: addressbook/backend/ebook/e-card.c:1333
-msgid "Address Label"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1340
-msgid "Phone"
-msgstr "ስልክ"
-
-#: addressbook/backend/ebook/e-card.c:1347
#: addressbook/backend/ebook/e-card-simple.c:62
+#: addressbook/backend/ebook/e-card.c:1347
#: addressbook/gui/widgets/e-addressbook-view.etspec.h:12
msgid "Email"
msgstr "ኢሜይል"
-#: addressbook/backend/ebook/e-card.c:1354
-msgid "Birth date"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1360
-#: calendar/gui/e-calendar-table.etspec.h:18
-msgid "URL"
-msgstr "URL"
-
-#: addressbook/backend/ebook/e-card.c:1367
-#: addressbook/backend/ebook/e-card-simple.c:69
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:28
-msgid "Organization"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1374
-msgid "Organizational Unit"
+#: addressbook/backend/ebook/e-card-simple.c:63
+#: addressbook/gui/contact-editor/e-contact-editor.c:1752
+msgid "Primary"
msgstr ""
-#: addressbook/backend/ebook/e-card.c:1381
-#: addressbook/backend/ebook/e-card-simple.c:90
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:27
-msgid "Office"
-msgstr "ቢሮ"
-
-#: addressbook/backend/ebook/e-card.c:1388
-#: addressbook/backend/ebook/e-card-simple.c:91
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:39
-msgid "Title"
-msgstr "አርእስት"
-
-#: addressbook/backend/ebook/e-card.c:1395
-#: calendar/gui/e-meeting-time-sel.etspec.h:9
-msgid "Role"
+#: addressbook/backend/ebook/e-card-simple.c:63
+msgid "Prim"
msgstr ""
-#: addressbook/backend/ebook/e-card.c:1402
-#: addressbook/backend/ebook/e-card-simple.c:93
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:23
-msgid "Manager"
-msgstr "መቆጣጠሪያ"
-
-#: addressbook/backend/ebook/e-card.c:1409
#: addressbook/backend/ebook/e-card-simple.c:64
#: addressbook/backend/ebook/e-card-simple.c:94
+#: addressbook/backend/ebook/e-card.c:1409
#: addressbook/gui/contact-editor/e-contact-editor.c:1737
#: addressbook/gui/widgets/e-addressbook-view.etspec.h:2
msgid "Assistant"
msgstr ""
-#: addressbook/backend/ebook/e-card.c:1416
-#: addressbook/backend/ebook/e-card-simple.c:95
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:25
-msgid "Nickname"
-msgstr "ቅጽል ስም"
-
-#: addressbook/backend/ebook/e-card.c:1423
-#: addressbook/backend/ebook/e-card-simple.c:96
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:36
-msgid "Spouse"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1430
-#: addressbook/backend/ebook/e-card-simple.c:101
-msgid "Anniversary"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1436
-msgid "Mailer"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1443
-#: addressbook/backend/ebook/e-card-simple.c:98
-msgid "Calendar URI"
-msgstr "የቀን መቁጠሪያ URI"
-
-#: addressbook/backend/ebook/e-card.c:1450
-msgid "Free/Busy URL"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1457
-#, fuzzy
-msgid "ICS Calendar"
-msgstr "ቀን መቁጠሪያ"
-
-#: addressbook/backend/ebook/e-card.c:1464
-#: addressbook/backend/ebook/e-card-simple.c:97
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:26
-msgid "Note"
-msgstr "ማስታወሻ"
-
-#: addressbook/backend/ebook/e-card.c:1471
-msgid "Related Contacts"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1478
-#: addressbook/backend/ebook/e-card-simple.c:105
-#: calendar/gui/e-calendar-table.etspec.h:4
-msgid "Categories"
-msgstr "ምድቦች"
-
-#: addressbook/backend/ebook/e-card.c:1485
-msgid "Category List"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1492
-msgid "Wants HTML"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1499
-msgid "Wants HTML set"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1506 ui/evolution-calendar.xml.h:16
-msgid "List"
-msgstr "ዝርዝር"
-
-#: addressbook/backend/ebook/e-card.c:1513
-msgid "List Show Addresses"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1520
-msgid "Arbitrary"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1527
-msgid "ID"
-msgstr "ID"
-
-#: addressbook/backend/ebook/e-card.c:1534
-msgid "Last Use"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card.c:1545
-msgid "Use Score"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card-simple.c:63
-#: addressbook/gui/contact-editor/e-contact-editor.c:1752
-msgid "Primary"
-msgstr ""
-
-#: addressbook/backend/ebook/e-card-simple.c:63
-msgid "Prim"
-msgstr ""
-
#: addressbook/backend/ebook/e-card-simple.c:65
#: addressbook/backend/ebook/e-card-simple.c:70
#: addressbook/gui/contact-editor/e-contact-editor.c:1738
@@ -236,6 +107,12 @@ msgid "Home"
msgstr "መጀመሪያ"
#: addressbook/backend/ebook/e-card-simple.c:69
+#: addressbook/backend/ebook/e-card.c:1367
+#: addressbook/gui/widgets/e-addressbook-view.etspec.h:28
+msgid "Organization"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card-simple.c:69
msgid "Org"
msgstr ""
@@ -354,9 +231,21 @@ msgid "Dep"
msgstr ""
#: addressbook/backend/ebook/e-card-simple.c:90
+#: addressbook/backend/ebook/e-card.c:1381
+#: addressbook/gui/widgets/e-addressbook-view.etspec.h:27
+msgid "Office"
+msgstr "ቢሮ"
+
+#: addressbook/backend/ebook/e-card-simple.c:90
msgid "Off"
msgstr "አጥፋ"
+#: addressbook/backend/ebook/e-card-simple.c:91
+#: addressbook/backend/ebook/e-card.c:1388
+#: addressbook/gui/widgets/e-addressbook-view.etspec.h:39
+msgid "Title"
+msgstr "አርእስት"
+
#: addressbook/backend/ebook/e-card-simple.c:92
#: addressbook/gui/widgets/e-addressbook-view.etspec.h:34
msgid "Profession"
@@ -367,6 +256,12 @@ msgid "Prof"
msgstr ""
#: addressbook/backend/ebook/e-card-simple.c:93
+#: addressbook/backend/ebook/e-card.c:1402
+#: addressbook/gui/widgets/e-addressbook-view.etspec.h:23
+msgid "Manager"
+msgstr "መቆጣጠሪያ"
+
+#: addressbook/backend/ebook/e-card-simple.c:93
msgid "Man"
msgstr ""
@@ -375,9 +270,32 @@ msgid "Ass"
msgstr ""
#: addressbook/backend/ebook/e-card-simple.c:95
+#: addressbook/backend/ebook/e-card.c:1416
+#: addressbook/gui/widgets/e-addressbook-view.etspec.h:25
+msgid "Nickname"
+msgstr "ቅጽል ስም"
+
+#: addressbook/backend/ebook/e-card-simple.c:95
msgid "Nick"
msgstr "ቅጽል"
+#: addressbook/backend/ebook/e-card-simple.c:96
+#: addressbook/backend/ebook/e-card.c:1423
+#: addressbook/gui/widgets/e-addressbook-view.etspec.h:36
+msgid "Spouse"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card-simple.c:97
+#: addressbook/backend/ebook/e-card.c:1464
+#: addressbook/gui/widgets/e-addressbook-view.etspec.h:26
+msgid "Note"
+msgstr "ማስታወሻ"
+
+#: addressbook/backend/ebook/e-card-simple.c:98
+#: addressbook/backend/ebook/e-card.c:1443
+msgid "Calendar URI"
+msgstr "የቀን መቁጠሪያ URI"
+
#: addressbook/backend/ebook/e-card-simple.c:98
msgid "CALUri"
msgstr ""
@@ -401,6 +319,11 @@ msgid "icsCalendar"
msgstr "ቀን መቁጠሪያ"
#: addressbook/backend/ebook/e-card-simple.c:101
+#: addressbook/backend/ebook/e-card.c:1430
+msgid "Anniversary"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card-simple.c:101
msgid "Anniv"
msgstr ""
@@ -408,6 +331,12 @@ msgstr ""
msgid "Birth Date"
msgstr ""
+#: addressbook/backend/ebook/e-card-simple.c:105
+#: addressbook/backend/ebook/e-card.c:1478
+#: calendar/gui/e-calendar-table.etspec.h:4
+msgid "Categories"
+msgstr "ምድቦች"
+
#: addressbook/backend/ebook/e-card-simple.c:106
msgid "Family Name"
msgstr "የቤተሰብ ስም"
@@ -422,30 +351,107 @@ msgid "%x"
msgstr "%x"
#: addressbook/backend/ebook/e-card-simple.c:912
-#: addressbook/backend/ebook/e-destination.c:709
+#: addressbook/backend/ebook/e-destination.c:706
msgid "Unnamed List"
msgstr ""
-#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in.h:1
-msgid "Evolution LDIF importer"
+#: addressbook/backend/ebook/e-card.c:1313
+#: addressbook/gui/contact-editor/fullname.glade.h:4
+#: addressbook/gui/widgets/e-addressbook-view.etspec.h:17
+msgid "Full Name"
+msgstr "ሙሉ ስም"
+
+#: addressbook/backend/ebook/e-card.c:1326
+#: addressbook/gui/contact-editor/e-contact-editor-address.c:96
+msgid "Address"
+msgstr "አድራሻ"
+
+#: addressbook/backend/ebook/e-card.c:1333
+msgid "Address Label"
msgstr ""
-#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in.h:2
-msgid "LDAP Data Interchange Format (.ldif)"
+#: addressbook/backend/ebook/e-card.c:1340
+msgid "Phone"
+msgstr "ስልክ"
+
+#: addressbook/backend/ebook/e-card.c:1354
+msgid "Birth date"
msgstr ""
-#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in.h:1
-msgid "Evolution VCard Importer"
+#: addressbook/backend/ebook/e-card.c:1360
+#: calendar/gui/e-calendar-table.etspec.h:19
+msgid "URL"
+msgstr "URL"
+
+#: addressbook/backend/ebook/e-card.c:1374
+msgid "Organizational Unit"
msgstr ""
-#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in.h:2
-msgid "Evolution VCard importer"
+#: addressbook/backend/ebook/e-card.c:1395
+#: calendar/gui/dialogs/meeting-page.etspec.h:9
+#: calendar/gui/e-meeting-time-sel.etspec.h:9
+msgid "Role"
msgstr ""
-#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in.h:3
-msgid "VCard (.vcf, .gcrd)"
+#: addressbook/backend/ebook/e-card.c:1436 mail/mail-format.c:963
+msgid "Mailer"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card.c:1450
+msgid "Free/Busy URL"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card.c:1457
+#, fuzzy
+msgid "ICS Calendar"
+msgstr "ቀን መቁጠሪያ"
+
+#: addressbook/backend/ebook/e-card.c:1471
+msgid "Related Contacts"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card.c:1485
+msgid "Category List"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card.c:1492
+msgid "Wants HTML"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card.c:1499
+msgid "Wants HTML set"
msgstr ""
+#: addressbook/backend/ebook/e-card.c:1506
+msgid "List"
+msgstr "ዝርዝር"
+
+#: addressbook/backend/ebook/e-card.c:1513
+msgid "List Show Addresses"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card.c:1520
+msgid "Arbitrary"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card.c:1527
+msgid "ID"
+msgstr "ID"
+
+#: addressbook/backend/ebook/e-card.c:1534
+msgid "Last Use"
+msgstr ""
+
+#: addressbook/backend/ebook/e-card.c:1545
+msgid "Use Score"
+msgstr ""
+
+#: addressbook/backend/ebook/test-client-list.c:15
+#: addressbook/backend/ebook/test-client.c:33
+#: calendar/gui/alarm-notify/notify-main.c:171
+msgid "Could not initialize Bonobo"
+msgstr "bonobo ማስጀመር አልቻልኩም!"
+
#: addressbook/backend/pas/pas-backend-file.c:464
#: addressbook/backend/pas/pas-backend-ldap.c:3050
msgid "Searching..."
@@ -501,14 +507,14 @@ msgid "EBook not loaded\n"
msgstr ""
#: addressbook/conduit/address-conduit.c:1376
-#: calendar/conduits/calendar/calendar-conduit.c:1351
-#: calendar/conduits/todo/todo-conduit.c:893
+#: calendar/conduits/calendar/calendar-conduit.c:1342
+#: calendar/conduits/todo/todo-conduit.c:884
msgid "Could not start wombat server"
msgstr ""
#: addressbook/conduit/address-conduit.c:1377
-#: calendar/conduits/calendar/calendar-conduit.c:1352
-#: calendar/conduits/todo/todo-conduit.c:894
+#: calendar/conduits/calendar/calendar-conduit.c:1343
+#: calendar/conduits/todo/todo-conduit.c:885
msgid "Could not start wombat"
msgstr ""
@@ -517,6 +523,137 @@ msgstr ""
msgid "Could not read pilot's Address application block"
msgstr ""
+#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:1
+msgid "Configure access to LDAP directory servers here"
+msgstr ""
+
+#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:2
+msgid "Directory Servers"
+msgstr ""
+
+#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:3
+msgid "Evolution Addressbook"
+msgstr ""
+
+#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:4
+msgid "Evolution Addressbook LDAP Configuration Control"
+msgstr ""
+
+#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:5
+msgid "Evolution Addressbook address pop-up"
+msgstr ""
+
+#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:6
+msgid "Evolution Addressbook address viewer"
+msgstr ""
+
+#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:7
+msgid "Evolution Addressbook card viewer"
+msgstr ""
+
+#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:8
+msgid "Evolution Addressbook component"
+msgstr ""
+
+#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:9
+msgid "Evolution Addressbook folder viewer"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:76
+#: addressbook/gui/component/addressbook-component.c:620
+#: importers/netscape-importer.c:1874 mail/importers/netscape-importer.c:1844
+#: shell/e-local-storage.c:178 shell/e-shortcuts.c:1087
+msgid "Contacts"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:76
+msgid "Folder containing contact information"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:78
+msgid "LDAP Server"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:78
+msgid "LDAP server containing contact information"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:80
+msgid "Public Contacts"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:80
+msgid "Public folder containing contact information"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:574
+msgid "New Contact"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:574
+msgid "_Contact"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:575
+msgid "Create a new contact"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:578
+msgid "New Contact List"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:578
+msgid "Contact _List"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-component.c:579
+msgid "Create a new contact list"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-config.c:206
+msgid "Failed to connect to LDAP server"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-config.c:231
+msgid "Failed to authenticate with LDAP server"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-config.c:259
+msgid "Could not perform query on Root DSE"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-config.c:682
+msgid "The server responded with no supported search bases"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-config.c:1193
+msgid "This server does not support LDAPv3 schema information"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-config.c:1215
+msgid "Error retrieving schema information"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-config.c:1223
+msgid "Server did not respond with valid schema information"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-config.c:1637
+msgid "Account Name"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-config.c:1639
+msgid "Server Name"
+msgstr "የሰርቨር ስም"
+
+#: addressbook/gui/component/addressbook-config.c:1676
+msgid "LDAP was not enabled in this build of Evolution"
+msgstr ""
+
+#: addressbook/gui/component/addressbook-storage.c:178
+msgid "Other Contacts"
+msgstr ""
+
#: addressbook/gui/component/addressbook.c:502
msgid ""
"We were unable to open this addressbook. Please check that the\n"
@@ -624,101 +761,6 @@ msgstr ""
msgid "The URI that the Folder Browser will display"
msgstr ""
-#: addressbook/gui/component/addressbook-component.c:76
-#: addressbook/gui/component/addressbook-component.c:628
-#: importers/netscape-importer.c:1874 mail/importers/netscape-importer.c:1844
-#: shell/e-local-storage.c:178 shell/e-shortcuts.c:1087
-msgid "Contacts"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:76
-msgid "Folder containing contact information"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:78
-msgid "LDAP Server"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:78
-msgid "LDAP server containing contact information"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:80
-msgid "Public Contacts"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:80
-msgid "Public folder containing contact information"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:582
-msgid "New Contact"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:582
-msgid "_Contact"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:583
-msgid "Create a new contact"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:586
-msgid "New Contact List"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:586
-msgid "Contact _List"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-component.c:587
-msgid "Create a new contact list"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-config.c:206
-msgid "Failed to connect to LDAP server"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-config.c:231
-msgid "Failed to authenticate with LDAP server"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-config.c:259
-msgid "Could not perform query on Root DSE"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-config.c:682
-msgid "The server responded with no supported search bases"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-config.c:1193
-msgid "This server does not support LDAPv3 schema information"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-config.c:1215
-msgid "Error retrieving schema information"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-config.c:1223
-msgid "Server did not respond with valid schema information"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-config.c:1637
-msgid "Account Name"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-config.c:1639
-msgid "Server Name"
-msgstr "የሰርቨር ስም"
-
-#: addressbook/gui/component/addressbook-config.c:1676
-msgid "LDAP was not enabled in this build of Evolution"
-msgstr ""
-
-#: addressbook/gui/component/addressbook-storage.c:178
-msgid "Other Contacts"
-msgstr ""
-
#.
#. * This is the code for the UI thingie that lets you manipulate the e-mail
#. * addresses (and *only* the e-mail addresses) associated with an existing
@@ -747,69 +789,33 @@ msgstr ""
msgid "Add address to existing contact \"%s\""
msgstr ""
-#: addressbook/gui/component/e-address-popup.c:917
+#: addressbook/gui/component/e-address-popup.c:914
msgid "Querying Addressbook..."
msgstr ""
-#: addressbook/gui/component/e-address-popup.c:1001
-#: addressbook/gui/component/e-address-widget.c:401
+#: addressbook/gui/component/e-address-popup.c:998
+#: addressbook/gui/component/e-address-widget.c:392
msgid "Edit Contact Info"
msgstr ""
-#: addressbook/gui/component/e-address-popup.c:1031
-#: addressbook/gui/component/e-address-widget.c:437
+#: addressbook/gui/component/e-address-popup.c:1028
+#: addressbook/gui/component/e-address-widget.c:428
#: addressbook/gui/component/select-names/e-select-names-popup.c:324
msgid "Add to Contacts"
msgstr ""
-#: addressbook/gui/component/e-address-popup.c:1056
+#: addressbook/gui/component/e-address-popup.c:1053
msgid "Merge E-Mail Address"
msgstr ""
-#: addressbook/gui/component/e-address-widget.c:378
+#: addressbook/gui/component/e-address-widget.c:369
msgid "Disable Queries"
msgstr ""
-#: addressbook/gui/component/e-address-widget.c:378
+#: addressbook/gui/component/e-address-widget.c:369
msgid "Enable Queries (Dangerous!)"
msgstr ""
-#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:1
-msgid "Configure access to LDAP directory servers here"
-msgstr ""
-
-#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:2
-msgid "Directory Servers"
-msgstr ""
-
-#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:3
-msgid "Evolution Addressbook"
-msgstr ""
-
-#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:4
-msgid "Evolution Addressbook LDAP Configuration Control"
-msgstr ""
-
-#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:5
-msgid "Evolution Addressbook address pop-up"
-msgstr ""
-
-#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:6
-msgid "Evolution Addressbook address viewer"
-msgstr ""
-
-#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:7
-msgid "Evolution Addressbook card viewer"
-msgstr ""
-
-#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:8
-msgid "Evolution Addressbook component"
-msgstr ""
-
-#: addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in.h:9
-msgid "Evolution Addressbook folder viewer"
-msgstr ""
-
#: addressbook/gui/component/ldap-config.glade.h:1
#: addressbook/gui/contact-list-editor/contact-list-editor.glade.h:1
#: mail/mail-config.glade.h:1
@@ -949,9 +955,10 @@ msgstr "አንድ"
msgid "S_earch scope: "
msgstr ""
+#. No time range is set, so don't start a query
#: addressbook/gui/component/ldap-config.glade.h:34
-#: calendar/gui/e-cal-view.c:541 calendar/gui/e-day-view.c:3261
-#: calendar/gui/e-week-view.c:1181 calendar/gui/gnome-cal.c:625
+#: calendar/gui/calendar-model.c:1983 calendar/gui/e-day-view.c:1712
+#: calendar/gui/e-week-view.c:1256
msgid "Searching"
msgstr ""
@@ -1134,11 +1141,11 @@ msgstr ""
#: addressbook/gui/component/ldap-config.glade.h:85 filter/filter.glade.h:14
#: mail/mail-config.glade.h:143 ui/evolution-addressbook.xml.h:33
-#: ui/evolution-calendar.xml.h:35 ui/evolution-composer-entries.xml.h:8
-#: ui/evolution-mail-list.xml.h:24 ui/evolution-mail-messagedisplay.xml.h:6
+#: ui/evolution-calendar.xml.h:31 ui/evolution-composer-entries.xml.h:8
+#: ui/evolution-mail-list.xml.h:25 ui/evolution-mail-messagedisplay.xml.h:6
#: ui/evolution-message-composer.xml.h:41
-#: ui/evolution-signature-editor.xml.h:12 ui/evolution-subscribe.xml.h:10
-#: ui/evolution-tasks.xml.h:19
+#: ui/evolution-signature-editor.xml.h:11 ui/evolution-subscribe.xml.h:10
+#: ui/evolution-tasks.xml.h:17
msgid "_Edit"
msgstr "አስተካክል"
@@ -1178,24 +1185,20 @@ msgstr ""
msgid "searching-tab"
msgstr ""
-#: addressbook/gui/component/select-names/e-select-names.c:509
-msgid "Select Contacts from Addressbook"
+#: addressbook/gui/component/select-names/GNOME_Evolution_Addressbook_SelectNames.server.in.in.h:1
+msgid "Evolution Addressbook name selection interface"
msgstr ""
-#: addressbook/gui/component/select-names/e-select-names.c:650
-msgid "Find contact in"
-msgstr ""
+#: addressbook/gui/component/select-names/e-select-names-popup.c:204
+msgid "Remove All"
+msgstr "ሁሉንም አስወግድ"
-#: addressbook/gui/component/select-names/e-select-names.c:694
#: addressbook/gui/component/select-names/e-select-names-popup.c:211
-#: composer/e-msg-composer-attachment-bar.c:444
+#: addressbook/gui/component/select-names/e-select-names.c:694
+#: composer/e-msg-composer-attachment-bar.c:507
msgid "Remove"
msgstr "አስወግድ"
-#: addressbook/gui/component/select-names/e-select-names-popup.c:204
-msgid "Remove All"
-msgstr "ሁሉንም አስወግድ"
-
#: addressbook/gui/component/select-names/e-select-names-popup.c:218
msgid "View Contact List"
msgstr ""
@@ -1218,8 +1221,12 @@ msgstr ""
msgid "Source"
msgstr "ምንጭ"
-#: addressbook/gui/component/select-names/GNOME_Evolution_Addressbook_SelectNames.server.in.in.h:1
-msgid "Evolution Addressbook name selection interface"
+#: addressbook/gui/component/select-names/e-select-names.c:509
+msgid "Select Contacts from Addressbook"
+msgstr ""
+
+#: addressbook/gui/component/select-names/e-select-names.c:650
+msgid "Find contact in"
msgstr ""
#: addressbook/gui/component/select-names/select-names.glade.h:2
@@ -1292,7 +1299,7 @@ msgid "D_epartment:"
msgstr ""
#: addressbook/gui/contact-editor/contact-editor.glade.h:11
-#: calendar/gui/dialogs/task-editor.c:200
+#: calendar/gui/dialogs/task-editor.c:197
msgid "Details"
msgstr "ዝርዝሮች"
@@ -1358,13 +1365,11 @@ msgid "_Categories..."
msgstr "ምድብ... (_T)"
#: addressbook/gui/contact-editor/contact-editor.glade.h:28
-#: calendar/gui/dialogs/meeting-page.c:634
-#: calendar/gui/e-calendar-table.c:1008 calendar/gui/e-calendar-table.c:1026
-#: calendar/gui/e-cal-view.c:1144 calendar/gui/e-cal-view.c:1176
-#: ui/evolution-addressbook.xml.h:32 ui/evolution-calendar.xml.h:34
-#: ui/evolution-comp-editor.xml.h:17 ui/evolution-contact-editor.xml.h:14
-#: ui/evolution-mail-message.xml.h:104 ui/evolution-tasks.xml.h:18
-#: ui/evolution.xml.h:45
+#: calendar/gui/dialogs/meeting-page.c:717 calendar/gui/e-calendar-table.c:977
+#: calendar/gui/e-day-view.c:3755 calendar/gui/e-week-view.c:3631
+#: mail/folder-browser.c:1790 ui/evolution-addressbook.xml.h:32
+#: ui/evolution-calendar.xml.h:30 ui/evolution-mail-message.xml.h:97
+#: ui/evolution-tasks.xml.h:16 ui/evolution.xml.h:45
msgid "_Delete"
msgstr "አጥፉ"
@@ -1408,15 +1413,15 @@ msgid "_Web page address:"
msgstr ""
#: addressbook/gui/contact-editor/e-contact-editor-address.c:102
-#: addressbook/gui/contact-editor/e-contact-editor.c:184
#: addressbook/gui/contact-editor/e-contact-editor-fullname.c:95
+#: addressbook/gui/contact-editor/e-contact-editor.c:184
#: addressbook/gui/contact-list-editor/e-contact-list-editor.c:163
#: addressbook/gui/widgets/e-addressbook-model.c:318
-#: addressbook/gui/widgets/e-addressbook-reflow-adapter.c:408
-#: addressbook/gui/widgets/e-minicard.c:183
+#: addressbook/gui/widgets/e-addressbook-reflow-adapter.c:393
#: addressbook/gui/widgets/e-minicard-label.c:164
-#: addressbook/gui/widgets/e-minicard-view.c:478
#: addressbook/gui/widgets/e-minicard-view-widget.c:120
+#: addressbook/gui/widgets/e-minicard-view.c:478
+#: addressbook/gui/widgets/e-minicard.c:183
msgid "Editable"
msgstr ""
@@ -2444,17 +2449,17 @@ msgstr "ዚምቧቤ"
#: addressbook/gui/contact-editor/e-contact-editor.c:156
#: addressbook/gui/contact-list-editor/e-contact-list-editor.c:142
#: addressbook/gui/widgets/e-addressbook-model.c:304
-#: addressbook/gui/widgets/e-addressbook-reflow-adapter.c:394
+#: addressbook/gui/widgets/e-addressbook-reflow-adapter.c:379
#: addressbook/gui/widgets/e-addressbook-view.c:180
-#: addressbook/gui/widgets/e-minicard-view.c:464
#: addressbook/gui/widgets/e-minicard-view-widget.c:106
+#: addressbook/gui/widgets/e-minicard-view.c:464
msgid "Book"
msgstr ""
#: addressbook/gui/contact-editor/e-contact-editor.c:163
#: addressbook/gui/contact-list-editor/e-contact-list-editor.c:149
-#: addressbook/gui/widgets/e-minicard.c:190
#: addressbook/gui/widgets/e-minicard-widget.c:93
+#: addressbook/gui/widgets/e-minicard.c:190
msgid "Card"
msgstr ""
@@ -2675,7 +2680,7 @@ msgstr ""
msgid "Contact List Editor"
msgstr ""
-#: addressbook/gui/contact-list-editor/e-contact-list-editor.c:457
+#: addressbook/gui/contact-list-editor/e-contact-list-editor.c:456
msgid "Save List as VCard"
msgstr ""
@@ -2717,7 +2722,7 @@ msgid ""
msgstr ""
#. FIXME: get the toplevel window...
-#: addressbook/gui/search/e-addressbook-search-dialog.c:116
+#: addressbook/gui/search/e-addressbook-search-dialog.c:117
#: widgets/misc/e-filter-bar.c:148
msgid "Advanced Search"
msgstr ""
@@ -2736,10 +2741,10 @@ msgid "%d cards"
msgstr ""
#: addressbook/gui/widgets/e-addressbook-model.c:311
-#: addressbook/gui/widgets/e-addressbook-reflow-adapter.c:401
+#: addressbook/gui/widgets/e-addressbook-reflow-adapter.c:386
#: addressbook/gui/widgets/e-addressbook-view.c:187
-#: addressbook/gui/widgets/e-minicard-view.c:471
#: addressbook/gui/widgets/e-minicard-view-widget.c:113
+#: addressbook/gui/widgets/e-minicard-view.c:471
msgid "Query"
msgstr ""
@@ -2747,244 +2752,245 @@ msgstr ""
msgid "Error getting book view"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-reflow-adapter.c:415
+#: addressbook/gui/widgets/e-addressbook-reflow-adapter.c:400
msgid "Model"
msgstr "ሞዴል"
-#: addressbook/gui/widgets/e-addressbook-table-adapter.c:148
-#: addressbook/gui/widgets/e-addressbook-util.c:106
+#: addressbook/gui/widgets/e-addressbook-table-adapter.c:145
+#: addressbook/gui/widgets/e-addressbook-util.c:105
#: addressbook/gui/widgets/e-minicard.c:531
msgid "Error modifying card"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:37
-#: shell/evolution-shell-component.c:1183
+#: addressbook/gui/widgets/e-addressbook-util.c:36
+#: shell/evolution-shell-component.c:1180
msgid "Success"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:38
+#: addressbook/gui/widgets/e-addressbook-util.c:37
#: camel/providers/imap/camel-imap-command.c:306
#: camel/providers/imap/camel-imap-command.c:403
#: camel/providers/pop3/camel-pop3-store.c:526
#: camel/providers/pop3/camel-pop3-store.c:533 shell/e-shell.c:2077
-#: shell/e-storage.c:598 shell/evolution-shell-component.c:1222
+#: shell/e-storage.c:598 shell/evolution-shell-component.c:1219
msgid "Unknown error"
msgstr "ያልታወቀ ስህተት"
-#: addressbook/gui/widgets/e-addressbook-util.c:39
+#: addressbook/gui/widgets/e-addressbook-util.c:38
msgid "Repository offline"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:40 shell/e-storage.c:584
-#: shell/evolution-shell-component.c:1213
+#: addressbook/gui/widgets/e-addressbook-util.c:39 shell/e-storage.c:584
+#: shell/evolution-shell-component.c:1210
msgid "Permission denied"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:41
+#: addressbook/gui/widgets/e-addressbook-util.c:40
msgid "Card not found"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:42
+#: addressbook/gui/widgets/e-addressbook-util.c:41
msgid "Card ID already exists"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:43
+#: addressbook/gui/widgets/e-addressbook-util.c:42
msgid "Protocol not supported"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:44
+#: addressbook/gui/widgets/e-addressbook-util.c:43
+#: calendar/gui/calendar-model.c:759 calendar/gui/calendar-model.c:1184
#: calendar/gui/dialogs/task-details-page.glade.h:3
-#: calendar/gui/e-calendar-table.c:479 calendar/gui/e-cal-model-tasks.c:325
-#: calendar/gui/e-cal-model-tasks.c:604 calendar/gui/e-tasks.c:253
-#: calendar/gui/print.c:2314 camel/camel-service.c:733
-#: camel/camel-service.c:771 camel/camel-service.c:855
-#: camel/camel-service.c:895 camel/providers/pop3/camel-pop3-store.c:443
+#: calendar/gui/e-calendar-table.c:477 calendar/gui/print.c:2307
+#: camel/camel-service.c:745 camel/camel-service.c:785
+#: camel/camel-service.c:875 camel/camel-service.c:917
+#: camel/providers/pop3/camel-pop3-store.c:443
#: camel/providers/pop3/camel-pop3-store.c:520
msgid "Cancelled"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:45
+#: addressbook/gui/widgets/e-addressbook-util.c:44
msgid "Authentication Failed"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:46
+#: addressbook/gui/widgets/e-addressbook-util.c:45
msgid "Authentication Required"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:47
+#: addressbook/gui/widgets/e-addressbook-util.c:46
msgid "TLS not Available"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:48
+#: addressbook/gui/widgets/e-addressbook-util.c:47
msgid "Addressbook does not exist"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:49
+#: addressbook/gui/widgets/e-addressbook-util.c:48
msgid "Other error"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:76
+#: addressbook/gui/widgets/e-addressbook-util.c:75
msgid "Do you want to save changes?"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:78
+#: addressbook/gui/widgets/e-addressbook-util.c:77
msgid "_Discard"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:97
+#: addressbook/gui/widgets/e-addressbook-util.c:96
msgid "Error adding list"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:97
-#: addressbook/gui/widgets/e-addressbook-util.c:273
+#: addressbook/gui/widgets/e-addressbook-util.c:96
+#: addressbook/gui/widgets/e-addressbook-util.c:272
msgid "Error adding card"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:106
+#: addressbook/gui/widgets/e-addressbook-util.c:105
msgid "Error modifying list"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:116
+#: addressbook/gui/widgets/e-addressbook-util.c:115
msgid "Error removing list"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:116
-#: addressbook/gui/widgets/e-addressbook-util.c:231
+#: addressbook/gui/widgets/e-addressbook-util.c:115
+#: addressbook/gui/widgets/e-addressbook-util.c:230
msgid "Error removing card"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:198
+#: addressbook/gui/widgets/e-addressbook-util.c:197
#, c-format
msgid ""
"Opening %d cards will open %d new windows as well.\n"
"Do you really want to display all of these cards?"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:329
+#: addressbook/gui/widgets/e-addressbook-util.c:328
msgid "Move card to"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:331
+#: addressbook/gui/widgets/e-addressbook-util.c:330
msgid "Copy card to"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:334
+#: addressbook/gui/widgets/e-addressbook-util.c:333
msgid "Move cards to"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:336
+#: addressbook/gui/widgets/e-addressbook-util.c:335
msgid "Copy cards to"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:518
+#: addressbook/gui/widgets/e-addressbook-util.c:517
msgid "Multiple VCards"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-util.c:526
+#: addressbook/gui/widgets/e-addressbook-util.c:525
#, c-format
msgid "VCard for %s"
msgstr ""
#: addressbook/gui/widgets/e-addressbook-view.c:194
-#: calendar/gui/e-calendar-table.etspec.h:17
+#: calendar/gui/dialogs/meeting-page.etspec.h:11
+#: calendar/gui/e-calendar-table.etspec.h:18
#: calendar/gui/e-meeting-time-sel.etspec.h:11
msgid "Type"
msgstr "ዓይነት"
-#: addressbook/gui/widgets/e-addressbook-view.c:398
+#: addressbook/gui/widgets/e-addressbook-view.c:394
#: importers/evolution-gnomecard-importer.c:228 importers/pine-importer.c:642
#: mail/importers/pine-importer.c:577
msgid "Addressbook"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:680
-#: addressbook/gui/widgets/e-addressbook-view.c:899
-#: addressbook/gui/widgets/e-addressbook-view.c:1883
+#: addressbook/gui/widgets/e-addressbook-view.c:676
+#: addressbook/gui/widgets/e-addressbook-view.c:895
+#: addressbook/gui/widgets/e-addressbook-view.c:1879
#: ui/evolution-addressbook.xml.h:19
msgid "Save as VCard"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:886
+#: addressbook/gui/widgets/e-addressbook-view.c:882
msgid "New Contact..."
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:887
+#: addressbook/gui/widgets/e-addressbook-view.c:883
msgid "New Contact List..."
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:890
+#: addressbook/gui/widgets/e-addressbook-view.c:886
msgid "Go to Folder..."
msgstr "ወደ ዶሴን ሂዱ..."
-#: addressbook/gui/widgets/e-addressbook-view.c:891
+#: addressbook/gui/widgets/e-addressbook-view.c:887
msgid "Import..."
msgstr "ከውጭ አስገባ"
-#: addressbook/gui/widgets/e-addressbook-view.c:893
+#: addressbook/gui/widgets/e-addressbook-view.c:889
msgid "Search for Contacts..."
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:894
+#: addressbook/gui/widgets/e-addressbook-view.c:890
msgid "Addressbook Sources..."
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:896
+#: addressbook/gui/widgets/e-addressbook-view.c:892
msgid "Pilot Settings..."
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:900
+#: addressbook/gui/widgets/e-addressbook-view.c:896
#: ui/evolution-addressbook.xml.h:10
msgid "Forward Contact"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:901
+#: addressbook/gui/widgets/e-addressbook-view.c:897
msgid "Send Message to Contact"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:902 calendar/gui/print.c:2446
+#: addressbook/gui/widgets/e-addressbook-view.c:898 calendar/gui/print.c:2439
#: ui/evolution-addressbook.xml.h:16 ui/evolution-comp-editor.xml.h:8
-#: ui/evolution-contact-editor.xml.h:5 ui/evolution-mail-message.xml.h:72
+#: ui/evolution-contact-editor.xml.h:4 ui/evolution-mail-message.xml.h:67
#: ui/my-evolution.xml.h:1
msgid "Print"
msgstr "አትም"
-#: addressbook/gui/widgets/e-addressbook-view.c:904
+#: addressbook/gui/widgets/e-addressbook-view.c:900
msgid "Print Envelope"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:908
+#: addressbook/gui/widgets/e-addressbook-view.c:904
msgid "Copy to folder..."
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:909
+#: addressbook/gui/widgets/e-addressbook-view.c:905
msgid "Move to folder..."
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:912
+#: addressbook/gui/widgets/e-addressbook-view.c:908
#: ui/evolution-addressbook.xml.h:6 ui/evolution-tasks.xml.h:4
msgid "Cut"
msgstr "ቁረጥ"
-#: addressbook/gui/widgets/e-addressbook-view.c:913
-#: ui/evolution-addressbook.xml.h:2 ui/evolution-mail-message.xml.h:9
+#: addressbook/gui/widgets/e-addressbook-view.c:909
+#: ui/evolution-addressbook.xml.h:2 ui/evolution-mail-message.xml.h:8
#: ui/evolution-tasks.xml.h:2
msgid "Copy"
msgstr "ቅጂ"
-#: addressbook/gui/widgets/e-addressbook-view.c:914
-#: ui/evolution-addressbook.xml.h:13 ui/evolution-tasks.xml.h:10
+#: addressbook/gui/widgets/e-addressbook-view.c:910
+#: ui/evolution-addressbook.xml.h:13 ui/evolution-tasks.xml.h:9
msgid "Paste"
msgstr "ለጥፍ"
-#: addressbook/gui/widgets/e-addressbook-view.c:915 filter/libfilter-i18n.h:10
+#: addressbook/gui/widgets/e-addressbook-view.c:911 filter/libfilter-i18n.h:11
#: mail/mail-accounts.c:234 ui/evolution-addressbook.xml.h:8
-#: ui/evolution-comp-editor.xml.h:4 ui/evolution-contact-editor.xml.h:3
-#: ui/evolution-contact-list-editor.xml.h:3 ui/evolution-mail-message.xml.h:24
+#: ui/evolution-comp-editor.xml.h:4 ui/evolution-contact-editor.xml.h:2
+#: ui/evolution-contact-list-editor.xml.h:2 ui/evolution-mail-message.xml.h:20
msgid "Delete"
msgstr "አጥፉ"
-#: addressbook/gui/widgets/e-addressbook-view.c:919
-#: calendar/gui/e-cal-view.c:1109
+#: addressbook/gui/widgets/e-addressbook-view.c:915
+#: calendar/gui/e-day-view.c:3715 calendar/gui/e-week-view.c:3596
msgid "Current View"
msgstr "የአሁኑ ዕይታ"
@@ -2992,7 +2998,7 @@ msgstr "የአሁኑ ዕይታ"
#. Translators: put here a list of labels you want to see on buttons in
#. addressbook. You may use any character to separate labels but it must
#. also be placed at the begining ot the string
-#: addressbook/gui/widgets/e-addressbook-view.c:953
+#: addressbook/gui/widgets/e-addressbook-view.c:949
msgid ",123,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"
msgstr ""
@@ -3000,11 +3006,11 @@ msgstr ""
#. in addressbook. You may use any character to separate labels but it
#. must also be placed at the begining ot the string.
#. Use lower case letters if possible.
-#: addressbook/gui/widgets/e-addressbook-view.c:958
+#: addressbook/gui/widgets/e-addressbook-view.c:954
msgid ",0,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"
msgstr ""
-#: addressbook/gui/widgets/e-addressbook-view.c:1356
+#: addressbook/gui/widgets/e-addressbook-view.c:1352
#, c-format
msgid ""
"The addressbook backend for\n"
@@ -3072,29 +3078,6 @@ msgstr ""
msgid "Primary Phone"
msgstr ""
-#: addressbook/gui/widgets/e-minicard.c:146
-#: addressbook/gui/widgets/e-minicard-label.c:115
-msgid "Width"
-msgstr "ስፋት"
-
-#: addressbook/gui/widgets/e-minicard.c:153
-#: addressbook/gui/widgets/e-minicard-label.c:122
-msgid "Height"
-msgstr "እርዝማኔ"
-
-#: addressbook/gui/widgets/e-minicard.c:161
-#: addressbook/gui/widgets/e-minicard-label.c:129
-msgid "Has Focus"
-msgstr ""
-
-#: addressbook/gui/widgets/e-minicard.c:169
-msgid "Selected"
-msgstr "ተመርጠዋል"
-
-#: addressbook/gui/widgets/e-minicard.c:176
-msgid "Has Cursor"
-msgstr ""
-
#: addressbook/gui/widgets/e-minicard-control.c:204
#, c-format
msgid "and %d other cards."
@@ -3108,6 +3091,21 @@ msgstr ""
msgid "Save in addressbook"
msgstr ""
+#: addressbook/gui/widgets/e-minicard-label.c:115
+#: addressbook/gui/widgets/e-minicard.c:146
+msgid "Width"
+msgstr "ስፋት"
+
+#: addressbook/gui/widgets/e-minicard-label.c:122
+#: addressbook/gui/widgets/e-minicard.c:153
+msgid "Height"
+msgstr "እርዝማኔ"
+
+#: addressbook/gui/widgets/e-minicard-label.c:129
+#: addressbook/gui/widgets/e-minicard.c:161
+msgid "Has Focus"
+msgstr ""
+
#: addressbook/gui/widgets/e-minicard-label.c:136
msgid "Field"
msgstr "መጻፊያ ሳጥን"
@@ -3124,6 +3122,10 @@ msgstr ""
msgid "Max field name length"
msgstr ""
+#: addressbook/gui/widgets/e-minicard-view-widget.c:127
+msgid "Column Width"
+msgstr ""
+
#: addressbook/gui/widgets/e-minicard-view.c:141
msgid ""
"\n"
@@ -3144,8 +3146,12 @@ msgstr ""
msgid "Adapter"
msgstr ""
-#: addressbook/gui/widgets/e-minicard-view-widget.c:127
-msgid "Column Width"
+#: addressbook/gui/widgets/e-minicard.c:169
+msgid "Selected"
+msgstr "ተመርጠዋል"
+
+#: addressbook/gui/widgets/e-minicard.c:176
+msgid "Has Cursor"
msgstr ""
#: addressbook/gui/widgets/gal-view-factory-minicard.c:24
@@ -3156,18 +3162,18 @@ msgstr ""
msgid "GTK Tree View"
msgstr "የGTK ዛፍ ዕይታ"
-#: addressbook/printing/e-contact-print.c:1158
-msgid "Print cards"
+#: addressbook/printing/e-contact-print-envelope.c:217
+#: addressbook/printing/e-contact-print-envelope.c:238
+msgid "Print envelope"
msgstr ""
-#: addressbook/printing/e-contact-print.c:1224
-#: addressbook/printing/e-contact-print.c:1250
-msgid "Print card"
+#: addressbook/printing/e-contact-print.c:1139
+msgid "Print cards"
msgstr ""
-#: addressbook/printing/e-contact-print-envelope.c:217
-#: addressbook/printing/e-contact-print-envelope.c:238
-msgid "Print envelope"
+#: addressbook/printing/e-contact-print.c:1204
+#: addressbook/printing/e-contact-print.c:1226
+msgid "Print card"
msgstr ""
#: addressbook/printing/e-contact-print.glade.h:1
@@ -3339,61 +3345,6 @@ msgstr "ስፋት"
msgid "_Font..."
msgstr "የፊደል ቅርጽ"
-#: addressbook/tools/evolution-addressbook-export.c:56
-msgid "Specify the output file instead of standard output"
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:57
-msgid "OUTPUTFILE"
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:58
-msgid "List local addressbook folders"
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:60
-msgid "Show cards as vcard or csv file"
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:60
-msgid "[vcard|csv]"
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:61
-msgid "Export in asynchronous mode "
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:63
-msgid ""
-"The number of cards in one output file in asychronous mode,default size 100."
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:63
-msgid "NUMBER"
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:91
-msgid ""
-"Command line arguments error, please use --help option to see the usage."
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:105
-msgid "Only support csv or vcard format."
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:114
-msgid "In async mode, output must be file."
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:122
-msgid "In normal mode, there should not need size option."
-msgstr ""
-
-#: addressbook/tools/evolution-addressbook-export.c:153
-#, fuzzy
-msgid "Impossible internal error."
-msgstr "የውስጥ ብልሽት"
-
#: calendar/cal-util/cal-component.c:1218
msgid "Untitled appointment"
msgstr ""
@@ -3523,30 +3474,28 @@ msgid "31st"
msgstr "31ኛ"
#: calendar/cal-util/cal-util.c:550 calendar/cal-util/cal-util.c:572
-#: calendar/gui/dialogs/task-details-page.glade.h:5
-#: calendar/gui/e-calendar-table.c:403 calendar/gui/e-tasks.c:271
-#: mail/message-list.c:912
+#: calendar/gui/dialogs/task-details-page.glade.h:6
+#: calendar/gui/e-calendar-table.c:401 mail/message-list.c:753
msgid "High"
msgstr "ከፍ ያለ"
#: calendar/cal-util/cal-util.c:552 calendar/cal-util/cal-util.c:574
-#: calendar/gui/dialogs/task-details-page.glade.h:8
-#: calendar/gui/e-calendar-table.c:404 calendar/gui/e-cal-model.c:826
-#: calendar/gui/e-tasks.c:273 mail/message-list.c:911
+#: calendar/gui/calendar-model.c:1709
+#: calendar/gui/dialogs/task-details-page.glade.h:9
+#: calendar/gui/e-calendar-table.c:402 mail/message-list.c:752
msgid "Normal"
msgstr "የተለመደ"
#: calendar/cal-util/cal-util.c:554 calendar/cal-util/cal-util.c:576
-#: calendar/gui/dialogs/task-details-page.glade.h:7
-#: calendar/gui/e-calendar-table.c:405 calendar/gui/e-tasks.c:275
-#: mail/message-list.c:910
+#: calendar/gui/dialogs/task-details-page.glade.h:8
+#: calendar/gui/e-calendar-table.c:403 mail/message-list.c:751
msgid "Low"
msgstr "ዝቅ ያለ"
#. An empty string is the same as 'None'.
#: calendar/cal-util/cal-util.c:570
-#: calendar/gui/dialogs/task-details-page.glade.h:11
-#: calendar/gui/e-calendar-table.c:406
+#: calendar/gui/dialogs/task-details-page.glade.h:13
+#: calendar/gui/e-calendar-table.c:404
msgid "Undefined"
msgstr ""
@@ -3554,13 +3503,13 @@ msgstr ""
msgid "Split Multi-Day Events:"
msgstr ""
-#: calendar/conduits/calendar/calendar-conduit.c:1297
-#: calendar/conduits/todo/todo-conduit.c:838
+#: calendar/conduits/calendar/calendar-conduit.c:1289
+#: calendar/conduits/todo/todo-conduit.c:830
msgid "Error while communicating with calendar server"
msgstr ""
-#: calendar/conduits/calendar/calendar-conduit.c:1456
-#: calendar/conduits/calendar/calendar-conduit.c:1459
+#: calendar/conduits/calendar/calendar-conduit.c:1440
+#: calendar/conduits/calendar/calendar-conduit.c:1443
msgid "Could not read pilot's Calendar application block"
msgstr ""
@@ -3568,32 +3517,74 @@ msgstr ""
msgid "Default Priority:"
msgstr ""
-#: calendar/conduits/todo/todo-conduit.c:970
-#: calendar/conduits/todo/todo-conduit.c:973
+#: calendar/conduits/todo/todo-conduit.c:954
+#: calendar/conduits/todo/todo-conduit.c:957
msgid "Could not read pilot's ToDo application block"
msgstr ""
-#: calendar/gui/alarm-notify/alarm-notify-dialog.c:213
+#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:1
+msgid "Calendar and Tasks"
+msgstr ""
+
+#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:2
+msgid "Configure your timezone, Calendar and Task List here "
+msgstr ""
+
+#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:3
+msgid "Evolution Calendar and Tasks"
+msgstr ""
+
+#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:4
+msgid "Evolution Calendar and Tasks component"
+msgstr ""
+
+#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:5
+msgid "Evolution Calendar configuration control"
+msgstr ""
+
+#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:6
+msgid "Evolution Calendar scheduling message viewer"
+msgstr ""
+
+#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:7
+msgid "Evolution Calendar viewer"
+msgstr ""
+
+#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:8
+msgid "Evolution Calendar/Task editor"
+msgstr ""
+
+#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:9
+msgid "Evolution Tasks viewer"
+msgstr ""
+
+#: calendar/gui/alarm-notify/GNOME_Evolution_Calendar_AlarmNotify.server.in.in.h:1
+msgid "Evolution Calendar alarm notification service"
+msgstr ""
+
+#: calendar/gui/alarm-notify/alarm-notify-dialog.c:212
msgid "Starting:"
msgstr "እየጀመረ ነው"
-#: calendar/gui/alarm-notify/alarm-notify-dialog.c:215
+#: calendar/gui/alarm-notify/alarm-notify-dialog.c:214
msgid "Ending:"
msgstr ""
-#: calendar/gui/alarm-notify/alarm-notify-dialog.c:254
+#: calendar/gui/alarm-notify/alarm-notify-dialog.c:227
+msgid "invalid time"
+msgstr ""
+
+#: calendar/gui/alarm-notify/alarm-notify-dialog.c:272
msgid "Evolution Alarm"
msgstr ""
-#: calendar/gui/alarm-notify/alarm-notify-dialog.c:347
+#: calendar/gui/alarm-notify/alarm-notify-dialog.c:365
#, c-format
msgid "Alarm on %s"
msgstr ""
#: calendar/gui/alarm-notify/alarm-notify.glade.h:1
-#: ui/evolution-comp-editor.xml.h:1 ui/evolution-contact-editor.xml.h:1
-#: ui/evolution-contact-list-editor.xml.h:1
-#: ui/evolution-signature-editor.xml.h:1
+#: ui/evolution-comp-editor.xml.h:1
msgid "C_lose"
msgstr "ዝጋ"
@@ -3609,25 +3600,16 @@ msgstr ""
msgid "_Edit appointment"
msgstr ""
-#: calendar/gui/alarm-notify/alarm-queue.c:874
+#: calendar/gui/alarm-notify/alarm-queue.c:770
msgid "No description available."
msgstr ""
-#: calendar/gui/alarm-notify/alarm-queue.c:892
-#, c-format
-msgid ""
-"Alarm on %s\n"
-"%s\n"
-"Starting at %s\n"
-"Ending at %s"
-msgstr ""
-
-#: calendar/gui/alarm-notify/alarm-queue.c:979
-#: calendar/gui/alarm-notify/alarm-queue.c:1003
+#: calendar/gui/alarm-notify/alarm-queue.c:843
+#: calendar/gui/alarm-notify/alarm-queue.c:867 widgets/misc/e-messagebox.c:161
msgid "Warning"
msgstr "ማስጠንቀቂያ"
-#: calendar/gui/alarm-notify/alarm-queue.c:983
+#: calendar/gui/alarm-notify/alarm-queue.c:847
msgid ""
"Evolution does not support calendar reminders with\n"
"email notifications yet, but this reminder was\n"
@@ -3635,7 +3617,7 @@ msgid ""
"a normal reminder dialog box instead."
msgstr ""
-#: calendar/gui/alarm-notify/alarm-queue.c:1009
+#: calendar/gui/alarm-notify/alarm-queue.c:873
#, c-format
msgid ""
"An Evolution Calendar reminder is about to trigger. This reminder is "
@@ -3646,78 +3628,69 @@ msgid ""
"Are you sure you want to run this program?"
msgstr ""
-#: calendar/gui/alarm-notify/alarm-queue.c:1023
+#: calendar/gui/alarm-notify/alarm-queue.c:887
msgid "Do not ask me about this program again."
msgstr ""
-#: calendar/gui/alarm-notify/GNOME_Evolution_Calendar_AlarmNotify.server.in.in.h:1
-msgid "Evolution Calendar alarm notification service"
-msgstr ""
-
-#: calendar/gui/alarm-notify/notify-main.c:173
-msgid "Could not initialize Bonobo"
-msgstr "bonobo ማስጀመር አልቻልኩም!"
-
-#: calendar/gui/alarm-notify/notify-main.c:176
+#: calendar/gui/alarm-notify/notify-main.c:174
msgid "Could not initialize gnome-vfs"
msgstr ""
-#: calendar/gui/alarm-notify/notify-main.c:185
+#: calendar/gui/alarm-notify/notify-main.c:183
msgid "Could not create the alarm notify service factory"
msgstr ""
-#: calendar/gui/calendar-commands.c:376
-msgid ""
-"This operation will permanently erase all events older than the selected "
-"amount of time. If you continue, you will not be able to recover these "
-"events."
+#: calendar/gui/cal-search-bar.c:50
+msgid "Summary contains"
msgstr ""
-#: calendar/gui/calendar-commands.c:382
-msgid "Purge events older than"
+#: calendar/gui/cal-search-bar.c:51
+msgid "Description contains"
msgstr ""
-#: calendar/gui/calendar-commands.c:387
-#: calendar/gui/dialogs/alarm-options.glade.h:10 filter/filter.glade.h:17
-msgid "days"
-msgstr "ቀን"
+#: calendar/gui/cal-search-bar.c:52
+msgid "Comment contains"
+msgstr ""
-#: calendar/gui/calendar-commands.c:485
+#: calendar/gui/cal-search-bar.c:358 mail/mail-ops.c:1106
+msgid "Unmatched"
+msgstr ""
+
+#: calendar/gui/calendar-commands.c:419
msgid "%A %d %B %Y"
msgstr "%A %d %B %Y"
#. strftime format %a = abbreviated weekday name, %d = day of month,
#. %b = abbreviated month name. Don't use any other specifiers.
-#: calendar/gui/calendar-commands.c:488 calendar/gui/e-day-view.c:1364
-#: calendar/gui/e-day-view-top-item.c:266
-#: calendar/gui/e-week-view-main-item.c:325
+#: calendar/gui/calendar-commands.c:422 calendar/gui/e-day-view-top-item.c:265
+#: calendar/gui/e-day-view.c:1438 calendar/gui/e-week-view-main-item.c:325
msgid "%a %d %b"
msgstr "%a %d %b"
-#: calendar/gui/calendar-commands.c:490 calendar/gui/calendar-commands.c:495
-#: calendar/gui/calendar-commands.c:497
+#: calendar/gui/calendar-commands.c:424 calendar/gui/calendar-commands.c:429
+#: calendar/gui/calendar-commands.c:431
msgid "%a %d %b %Y"
msgstr "%a %d %b %Y"
-#: calendar/gui/calendar-commands.c:514 calendar/gui/calendar-commands.c:520
-#: calendar/gui/calendar-commands.c:526 calendar/gui/calendar-commands.c:528
+#: calendar/gui/calendar-commands.c:442 calendar/gui/calendar-commands.c:449
+#: calendar/gui/calendar-commands.c:455 calendar/gui/calendar-commands.c:457
msgid "%d %B %Y"
msgstr "%d %B %Y"
#. strftime format %d = day of month, %B = full
#. month name. You can change the order but don't
#. change the specifiers or add anything.
-#: calendar/gui/calendar-commands.c:518
-#: calendar/gui/e-week-view-main-item.c:333 calendar/gui/print.c:1508
+#: calendar/gui/calendar-commands.c:447
+#: calendar/gui/e-week-view-main-item.c:333 calendar/gui/print.c:1509
msgid "%d %B"
msgstr "%d %B"
-#: calendar/gui/calendar-commands.c:918
+#: calendar/gui/calendar-commands.c:849
msgid ""
"Could not create the calendar view. Please check your ORBit and OAF setup."
msgstr ""
-#: calendar/gui/calendar-component.c:70 calendar/gui/gnome-cal.c:1569
+#: calendar/gui/calendar-component.c:70 calendar/gui/gnome-cal.c:1353
#: importers/netscape-importer.c:1873 mail/importers/netscape-importer.c:1843
#: my-evolution/my-evolution.glade.h:2 shell/e-local-storage.c:177
#: shell/e-shortcuts.c:1085
@@ -3736,11 +3709,11 @@ msgstr ""
msgid "Public folder containing appointments and events"
msgstr ""
-#: calendar/gui/calendar-component.c:80 calendar/gui/e-tasks.c:1080
-#: calendar/gui/print.c:1787 calendar/gui/tasks-control.c:487
+#: calendar/gui/calendar-component.c:80 calendar/gui/e-tasks.c:738
+#: calendar/gui/print.c:1789 calendar/gui/tasks-control.c:504
#: calendar/importers/icalendar-importer.c:644
#: importers/netscape-importer.c:1875 mail/importers/netscape-importer.c:1845
-#: my-evolution/e-summary-tasks.c:348 my-evolution/e-summary-tasks.c:357
+#: my-evolution/e-summary-tasks.c:329 my-evolution/e-summary-tasks.c:338
#: shell/e-local-storage.c:183 shell/e-shortcuts.c:1086
msgid "Tasks"
msgstr ""
@@ -3806,6 +3779,104 @@ msgstr ""
msgid "Create a new all-day appointment"
msgstr ""
+#: calendar/gui/calendar-model.c:405 calendar/gui/calendar-model.c:964
+#: calendar/gui/e-calendar-table.c:380
+msgid "Private"
+msgstr ""
+
+#: calendar/gui/calendar-model.c:408 calendar/gui/calendar-model.c:966
+#: calendar/gui/e-calendar-table.c:381
+msgid "Confidential"
+msgstr "ሚስጢራዊ"
+
+#: calendar/gui/calendar-model.c:411 calendar/gui/e-calendar-table.c:379
+msgid "Public"
+msgstr ""
+
+#: calendar/gui/calendar-model.c:523
+msgid "N"
+msgstr "n"
+
+#: calendar/gui/calendar-model.c:523
+msgid "S"
+msgstr "s"
+
+#: calendar/gui/calendar-model.c:525
+msgid "E"
+msgstr "ምሥራቅ"
+
+#: calendar/gui/calendar-model.c:525
+msgid "W"
+msgstr "ምዕራብ"
+
+#: calendar/gui/calendar-model.c:590 calendar/gui/calendar-model.c:1134
+#: calendar/gui/e-calendar-table.c:453
+msgid "Free"
+msgstr "ነፃ"
+
+#: calendar/gui/calendar-model.c:592 calendar/gui/e-calendar-table.c:454
+#: calendar/gui/e-meeting-time-sel.c:406
+#: shell/evolution-shell-component.c:1204
+msgid "Busy"
+msgstr ""
+
+#: calendar/gui/calendar-model.c:750 calendar/gui/calendar-model.c:1178
+#: calendar/gui/dialogs/task-details-page.glade.h:10
+#: calendar/gui/e-calendar-table.c:474 calendar/gui/print.c:2298
+msgid "Not Started"
+msgstr ""
+
+#: calendar/gui/calendar-model.c:753 calendar/gui/calendar-model.c:1180
+#: calendar/gui/dialogs/task-details-page.glade.h:7
+#: calendar/gui/e-calendar-table.c:475 calendar/gui/print.c:2301
+msgid "In Progress"
+msgstr ""
+
+#: calendar/gui/calendar-model.c:756 calendar/gui/calendar-model.c:1182
+#: calendar/gui/dialogs/task-details-page.glade.h:4
+#: calendar/gui/e-calendar-table.c:476 calendar/gui/e-meeting-model.c:294
+#: calendar/gui/e-meeting-model.c:317 calendar/gui/print.c:2304
+msgid "Completed"
+msgstr ""
+
+#: calendar/gui/calendar-model.c:1036
+msgid ""
+"The geographical position must be entered in the format: \n"
+"\n"
+"45.436845,125.862501"
+msgstr ""
+
+#. An empty string is the same as 'None'.
+#: calendar/gui/calendar-model.c:1176 calendar/gui/dialogs/meeting-page.c:330
+#: calendar/gui/dialogs/meeting-page.glade.h:2 composer/e-msg-composer.c:2056
+#: mail/folder-browser.c:1752 mail/mail-account-gui.c:1260
+#: mail/mail-account-gui.c:1692 mail/mail-accounts.c:442
+#: mail/mail-config.glade.h:76
+#: widgets/e-timezone-dialog/e-timezone-dialog.c:194
+#: widgets/misc/e-cell-date-edit.c:257 widgets/misc/e-dateedit.c:442
+#: widgets/misc/e-dateedit.c:1458 widgets/misc/e-dateedit.c:1573
+msgid "None"
+msgstr "ምንም"
+
+#: calendar/gui/calendar-model.c:1711
+msgid "Recurring"
+msgstr ""
+
+#: calendar/gui/calendar-model.c:1713
+msgid "Assigned"
+msgstr ""
+
+#: calendar/gui/calendar-model.c:1719 calendar/gui/e-meeting-model.c:266
+#: calendar/gui/e-meeting-model.c:276 calendar/gui/e-meeting-model.c:534
+#: calendar/gui/e-meeting-model.c:784
+msgid "Yes"
+msgstr "አዎ"
+
+#: calendar/gui/calendar-model.c:1719 calendar/gui/e-meeting-model.c:278
+#: calendar/gui/e-meeting-model.c:785
+msgid "No"
+msgstr "አይ"
+
#: calendar/gui/calendar-view-factory.c:118
msgid "Day View"
msgstr "የቀን ዕይታ"
@@ -3822,69 +3893,48 @@ msgstr "የሳመንት ዕይታ"
msgid "Month View"
msgstr "የወር ዕይታ"
-#: calendar/gui/calendar-view-factory.c:130
-#, fuzzy
-msgid "List View"
-msgstr "የተለመደው ዕይታ"
-
-#: calendar/gui/cal-search-bar.c:50
-msgid "Summary contains"
-msgstr ""
-
-#: calendar/gui/cal-search-bar.c:51
-msgid "Description contains"
-msgstr ""
-
-#: calendar/gui/cal-search-bar.c:52
-msgid "Comment contains"
-msgstr ""
-
-#: calendar/gui/cal-search-bar.c:358 mail/mail-ops.c:1120
-msgid "Unmatched"
-msgstr ""
-
-#: calendar/gui/comp-editor-factory.c:462
+#: calendar/gui/comp-editor-factory.c:456
msgid "Error while opening the calendar"
msgstr ""
-#: calendar/gui/comp-editor-factory.c:473
+#: calendar/gui/comp-editor-factory.c:467
msgid "Method not supported when opening the calendar"
msgstr ""
-#: calendar/gui/comp-editor-factory.c:479
+#: calendar/gui/comp-editor-factory.c:473
msgid "Permission denied to open the calendar"
msgstr ""
-#: calendar/gui/control-factory.c:125
+#: calendar/gui/control-factory.c:119
#, c-format
msgid "Could not open the folder in '%s'"
msgstr ""
-#: calendar/gui/control-factory.c:171
+#: calendar/gui/control-factory.c:165
msgid "The URI that the calendar will display"
msgstr ""
-#: calendar/gui/control-factory.c:178
+#: calendar/gui/control-factory.c:172
msgid "The type of view to show"
msgstr ""
-#: calendar/gui/dialogs/alarm-options.c:466
+#: calendar/gui/dialogs/alarm-options.c:420
msgid "Audio Alarm Options"
msgstr ""
-#: calendar/gui/dialogs/alarm-options.c:475
+#: calendar/gui/dialogs/alarm-options.c:429
msgid "Message Alarm Options"
msgstr ""
-#: calendar/gui/dialogs/alarm-options.c:484
+#: calendar/gui/dialogs/alarm-options.c:438
msgid "Email Alarm Options"
msgstr ""
-#: calendar/gui/dialogs/alarm-options.c:493
+#: calendar/gui/dialogs/alarm-options.c:447
msgid "Program Alarm Options"
msgstr ""
-#: calendar/gui/dialogs/alarm-options.c:509
+#: calendar/gui/dialogs/alarm-options.c:456
msgid "Unknown Alarm Options"
msgstr ""
@@ -3923,6 +3973,10 @@ msgstr "ላክ"
msgid "With these arguments:"
msgstr ""
+#: calendar/gui/dialogs/alarm-options.glade.h:10 filter/filter.glade.h:17
+msgid "days"
+msgstr "ቀን"
+
#: calendar/gui/dialogs/alarm-options.glade.h:11
msgid "dialog1"
msgstr ""
@@ -3935,8 +3989,7 @@ msgstr ""
msgid "hours"
msgstr "ሰዓትን"
-#: calendar/gui/dialogs/alarm-options.glade.h:14
-#: executive-summary/test-service/rdf-summary.c:806 filter/filter.glade.h:19
+#: calendar/gui/dialogs/alarm-options.glade.h:14 filter/filter.glade.h:19
msgid "minutes"
msgstr "ደቂቃዎች"
@@ -3950,11 +4003,11 @@ msgstr ""
msgid "Date/Time:"
msgstr "ቀን/ሰዓት፦"
-#: calendar/gui/dialogs/alarm-page.glade.h:3 calendar/gui/e-alarm-list.c:465
+#: calendar/gui/dialogs/alarm-page.glade.h:3 calendar/gui/e-alarm-list.c:461
msgid "Display a message"
msgstr ""
-#: calendar/gui/dialogs/alarm-page.glade.h:4 calendar/gui/e-alarm-list.c:461
+#: calendar/gui/dialogs/alarm-page.glade.h:4 calendar/gui/e-alarm-list.c:457
msgid "Play a sound"
msgstr "ድምፅ አጫውት"
@@ -3962,7 +4015,7 @@ msgstr "ድምፅ አጫውት"
msgid "Reminders"
msgstr ""
-#: calendar/gui/dialogs/alarm-page.glade.h:6 calendar/gui/e-alarm-list.c:473
+#: calendar/gui/dialogs/alarm-page.glade.h:6 calendar/gui/e-alarm-list.c:469
msgid "Run a program"
msgstr "ፕሮግራምን አስኪድ"
@@ -3972,8 +4025,7 @@ msgstr ""
#: calendar/gui/dialogs/alarm-page.glade.h:8
#: calendar/gui/dialogs/recurrence-page.glade.h:8
-#: calendar/gui/e-itip-control.c:1022 calendar/gui/e-itip-control.glade.h:11
-#: calendar/gui/e-tasks.c:208
+#: calendar/gui/e-itip-control.c:1052 calendar/gui/e-itip-control.glade.h:11
msgid "Summary:"
msgstr "ማጠቃለያ፦"
@@ -4056,7 +4108,7 @@ msgstr "ቀን"
#: calendar/gui/dialogs/cal-prefs-dialog.glade.h:12
#: calendar/gui/dialogs/recurrence-page.c:1040
-#: calendar/gui/e-itip-control.c:647
+#: calendar/gui/e-itip-control.c:677
msgid "Friday"
msgstr "ዓርብ"
@@ -4070,7 +4122,7 @@ msgstr "ደቂቃዎች"
#: calendar/gui/dialogs/cal-prefs-dialog.glade.h:15
#: calendar/gui/dialogs/recurrence-page.c:1036
-#: calendar/gui/e-itip-control.c:643
+#: calendar/gui/e-itip-control.c:673
msgid "Monday"
msgstr "ሰኞ"
@@ -4080,7 +4132,7 @@ msgstr "_እሑድ"
#: calendar/gui/dialogs/cal-prefs-dialog.glade.h:17
#: calendar/gui/dialogs/recurrence-page.c:1041
-#: calendar/gui/e-itip-control.c:648
+#: calendar/gui/e-itip-control.c:678
msgid "Saturday"
msgstr "ቅዳሜ"
@@ -4094,7 +4146,7 @@ msgstr ""
#: calendar/gui/dialogs/cal-prefs-dialog.glade.h:20
#: calendar/gui/dialogs/recurrence-page.c:1042
-#: calendar/gui/e-itip-control.c:642
+#: calendar/gui/e-itip-control.c:672
msgid "Sunday"
msgstr "እሑድ"
@@ -4112,7 +4164,7 @@ msgstr ""
#: calendar/gui/dialogs/cal-prefs-dialog.glade.h:24
#: calendar/gui/dialogs/recurrence-page.c:1039
-#: calendar/gui/e-itip-control.c:646
+#: calendar/gui/e-itip-control.c:676
msgid "Thursday"
msgstr "ሐሙስ"
@@ -4130,7 +4182,7 @@ msgstr ""
#: calendar/gui/dialogs/cal-prefs-dialog.glade.h:28
#: calendar/gui/dialogs/recurrence-page.c:1037
-#: calendar/gui/e-itip-control.c:644
+#: calendar/gui/e-itip-control.c:674
msgid "Tuesday"
msgstr "ማክሰኞ"
@@ -4140,12 +4192,12 @@ msgstr ""
#: calendar/gui/dialogs/cal-prefs-dialog.glade.h:30
#: calendar/gui/dialogs/recurrence-page.c:1038
-#: calendar/gui/e-itip-control.c:645
+#: calendar/gui/e-itip-control.c:675
msgid "Wednesday"
msgstr "ረቡዕ"
#: calendar/gui/dialogs/cal-prefs-dialog.glade.h:31
-#: ui/evolution-calendar.xml.h:31
+#: ui/evolution-calendar.xml.h:27
msgid "Work Week"
msgstr ""
@@ -4252,50 +4304,75 @@ msgstr ""
msgid "Are you sure you want to cancel and delete this journal entry?"
msgstr ""
-#: calendar/gui/dialogs/changed-comp.c:59
+#: calendar/gui/dialogs/changed-comp.c:58
msgid "This event has been deleted."
msgstr ""
-#: calendar/gui/dialogs/changed-comp.c:63
+#: calendar/gui/dialogs/changed-comp.c:62
msgid "This task has been deleted."
msgstr ""
-#: calendar/gui/dialogs/changed-comp.c:67
+#: calendar/gui/dialogs/changed-comp.c:66
msgid "This journal entry has been deleted."
msgstr ""
-#: calendar/gui/dialogs/changed-comp.c:76
+#: calendar/gui/dialogs/changed-comp.c:75
#, c-format
msgid "%s You have made changes. Forget those changes and close the editor?"
msgstr ""
-#: calendar/gui/dialogs/changed-comp.c:78
+#: calendar/gui/dialogs/changed-comp.c:77
#, c-format
msgid "%s You have made no changes, close the editor?"
msgstr ""
-#: calendar/gui/dialogs/changed-comp.c:83
+#: calendar/gui/dialogs/changed-comp.c:82
msgid "This event has been changed."
msgstr ""
-#: calendar/gui/dialogs/changed-comp.c:87
+#: calendar/gui/dialogs/changed-comp.c:86
msgid "This task has been changed."
msgstr ""
-#: calendar/gui/dialogs/changed-comp.c:91
+#: calendar/gui/dialogs/changed-comp.c:90
msgid "This journal entry has been changed."
msgstr ""
-#: calendar/gui/dialogs/changed-comp.c:100
+#: calendar/gui/dialogs/changed-comp.c:99
#, c-format
msgid "%s You have made changes. Forget those changes and update the editor?"
msgstr ""
-#: calendar/gui/dialogs/changed-comp.c:102
+#: calendar/gui/dialogs/changed-comp.c:101
#, c-format
msgid "%s You have made no changes, update the editor?"
msgstr ""
+#: calendar/gui/dialogs/comp-editor-page.c:409
+#, c-format
+msgid "Validation error: %s"
+msgstr ""
+
+#: calendar/gui/dialogs/comp-editor-util.c:187 calendar/gui/print.c:2216
+msgid " to "
+msgstr "ወደ"
+
+#: calendar/gui/dialogs/comp-editor-util.c:191 calendar/gui/print.c:2220
+msgid " (Completed "
+msgstr ""
+
+#: calendar/gui/dialogs/comp-editor-util.c:193 calendar/gui/print.c:2222
+msgid "Completed "
+msgstr ""
+
+#: calendar/gui/dialogs/comp-editor-util.c:198 calendar/gui/print.c:2227
+msgid " (Due "
+msgstr ""
+
+#: calendar/gui/dialogs/comp-editor-util.c:200 calendar/gui/print.c:2229
+msgid "Due "
+msgstr ""
+
#: calendar/gui/dialogs/comp-editor.c:334
msgid "Could not update invalid object"
msgstr ""
@@ -4341,47 +4418,21 @@ msgid "No summary"
msgstr ""
#: calendar/gui/dialogs/comp-editor.c:1281
-#: calendar/gui/e-calendar-table.c:1138 calendar/gui/e-cal-view.c:878
-#: composer/e-msg-composer.c:1191
+#: calendar/gui/e-calendar-table.c:1068 calendar/gui/e-day-view.c:3993
+#: calendar/gui/e-week-view.c:3840 composer/e-msg-composer.c:1164
msgid "Save as..."
msgstr "በሌላ ስም አስቀምጥ..."
-#: calendar/gui/dialogs/comp-editor.c:1384
-#: calendar/gui/dialogs/comp-editor.c:1408
-#: calendar/gui/dialogs/comp-editor.c:1434
+#: calendar/gui/dialogs/comp-editor.c:1382
+#: calendar/gui/dialogs/comp-editor.c:1406
+#: calendar/gui/dialogs/comp-editor.c:1432
msgid "Changes made to this item may be discarded if an update arrives"
msgstr ""
-#: calendar/gui/dialogs/comp-editor.c:1464
-#: calendar/gui/dialogs/comp-editor.c:1473
+#: calendar/gui/dialogs/comp-editor.c:1459
msgid "Unable to obtain current version!"
msgstr ""
-#: calendar/gui/dialogs/comp-editor-page.c:409
-#, c-format
-msgid "Validation error: %s"
-msgstr ""
-
-#: calendar/gui/dialogs/comp-editor-util.c:187 calendar/gui/print.c:2223
-msgid " to "
-msgstr "ወደ"
-
-#: calendar/gui/dialogs/comp-editor-util.c:191 calendar/gui/print.c:2227
-msgid " (Completed "
-msgstr ""
-
-#: calendar/gui/dialogs/comp-editor-util.c:193 calendar/gui/print.c:2229
-msgid "Completed "
-msgstr ""
-
-#: calendar/gui/dialogs/comp-editor-util.c:198 calendar/gui/print.c:2234
-msgid " (Due "
-msgstr ""
-
-#: calendar/gui/dialogs/comp-editor-util.c:200 calendar/gui/print.c:2236
-msgid "Due "
-msgstr ""
-
#: calendar/gui/dialogs/delete-comp.c:96
#, c-format
msgid "Are you sure you want to delete the appointment `%s'?"
@@ -4484,31 +4535,31 @@ msgstr ""
msgid "Enter Delegate"
msgstr ""
-#: calendar/gui/dialogs/event-editor.c:200 calendar/gui/print.c:2260
+#: calendar/gui/dialogs/event-editor.c:199 calendar/gui/print.c:2253
msgid "Appointment"
msgstr ""
-#: calendar/gui/dialogs/event-editor.c:207
+#: calendar/gui/dialogs/event-editor.c:206
msgid "Reminder"
msgstr ""
-#: calendar/gui/dialogs/event-editor.c:214
+#: calendar/gui/dialogs/event-editor.c:213
msgid "Recurrence"
msgstr ""
-#: calendar/gui/dialogs/event-editor.c:221
-#: calendar/gui/dialogs/event-editor.c:294
-#: calendar/gui/dialogs/event-editor.c:438
+#: calendar/gui/dialogs/event-editor.c:220
+#: calendar/gui/dialogs/event-editor.c:292
+#: calendar/gui/dialogs/event-editor.c:436
msgid "Scheduling"
msgstr ""
-#: calendar/gui/dialogs/event-editor.c:228
-#: calendar/gui/dialogs/event-editor.c:297
-#: calendar/gui/dialogs/event-editor.c:441 ui/evolution-event-editor.xml.h:6
+#: calendar/gui/dialogs/event-editor.c:227
+#: calendar/gui/dialogs/event-editor.c:295
+#: calendar/gui/dialogs/event-editor.c:439 ui/evolution-event-editor.xml.h:6
msgid "Meeting"
msgstr "ስብሰባ"
-#: calendar/gui/dialogs/event-page.c:603 calendar/gui/dialogs/task-page.c:509
+#: calendar/gui/dialogs/event-page.c:603 calendar/gui/dialogs/task-page.c:507
msgid "Start date is wrong"
msgstr ""
@@ -4544,8 +4595,8 @@ msgid "Classification"
msgstr ""
#: calendar/gui/dialogs/event-page.glade.h:6
-#, fuzzy
-msgid "Co_nfidential"
+#: calendar/gui/dialogs/task-page.glade.h:4
+msgid "Con_fidential"
msgstr "ሚስጢራዊ"
#: calendar/gui/dialogs/event-page.glade.h:7
@@ -4572,6 +4623,7 @@ msgid "Pu_blic"
msgstr ""
#: calendar/gui/dialogs/event-page.glade.h:12
+#: calendar/gui/e-calendar-table.etspec.h:13
msgid "Show Time As"
msgstr ""
@@ -4588,34 +4640,74 @@ msgstr ""
msgid "_Start time:"
msgstr ""
-#. an empty string is the same as 'None'
-#: calendar/gui/dialogs/meeting-page.c:311
-#: calendar/gui/dialogs/meeting-page.glade.h:2
-#: calendar/gui/e-cal-model-tasks.c:596 composer/e-msg-composer.c:2093
-#: mail/mail-account-gui.c:1260 mail/mail-account-gui.c:1692
-#: mail/mail-accounts.c:442 mail/mail-config.glade.h:76
-#: widgets/e-timezone-dialog/e-timezone-dialog.c:194
-#: widgets/misc/e-cell-date-edit.c:257 widgets/misc/e-dateedit.c:445
-#: widgets/misc/e-dateedit.c:1483 widgets/misc/e-dateedit.c:1598
-msgid "None"
-msgstr "ምንም"
-
-#: calendar/gui/dialogs/meeting-page.c:416
+#: calendar/gui/dialogs/meeting-page.c:437
msgid "The organizer selected no longer has an account."
msgstr ""
-#: calendar/gui/dialogs/meeting-page.c:422
+#: calendar/gui/dialogs/meeting-page.c:443
msgid "An organizer is required."
msgstr ""
-#: calendar/gui/dialogs/meeting-page.c:437
+#: calendar/gui/dialogs/meeting-page.c:458
msgid "At least one attendee is required."
msgstr ""
-#: calendar/gui/dialogs/meeting-page.c:630
+#: calendar/gui/dialogs/meeting-page.c:629
+msgid "That person is already attending the meeting!"
+msgstr ""
+
+#: calendar/gui/dialogs/meeting-page.c:713
msgid "_Delegate To..."
msgstr ""
+#: calendar/gui/dialogs/meeting-page.etspec.h:1
+#: calendar/gui/e-meeting-time-sel.etspec.h:1
+msgid "Attendee"
+msgstr ""
+
+#: calendar/gui/dialogs/meeting-page.etspec.h:2
+#: calendar/gui/e-meeting-time-sel.etspec.h:2
+msgid "Click here to add an attendee"
+msgstr ""
+
+#: calendar/gui/dialogs/meeting-page.etspec.h:3
+#: calendar/gui/e-meeting-time-sel.etspec.h:3
+msgid "Common Name"
+msgstr ""
+
+#: calendar/gui/dialogs/meeting-page.etspec.h:4
+#: calendar/gui/e-meeting-time-sel.etspec.h:4
+msgid "Delegated From"
+msgstr ""
+
+#: calendar/gui/dialogs/meeting-page.etspec.h:5
+#: calendar/gui/e-meeting-time-sel.etspec.h:5
+msgid "Delegated To"
+msgstr ""
+
+#: calendar/gui/dialogs/meeting-page.etspec.h:6
+#: calendar/gui/e-meeting-time-sel.etspec.h:6
+msgid "Language"
+msgstr "ቋንቋ"
+
+#: calendar/gui/dialogs/meeting-page.etspec.h:7
+#: calendar/gui/e-meeting-time-sel.etspec.h:7
+msgid "Member"
+msgstr ""
+
+#: calendar/gui/dialogs/meeting-page.etspec.h:8
+#: calendar/gui/e-itip-control.c:1179
+#: calendar/gui/e-meeting-time-sel.etspec.h:8
+msgid "RSVP"
+msgstr ""
+
+#: calendar/gui/dialogs/meeting-page.etspec.h:10
+#: calendar/gui/e-calendar-table.etspec.h:15
+#: calendar/gui/e-meeting-time-sel.etspec.h:10 filter/libfilter-i18n.h:58
+#: mail/message-list.etspec.h:12
+msgid "Status"
+msgstr "ሁኔታ"
+
#: calendar/gui/dialogs/meeting-page.glade.h:3
#: calendar/gui/e-itip-control.glade.h:9
msgid "Organizer:"
@@ -4626,7 +4718,7 @@ msgid "_Change Organizer"
msgstr ""
#: calendar/gui/dialogs/meeting-page.glade.h:5
-#: calendar/gui/e-meeting-time-sel.c:411
+#: calendar/gui/e-meeting-time-sel.c:424
msgid "_Invite Others..."
msgstr ""
@@ -4775,7 +4867,7 @@ msgid ""
"Do you wish to save your changes?"
msgstr ""
-#: calendar/gui/dialogs/save-comp.c:58 composer/e-msg-composer.c:1599
+#: calendar/gui/dialogs/save-comp.c:58 composer/e-msg-composer.c:1557
msgid "_Discard Changes"
msgstr ""
@@ -4800,81 +4892,52 @@ msgstr ""
msgid "The task information has changed. Send an updated version?"
msgstr ""
-#: calendar/gui/dialogs/task-details-page.c:405
+#: calendar/gui/dialogs/task-details-page.c:401
msgid "Completed date is wrong"
msgstr ""
#: calendar/gui/dialogs/task-details-page.glade.h:2
+#: calendar/gui/e-calendar-table.etspec.h:2
#, no-c-format
-msgid "% _Complete"
-msgstr ""
-
-#: calendar/gui/dialogs/task-details-page.glade.h:4
-#: calendar/gui/e-calendar-table.c:478 calendar/gui/e-cal-model-tasks.c:323
-#: calendar/gui/e-cal-model-tasks.c:602 calendar/gui/e-tasks.c:250
-#: calendar/gui/print.c:2311
-msgid "Completed"
-msgstr ""
-
-#: calendar/gui/dialogs/task-details-page.glade.h:6
-#: calendar/gui/e-calendar-table.c:477 calendar/gui/e-cal-model-tasks.c:321
-#: calendar/gui/e-cal-model-tasks.c:600 calendar/gui/e-cal-model-tasks.c:662
-#: calendar/gui/e-tasks.c:247 calendar/gui/print.c:2308
-msgid "In Progress"
+msgid "% Complete"
msgstr ""
-#: calendar/gui/dialogs/task-details-page.glade.h:9
-#: calendar/gui/e-calendar-table.c:476 calendar/gui/e-cal-model-tasks.c:319
-#: calendar/gui/e-cal-model-tasks.c:598 calendar/gui/e-tasks.c:257
-#: calendar/gui/print.c:2305
-msgid "Not Started"
+#: calendar/gui/dialogs/task-details-page.glade.h:5
+msgid "Date Completed:"
msgstr ""
-#: calendar/gui/dialogs/task-details-page.glade.h:10
+#: calendar/gui/dialogs/task-details-page.glade.h:11
msgid "Progress"
msgstr "ይሻሻል"
#: calendar/gui/dialogs/task-details-page.glade.h:12
-#, fuzzy
-msgid "_Date Completed:"
-msgstr "አጥፉ"
+msgid "URL:"
+msgstr "url"
-#: calendar/gui/dialogs/task-details-page.glade.h:13
+#: calendar/gui/dialogs/task-details-page.glade.h:14
msgid "_Priority:"
msgstr "ቅድሚያ"
-#: calendar/gui/dialogs/task-details-page.glade.h:14
+#: calendar/gui/dialogs/task-details-page.glade.h:15
msgid "_Status:"
msgstr "ሁኔታ"
-#: calendar/gui/dialogs/task-details-page.glade.h:15
-msgid "_Web Page:"
-msgstr ""
-
-#: calendar/gui/dialogs/task-editor.c:193
+#: calendar/gui/dialogs/task-editor.c:190
msgid "Basic"
msgstr "ቀላል"
-#: calendar/gui/dialogs/task-editor.c:207
-#: calendar/gui/dialogs/task-editor.c:270
-#: calendar/gui/dialogs/task-editor.c:407
+#: calendar/gui/dialogs/task-editor.c:204
+#: calendar/gui/dialogs/task-editor.c:252
+#: calendar/gui/dialogs/task-editor.c:387
msgid "Assignment"
msgstr ""
-#: calendar/gui/dialogs/task-page.c:482
+#: calendar/gui/dialogs/task-page.c:480
msgid "Due date is wrong"
msgstr ""
-#: calendar/gui/dialogs/task-page.c:542
-msgid "Due date is before start date!"
-msgstr ""
-
-#: calendar/gui/dialogs/task-page.glade.h:4
-msgid "Con_fidential"
-msgstr "ሚስጢራዊ"
-
-#: calendar/gui/dialogs/task-page.glade.h:6 calendar/gui/e-itip-control.c:1077
-#: calendar/gui/e-itip-control.glade.h:6 calendar/gui/e-tasks.c:287
+#: calendar/gui/dialogs/task-page.glade.h:6 calendar/gui/e-itip-control.c:1107
+#: calendar/gui/e-itip-control.glade.h:6
#: composer/e-msg-composer-attachment.glade.h:3 mail/mail-config.glade.h:43
msgid "Description:"
msgstr "መግለጫ"
@@ -4887,258 +4950,223 @@ msgstr ""
msgid "_Due Date:"
msgstr ""
-#: calendar/gui/e-alarm-list.c:397
+#: calendar/gui/e-alarm-list.c:393
#, c-format
msgid "%d days"
msgstr "%d ቀን"
-#: calendar/gui/e-alarm-list.c:400
+#: calendar/gui/e-alarm-list.c:396
msgid "1 day"
msgstr "1 ቀን"
-#: calendar/gui/e-alarm-list.c:405
+#: calendar/gui/e-alarm-list.c:401
#, c-format
msgid "%d weeks"
msgstr "%d ሳመንት"
-#: calendar/gui/e-alarm-list.c:408
+#: calendar/gui/e-alarm-list.c:404
msgid "1 week"
msgstr "1 ሳመንት"
-#: calendar/gui/e-alarm-list.c:413
+#: calendar/gui/e-alarm-list.c:409
#, c-format
msgid "%d hours"
msgstr "%d ሰዓት"
-#: calendar/gui/e-alarm-list.c:416
+#: calendar/gui/e-alarm-list.c:412
msgid "1 hour"
msgstr "1 ሰዓት"
-#: calendar/gui/e-alarm-list.c:421
+#: calendar/gui/e-alarm-list.c:417
#, c-format
msgid "%d minutes"
msgstr "%d ደቂቃዎች"
-#: calendar/gui/e-alarm-list.c:424
+#: calendar/gui/e-alarm-list.c:420
msgid "1 minute"
msgstr "1 ደቂቃ"
-#: calendar/gui/e-alarm-list.c:429
+#: calendar/gui/e-alarm-list.c:425
#, c-format
msgid "%d seconds"
msgstr "%d ሴኮንዶች"
-#: calendar/gui/e-alarm-list.c:432
+#: calendar/gui/e-alarm-list.c:428
msgid "1 second"
msgstr "1 ሴኮንድ"
-#: calendar/gui/e-alarm-list.c:469
+#: calendar/gui/e-alarm-list.c:465
msgid "Send an email"
msgstr ""
-#: calendar/gui/e-alarm-list.c:479
+#: calendar/gui/e-alarm-list.c:475
msgid "Unknown action to be performed"
msgstr ""
-#: calendar/gui/e-alarm-list.c:491
+#: calendar/gui/e-alarm-list.c:487
#, c-format
msgid "%s %s before the start of the appointment"
msgstr ""
-#: calendar/gui/e-alarm-list.c:494
+#: calendar/gui/e-alarm-list.c:490
#, c-format
msgid "%s %s after the start of the appointment"
msgstr ""
-#: calendar/gui/e-alarm-list.c:499
+#: calendar/gui/e-alarm-list.c:495
#, c-format
msgid "%s at the start of the appointment"
msgstr ""
-#: calendar/gui/e-alarm-list.c:508
+#: calendar/gui/e-alarm-list.c:504
#, c-format
msgid "%s %s before the end of the appointment"
msgstr ""
-#: calendar/gui/e-alarm-list.c:511
+#: calendar/gui/e-alarm-list.c:507
#, c-format
msgid "%s %s after the end of the appointment"
msgstr ""
-#: calendar/gui/e-alarm-list.c:516
+#: calendar/gui/e-alarm-list.c:512
#, c-format
msgid "%s at the end of the appointment"
msgstr ""
-#: calendar/gui/e-alarm-list.c:540
+#: calendar/gui/e-alarm-list.c:536
#, c-format
msgid "%s at %s"
msgstr "%s በ %s"
-#: calendar/gui/e-alarm-list.c:546
+#: calendar/gui/e-alarm-list.c:542
#, c-format
msgid "%s for an unknown trigger type"
msgstr ""
-#: calendar/gui/e-calendar-table.c:381 calendar/gui/e-cal-model.c:280
-#: calendar/gui/e-cal-model.c:287
-msgid "Public"
-msgstr ""
-
-#: calendar/gui/e-calendar-table.c:382 calendar/gui/e-cal-model.c:289
-msgid "Private"
-msgstr ""
-
-#: calendar/gui/e-calendar-table.c:383 calendar/gui/e-cal-model.c:291
-msgid "Confidential"
-msgstr "ሚስጢራዊ"
-
-#: calendar/gui/e-calendar-table.c:425
+#: calendar/gui/e-calendar-table.c:423
msgid "0%"
msgstr "+0"
-#: calendar/gui/e-calendar-table.c:426
+#: calendar/gui/e-calendar-table.c:424
msgid "10%"
msgstr "10"
-#: calendar/gui/e-calendar-table.c:427
+#: calendar/gui/e-calendar-table.c:425
msgid "20%"
msgstr "20"
-#: calendar/gui/e-calendar-table.c:428
+#: calendar/gui/e-calendar-table.c:426
msgid "30%"
msgstr ""
-#: calendar/gui/e-calendar-table.c:429
+#: calendar/gui/e-calendar-table.c:427
msgid "40%"
msgstr ""
-#: calendar/gui/e-calendar-table.c:430
+#: calendar/gui/e-calendar-table.c:428
msgid "50%"
msgstr "50%"
-#: calendar/gui/e-calendar-table.c:431
+#: calendar/gui/e-calendar-table.c:429
msgid "60%"
msgstr "60"
-#: calendar/gui/e-calendar-table.c:432
+#: calendar/gui/e-calendar-table.c:430
msgid "70%"
msgstr "70"
-#: calendar/gui/e-calendar-table.c:433
+#: calendar/gui/e-calendar-table.c:431
msgid "80%"
msgstr "80"
-#: calendar/gui/e-calendar-table.c:434
+#: calendar/gui/e-calendar-table.c:432
msgid "90%"
msgstr ""
-#: calendar/gui/e-calendar-table.c:435
+#: calendar/gui/e-calendar-table.c:433
msgid "100%"
msgstr "100"
-#: calendar/gui/e-calendar-table.c:455 calendar/gui/e-cal-model-calendar.c:163
-msgid "Free"
-msgstr "ነፃ"
-
-#: calendar/gui/e-calendar-table.c:456 calendar/gui/e-cal-model-calendar.c:166
-#: calendar/gui/e-meeting-time-sel.c:393
-#: shell/evolution-shell-component.c:1207
-msgid "Busy"
-msgstr ""
-
-#: calendar/gui/e-calendar-table.c:724 calendar/gui/e-cal-view.c:562
+#: calendar/gui/e-calendar-table.c:726 calendar/gui/e-day-view.c:2867
+#: calendar/gui/e-week-view.c:1933
msgid "Deleting selected objects"
msgstr ""
-#: calendar/gui/e-calendar-table.c:988 calendar/gui/e-calendar-table.c:1029
-#: calendar/gui/e-cal-view.c:1126 calendar/gui/e-cal-view.c:1192
+#: calendar/gui/e-calendar-table.c:958 calendar/gui/e-day-view.c:3737
+#: calendar/gui/e-week-view.c:3613 mail/folder-browser.c:1763
#: shell/e-shortcuts-view.c:422 ui/evolution-addressbook.xml.h:36
msgid "_Open"
msgstr "ክፈት"
-#: calendar/gui/e-calendar-table.c:989
-msgid "Open _Web Page"
-msgstr ""
-
-#: calendar/gui/e-calendar-table.c:990 calendar/gui/e-calendar-table.c:1035
-#: calendar/gui/e-cal-view.c:1127 calendar/gui/e-cal-view.c:1198
-#: ui/evolution-mail-message.xml.h:120
-msgid "_Save As..."
+#: calendar/gui/e-calendar-table.c:959
+msgid "_Save as..."
msgstr "በሌላ ስም አስቀምጥ"
-#: calendar/gui/e-calendar-table.c:991 calendar/gui/e-calendar-table.c:1033
-#: calendar/gui/e-cal-view.c:1101 calendar/gui/e-cal-view.c:1128
-#: calendar/gui/e-cal-view.c:1196 ui/evolution-addressbook.xml.h:38
-#: ui/evolution-calendar.xml.h:37 ui/evolution-comp-editor.xml.h:19
-#: ui/evolution-contact-editor.xml.h:17 ui/evolution-mail-message.xml.h:116
-#: ui/evolution-tasks.xml.h:21 ui/my-evolution.xml.h:6
+#: calendar/gui/e-calendar-table.c:960 calendar/gui/e-day-view.c:3739
+#: calendar/gui/e-week-view.c:3588 calendar/gui/e-week-view.c:3615
+#: ui/evolution-addressbook.xml.h:38 ui/evolution-calendar.xml.h:33
+#: ui/evolution-contact-editor.xml.h:14 ui/evolution-mail-message.xml.h:108
+#: ui/evolution-tasks.xml.h:20 ui/my-evolution.xml.h:6
msgid "_Print..."
msgstr "አትም"
-#: calendar/gui/e-calendar-table.c:995 calendar/gui/e-calendar-table.c:1024
-#: calendar/gui/e-cal-view.c:1133 calendar/gui/e-cal-view.c:1174
-#: ui/evolution-addressbook.xml.h:1 ui/evolution-calendar.xml.h:1
-#: ui/evolution-tasks.xml.h:1
+#: calendar/gui/e-calendar-table.c:964 calendar/gui/e-day-view.c:3744
+#: calendar/gui/e-week-view.c:3620 ui/evolution-addressbook.xml.h:1
+#: ui/evolution-calendar.xml.h:1 ui/evolution-tasks.xml.h:1
msgid "C_ut"
msgstr "ቁረጥ"
-#: calendar/gui/e-calendar-table.c:996 calendar/gui/e-calendar-table.c:1022
-#: calendar/gui/e-cal-view.c:1134 calendar/gui/e-cal-view.c:1172
-#: ui/evolution-addressbook.xml.h:30 ui/evolution-calendar.xml.h:33
-#: ui/evolution-composer-entries.xml.h:7 ui/evolution-mail-message.xml.h:101
-#: ui/evolution-tasks.xml.h:17
+#: calendar/gui/e-calendar-table.c:965 calendar/gui/e-day-view.c:3745
+#: calendar/gui/e-week-view.c:3621 ui/evolution-addressbook.xml.h:30
+#: ui/evolution-calendar.xml.h:29 ui/evolution-composer-entries.xml.h:7
+#: ui/evolution-mail-list.xml.h:24 ui/evolution-tasks.xml.h:15
msgid "_Copy"
msgstr "ቅጂ"
-#: calendar/gui/e-calendar-table.c:997 calendar/gui/e-calendar-table.c:1031
-#: calendar/gui/e-cal-view.c:1105 calendar/gui/e-cal-view.c:1135
-#: calendar/gui/e-cal-view.c:1194 ui/evolution-addressbook.xml.h:37
-#: ui/evolution-calendar.xml.h:36 ui/evolution-composer-entries.xml.h:9
-#: ui/evolution-mail-message.xml.h:114 ui/evolution-tasks.xml.h:20
+#: calendar/gui/e-calendar-table.c:966 calendar/gui/e-day-view.c:3710
+#: calendar/gui/e-day-view.c:3746 calendar/gui/e-week-view.c:3592
+#: calendar/gui/e-week-view.c:3622 ui/evolution-addressbook.xml.h:37
+#: ui/evolution-calendar.xml.h:32 ui/evolution-composer-entries.xml.h:9
+#: ui/evolution-mail-list.xml.h:29 ui/evolution-tasks.xml.h:19
msgid "_Paste"
msgstr "ለጥፍ"
-#: calendar/gui/e-calendar-table.c:1001
+#: calendar/gui/e-calendar-table.c:970
msgid "_Assign Task"
msgstr ""
-#: calendar/gui/e-calendar-table.c:1002
+#: calendar/gui/e-calendar-table.c:971
msgid "_Forward as iCalendar"
msgstr ""
-#: calendar/gui/e-calendar-table.c:1003
+#: calendar/gui/e-calendar-table.c:972
msgid "_Mark as Complete"
msgstr ""
-#: calendar/gui/e-calendar-table.c:1004
+#: calendar/gui/e-calendar-table.c:973
msgid "_Mark Selected Tasks as Complete"
msgstr ""
-#: calendar/gui/e-calendar-table.c:1009 calendar/gui/e-calendar-table.c:1027
+#: calendar/gui/e-calendar-table.c:978
msgid "_Delete Selected Tasks"
msgstr ""
-#: calendar/gui/e-calendar-table.c:1341 calendar/gui/e-cal-view.c:253
+#: calendar/gui/e-calendar-table.c:1265 calendar/gui/e-day-view.c:7929
+#: calendar/gui/e-week-view.c:4335
msgid "Updating objects"
msgstr ""
-#: calendar/gui/e-calendar-table.c:1424
+#: calendar/gui/e-calendar-table.c:1348
#: calendar/gui/e-calendar-table.etspec.h:6
msgid "Click to add a task"
msgstr ""
-#: calendar/gui/e-calendar-table.etspec.h:2
-#, no-c-format
-msgid "% Complete"
-msgstr ""
-
#: calendar/gui/e-calendar-table.etspec.h:3
msgid "Alarms"
msgstr ""
-#: calendar/gui/e-calendar-table.etspec.h:7 camel/camel-filter-driver.c:1173
-#: camel/camel-filter-driver.c:1268 mail/mail-send-recv.c:578
+#: calendar/gui/e-calendar-table.etspec.h:7 camel/camel-filter-driver.c:1156
+#: camel/camel-filter-driver.c:1251
msgid "Complete"
msgstr ""
@@ -5147,12 +5175,11 @@ msgid "Completion Date"
msgstr ""
#: calendar/gui/e-calendar-table.etspec.h:9
-#, fuzzy
-msgid "Description"
-msgstr "መግለጫ"
+msgid "Due Date"
+msgstr ""
#: calendar/gui/e-calendar-table.etspec.h:10
-msgid "Due Date"
+msgid "End Date"
msgstr ""
#: calendar/gui/e-calendar-table.etspec.h:11
@@ -5163,621 +5190,574 @@ msgstr ""
msgid "Priority"
msgstr "ቅድሚያ"
-#: calendar/gui/e-calendar-table.etspec.h:13
+#: calendar/gui/e-calendar-table.etspec.h:14
msgid "Start Date"
msgstr ""
-#: calendar/gui/e-calendar-table.etspec.h:14
-#: calendar/gui/e-meeting-time-sel.etspec.h:10 filter/libfilter-i18n.h:36
-#: mail/message-list.etspec.h:12
-msgid "Status"
-msgstr "ሁኔታ"
-
-#: calendar/gui/e-calendar-table.etspec.h:15
+#: calendar/gui/e-calendar-table.etspec.h:16
#: my-evolution/component-factory.c:56 shell/e-shell.c:750
#: shell/e-shortcuts.c:1082
msgid "Summary"
msgstr "ማጠቃለያ"
-#: calendar/gui/e-calendar-table.etspec.h:16
+#: calendar/gui/e-calendar-table.etspec.h:17
msgid "Task sort"
msgstr ""
-#: calendar/gui/e-calendar-table.etspec.h:19 mail/mail-config.glade.h:171
-msgid "color"
-msgstr "ቀለም"
-
-#: calendar/gui/e-calendar-table.etspec.h:20
-msgid "component"
+#. strftime format of a weekday, a date and a time, 24-hour.
+#: calendar/gui/e-cell-date-edit-text.c:118 e-util/e-time-utils.c:167
+#: e-util/e-time-utils.c:380
+msgid "%a %m/%d/%Y %H:%M:%S"
msgstr ""
-#: calendar/gui/e-cal-model.c:293 calendar/gui/e-cal-model.c:296
-#: calendar/gui/e-itip-control.c:1062 calendar/gui/e-itip-control.c:1278
-#: camel/camel-gpg-context.c:1574 camel/camel-gpg-context.c:1625
-#: camel/camel-tcp-stream-openssl.c:631
-#: camel/providers/smtp/camel-smtp-transport.c:172
-#: camel/providers/smtp/camel-smtp-transport.c:227
-#: widgets/misc/e-charset-picker.c:60
-msgid "Unknown"
-msgstr "ያልታወቀ"
-
-#: calendar/gui/e-cal-model.c:828
-msgid "Recurring"
+#. strftime format of a weekday, a date and a time, 12-hour.
+#: calendar/gui/e-cell-date-edit-text.c:121 e-util/e-time-utils.c:162
+#: e-util/e-time-utils.c:389
+msgid "%a %m/%d/%Y %I:%M:%S %p"
msgstr ""
-#: calendar/gui/e-cal-model.c:830
-msgid "Assigned"
+#: calendar/gui/e-cell-date-edit-text.c:126
+#, c-format
+msgid ""
+"The date must be entered in the format: \n"
+"\n"
+"%s"
msgstr ""
-#: calendar/gui/e-cal-model.c:832 calendar/gui/e-cal-model-tasks.c:933
-msgid "Yes"
-msgstr "አዎ"
-
-#: calendar/gui/e-cal-model.c:832 calendar/gui/e-cal-model-tasks.c:933
-msgid "No"
-msgstr "አይ"
-
-#: calendar/gui/e-cal-model-tasks.c:275
-msgid "N"
-msgstr "n"
+#: calendar/gui/e-day-view-time-item.c:532
+#, c-format
+msgid "%02i minute divisions"
+msgstr ""
-#: calendar/gui/e-cal-model-tasks.c:275
-msgid "S"
-msgstr "s"
+#. strftime format %A = full weekday name, %d = day of month,
+#. %B = full month name. Don't use any other specifiers.
+#: calendar/gui/e-day-view-top-item.c:261 calendar/gui/e-day-view.c:1421
+#: calendar/gui/e-week-view-main-item.c:316 calendar/gui/print.c:1525
+msgid "%A %d %B"
+msgstr "%A %d %B"
-#: calendar/gui/e-cal-model-tasks.c:277
-msgid "E"
-msgstr "ምሥራቅ"
+#. strftime format %d = day of month, %b = abbreviated month name.
+#. Don't use any other specifiers.
+#: calendar/gui/e-day-view-top-item.c:269 calendar/gui/e-day-view.c:1454
+#: calendar/gui/e-week-view-main-item.c:339
+msgid "%d %b"
+msgstr "%d %b"
-#: calendar/gui/e-cal-model-tasks.c:277
-msgid "W"
-msgstr "ምዕራብ"
+#. String to use in 12-hour time format for times in the morning.
+#: calendar/gui/e-day-view.c:636 calendar/gui/e-week-view.c:350
+#: calendar/gui/print.c:809
+msgid "am"
+msgstr "ጠዋት"
-#: calendar/gui/e-cal-model-tasks.c:550
-msgid ""
-"The geographical position must be entered in the format: \n"
-"\n"
-"45.436845,125.862501"
-msgstr ""
+#. String to use in 12-hour time format for times in the afternoon.
+#: calendar/gui/e-day-view.c:639 calendar/gui/e-week-view.c:353
+#: calendar/gui/print.c:811
+msgid "pm"
+msgstr "ከሳዓት"
-#: calendar/gui/e-cal-view.c:1094 calendar/gui/e-cal-view.c:1184
-msgid "New _Appointment..."
+#: calendar/gui/e-day-view.c:3694
+msgid "New _Appointment"
msgstr ""
-#: calendar/gui/e-cal-view.c:1095 calendar/gui/e-cal-view.c:1186
+#: calendar/gui/e-day-view.c:3696 calendar/gui/e-week-view.c:3582
msgid "New All Day _Event"
msgstr ""
-#: calendar/gui/e-cal-view.c:1096 calendar/gui/e-cal-view.c:1188
+#: calendar/gui/e-day-view.c:3698 calendar/gui/e-week-view.c:3583
msgid "New Meeting"
msgstr ""
-#: calendar/gui/e-cal-view.c:1097 calendar/gui/e-cal-view.c:1190
+#: calendar/gui/e-day-view.c:3700 calendar/gui/e-week-view.c:3584
msgid "New Task"
msgstr ""
-#: calendar/gui/e-cal-view.c:1111 calendar/gui/e-cal-view.c:1180
+#: calendar/gui/e-day-view.c:3705 ui/evolution-comp-editor.xml.h:11
+msgid "Print..."
+msgstr "አትም"
+
+#: calendar/gui/e-day-view.c:3717 calendar/gui/e-week-view.c:3598
#: ui/evolution-calendar.xml.h:13
msgid "Go to _Today"
msgstr ""
-#: calendar/gui/e-cal-view.c:1112 calendar/gui/e-cal-view.c:1182
+#: calendar/gui/e-day-view.c:3719 calendar/gui/e-week-view.c:3599
msgid "_Go to Date..."
msgstr ""
-#: calendar/gui/e-cal-view.c:1116 ui/evolution-calendar.xml.h:38
+#: calendar/gui/e-day-view.c:3724 calendar/gui/e-week-view.c:3603
+#: ui/evolution-calendar.xml.h:34
msgid "_Publish Free/Busy Information"
msgstr ""
-#: calendar/gui/e-cal-view.c:1120 calendar/gui/e-cal-view.c:1200
+#: calendar/gui/e-day-view.c:3729 calendar/gui/e-week-view.c:3607
#: ui/evolution.xml.h:60
msgid "_Settings..."
msgstr "ምርጫዎች"
-#: calendar/gui/e-cal-view.c:1139
+#: calendar/gui/e-day-view.c:3738 calendar/gui/e-week-view.c:3614
+#: mail/folder-browser.c:1765 ui/evolution-mail-message.xml.h:112
+msgid "_Save As..."
+msgstr "በሌላ ስም አስቀምጥ"
+
+#: calendar/gui/e-day-view.c:3750 calendar/gui/e-week-view.c:3626
msgid "_Schedule Meeting..."
msgstr ""
-#: calendar/gui/e-cal-view.c:1140
+#: calendar/gui/e-day-view.c:3751 calendar/gui/e-week-view.c:3627
msgid "_Forward as iCalendar..."
msgstr ""
-#: calendar/gui/e-cal-view.c:1145
+#: calendar/gui/e-day-view.c:3756 calendar/gui/e-week-view.c:3632
msgid "Make this Occurrence _Movable"
msgstr ""
-#: calendar/gui/e-cal-view.c:1146 calendar/gui/e-cal-view.c:1177
+#: calendar/gui/e-day-view.c:3757 calendar/gui/e-week-view.c:3633
msgid "Delete this _Occurrence"
msgstr ""
-#: calendar/gui/e-cal-view.c:1147 calendar/gui/e-cal-view.c:1178
+#: calendar/gui/e-day-view.c:3758 calendar/gui/e-week-view.c:3634
msgid "Delete _All Occurrences"
msgstr ""
-#. strftime format of a weekday, a date and a time, 24-hour.
-#: calendar/gui/e-cell-date-edit-text.c:118 e-util/e-time-utils.c:180
-#: e-util/e-time-utils.c:393
-msgid "%a %m/%d/%Y %H:%M:%S"
-msgstr ""
-
-#. strftime format of a weekday, a date and a time, 12-hour.
-#: calendar/gui/e-cell-date-edit-text.c:121 e-util/e-time-utils.c:175
-#: e-util/e-time-utils.c:402
-msgid "%a %m/%d/%Y %I:%M:%S %p"
-msgstr ""
-
-#: calendar/gui/e-cell-date-edit-text.c:126
-#, c-format
-msgid ""
-"The date must be entered in the format: \n"
-"\n"
-"%s"
-msgstr ""
-
-#. String to use in 12-hour time format for times in the morning.
-#: calendar/gui/e-day-view.c:600 calendar/gui/e-week-view.c:326
-#: calendar/gui/print.c:809
-msgid "am"
-msgstr "ጠዋት"
-
-#. String to use in 12-hour time format for times in the afternoon.
-#: calendar/gui/e-day-view.c:603 calendar/gui/e-week-view.c:329
-#: calendar/gui/print.c:811
-msgid "pm"
-msgstr "ከሳዓት"
-
-#. strftime format %A = full weekday name, %d = day of month,
-#. %B = full month name. Don't use any other specifiers.
-#: calendar/gui/e-day-view.c:1347 calendar/gui/e-day-view-top-item.c:262
-#: calendar/gui/e-week-view-main-item.c:316 calendar/gui/print.c:1524
-msgid "%A %d %B"
-msgstr "%A %d %B"
-
-#. strftime format %d = day of month, %b = abbreviated month name.
-#. Don't use any other specifiers.
-#: calendar/gui/e-day-view.c:1380 calendar/gui/e-day-view-top-item.c:270
-#: calendar/gui/e-week-view-main-item.c:339
-msgid "%d %b"
-msgstr "%d %b"
-
-#: calendar/gui/e-day-view-time-item.c:532
-#, c-format
-msgid "%02i minute divisions"
-msgstr ""
-
-#: calendar/gui/e-itip-control.c:676
+#: calendar/gui/e-itip-control.c:706
msgid "Yes. (Complex Recurrence)"
msgstr ""
-#: calendar/gui/e-itip-control.c:688
+#: calendar/gui/e-itip-control.c:718
msgid "Every day"
msgstr "በየቀን"
-#: calendar/gui/e-itip-control.c:690
+#: calendar/gui/e-itip-control.c:720
#, c-format
msgid "Every %d days"
msgstr "በየ%d ቀን"
-#: calendar/gui/e-itip-control.c:696
+#: calendar/gui/e-itip-control.c:726
msgid "Every week"
msgstr "በየሳመንት"
-#: calendar/gui/e-itip-control.c:698
+#: calendar/gui/e-itip-control.c:728
#, c-format
msgid "Every %d weeks"
msgstr "በየ%d ሳመንት"
-#: calendar/gui/e-itip-control.c:701
+#: calendar/gui/e-itip-control.c:731
msgid "Every week on "
msgstr ""
-#: calendar/gui/e-itip-control.c:703
+#: calendar/gui/e-itip-control.c:733
#, c-format
msgid "Every %d weeks on "
msgstr ""
-#: calendar/gui/e-itip-control.c:711
+#: calendar/gui/e-itip-control.c:741
msgid " and "
msgstr " እና "
-#: calendar/gui/e-itip-control.c:718
+#: calendar/gui/e-itip-control.c:748
#, c-format
msgid "The %s day of "
msgstr ""
-#: calendar/gui/e-itip-control.c:731
+#: calendar/gui/e-itip-control.c:761
#, c-format
msgid "The %s %s of "
msgstr ""
-#: calendar/gui/e-itip-control.c:736
+#: calendar/gui/e-itip-control.c:766
msgid "every month"
msgstr "በየወር"
-#: calendar/gui/e-itip-control.c:741
+#: calendar/gui/e-itip-control.c:771
#, c-format
msgid "every %d months"
msgstr "በየ%d ወር"
-#: calendar/gui/e-itip-control.c:747
+#: calendar/gui/e-itip-control.c:777
msgid "Every year"
msgstr "በየ ዓመት"
-#: calendar/gui/e-itip-control.c:749
+#: calendar/gui/e-itip-control.c:779
#, c-format
msgid "Every %d years"
msgstr "በየ%d ዓመታት"
-#: calendar/gui/e-itip-control.c:761
+#: calendar/gui/e-itip-control.c:791
#, c-format
msgid " a total of %d times"
msgstr ""
-#: calendar/gui/e-itip-control.c:769
+#: calendar/gui/e-itip-control.c:799
msgid ", ending on "
msgstr ""
-#: calendar/gui/e-itip-control.c:793
+#: calendar/gui/e-itip-control.c:823
msgid "<b>Starts:</b> "
msgstr ""
-#: calendar/gui/e-itip-control.c:803
+#: calendar/gui/e-itip-control.c:833
msgid "<b>Ends:</b> "
msgstr ""
-#: calendar/gui/e-itip-control.c:823
+#: calendar/gui/e-itip-control.c:853
msgid "<b>Completed:</b> "
msgstr ""
-#: calendar/gui/e-itip-control.c:833
+#: calendar/gui/e-itip-control.c:863
msgid "<b>Due:</b> "
msgstr ""
-#: calendar/gui/e-itip-control.c:870 calendar/gui/e-itip-control.c:923
+#: calendar/gui/e-itip-control.c:900 calendar/gui/e-itip-control.c:953
msgid "iCalendar Information"
msgstr ""
#. Title
-#: calendar/gui/e-itip-control.c:885
+#: calendar/gui/e-itip-control.c:915
msgid "iCalendar Error"
msgstr ""
-#: calendar/gui/e-itip-control.c:954 calendar/gui/e-itip-control.c:970
-#: calendar/gui/e-itip-control.c:981 calendar/gui/e-itip-control.c:998
+#: calendar/gui/e-itip-control.c:984 calendar/gui/e-itip-control.c:1000
+#: calendar/gui/e-itip-control.c:1011 calendar/gui/e-itip-control.c:1028
msgid "An unknown person"
msgstr ""
#. Describe what the user can do
-#: calendar/gui/e-itip-control.c:1005
+#: calendar/gui/e-itip-control.c:1035
msgid ""
"<br> Please review the following information, and then select an action from "
"the menu below."
msgstr ""
-#: calendar/gui/e-itip-control.c:1020
+#: calendar/gui/e-itip-control.c:1050
msgid "<i>None</i>"
msgstr "<i>ምንም</i>"
-#: calendar/gui/e-itip-control.c:1031
+#: calendar/gui/e-itip-control.c:1061
msgid "Location:"
msgstr "ቦታ፦"
-#. write status
-#: calendar/gui/e-itip-control.c:1045 calendar/gui/e-tasks.c:243
+#: calendar/gui/e-itip-control.c:1075
msgid "Status:"
msgstr "ሁኔታ፦"
-#: calendar/gui/e-itip-control.c:1050 calendar/gui/itip-utils.c:414
+#: calendar/gui/e-itip-control.c:1080 calendar/gui/e-meeting-model.c:286
+#: calendar/gui/e-meeting-model.c:309 calendar/gui/e-meeting-model.c:798
+#: calendar/gui/itip-utils.c:414
msgid "Accepted"
msgstr ""
-#: calendar/gui/e-itip-control.c:1054 calendar/gui/itip-utils.c:417
+#: calendar/gui/e-itip-control.c:1084 calendar/gui/itip-utils.c:417
msgid "Tentatively Accepted"
msgstr ""
-#: calendar/gui/e-itip-control.c:1058 calendar/gui/itip-utils.c:420
-#: calendar/gui/itip-utils.c:446
+#: calendar/gui/e-itip-control.c:1088 calendar/gui/e-meeting-model.c:288
+#: calendar/gui/e-meeting-model.c:311 calendar/gui/e-meeting-model.c:799
+#: calendar/gui/itip-utils.c:420 calendar/gui/itip-utils.c:446
msgid "Declined"
msgstr ""
-#: calendar/gui/e-itip-control.c:1117 calendar/gui/e-itip-control.c:1145
-#: calendar/gui/e-itip-control.c:1171 calendar/gui/e-itip-control.c:1184
-#: calendar/gui/e-itip-control.c:1197 calendar/gui/e-itip-control.c:1210
+#: calendar/gui/e-itip-control.c:1092 calendar/gui/e-itip-control.c:1300
+#: calendar/gui/e-meeting-model.c:222 calendar/gui/e-meeting-model.c:257
+#: calendar/gui/e-meeting-model.c:322 calendar/gui/e-meeting-model.c:756
+#: calendar/gui/e-meeting-model.c:772 camel/camel-gpg-context.c:1574
+#: camel/camel-gpg-context.c:1625 camel/camel-tcp-stream-openssl.c:634
+#: camel/providers/smtp/camel-smtp-transport.c:173
+#: camel/providers/smtp/camel-smtp-transport.c:228 mail/folder-browser.c:345
+#: mail/mail-display.c:953 widgets/misc/e-charset-picker.c:60
+msgid "Unknown"
+msgstr "ያልታወቀ"
+
+#: calendar/gui/e-itip-control.c:1147 calendar/gui/e-itip-control.c:1175
+#: calendar/gui/e-itip-control.c:1201 calendar/gui/e-itip-control.c:1214
+#: calendar/gui/e-itip-control.c:1227 calendar/gui/e-itip-control.c:1240
msgid "Choose an action:"
msgstr ""
-#: calendar/gui/e-itip-control.c:1118
+#: calendar/gui/e-itip-control.c:1148
msgid "Update"
msgstr "አሻሽል"
-#: calendar/gui/e-itip-control.c:1119 calendar/gui/e-itip-control.c:1150
-#: calendar/gui/e-itip-control.c:1173 calendar/gui/e-itip-control.c:1186
-#: calendar/gui/e-itip-control.c:1199 calendar/gui/e-itip-control.c:1212
+#: calendar/gui/e-itip-control.c:1149 calendar/gui/e-itip-control.c:1180
+#: calendar/gui/e-itip-control.c:1203 calendar/gui/e-itip-control.c:1216
+#: calendar/gui/e-itip-control.c:1229 calendar/gui/e-itip-control.c:1242
#: shell/e-shell.c:2067 widgets/misc/e-cell-date-edit.c:265
msgid "OK"
msgstr "እሺ"
-#: calendar/gui/e-itip-control.c:1146
+#: calendar/gui/e-itip-control.c:1176
msgid "Accept"
msgstr ""
-#: calendar/gui/e-itip-control.c:1147
+#: calendar/gui/e-itip-control.c:1177
msgid "Tentatively accept"
msgstr ""
-#: calendar/gui/e-itip-control.c:1148
+#: calendar/gui/e-itip-control.c:1178
msgid "Decline"
msgstr ""
-#: calendar/gui/e-itip-control.c:1149
-#: calendar/gui/e-meeting-time-sel.etspec.h:8
-msgid "RSVP"
-msgstr ""
-
-#: calendar/gui/e-itip-control.c:1172
+#: calendar/gui/e-itip-control.c:1202
msgid "Send Free/Busy Information"
msgstr ""
-#: calendar/gui/e-itip-control.c:1185
+#: calendar/gui/e-itip-control.c:1215
msgid "Update respondent status"
msgstr ""
-#: calendar/gui/e-itip-control.c:1198
+#: calendar/gui/e-itip-control.c:1228
msgid "Send Latest Information"
msgstr ""
-#: calendar/gui/e-itip-control.c:1211 calendar/gui/itip-utils.c:434
-#: mail/mail-send-recv.c:388 mail/mail-send-recv.c:440
-#: shell/e-shell-startup-wizard.c:781 shell/evolution-shell-component.c:1185
-#: ui/evolution-mail-global.xml.h:1
+#: calendar/gui/e-itip-control.c:1241 calendar/gui/itip-utils.c:434
+#: mail/mail-send-recv.c:387 mail/mail-send-recv.c:444
+#: shell/evolution-shell-component.c:1182 ui/evolution-mail-global.xml.h:1
msgid "Cancel"
msgstr "ተወው"
-#: calendar/gui/e-itip-control.c:1300
+#: calendar/gui/e-itip-control.c:1322
#, c-format
msgid "<b>%s</b> has published meeting information."
msgstr ""
-#: calendar/gui/e-itip-control.c:1301
+#: calendar/gui/e-itip-control.c:1323
msgid "Meeting Information"
msgstr ""
-#: calendar/gui/e-itip-control.c:1306
+#: calendar/gui/e-itip-control.c:1328
#, c-format
msgid "<b>%s</b> requests the presence of %s at a meeting."
msgstr ""
-#: calendar/gui/e-itip-control.c:1308
+#: calendar/gui/e-itip-control.c:1330
#, c-format
msgid "<b>%s</b> requests your presence at a meeting."
msgstr ""
-#: calendar/gui/e-itip-control.c:1309
+#: calendar/gui/e-itip-control.c:1331
msgid "Meeting Proposal"
msgstr ""
-#: calendar/gui/e-itip-control.c:1313
+#: calendar/gui/e-itip-control.c:1335
#, c-format
msgid "<b>%s</b> wishes to add to an existing meeting."
msgstr ""
-#: calendar/gui/e-itip-control.c:1314
+#: calendar/gui/e-itip-control.c:1336
msgid "Meeting Update"
msgstr ""
-#: calendar/gui/e-itip-control.c:1318
+#: calendar/gui/e-itip-control.c:1340
#, c-format
msgid "<b>%s</b> wishes to receive the latest meeting information."
msgstr ""
-#: calendar/gui/e-itip-control.c:1319
+#: calendar/gui/e-itip-control.c:1341
msgid "Meeting Update Request"
msgstr ""
-#: calendar/gui/e-itip-control.c:1326
+#: calendar/gui/e-itip-control.c:1348
#, c-format
msgid "<b>%s</b> has replied to a meeting request."
msgstr ""
-#: calendar/gui/e-itip-control.c:1327
+#: calendar/gui/e-itip-control.c:1349
msgid "Meeting Reply"
msgstr ""
-#: calendar/gui/e-itip-control.c:1334
+#: calendar/gui/e-itip-control.c:1356
#, c-format
msgid "<b>%s</b> has cancelled a meeting."
msgstr ""
-#: calendar/gui/e-itip-control.c:1335
+#: calendar/gui/e-itip-control.c:1357
msgid "Meeting Cancellation"
msgstr ""
-#: calendar/gui/e-itip-control.c:1342 calendar/gui/e-itip-control.c:1409
-#: calendar/gui/e-itip-control.c:1444
+#: calendar/gui/e-itip-control.c:1364 calendar/gui/e-itip-control.c:1431
+#: calendar/gui/e-itip-control.c:1466
#, c-format
msgid "<b>%s</b> has sent an unintelligible message."
msgstr ""
-#: calendar/gui/e-itip-control.c:1343
+#: calendar/gui/e-itip-control.c:1365
msgid "Bad Meeting Message"
msgstr ""
-#: calendar/gui/e-itip-control.c:1367
+#: calendar/gui/e-itip-control.c:1389
#, c-format
msgid "<b>%s</b> has published task information."
msgstr ""
-#: calendar/gui/e-itip-control.c:1368
+#: calendar/gui/e-itip-control.c:1390
msgid "Task Information"
msgstr ""
-#: calendar/gui/e-itip-control.c:1373
+#: calendar/gui/e-itip-control.c:1395
#, c-format
msgid "<b>%s</b> requests %s to perform a task."
msgstr ""
-#: calendar/gui/e-itip-control.c:1375
+#: calendar/gui/e-itip-control.c:1397
#, c-format
msgid "<b>%s</b> requests you perform a task."
msgstr ""
-#: calendar/gui/e-itip-control.c:1376
+#: calendar/gui/e-itip-control.c:1398
msgid "Task Proposal"
msgstr ""
-#: calendar/gui/e-itip-control.c:1380
+#: calendar/gui/e-itip-control.c:1402
#, c-format
msgid "<b>%s</b> wishes to add to an existing task."
msgstr ""
-#: calendar/gui/e-itip-control.c:1381
+#: calendar/gui/e-itip-control.c:1403
msgid "Task Update"
msgstr ""
-#: calendar/gui/e-itip-control.c:1385
+#: calendar/gui/e-itip-control.c:1407
#, c-format
msgid "<b>%s</b> wishes to receive the latest task information."
msgstr ""
-#: calendar/gui/e-itip-control.c:1386
+#: calendar/gui/e-itip-control.c:1408
msgid "Task Update Request"
msgstr ""
-#: calendar/gui/e-itip-control.c:1393
+#: calendar/gui/e-itip-control.c:1415
#, c-format
msgid "<b>%s</b> has replied to a task assignment."
msgstr ""
-#: calendar/gui/e-itip-control.c:1394
+#: calendar/gui/e-itip-control.c:1416
msgid "Task Reply"
msgstr ""
-#: calendar/gui/e-itip-control.c:1401
+#: calendar/gui/e-itip-control.c:1423
#, c-format
msgid "<b>%s</b> has cancelled a task."
msgstr ""
-#: calendar/gui/e-itip-control.c:1402
+#: calendar/gui/e-itip-control.c:1424
msgid "Task Cancellation"
msgstr ""
-#: calendar/gui/e-itip-control.c:1410
+#: calendar/gui/e-itip-control.c:1432
msgid "Bad Task Message"
msgstr ""
-#: calendar/gui/e-itip-control.c:1429
+#: calendar/gui/e-itip-control.c:1451
#, c-format
msgid "<b>%s</b> has published free/busy information."
msgstr ""
-#: calendar/gui/e-itip-control.c:1430
+#: calendar/gui/e-itip-control.c:1452
msgid "Free/Busy Information"
msgstr ""
-#: calendar/gui/e-itip-control.c:1434
+#: calendar/gui/e-itip-control.c:1456
#, c-format
msgid "<b>%s</b> requests your free/busy information."
msgstr ""
-#: calendar/gui/e-itip-control.c:1435
+#: calendar/gui/e-itip-control.c:1457
msgid "Free/Busy Request"
msgstr ""
-#: calendar/gui/e-itip-control.c:1439
+#: calendar/gui/e-itip-control.c:1461
#, c-format
msgid "<b>%s</b> has replied to a free/busy request."
msgstr ""
-#: calendar/gui/e-itip-control.c:1440
+#: calendar/gui/e-itip-control.c:1462
msgid "Free/Busy Reply"
msgstr ""
-#: calendar/gui/e-itip-control.c:1445
+#: calendar/gui/e-itip-control.c:1467
msgid "Bad Free/Busy Message"
msgstr ""
-#: calendar/gui/e-itip-control.c:1521
+#: calendar/gui/e-itip-control.c:1543
msgid "The message does not appear to be properly formed"
msgstr ""
-#: calendar/gui/e-itip-control.c:1584
+#: calendar/gui/e-itip-control.c:1606
msgid "The message contains only unsupported requests."
msgstr ""
-#: calendar/gui/e-itip-control.c:1615 calendar/gui/e-itip-control.c:1621
+#: calendar/gui/e-itip-control.c:1637 calendar/gui/e-itip-control.c:1643
msgid "The attachment does not contain a valid calendar message"
msgstr ""
-#: calendar/gui/e-itip-control.c:1646
+#: calendar/gui/e-itip-control.c:1668
msgid "The attachment has no viewable calendar items"
msgstr ""
-#: calendar/gui/e-itip-control.c:1887 calendar/gui/e-itip-control.c:1948
-#: calendar/gui/e-itip-control.c:1986
+#: calendar/gui/e-itip-control.c:1909 calendar/gui/e-itip-control.c:2001
msgid "Object is invalid and cannot be updated\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:1890 calendar/gui/e-itip-control.c:1989
+#: calendar/gui/e-itip-control.c:1912 calendar/gui/e-itip-control.c:2004
msgid "There was an error on the CORBA system\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:1893 calendar/gui/e-itip-control.c:1992
+#: calendar/gui/e-itip-control.c:1915 calendar/gui/e-itip-control.c:2007
msgid "Object could not be found\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:1896
+#: calendar/gui/e-itip-control.c:1918
msgid "You do not have the right permissions to update the calendar\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:1899
+#: calendar/gui/e-itip-control.c:1921
msgid "Update complete\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:1902
+#: calendar/gui/e-itip-control.c:1924
msgid "Calendar file could not be updated!\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:1932 calendar/gui/e-itip-control.c:2004
+#: calendar/gui/e-itip-control.c:1953 calendar/gui/e-itip-control.c:2019
msgid "Attendee status can not be updated because the item no longer exists"
msgstr ""
-#: calendar/gui/e-itip-control.c:1958
+#: calendar/gui/e-itip-control.c:1974
msgid "This response is not from a current attendee. Add as an attendee?"
msgstr ""
-#: calendar/gui/e-itip-control.c:1970
+#: calendar/gui/e-itip-control.c:1986
msgid "Attendee status could not be updated because of an invalid status!\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:1995
+#: calendar/gui/e-itip-control.c:2010
msgid "You don't have the right permissions to update the calendar\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:1998
+#: calendar/gui/e-itip-control.c:2013
msgid "Attendee status updated\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:2001
+#: calendar/gui/e-itip-control.c:2016
msgid "Attendee status could not be updated!\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:2038
+#: calendar/gui/e-itip-control.c:2053
msgid "Removal Complete"
msgstr ""
-#: calendar/gui/e-itip-control.c:2070 calendar/gui/e-itip-control.c:2120
+#: calendar/gui/e-itip-control.c:2085 calendar/gui/e-itip-control.c:2135
msgid "Item sent!\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:2072 calendar/gui/e-itip-control.c:2124
+#: calendar/gui/e-itip-control.c:2087 calendar/gui/e-itip-control.c:2139
msgid "The item could not be sent!\n"
msgstr ""
-#: calendar/gui/e-itip-control.c:2215
+#: calendar/gui/e-itip-control.c:2212
msgid "Select Calendar Folder"
msgstr ""
-#: calendar/gui/e-itip-control.c:2221
+#: calendar/gui/e-itip-control.c:2219
msgid "Select Tasks Folder"
msgstr ""
@@ -5818,271 +5798,247 @@ msgstr ""
msgid "date-start"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:392
-msgid "Tentative"
+#: calendar/gui/e-meeting-model.c:79
+msgid "Chair Persons"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:394 designs/OOA/ooa.glade.h:11
-msgid "Out of Office"
+#: calendar/gui/e-meeting-model.c:80 calendar/gui/e-meeting-model.c:1636
+msgid "Required Participants"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:395
-msgid "No Information"
+#: calendar/gui/e-meeting-model.c:81
+msgid "Optional Participants"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:434
-msgid "_Options"
-msgstr "ምርጫዎች (_O)"
-
-#: calendar/gui/e-meeting-time-sel.c:451
-msgid "Show _Only Working Hours"
+#: calendar/gui/e-meeting-model.c:82
+msgid "Resources"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:461
-msgid "Show _Zoomed Out"
+#: calendar/gui/e-meeting-model.c:197 calendar/gui/e-meeting-model.c:214
+#: calendar/gui/e-meeting-model.c:530 calendar/gui/e-meeting-model.c:752
+msgid "Individual"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:476
-msgid "_Update Free/Busy"
+#: calendar/gui/e-meeting-model.c:199 calendar/gui/e-meeting-model.c:216
+#: calendar/gui/e-meeting-model.c:753
+msgid "Group"
+msgstr "የውይይት መድረክ"
+
+#: calendar/gui/e-meeting-model.c:201 calendar/gui/e-meeting-model.c:218
+#: calendar/gui/e-meeting-model.c:754
+msgid "Resource"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:491
-msgid "_<<"
-msgstr "_<<"
+#: calendar/gui/e-meeting-model.c:203 calendar/gui/e-meeting-model.c:220
+#: calendar/gui/e-meeting-model.c:755
+msgid "Room"
+msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:509
-msgid "_Autopick"
+#: calendar/gui/e-meeting-model.c:232 calendar/gui/e-meeting-model.c:249
+#: calendar/gui/e-meeting-model.c:768
+msgid "Chair"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:524
-msgid ">_>"
-msgstr ">_>"
+#: calendar/gui/e-meeting-model.c:234 calendar/gui/e-meeting-model.c:251
+#: calendar/gui/e-meeting-model.c:532 calendar/gui/e-meeting-model.c:769
+msgid "Required Participant"
+msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:541
-msgid "_All People and Resources"
+#: calendar/gui/e-meeting-model.c:236 calendar/gui/e-meeting-model.c:253
+#: calendar/gui/e-meeting-model.c:770
+msgid "Optional Participant"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:550
-msgid "All _People and One Resource"
+#: calendar/gui/e-meeting-model.c:238 calendar/gui/e-meeting-model.c:255
+#: calendar/gui/e-meeting-model.c:771
+msgid "Non-Participant"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:559
-msgid "_Required People"
+#: calendar/gui/e-meeting-model.c:284 calendar/gui/e-meeting-model.c:307
+#: calendar/gui/e-meeting-model.c:540 calendar/gui/e-meeting-model.c:797
+msgid "Needs Action"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:568
-msgid "Required People and _One Resource"
+#: calendar/gui/e-meeting-model.c:290 calendar/gui/e-meeting-model.c:313
+#: calendar/gui/e-meeting-model.c:800 calendar/gui/e-meeting-time-sel.c:405
+msgid "Tentative"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:587
-msgid "Meeting _start time:"
+#: calendar/gui/e-meeting-model.c:292 calendar/gui/e-meeting-model.c:315
+#: calendar/gui/e-meeting-model.c:801
+msgid "Delegated"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.c:607
-msgid "Meeting _end time:"
+#: calendar/gui/e-meeting-model.c:296 calendar/gui/e-meeting-model.c:319
+msgid "In Process"
msgstr ""
#. This is a strftime() format string %A = full weekday name,
#. %B = full month name, %d = month day, %Y = full year.
-#: calendar/gui/e-meeting-time-sel.c:2054
-#: calendar/gui/e-meeting-time-sel-item.c:452
+#: calendar/gui/e-meeting-time-sel-item.c:458
+#: calendar/gui/e-meeting-time-sel.c:2098
msgid "%A, %B %d, %Y"
msgstr "%A, %B %d, %Y"
-#. This is a strftime() format string %a = abbreviated weekday name,
-#. %m = month number, %d = month day, %Y = full year.
-#: calendar/gui/e-meeting-time-sel.c:2087
-#: calendar/gui/e-meeting-time-sel-item.c:456 e-util/e-time-utils.c:203
-#: e-util/e-time-utils.c:296 e-util/e-time-utils.c:384
+#. This is a strftime() format string %a = abbreviated weekday
+#. name, %m = month number, %d = month day, %Y = full year.
+#: calendar/gui/e-meeting-time-sel-item.c:462
+#: calendar/gui/e-meeting-time-sel.c:2131 e-util/e-time-utils.c:190
+#: e-util/e-time-utils.c:283 e-util/e-time-utils.c:371
msgid "%a %m/%d/%Y"
msgstr "%a %m/%d/%Y"
-#: calendar/gui/e-meeting-time-sel.etspec.h:1
-msgid "Attendee"
+#. This is a strftime() format string %m = month number,
+#. %d = month day, %Y = full year.
+#: calendar/gui/e-meeting-time-sel-item.c:466 e-util/e-time-utils.c:225
+#: e-util/e-time-utils.c:286 widgets/misc/e-dateedit.c:1582
+msgid "%m/%d/%Y"
+msgstr "%d/%m/%Y"
+
+#: calendar/gui/e-meeting-time-sel.c:407 designs/OOA/ooa.glade.h:11
+msgid "Out of Office"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.etspec.h:2
-msgid "Click here to add an attendee"
+#: calendar/gui/e-meeting-time-sel.c:408
+msgid "No Information"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.etspec.h:3
-msgid "Common Name"
+#: calendar/gui/e-meeting-time-sel.c:447
+msgid "_Options"
+msgstr "ምርጫዎች (_O)"
+
+#: calendar/gui/e-meeting-time-sel.c:464
+msgid "Show _Only Working Hours"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.etspec.h:4
-msgid "Delegated From"
+#: calendar/gui/e-meeting-time-sel.c:474
+msgid "Show _Zoomed Out"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.etspec.h:5
-msgid "Delegated To"
+#: calendar/gui/e-meeting-time-sel.c:489
+msgid "_Update Free/Busy"
msgstr ""
-#: calendar/gui/e-meeting-time-sel.etspec.h:6
-msgid "Language"
-msgstr "ቋንቋ"
+#: calendar/gui/e-meeting-time-sel.c:504
+msgid "_<<"
+msgstr "_<<"
-#: calendar/gui/e-meeting-time-sel.etspec.h:7
-msgid "Member"
+#: calendar/gui/e-meeting-time-sel.c:522
+msgid "_Autopick"
msgstr ""
-#. This is a strftime() format string %m = month number,
-#. %d = month day, %Y = full year.
-#: calendar/gui/e-meeting-time-sel-item.c:460 e-util/e-time-utils.c:238
-#: e-util/e-time-utils.c:299 widgets/misc/e-dateedit.c:1607
-msgid "%m/%d/%Y"
-msgstr "%d/%m/%Y"
+#: calendar/gui/e-meeting-time-sel.c:537
+msgid ">_>"
+msgstr ">_>"
-#: calendar/gui/e-tasks.c:151
-msgid "invalid time"
+#: calendar/gui/e-meeting-time-sel.c:554
+msgid "_All People and Resources"
msgstr ""
-#: calendar/gui/e-tasks.c:221
-#, fuzzy
-msgid "Start Date:"
-msgstr "ቀን፦"
+#: calendar/gui/e-meeting-time-sel.c:563
+msgid "All _People and One Resource"
+msgstr ""
-#: calendar/gui/e-tasks.c:237
-#, fuzzy
-msgid "Due Date:"
-msgstr "ቀን፦"
+#: calendar/gui/e-meeting-time-sel.c:572
+msgid "_Required People"
+msgstr ""
-#. write priority
-#: calendar/gui/e-tasks.c:265
-#, fuzzy
-msgid "Priority:"
-msgstr "ቅድሚያ"
+#: calendar/gui/e-meeting-time-sel.c:581
+msgid "Required People and _One Resource"
+msgstr ""
-#. URL
-#: calendar/gui/e-tasks.c:321
-#, fuzzy
-msgid "Web Page:"
-msgstr "ገጽ"
+#: calendar/gui/e-meeting-time-sel.c:600
+msgid "Meeting _start time:"
+msgstr ""
+
+#: calendar/gui/e-meeting-time-sel.c:620
+msgid "Meeting _end time:"
+msgstr ""
-#: calendar/gui/e-tasks.c:702
+#: calendar/gui/e-tasks.c:360 calendar/gui/gnome-cal.c:2006
+#: calendar/gui/gnome-cal.c:2017
#, c-format
msgid "Opening tasks at %s"
msgstr ""
-#: calendar/gui/e-tasks.c:731 calendar/gui/tasks-control.c:201
+#: calendar/gui/e-tasks.c:389 calendar/gui/tasks-control.c:201
#, c-format
msgid "Could not load the tasks in `%s'"
msgstr ""
-#: calendar/gui/e-tasks.c:746
+#: calendar/gui/e-tasks.c:404
#, c-format
msgid "The method required to load `%s' is not supported"
msgstr ""
-#: calendar/gui/e-tasks.c:760 calendar/gui/gnome-cal.c:1730
+#: calendar/gui/e-tasks.c:418 calendar/gui/gnome-cal.c:1509
#, c-format
msgid "You don't have permission to open the folder in `%s'"
msgstr ""
-#: calendar/gui/e-tasks.c:828 calendar/gui/gnome-cal.c:1944
+#: calendar/gui/e-tasks.c:486 calendar/gui/gnome-cal.c:1728
#, c-format
msgid ""
"Error on %s:\n"
" %s"
msgstr ""
-#: calendar/gui/e-tasks.c:899
+#: calendar/gui/e-tasks.c:557
msgid "Completing tasks..."
msgstr ""
-#: calendar/gui/e-tasks.c:922
+#: calendar/gui/e-tasks.c:580
msgid "Deleting selected objects..."
msgstr ""
-#: calendar/gui/e-tasks.c:1017
+#: calendar/gui/e-tasks.c:675
msgid "Expunging"
msgstr ""
-#: calendar/gui/gnome-cal.c:1702
+#: calendar/gui/e-week-view.c:3581
+msgid "New _Appointment..."
+msgstr ""
+
+#: calendar/gui/gnome-cal.c:1481
#, c-format
msgid "Could not open the folder in `%s'"
msgstr ""
-#: calendar/gui/gnome-cal.c:1716
+#: calendar/gui/gnome-cal.c:1495
#, c-format
msgid "The method required to open `%s' is not supported"
msgstr ""
-#: calendar/gui/gnome-cal.c:1772
+#: calendar/gui/gnome-cal.c:1556
#, c-format
msgid "Adding alarms for %s"
msgstr ""
-#: calendar/gui/gnome-cal.c:1964
+#: calendar/gui/gnome-cal.c:1748
#, c-format
msgid ""
-"The task backend for\n"
+"The calendar backend for\n"
"%s\n"
" has crashed. You will have to restart Evolution in order to use it again"
msgstr ""
-#: calendar/gui/gnome-cal.c:1970
+#: calendar/gui/gnome-cal.c:1757
#, c-format
msgid ""
-"The calendar backend for\n"
+"The task backend for\n"
"%s\n"
" has crashed. You will have to restart Evolution in order to use it again"
msgstr ""
-#: calendar/gui/gnome-cal.c:2176
+#: calendar/gui/gnome-cal.c:1988
#, c-format
msgid "Opening calendar at %s"
msgstr ""
-#: calendar/gui/gnome-cal.c:2197
+#: calendar/gui/gnome-cal.c:2028
msgid "Opening default tasks folder"
msgstr ""
-#: calendar/gui/gnome-cal.c:3094
-#, c-format
-msgid "Purging event %s"
-msgstr ""
-
-#: calendar/gui/gnome-cal.c:3178
-#, fuzzy
-msgid "Purging"
-msgstr "አትም"
-
-#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:1
-msgid "Calendar and Tasks"
-msgstr ""
-
-#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:2
-msgid "Configure your timezone, Calendar and Task List here "
-msgstr ""
-
-#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:3
-msgid "Evolution Calendar and Tasks"
-msgstr ""
-
-#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:4
-msgid "Evolution Calendar and Tasks component"
-msgstr ""
-
-#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:5
-msgid "Evolution Calendar configuration control"
-msgstr ""
-
-#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:6
-msgid "Evolution Calendar scheduling message viewer"
-msgstr ""
-
-#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:7
-msgid "Evolution Calendar viewer"
-msgstr ""
-
-#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:8
-msgid "Evolution Calendar/Task editor"
-msgstr ""
-
-#: calendar/gui/GNOME_Evolution_Calendar.server.in.in.h:9
-msgid "Evolution Tasks viewer"
-msgstr ""
-
#: calendar/gui/goto-dialog.glade.h:1
msgid "April"
msgstr "ኤፕረል"
@@ -6189,7 +6145,7 @@ msgstr ""
msgid "iCalendar information"
msgstr ""
-#: calendar/gui/itip-utils.c:668
+#: calendar/gui/itip-utils.c:667
msgid "You must be an attendee of the event."
msgstr ""
@@ -6222,81 +6178,82 @@ msgid "Sa"
msgstr "ቅ"
#. Day
-#: calendar/gui/print.c:1882
+#: calendar/gui/print.c:1875
msgid "Selected day (%a %b %d %Y)"
msgstr ""
-#: calendar/gui/print.c:1907 calendar/gui/print.c:1911
+#: calendar/gui/print.c:1900 calendar/gui/print.c:1904
msgid "%a %b %d"
msgstr "%a %b %d"
-#: calendar/gui/print.c:1908
+#: calendar/gui/print.c:1901
msgid "%a %d %Y"
msgstr "%a %d %Y"
-#: calendar/gui/print.c:1912 calendar/gui/print.c:1914
-#: calendar/gui/print.c:1915
+#: calendar/gui/print.c:1905 calendar/gui/print.c:1907
+#: calendar/gui/print.c:1908
msgid "%a %b %d %Y"
msgstr "%a %b %d %Y"
-#: calendar/gui/print.c:1919
+#: calendar/gui/print.c:1912
#, c-format
msgid "Selected week (%s - %s)"
msgstr ""
#. Month
-#: calendar/gui/print.c:1927
+#: calendar/gui/print.c:1920
msgid "Selected month (%b %Y)"
msgstr ""
#. Year
-#: calendar/gui/print.c:1934
+#: calendar/gui/print.c:1927
msgid "Selected year (%Y)"
msgstr ""
-#: calendar/gui/print.c:2262
+#: calendar/gui/print.c:2255
msgid "Task"
msgstr ""
-#: calendar/gui/print.c:2321
+#: calendar/gui/print.c:2314
#, c-format
msgid "Status: %s"
msgstr "ሁኔታ፦ %s"
-#: calendar/gui/print.c:2338
+#: calendar/gui/print.c:2331
#, c-format
msgid "Priority: %s"
msgstr "ቅድሚያ፦ %s"
-#: calendar/gui/print.c:2350
+#: calendar/gui/print.c:2343
#, c-format
msgid "Percent Complete: %i"
msgstr ""
-#: calendar/gui/print.c:2362
+#: calendar/gui/print.c:2355
#, c-format
msgid "URL: %s"
msgstr "URL፦ %s"
-#: calendar/gui/print.c:2376
+#: calendar/gui/print.c:2369
#, c-format
msgid "Categories: %s"
msgstr "ምድቦች፦ %s"
-#: calendar/gui/print.c:2387
+#: calendar/gui/print.c:2380
msgid "Contacts: "
msgstr ""
-#: calendar/gui/print.c:2525 calendar/gui/print.c:2611
-#: calendar/gui/tasks-control.c:564 my-evolution/e-summary.c:649
+#: calendar/gui/print.c:2518 calendar/gui/print.c:2604
+#: calendar/gui/tasks-control.c:581 mail/mail-callbacks.c:2948
+#: my-evolution/e-summary.c:649
msgid "Print Preview"
msgstr "የቅድመ ህትመት ዕይታ"
-#: calendar/gui/print.c:2559
+#: calendar/gui/print.c:2552
msgid "Print Item"
msgstr ""
-#: calendar/gui/print.c:2632
+#: calendar/gui/print.c:2625
msgid "Print Setup"
msgstr "የህትመት ቅንጅት"
@@ -6304,7 +6261,7 @@ msgstr "የህትመት ቅንጅት"
msgid "The URI of the tasks folder to display"
msgstr ""
-#: calendar/gui/tasks-control.c:448
+#: calendar/gui/tasks-control.c:465
msgid ""
"This operation will permanently erase all tasks marked as completed. If you "
"continue, you will not be able to recover these tasks.\n"
@@ -6312,11 +6269,11 @@ msgid ""
"Really erase these tasks?"
msgstr ""
-#: calendar/gui/tasks-control.c:451
+#: calendar/gui/tasks-control.c:468
msgid "Do not ask me again."
msgstr ""
-#: calendar/gui/tasks-control.c:593
+#: calendar/gui/tasks-control.c:610
msgid "Print Tasks"
msgstr ""
@@ -8003,27 +7960,27 @@ msgstr ""
msgid "Pacific/Yap"
msgstr ""
-#: camel/camel-cipher-context.c:167
+#: camel/camel-cipher-context.c:178
msgid "Signing is not supported by this cipher"
msgstr ""
-#: camel/camel-cipher-context.c:207
+#: camel/camel-cipher-context.c:218
msgid "Verifying is not supported by this cipher"
msgstr ""
-#: camel/camel-cipher-context.c:251
+#: camel/camel-cipher-context.c:262
msgid "Encryption is not supported by this cipher"
msgstr ""
-#: camel/camel-cipher-context.c:293
+#: camel/camel-cipher-context.c:304
msgid "Decryption is not supported by this cipher"
msgstr ""
-#: camel/camel-cipher-context.c:331
+#: camel/camel-cipher-context.c:342
msgid "You may not import keys with this cipher"
msgstr ""
-#: camel/camel-cipher-context.c:363
+#: camel/camel-cipher-context.c:374
msgid "You may not export keys with this cipher"
msgstr ""
@@ -8056,11 +8013,7 @@ msgstr ""
msgid "Resynchronizing with server"
msgstr ""
-#: camel/camel-disco-folder.c:90
-msgid "Downloading new messages for offline mode"
-msgstr ""
-
-#: camel/camel-disco-folder.c:351
+#: camel/camel-disco-folder.c:278
#, c-format
msgid "Preparing folder '%s' for offline"
msgstr ""
@@ -8081,57 +8034,57 @@ msgstr ""
msgid "Failed to create create child process '%s': %s"
msgstr ""
-#: camel/camel-filter-driver.c:759
+#: camel/camel-filter-driver.c:744
#, c-format
msgid "Invalid message stream received from %s: %s"
msgstr ""
-#: camel/camel-filter-driver.c:940 camel/camel-filter-driver.c:949
+#: camel/camel-filter-driver.c:923 camel/camel-filter-driver.c:932
msgid "Syncing folders"
msgstr ""
-#: camel/camel-filter-driver.c:1038 camel/camel-filter-driver.c:1411
+#: camel/camel-filter-driver.c:1021 camel/camel-filter-driver.c:1394
#, c-format
msgid "Error parsing filter: %s: %s"
msgstr ""
-#: camel/camel-filter-driver.c:1047 camel/camel-filter-driver.c:1417
+#: camel/camel-filter-driver.c:1030 camel/camel-filter-driver.c:1400
#, c-format
msgid "Error executing filter: %s: %s"
msgstr ""
-#: camel/camel-filter-driver.c:1114
+#: camel/camel-filter-driver.c:1097
msgid "Unable to open spool folder"
msgstr ""
-#: camel/camel-filter-driver.c:1123
+#: camel/camel-filter-driver.c:1106
msgid "Unable to process spool folder"
msgstr ""
-#: camel/camel-filter-driver.c:1138
+#: camel/camel-filter-driver.c:1121
#, c-format
msgid "Getting message %d (%d%%)"
msgstr ""
-#: camel/camel-filter-driver.c:1142
+#: camel/camel-filter-driver.c:1125
msgid "Cannot open message"
msgstr ""
-#: camel/camel-filter-driver.c:1143 camel/camel-filter-driver.c:1155
+#: camel/camel-filter-driver.c:1126 camel/camel-filter-driver.c:1138
#, c-format
msgid "Failed on message %d"
msgstr ""
-#: camel/camel-filter-driver.c:1169 camel/camel-filter-driver.c:1263
+#: camel/camel-filter-driver.c:1152 camel/camel-filter-driver.c:1246
msgid "Syncing folder"
msgstr ""
-#: camel/camel-filter-driver.c:1230
+#: camel/camel-filter-driver.c:1213
#, c-format
msgid "Getting message %d of %d"
msgstr ""
-#: camel/camel-filter-driver.c:1245
+#: camel/camel-filter-driver.c:1228
#, c-format
msgid "Failed at message %d of %d"
msgstr ""
@@ -8153,54 +8106,50 @@ msgstr ""
msgid "Error executing filter search: %s: %s"
msgstr ""
-#: camel/camel-folder.c:585
+#: camel/camel-folder-search.c:346
#, c-format
-msgid "Unsupported operation: append message: for %s"
-msgstr ""
-
-#: camel/camel-folder.c:1163
-#, c-format
-msgid "Unsupported operation: search by expression: for %s"
+msgid ""
+"Cannot parse search expression: %s:\n"
+"%s"
msgstr ""
-#: camel/camel-folder.c:1203
+#: camel/camel-folder-search.c:356
#, c-format
-msgid "Unsupported operation: search by uids: for %s"
+msgid ""
+"Error executing search expression: %s:\n"
+"%s"
msgstr ""
-#: camel/camel-folder.c:1321
-msgid "Moving messages"
+#: camel/camel-folder-search.c:573 camel/camel-folder-search.c:601
+msgid "(match-all) requires a single bool result"
msgstr ""
-#: camel/camel-folder.c:1321
-msgid "Copying messages"
+#: camel/camel-folder-search.c:653
+#, c-format
+msgid "Performing query on unknown header: %s"
msgstr ""
-#: camel/camel-folder.c:1571
-msgid "Filtering new message(s)"
+#: camel/camel-folder.c:583
+#, c-format
+msgid "Unsupported operation: append message: for %s"
msgstr ""
-#: camel/camel-folder-search.c:348
+#: camel/camel-folder.c:1161
#, c-format
-msgid ""
-"Cannot parse search expression: %s:\n"
-"%s"
+msgid "Unsupported operation: search by expression: for %s"
msgstr ""
-#: camel/camel-folder-search.c:358
+#: camel/camel-folder.c:1201
#, c-format
-msgid ""
-"Error executing search expression: %s:\n"
-"%s"
+msgid "Unsupported operation: search by uids: for %s"
msgstr ""
-#: camel/camel-folder-search.c:569 camel/camel-folder-search.c:598
-msgid "(match-all) requires a single bool result"
+#: camel/camel-folder.c:1319
+msgid "Moving messages"
msgstr ""
-#: camel/camel-folder-search.c:650
-#, c-format
-msgid "Performing query on unknown header: %s"
+#: camel/camel-folder.c:1319
+msgid "Copying messages"
msgstr ""
#: camel/camel-gpg-context.c:762
@@ -8228,7 +8177,7 @@ msgstr ""
#: camel/camel-gpg-context.c:821 camel/camel-gpg-context.c:1297
#: camel/camel-gpg-context.c:1403 camel/camel-gpg-context.c:1473
-#: camel/camel-gpg-context.c:1529 mail/mail-send-recv.c:574
+#: camel/camel-gpg-context.c:1529 mail/mail-send-recv.c:577
msgid "Cancelled."
msgstr ""
@@ -8280,44 +8229,44 @@ msgstr ""
msgid "Cannot verify message signature: could not create temp file: %s"
msgstr ""
-#: camel/camel-lock.c:92 camel/camel-lock.c:113
+#: camel/camel-lock-client.c:111
#, c-format
-msgid "Could not create lock file for %s: %s"
+msgid "Cannot build locking helper pipe: %s"
msgstr ""
-#: camel/camel-lock.c:154
+#: camel/camel-lock-client.c:124
#, c-format
-msgid "Timed out trying to get lock file on %s. Try again later."
+msgid "Cannot fork locking helper: %s"
msgstr ""
-#: camel/camel-lock.c:209
+#: camel/camel-lock-client.c:202 camel/camel-lock-client.c:225
#, c-format
-msgid "Failed to get lock using fcntl(2): %s"
+msgid "Could not lock '%s': protocol error with lock-helper"
msgstr ""
-#: camel/camel-lock.c:272
+#: camel/camel-lock-client.c:215
#, c-format
-msgid "Failed to get lock using flock(2): %s"
+msgid "Could not lock '%s'"
msgstr ""
-#: camel/camel-lock-client.c:100
+#: camel/camel-lock.c:92 camel/camel-lock.c:113
#, c-format
-msgid "Cannot build locking helper pipe: %s"
+msgid "Could not create lock file for %s: %s"
msgstr ""
-#: camel/camel-lock-client.c:113
+#: camel/camel-lock.c:154
#, c-format
-msgid "Cannot fork locking helper: %s"
+msgid "Timed out trying to get lock file on %s. Try again later."
msgstr ""
-#: camel/camel-lock-client.c:191 camel/camel-lock-client.c:214
+#: camel/camel-lock.c:209
#, c-format
-msgid "Could not lock '%s': protocol error with lock-helper"
+msgid "Failed to get lock using fcntl(2): %s"
msgstr ""
-#: camel/camel-lock-client.c:204
+#: camel/camel-lock.c:272
#, c-format
-msgid "Could not lock '%s'"
+msgid "Failed to get lock using flock(2): %s"
msgstr ""
#: camel/camel-movemail.c:107
@@ -8386,11 +8335,11 @@ msgstr ""
msgid "Failed to decrypt MIME part: parse error"
msgstr ""
-#: camel/camel-multipart-signed.c:646
+#: camel/camel-multipart-signed.c:644
msgid "This is a digitally signed message part"
msgstr ""
-#: camel/camel-multipart-signed.c:700
+#: camel/camel-multipart-signed.c:698
msgid "parse error"
msgstr ""
@@ -8452,11 +8401,11 @@ msgid ""
"the server supports it."
msgstr ""
-#: camel/camel-sasl-digest-md5.c:48
+#: camel/camel-sasl-digest-md5.c:46
msgid "DIGEST-MD5"
msgstr ""
-#: camel/camel-sasl-digest-md5.c:50
+#: camel/camel-sasl-digest-md5.c:48
msgid ""
"This option will connect to the server using a secure DIGEST-MD5 password, "
"if the server supports it."
@@ -8547,7 +8496,7 @@ msgstr ""
#: camel/camel-sasl-gssapi.c:189 camel/camel-sasl-gssapi.c:238
#: camel/camel-sasl-gssapi.c:274 camel/camel-sasl-gssapi.c:289
#: camel/camel-sasl-kerberos4.c:219
-#: camel/providers/imap/camel-imap-store.c:1207
+#: camel/providers/imap/camel-imap-store.c:1052
msgid "Bad authentication response from server."
msgstr ""
@@ -8601,23 +8550,23 @@ msgstr ""
msgid "PLAIN"
msgstr "ቀላል"
-#: camel/camel-sasl-popb4smtp.c:36
+#: camel/camel-sasl-popb4smtp.c:34
msgid "POP before SMTP"
msgstr ""
-#: camel/camel-sasl-popb4smtp.c:38
+#: camel/camel-sasl-popb4smtp.c:36
msgid "This option will authorise a POP connection before attempting SMTP"
msgstr ""
-#: camel/camel-sasl-popb4smtp.c:103
+#: camel/camel-sasl-popb4smtp.c:107
msgid "POP Source URI"
msgstr ""
-#: camel/camel-sasl-popb4smtp.c:107
+#: camel/camel-sasl-popb4smtp.c:111
msgid "POP Before SMTP auth using an unknown transport"
msgstr ""
-#: camel/camel-sasl-popb4smtp.c:112
+#: camel/camel-sasl-popb4smtp.c:116
msgid "POP Before SMTP auth using a non-pop source"
msgstr ""
@@ -8626,55 +8575,55 @@ msgstr ""
msgid "Regular expression compilation failed: %s: %s"
msgstr ""
-#: camel/camel-service.c:277
+#: camel/camel-service.c:282
#, c-format
msgid "URL '%s' needs a username component"
msgstr ""
-#: camel/camel-service.c:285
+#: camel/camel-service.c:290
#, c-format
msgid "URL '%s' needs a host component"
msgstr ""
-#: camel/camel-service.c:293
+#: camel/camel-service.c:298
#, c-format
msgid "URL '%s' needs a path component"
msgstr ""
-#: camel/camel-service.c:738
+#: camel/camel-service.c:750
#, c-format
msgid "Resolving: %s"
msgstr ""
-#: camel/camel-service.c:769 camel/camel-service.c:893
+#: camel/camel-service.c:783 camel/camel-service.c:915
#, c-format
msgid "Failure in name lookup: %s"
msgstr ""
-#: camel/camel-service.c:790 camel/camel-service.c:914
+#: camel/camel-service.c:804
#, c-format
msgid "Host lookup failed: cannot create thread: %s"
msgstr ""
-#: camel/camel-service.c:803
+#: camel/camel-service.c:818
#, c-format
msgid "Host lookup failed: %s: host not found"
msgstr ""
-#: camel/camel-service.c:806
+#: camel/camel-service.c:821
#, c-format
msgid "Host lookup failed: %s: unknown reason"
msgstr ""
-#: camel/camel-service.c:860
+#: camel/camel-service.c:880
msgid "Resolving address"
msgstr ""
-#: camel/camel-service.c:929
+#: camel/camel-service.c:949
msgid "Host lookup failed: host not found"
msgstr ""
-#: camel/camel-service.c:932
+#: camel/camel-service.c:952
msgid "Host lookup failed: unknown reason"
msgstr ""
@@ -8686,12 +8635,12 @@ msgstr ""
msgid "For reading mail as a query of another set of folders"
msgstr ""
-#: camel/camel-session.c:350 camel/camel-session.c:400
+#: camel/camel-session.c:355 camel/camel-session.c:405
#, c-format
msgid "No provider available for protocol `%s'"
msgstr ""
-#: camel/camel-session.c:523
+#: camel/camel-session.c:528
#, c-format
msgid ""
"Could not create directory %s:\n"
@@ -8735,131 +8684,131 @@ msgstr ""
msgid "Failed to verify certificates."
msgstr ""
-#: camel/camel-store.c:212
+#: camel/camel-store.c:215
msgid "Cannot get folder: Invalid operation on this store"
msgstr ""
-#: camel/camel-store.c:266
+#: camel/camel-store.c:269
msgid "Cannot create folder: Invalid operation on this store"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:568
+#: camel/camel-tcp-stream-openssl.c:571
msgid "Unable to get issuer's certificate"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:570
+#: camel/camel-tcp-stream-openssl.c:573
msgid "Unable to get Certificate Revocation List"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:572
+#: camel/camel-tcp-stream-openssl.c:575
msgid "Unable to decrypt certificate signature"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:574
+#: camel/camel-tcp-stream-openssl.c:577
msgid "Unable to decrypt Certificate Revocation List signature"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:576
+#: camel/camel-tcp-stream-openssl.c:579
msgid "Unable to decode issuer's public key"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:578
+#: camel/camel-tcp-stream-openssl.c:581
msgid "Certificate signature failure"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:580
+#: camel/camel-tcp-stream-openssl.c:583
msgid "Certificate Revocation List signature failure"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:582
+#: camel/camel-tcp-stream-openssl.c:585
msgid "Certificate not yet valid"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:584
+#: camel/camel-tcp-stream-openssl.c:587
msgid "Certificate has expired"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:586
+#: camel/camel-tcp-stream-openssl.c:589
msgid "CRL not yet valid"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:588
+#: camel/camel-tcp-stream-openssl.c:591
msgid "CRL has expired"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:593
+#: camel/camel-tcp-stream-openssl.c:596
msgid "Error in CRL"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:595
+#: camel/camel-tcp-stream-openssl.c:598
msgid "Out of memory"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:597
+#: camel/camel-tcp-stream-openssl.c:600
msgid "Zero-depth self-signed certificate"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:599
+#: camel/camel-tcp-stream-openssl.c:602
msgid "Self-signed certificate in chain"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:601
+#: camel/camel-tcp-stream-openssl.c:604
msgid "Unable to get issuer's certificate locally"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:603
+#: camel/camel-tcp-stream-openssl.c:606
msgid "Unable to verify leaf signature"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:605
+#: camel/camel-tcp-stream-openssl.c:608
msgid "Certificate chain too long"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:607
+#: camel/camel-tcp-stream-openssl.c:610
msgid "Certificate Revoked"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:609
+#: camel/camel-tcp-stream-openssl.c:612
msgid "Invalid Certificate Authority (CA)"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:611
+#: camel/camel-tcp-stream-openssl.c:614
msgid "Path length exceeded"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:613
+#: camel/camel-tcp-stream-openssl.c:616
msgid "Invalid purpose"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:615
+#: camel/camel-tcp-stream-openssl.c:618
msgid "Certificate untrusted"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:617
+#: camel/camel-tcp-stream-openssl.c:620
msgid "Certificate rejected"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:620
+#: camel/camel-tcp-stream-openssl.c:623
msgid "Subject/Issuer mismatch"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:622
+#: camel/camel-tcp-stream-openssl.c:625
msgid "AKID/SKID mismatch"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:624
+#: camel/camel-tcp-stream-openssl.c:627
msgid "AKID/Issuer serial mismatch"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:626
+#: camel/camel-tcp-stream-openssl.c:629
msgid "Key usage does not support certificate signing"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:629
+#: camel/camel-tcp-stream-openssl.c:632
msgid "Error in application verification"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:696 camel/camel-tcp-stream-ssl.c:831
+#: camel/camel-tcp-stream-openssl.c:699 camel/camel-tcp-stream-ssl.c:823
#, c-format
msgid ""
"Issuer: %s\n"
@@ -8868,15 +8817,15 @@ msgid ""
"Signature: %s"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:702 camel/camel-tcp-stream-ssl.c:837
+#: camel/camel-tcp-stream-openssl.c:705 camel/camel-tcp-stream-ssl.c:829
msgid "GOOD"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:702 camel/camel-tcp-stream-ssl.c:837
+#: camel/camel-tcp-stream-openssl.c:705 camel/camel-tcp-stream-ssl.c:829
msgid "BAD"
msgstr ""
-#: camel/camel-tcp-stream-openssl.c:704
+#: camel/camel-tcp-stream-openssl.c:707
#, c-format
msgid ""
"Bad certificate from %s:\n"
@@ -8889,7 +8838,7 @@ msgid ""
msgstr ""
#. construct our user prompt
-#: camel/camel-tcp-stream-ssl.c:841
+#: camel/camel-tcp-stream-ssl.c:833
#, c-format
msgid ""
"SSL Certificate check for %s:\n"
@@ -8899,28 +8848,28 @@ msgid ""
"Do you wish to accept?"
msgstr ""
-#: camel/camel-tcp-stream-ssl.c:885
+#: camel/camel-tcp-stream-ssl.c:877
#, c-format
msgid ""
"Certificate problem: %s\n"
"Issuer: %s"
msgstr ""
-#: camel/camel-tcp-stream-ssl.c:937
+#: camel/camel-tcp-stream-ssl.c:929
#, c-format
msgid ""
"Bad certificate domain: %s\n"
"Issuer: %s"
msgstr ""
-#: camel/camel-tcp-stream-ssl.c:955
+#: camel/camel-tcp-stream-ssl.c:947
#, c-format
msgid ""
"Certificate expired: %s\n"
"Issuer: %s"
msgstr ""
-#: camel/camel-tcp-stream-ssl.c:972
+#: camel/camel-tcp-stream-ssl.c:964
#, c-format
msgid ""
"Certificate revocation list expired: %s\n"
@@ -8932,17 +8881,17 @@ msgstr ""
msgid "Could not parse URL `%s'"
msgstr ""
-#: camel/camel-vee-folder.c:611
+#: camel/camel-vee-folder.c:618
#, c-format
msgid "Error storing `%s': %s"
msgstr ""
-#: camel/camel-vee-folder.c:649
+#: camel/camel-vee-folder.c:656
#, c-format
msgid "No such message %s in %s"
msgstr ""
-#: camel/camel-vee-folder.c:812 camel/camel-vee-folder.c:818
+#: camel/camel-vee-folder.c:819 camel/camel-vee-folder.c:825
msgid "Cannot copy or move messages into a Virtual Folder"
msgstr ""
@@ -8969,12 +8918,12 @@ msgstr ""
#: camel/providers/imap/camel-imap-command.c:221
#: camel/providers/imap/camel-imap-command.c:260
#: camel/providers/imap/camel-imap-command.c:450
-#: camel/providers/imap/camel-imap-store.c:2806
+#: camel/providers/imap/camel-imap-store.c:2644
msgid "Operation cancelled"
msgstr ""
#: camel/providers/imap/camel-imap-command.c:305
-#: camel/providers/imap/camel-imap-store.c:2809
+#: camel/providers/imap/camel-imap-store.c:2647
#, c-format
msgid "Server unexpectedly disconnected: %s"
msgstr ""
@@ -9011,62 +8960,62 @@ msgstr ""
msgid "Unexpected OK response from IMAP server: %s"
msgstr ""
-#: camel/providers/imap/camel-imap-folder.c:223
+#: camel/providers/imap/camel-imap-folder.c:222
#, c-format
msgid "Could not create directory %s: %s"
msgstr ""
-#: camel/providers/imap/camel-imap-folder.c:242
+#: camel/providers/imap/camel-imap-folder.c:241
#, c-format
msgid "Could not load summary for %s"
msgstr ""
-#: camel/providers/imap/camel-imap-folder.c:308
+#: camel/providers/imap/camel-imap-folder.c:307
msgid "Folder was destroyed and recreated on server."
msgstr ""
#. Check UIDs and flags of all messages we already know of.
-#: camel/providers/imap/camel-imap-folder.c:550
+#: camel/providers/imap/camel-imap-folder.c:549
msgid "Scanning for changed messages"
msgstr ""
-#: camel/providers/imap/camel-imap-folder.c:1886
+#: camel/providers/imap/camel-imap-folder.c:1883
#, c-format
msgid "Unable to retrieve message: %s"
msgstr ""
-#: camel/providers/imap/camel-imap-folder.c:1923
-#: camel/providers/local/camel-maildir-folder.c:211
-#: camel/providers/local/camel-maildir-folder.c:224
-#: camel/providers/local/camel-maildir-folder.c:233
-#: camel/providers/local/camel-mbox-folder.c:422
-#: camel/providers/local/camel-mh-folder.c:200
-#: camel/providers/local/camel-mh-folder.c:210
-#: camel/providers/local/camel-mh-folder.c:219
+#: camel/providers/imap/camel-imap-folder.c:1920
+#: camel/providers/local/camel-maildir-folder.c:212
+#: camel/providers/local/camel-maildir-folder.c:225
+#: camel/providers/local/camel-maildir-folder.c:234
+#: camel/providers/local/camel-mbox-folder.c:351
+#: camel/providers/local/camel-mh-folder.c:201
+#: camel/providers/local/camel-mh-folder.c:211
+#: camel/providers/local/camel-mh-folder.c:220
#, c-format
msgid ""
"Cannot get message: %s\n"
" %s"
msgstr ""
-#: camel/providers/imap/camel-imap-folder.c:1923
-#: camel/providers/local/camel-maildir-folder.c:211
-#: camel/providers/local/camel-mbox-folder.c:422
-#: camel/providers/local/camel-mh-folder.c:200
+#: camel/providers/imap/camel-imap-folder.c:1920
+#: camel/providers/local/camel-maildir-folder.c:212
+#: camel/providers/local/camel-mbox-folder.c:351
+#: camel/providers/local/camel-mh-folder.c:201
msgid "No such message"
msgstr ""
-#: camel/providers/imap/camel-imap-folder.c:1946
-#: camel/providers/imap/camel-imap-folder.c:2542
+#: camel/providers/imap/camel-imap-folder.c:1943
+#: camel/providers/imap/camel-imap-folder.c:2539
msgid "This message is not currently available"
msgstr ""
-#: camel/providers/imap/camel-imap-folder.c:2206
-#: camel/providers/imap/camel-imap-folder.c:2276
+#: camel/providers/imap/camel-imap-folder.c:2203
+#: camel/providers/imap/camel-imap-folder.c:2273
msgid "Fetching summary information for new messages"
msgstr ""
-#: camel/providers/imap/camel-imap-folder.c:2580
+#: camel/providers/imap/camel-imap-folder.c:2577
msgid "Could not find message body in FETCH response."
msgstr ""
@@ -9116,100 +9065,85 @@ msgstr ""
msgid "Apply filters to new messages in INBOX on this server"
msgstr ""
-#: camel/providers/imap/camel-imap-provider.c:59
-msgid "Automatically synchronize remote mail locally"
-msgstr ""
-
-#: camel/providers/imap/camel-imap-provider.c:65
+#: camel/providers/imap/camel-imap-provider.c:63
msgid "IMAP"
msgstr ""
-#: camel/providers/imap/camel-imap-provider.c:67
+#: camel/providers/imap/camel-imap-provider.c:65
msgid "For reading and storing mail on IMAP servers."
msgstr ""
-#: camel/providers/imap/camel-imap-provider.c:82
-#: camel/providers/imapp/camel-imapp-provider.c:65
-#: camel/providers/nntp/camel-nntp-store.c:265
+#: camel/providers/imap/camel-imap-provider.c:80
+#: camel/providers/nntp/camel-nntp-store.c:267
#: camel/providers/pop3/camel-pop3-provider.c:71 mail/mail-config.glade.h:83
msgid "Password"
msgstr "ሚስጢራዊ ቃል"
-#: camel/providers/imap/camel-imap-provider.c:84
-#: camel/providers/imapp/camel-imapp-provider.c:67
+#: camel/providers/imap/camel-imap-provider.c:82
msgid "This option will connect to the IMAP server using a plaintext password."
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:459
+#: camel/providers/imap/camel-imap-store.c:457
#, c-format
msgid "IMAP server %s"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:461
+#: camel/providers/imap/camel-imap-store.c:459
#, c-format
msgid "IMAP service for %s on %s"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:589
-#: camel/providers/imap/camel-imap-store.c:821
-#: camel/providers/imapp/camel-imapp-store.c:233
-#: camel/providers/nntp/camel-nntp-store.c:128
-#: camel/providers/nntp/camel-nntp-store.c:146
+#: camel/providers/imap/camel-imap-store.c:587
+#: camel/providers/nntp/camel-nntp-store.c:130
+#: camel/providers/nntp/camel-nntp-store.c:148
#: camel/providers/pop3/camel-pop3-store.c:184
msgid "Connection cancelled"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:592
-#: camel/providers/imapp/camel-imapp-store.c:236
-#: camel/providers/nntp/camel-nntp-store.c:131
-#: camel/providers/smtp/camel-smtp-transport.c:275
+#: camel/providers/imap/camel-imap-store.c:590
+#: camel/providers/nntp/camel-nntp-store.c:133
+#: camel/providers/smtp/camel-smtp-transport.c:276
#, c-format
msgid "Could not connect to %s (port %d): %s"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:655
-#: camel/providers/imap/camel-imap-store.c:686
+#: camel/providers/imap/camel-imap-store.c:649
+#: camel/providers/imap/camel-imap-store.c:680
#, c-format
msgid "Failed to connect to IMAP server %s in secure mode: %s"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:656
+#: camel/providers/imap/camel-imap-store.c:650
#: camel/providers/pop3/camel-pop3-store.c:220
msgid "SSL/TLS extension not supported."
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:687
+#: camel/providers/imap/camel-imap-store.c:681
#: camel/providers/pop3/camel-pop3-store.c:261
msgid "SSL negotiations failed"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:824
-#, fuzzy, c-format
-msgid "Could not connect with command \"%s\": %s"
-msgstr "ፋይል sን መክፈት አልቻለም፦ %s፦ %s"
-
-#: camel/providers/imap/camel-imap-store.c:1237
+#: camel/providers/imap/camel-imap-store.c:1075
#, c-format
msgid "IMAP server %s does not support requested authentication type %s"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:1247
-#: camel/providers/smtp/camel-smtp-transport.c:485
+#: camel/providers/imap/camel-imap-store.c:1085
+#: camel/providers/smtp/camel-smtp-transport.c:486
#, c-format
msgid "No support for authentication type %s"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:1270
-#: camel/providers/imapp/camel-imapp-store.c:349
+#: camel/providers/imap/camel-imap-store.c:1108
#, c-format
msgid "%sPlease enter the IMAP password for %s@%s"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:1284
+#: camel/providers/imap/camel-imap-store.c:1122
msgid "You didn't enter a password."
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:1313
+#: camel/providers/imap/camel-imap-store.c:1151
#, c-format
msgid ""
"Unable to authenticate to IMAP server.\n"
@@ -9217,68 +9151,42 @@ msgid ""
"\n"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:1660
-#: camel/providers/imap/camel-imap-store.c:1802
+#: camel/providers/imap/camel-imap-store.c:1498
+#: camel/providers/imap/camel-imap-store.c:1640
#, c-format
msgid "No such folder %s"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:2003
+#: camel/providers/imap/camel-imap-store.c:1841
#, c-format
msgid ""
"The folder name \"%s\" is invalid because it containes the character \"%c\""
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:2015
+#: camel/providers/imap/camel-imap-store.c:1853
#, c-format
msgid "Unknown parent folder: %s"
msgstr ""
-#: camel/providers/imap/camel-imap-store.c:2051
+#: camel/providers/imap/camel-imap-store.c:1889
msgid "The parent folder is not allowed to contain subfolders"
msgstr ""
-#: camel/providers/imapp/camel-imapp-provider.c:39
-#: camel/providers/pop3/camel-pop3-provider.c:38
-msgid "Message storage"
-msgstr ""
-
-#: camel/providers/imapp/camel-imapp-provider.c:47
-msgid "IMAP+"
-msgstr ""
-
-#: camel/providers/imapp/camel-imapp-provider.c:49
-msgid ""
-"Experimental IMAP 4(.1) client\n"
-"This is untested and unsupported code, you want to use plain imap instead.\n"
-"\n"
-" !!! DO NOT USE THIS FOR PRODUCTION EMAIL !!!\n"
-msgstr ""
-
-#: camel/providers/imapp/camel-imapp-store.c:333
-#, c-format
-msgid "Could not connect to POP server on %s"
-msgstr ""
-
-#: camel/providers/local/camel-local-folder.c:179
-msgid "Index message body data"
-msgstr ""
-
#. $HOME relative path + protocol string
-#: camel/providers/local/camel-local-folder.c:379
+#: camel/providers/local/camel-local-folder.c:354
#, c-format
msgid "~%s (%s)"
msgstr "~%s (%s)"
#. /var/spool/mail relative path + protocol
-#: camel/providers/local/camel-local-folder.c:383
-#: camel/providers/local/camel-local-folder.c:386
+#: camel/providers/local/camel-local-folder.c:358
+#: camel/providers/local/camel-local-folder.c:361
#, c-format
msgid "mailbox:%s (%s)"
msgstr "የፖስታ ሳጥን፦%s (%s)"
#. a full path + protocol
-#: camel/providers/local/camel-local-folder.c:390
+#: camel/providers/local/camel-local-folder.c:365
#, c-format
msgid "%s (%s)"
msgstr "%s (%s)"
@@ -9332,54 +9240,50 @@ msgid ""
"May also be used to read a tree of Elm, Pine, or Mutt style folders."
msgstr ""
-#: camel/providers/local/camel-local-store.c:138
-#: camel/providers/local/camel-local-store.c:227
-#: camel/providers/local/camel-mbox-store.c:305
+#: camel/providers/local/camel-local-store.c:139
+#: camel/providers/local/camel-local-store.c:228
#: camel/providers/local/camel-spool-store.c:116
#, c-format
msgid "Store root %s is not an absolute path"
msgstr ""
-#: camel/providers/local/camel-local-store.c:145
+#: camel/providers/local/camel-local-store.c:146
#, c-format
msgid "Store root %s is not a regular directory"
msgstr ""
-#: camel/providers/local/camel-local-store.c:154
-#: camel/providers/local/camel-local-store.c:170
-#: camel/providers/local/camel-local-store.c:238
+#: camel/providers/local/camel-local-store.c:155
+#: camel/providers/local/camel-local-store.c:171
+#: camel/providers/local/camel-local-store.c:239
#, c-format
msgid "Cannot get folder: %s: %s"
msgstr ""
-#: camel/providers/local/camel-local-store.c:186
+#: camel/providers/local/camel-local-store.c:187
msgid "Local stores do not have an inbox"
msgstr ""
-#: camel/providers/local/camel-local-store.c:198
+#: camel/providers/local/camel-local-store.c:199
#, c-format
msgid "Local mail file %s"
msgstr ""
-#: camel/providers/local/camel-local-store.c:307 mail/mail-local.c:949
+#: camel/providers/local/camel-local-store.c:308 mail/mail-local.c:909
#, c-format
msgid "Could not rename folder %s to %s: %s"
msgstr ""
-#: camel/providers/local/camel-local-store.c:364
-#: camel/providers/local/camel-mbox-store.c:474
+#: camel/providers/local/camel-local-store.c:365
#, c-format
msgid "Could not rename '%s': %s"
msgstr ""
-#: camel/providers/local/camel-local-store.c:387
-#: camel/providers/local/camel-mbox-store.c:258
+#: camel/providers/local/camel-local-store.c:388
#, c-format
msgid "Could not delete folder summary file `%s': %s"
msgstr ""
-#: camel/providers/local/camel-local-store.c:397
-#: camel/providers/local/camel-mbox-store.c:270
+#: camel/providers/local/camel-local-store.c:398
#, c-format
msgid "Could not delete folder index file `%s': %s"
msgstr ""
@@ -9393,18 +9297,18 @@ msgstr ""
msgid "Unable to add message to summary: unknown reason"
msgstr ""
-#: camel/providers/local/camel-maildir-folder.c:183
+#: camel/providers/local/camel-maildir-folder.c:184
msgid "Maildir append message cancelled"
msgstr ""
-#: camel/providers/local/camel-maildir-folder.c:186
+#: camel/providers/local/camel-maildir-folder.c:187
#, c-format
msgid "Cannot append message to maildir folder: %s: %s"
msgstr ""
#
-#: camel/providers/local/camel-maildir-folder.c:234
-#: camel/providers/local/camel-mh-folder.c:220
+#: camel/providers/local/camel-maildir-folder.c:235
+#: camel/providers/local/camel-mh-folder.c:221
msgid "Invalid message contents"
msgstr ""
@@ -9418,7 +9322,7 @@ msgid ""
msgstr ""
#: camel/providers/local/camel-maildir-store.c:110
-#: camel/providers/local/camel-mbox-store.c:157
+#: camel/providers/local/camel-mbox-store.c:101
#: camel/providers/local/camel-mh-store.c:209
#: camel/providers/local/camel-spool-store.c:167
#, c-format
@@ -9481,44 +9385,44 @@ msgstr ""
msgid "Storing folder"
msgstr ""
-#: camel/providers/local/camel-mbox-folder.c:230
-#: camel/providers/local/camel-spool-folder.c:148
+#: camel/providers/local/camel-mbox-folder.c:159
+#: camel/providers/local/camel-spool-folder.c:149
#, c-format
msgid "Cannot create folder lock on %s: %s"
msgstr ""
-#: camel/providers/local/camel-mbox-folder.c:289
+#: camel/providers/local/camel-mbox-folder.c:218
#, c-format
msgid "Cannot open mailbox: %s: %s\n"
msgstr ""
-#: camel/providers/local/camel-mbox-folder.c:349
+#: camel/providers/local/camel-mbox-folder.c:278
msgid "Mail append cancelled"
msgstr ""
-#: camel/providers/local/camel-mbox-folder.c:352
+#: camel/providers/local/camel-mbox-folder.c:281
#, c-format
msgid "Cannot append message to mbox file: %s: %s"
msgstr ""
-#: camel/providers/local/camel-mbox-folder.c:440
-#: camel/providers/local/camel-mbox-folder.c:471
-#: camel/providers/local/camel-mbox-folder.c:479
+#: camel/providers/local/camel-mbox-folder.c:369
+#: camel/providers/local/camel-mbox-folder.c:400
+#: camel/providers/local/camel-mbox-folder.c:408
#, c-format
msgid ""
"Cannot get message: %s from folder %s\n"
" %s"
msgstr ""
-#: camel/providers/local/camel-mbox-folder.c:472
+#: camel/providers/local/camel-mbox-folder.c:401
msgid "The folder appears to be irrecoverably corrupted."
msgstr ""
-#: camel/providers/local/camel-mbox-folder.c:480
+#: camel/providers/local/camel-mbox-folder.c:409
msgid "Message construction failed: Corrupt mailbox?"
msgstr ""
-#: camel/providers/local/camel-mbox-store.c:149
+#: camel/providers/local/camel-mbox-store.c:94
#, c-format
msgid ""
"Could not open file `%s':\n"
@@ -9527,71 +9431,32 @@ msgstr ""
"ፋይል `%s'ን መክፈት አልቻለም፦\n"
"%s"
-#: camel/providers/local/camel-mbox-store.c:166
-#, fuzzy, c-format
-msgid ""
-"Could not create directory `%s':\n"
-"%s"
-msgstr ""
-"ዶሴ `%s'ን ማስፈጠር አልተቻለም፦\n"
-"%s"
-
-#: camel/providers/local/camel-mbox-store.c:178
+#: camel/providers/local/camel-mbox-store.c:110
#, c-format
msgid ""
"Could not create file `%s':\n"
"%s"
msgstr ""
-#: camel/providers/local/camel-mbox-store.c:188
-#: camel/providers/local/camel-mbox-store.c:229
+#: camel/providers/local/camel-mbox-store.c:119
+#: camel/providers/local/camel-mbox-store.c:146
#, c-format
msgid "`%s' is not a regular file."
msgstr ""
-#: camel/providers/local/camel-mbox-store.c:210
-#: camel/providers/local/camel-mbox-store.c:221
-#: camel/providers/local/camel-mbox-store.c:244
+#: camel/providers/local/camel-mbox-store.c:138
+#: camel/providers/local/camel-mbox-store.c:161
#, c-format
msgid ""
"Could not delete folder `%s':\n"
"%s"
msgstr ""
-#: camel/providers/local/camel-mbox-store.c:236
+#: camel/providers/local/camel-mbox-store.c:153
#, c-format
msgid "Folder `%s' is not empty. Not deleted."
msgstr ""
-#: camel/providers/local/camel-mbox-store.c:311
-msgid "Cannot create a folder by this name."
-msgstr ""
-
-#: camel/providers/local/camel-mbox-store.c:324
-#, fuzzy, c-format
-msgid "Cannot create directory `%s': %s."
-msgstr ""
-"ዶሴ `%s'ን ማስፈጠር አልተቻለም፦\n"
-"%s"
-
-#: camel/providers/local/camel-mbox-store.c:338
-#, fuzzy, c-format
-msgid "Cannot create folder: %s: %s"
-msgstr ""
-"ዶሴ `%s'ን ማስፈጠር አልተቻለም፦\n"
-"%s"
-
-#: camel/providers/local/camel-mbox-store.c:408
-#, fuzzy, c-format
-msgid "Could not rename %s to %s: %s"
-msgstr ""
-"ዶሴ `%s'ን ማስፈጠር አልተቻለም፦\n"
-"%s"
-
-#: camel/providers/local/camel-mbox-store.c:427
-msgid "The new folder name is illegal."
-msgstr ""
-
#: camel/providers/local/camel-mbox-summary.c:343
#, c-format
msgid "Could not open folder: %s: %s"
@@ -9621,7 +9486,7 @@ msgid "Cannot open temporary mailbox: %s"
msgstr ""
#: camel/providers/local/camel-mbox-summary.c:540
-#: camel/providers/local/camel-mbox-summary.c:704
+#: camel/providers/local/camel-mbox-summary.c:702
#, c-format
msgid "Could not close source folder %s: %s"
msgstr ""
@@ -9638,39 +9503,39 @@ msgstr ""
#: camel/providers/local/camel-mbox-summary.c:644
#: camel/providers/local/camel-mbox-summary.c:652
-#: camel/providers/local/camel-mbox-summary.c:845
-#: camel/providers/local/camel-mbox-summary.c:853
+#: camel/providers/local/camel-mbox-summary.c:843
+#: camel/providers/local/camel-mbox-summary.c:851
msgid "Summary and folder mismatch, even after a sync"
msgstr ""
-#: camel/providers/local/camel-mbox-summary.c:779
+#: camel/providers/local/camel-mbox-summary.c:777
#: camel/providers/local/camel-spool-summary.c:334
#, c-format
msgid "Unknown error: %s"
msgstr "ያልታወቀ ስህተት፦ %s"
-#: camel/providers/local/camel-mbox-summary.c:814
+#: camel/providers/local/camel-mbox-summary.c:812
#, c-format
msgid "Could not store folder: %s"
msgstr ""
-#: camel/providers/local/camel-mbox-summary.c:908
-#: camel/providers/local/camel-mbox-summary.c:934
+#: camel/providers/local/camel-mbox-summary.c:906
+#: camel/providers/local/camel-mbox-summary.c:932
#, c-format
msgid "Error writing to temp mailbox: %s"
msgstr ""
-#: camel/providers/local/camel-mbox-summary.c:925
+#: camel/providers/local/camel-mbox-summary.c:923
#, c-format
msgid "Writing to tmp mailbox failed: %s: %s"
msgstr ""
#
-#: camel/providers/local/camel-mh-folder.c:174
+#: camel/providers/local/camel-mh-folder.c:175
msgid "MH append message cancelled"
msgstr ""
-#: camel/providers/local/camel-mh-folder.c:177
+#: camel/providers/local/camel-mh-folder.c:178
#, c-format
msgid "Cannot append message to mh folder: %s: %s"
msgstr ""
@@ -9748,61 +9613,6 @@ msgid ""
"Folder may be corrupt, copy saved in `%s'"
msgstr ""
-#: camel/providers/nntp/camel-nntp-auth.c:44
-#, c-format
-msgid "Please enter the NNTP password for %s@%s"
-msgstr ""
-
-#: camel/providers/nntp/camel-nntp-auth.c:64
-msgid "Server rejected username"
-msgstr ""
-
-#: camel/providers/nntp/camel-nntp-auth.c:70
-msgid "Failed to send username to server"
-msgstr ""
-
-#: camel/providers/nntp/camel-nntp-auth.c:79
-msgid "Server rejected username/password"
-msgstr ""
-
-#: camel/providers/nntp/camel-nntp-folder.c:114
-#, c-format
-msgid "Internal error: uid in invalid format: %s"
-msgstr ""
-
-#: camel/providers/nntp/camel-nntp-folder.c:155
-#: camel/providers/nntp/camel-nntp-folder.c:161
-#: camel/providers/pop3/camel-pop3-folder.c:433
-#: camel/providers/pop3/camel-pop3-folder.c:494
-#: camel/providers/pop3/camel-pop3-folder.c:501
-#: camel/providers/pop3/camel-pop3-folder.c:512
-#, c-format
-msgid "Cannot get message %s: %s"
-msgstr ""
-
-#: camel/providers/nntp/camel-nntp-folder.c:159
-#: camel/providers/pop3/camel-pop3-folder.c:262
-#: camel/providers/pop3/camel-pop3-folder.c:430
-#: camel/providers/pop3/camel-pop3-folder.c:491
-#: camel/providers/pop3/camel-pop3-folder.c:509
-msgid "User cancelled"
-msgstr ""
-
-#: camel/providers/nntp/camel-nntp-grouplist.c:45
-msgid "Could not get group list from server."
-msgstr ""
-
-#: camel/providers/nntp/camel-nntp-grouplist.c:98
-#: camel/providers/nntp/camel-nntp-grouplist.c:107
-#, c-format
-msgid "Unable to load grouplist file for %s: %s"
-msgstr ""
-
-#: camel/providers/nntp/camel-nntp-grouplist.c:158
-#, c-format
-msgid "Unable to save grouplist file for %s: %s"
-msgstr ""
-
#: camel/providers/nntp/camel-nntp-provider.c:41
msgid "USENET news"
msgstr ""
@@ -9811,58 +9621,58 @@ msgstr ""
msgid "This is a provider for reading from and posting toUSENET newsgroups."
msgstr ""
-#: camel/providers/nntp/camel-nntp-store.c:149
+#: camel/providers/nntp/camel-nntp-store.c:151
#, c-format
msgid "Could not read greeting from %s: %s"
msgstr ""
-#: camel/providers/nntp/camel-nntp-store.c:161
+#: camel/providers/nntp/camel-nntp-store.c:163
#, c-format
msgid "NNTP server %s returned error code %d: %s"
msgstr ""
-#: camel/providers/nntp/camel-nntp-store.c:260
+#: camel/providers/nntp/camel-nntp-store.c:262
#, c-format
msgid "USENET News via %s"
msgstr ""
-#: camel/providers/nntp/camel-nntp-store.c:267
+#: camel/providers/nntp/camel-nntp-store.c:269
msgid ""
"This option will authenticate with the NNTP server using a plaintext "
"password."
msgstr ""
-#: camel/providers/nntp/camel-nntp-summary.c:237
+#: camel/providers/nntp/camel-nntp-summary.c:234
#, c-format
msgid "No such folder: %s"
msgstr ""
-#: camel/providers/nntp/camel-nntp-summary.c:241
+#: camel/providers/nntp/camel-nntp-summary.c:238
#, c-format
msgid "Could not get group: %s"
msgstr ""
-#: camel/providers/nntp/camel-nntp-summary.c:347
+#: camel/providers/nntp/camel-nntp-summary.c:344
#, c-format
msgid "NNTP Command failed: %s"
msgstr ""
-#: camel/providers/nntp/camel-nntp-summary.c:407
-#: camel/providers/nntp/camel-nntp-summary.c:508
+#: camel/providers/nntp/camel-nntp-summary.c:404
+#: camel/providers/nntp/camel-nntp-summary.c:505
#, c-format
msgid "%s: Scanning new messages"
msgstr ""
-#: camel/providers/nntp/camel-nntp-summary.c:523
+#: camel/providers/nntp/camel-nntp-summary.c:520
#, c-format
msgid "Unknown server response: %s"
msgstr ""
-#: camel/providers/nntp/camel-nntp-summary.c:569
+#: camel/providers/nntp/camel-nntp-summary.c:566
msgid "Use cancel"
msgstr ""
-#: camel/providers/nntp/camel-nntp-summary.c:571
+#: camel/providers/nntp/camel-nntp-summary.c:568
#, c-format
msgid "Operation failed: %s"
msgstr ""
@@ -9871,6 +9681,13 @@ msgstr ""
msgid "Retrieving POP summary"
msgstr ""
+#: camel/providers/pop3/camel-pop3-folder.c:262
+#: camel/providers/pop3/camel-pop3-folder.c:429
+#: camel/providers/pop3/camel-pop3-folder.c:490
+#: camel/providers/pop3/camel-pop3-folder.c:508
+msgid "User cancelled"
+msgstr ""
+
#: camel/providers/pop3/camel-pop3-folder.c:265
#, c-format
msgid "Cannot get POP summary: %s"
@@ -9880,22 +9697,34 @@ msgstr ""
msgid "Expunging deleted messages"
msgstr ""
-#: camel/providers/pop3/camel-pop3-folder.c:404
+#: camel/providers/pop3/camel-pop3-folder.c:403
#, c-format
msgid "No message with uid %s"
msgstr ""
#. Sigh, most of the crap in this function is so that the cancel button
#. returns the proper exception code. Sigh.
-#: camel/providers/pop3/camel-pop3-folder.c:411
+#: camel/providers/pop3/camel-pop3-folder.c:410
#, c-format
msgid "Retrieving POP message %d"
msgstr ""
-#: camel/providers/pop3/camel-pop3-folder.c:501
+#: camel/providers/pop3/camel-pop3-folder.c:432
+#: camel/providers/pop3/camel-pop3-folder.c:493
+#: camel/providers/pop3/camel-pop3-folder.c:500
+#: camel/providers/pop3/camel-pop3-folder.c:511
+#, c-format
+msgid "Cannot get message %s: %s"
+msgstr ""
+
+#: camel/providers/pop3/camel-pop3-folder.c:500
msgid "Unknown reason"
msgstr ""
+#: camel/providers/pop3/camel-pop3-provider.c:38
+msgid "Message storage"
+msgstr ""
+
#: camel/providers/pop3/camel-pop3-provider.c:40
msgid "Leave messages on server"
msgstr ""
@@ -10049,140 +9878,140 @@ msgstr "SMTP"
msgid "For delivering mail by connecting to a remote mailhub using SMTP.\n"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:174
+#: camel/providers/smtp/camel-smtp-transport.c:175
msgid "Syntax error, command unrecognized"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:176
+#: camel/providers/smtp/camel-smtp-transport.c:177
msgid "Syntax error in parameters or arguments"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:178
+#: camel/providers/smtp/camel-smtp-transport.c:179
msgid "Command not implemented"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:180
+#: camel/providers/smtp/camel-smtp-transport.c:181
msgid "Command parameter not implemented"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:182
+#: camel/providers/smtp/camel-smtp-transport.c:183
msgid "System status, or system help reply"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:184
+#: camel/providers/smtp/camel-smtp-transport.c:185
msgid "Help message"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:186
+#: camel/providers/smtp/camel-smtp-transport.c:187
msgid "Service ready"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:188
+#: camel/providers/smtp/camel-smtp-transport.c:189
msgid "Service closing transmission channel"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:190
+#: camel/providers/smtp/camel-smtp-transport.c:191
msgid "Service not available, closing transmission channel"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:192
+#: camel/providers/smtp/camel-smtp-transport.c:193
msgid "Requested mail action okay, completed"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:194
+#: camel/providers/smtp/camel-smtp-transport.c:195
msgid "User not local; will forward to <forward-path>"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:196
+#: camel/providers/smtp/camel-smtp-transport.c:197
msgid "Requested mail action not taken: mailbox unavailable"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:198
+#: camel/providers/smtp/camel-smtp-transport.c:199
msgid "Requested action not taken: mailbox unavailable"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:200
+#: camel/providers/smtp/camel-smtp-transport.c:201
msgid "Requested action aborted: error in processing"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:202
+#: camel/providers/smtp/camel-smtp-transport.c:203
msgid "User not local; please try <forward-path>"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:204
+#: camel/providers/smtp/camel-smtp-transport.c:205
msgid "Requested action not taken: insufficient system storage"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:206
+#: camel/providers/smtp/camel-smtp-transport.c:207
msgid "Requested mail action aborted: exceeded storage allocation"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:208
+#: camel/providers/smtp/camel-smtp-transport.c:209
msgid "Requested action not taken: mailbox name not allowed"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:210
+#: camel/providers/smtp/camel-smtp-transport.c:211
msgid "Start mail input; end with <CRLF>.<CRLF>"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:212
+#: camel/providers/smtp/camel-smtp-transport.c:213
msgid "Transaction failed"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:216
+#: camel/providers/smtp/camel-smtp-transport.c:217
msgid "A password transition is needed"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:218
+#: camel/providers/smtp/camel-smtp-transport.c:219
msgid "Authentication mechanism is too weak"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:220
+#: camel/providers/smtp/camel-smtp-transport.c:221
msgid "Encryption required for requested authentication mechanism"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:222
+#: camel/providers/smtp/camel-smtp-transport.c:223
msgid "Temporary authentication failure"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:224
+#: camel/providers/smtp/camel-smtp-transport.c:225
msgid "Authentication required"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:298
+#: camel/providers/smtp/camel-smtp-transport.c:299
msgid "Welcome response error"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:342
-#: camel/providers/smtp/camel-smtp-transport.c:381
+#: camel/providers/smtp/camel-smtp-transport.c:343
+#: camel/providers/smtp/camel-smtp-transport.c:382
#, c-format
msgid "Failed to connect to SMTP server %s in secure mode: %s"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:343
+#: camel/providers/smtp/camel-smtp-transport.c:344
msgid "server does not appear to support SSL"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:357
+#: camel/providers/smtp/camel-smtp-transport.c:358
#, c-format
msgid "STARTTLS request timed out: %s"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:372
+#: camel/providers/smtp/camel-smtp-transport.c:373
msgid "STARTTLS response error"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:475
+#: camel/providers/smtp/camel-smtp-transport.c:476
#, c-format
msgid "SMTP server %s does not support requested authentication type %s."
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:513
+#: camel/providers/smtp/camel-smtp-transport.c:514
#, c-format
msgid "%sPlease enter the SMTP password for %s@%s"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:532
+#: camel/providers/smtp/camel-smtp-transport.c:533
#, c-format
msgid ""
"Unable to authenticate to SMTP server.\n"
@@ -10190,87 +10019,87 @@ msgid ""
"\n"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:665
+#: camel/providers/smtp/camel-smtp-transport.c:666
#, c-format
msgid "SMTP server %s"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:667
+#: camel/providers/smtp/camel-smtp-transport.c:668
#, c-format
msgid "SMTP mail delivery via %s"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:685
+#: camel/providers/smtp/camel-smtp-transport.c:686
msgid "Cannot send message: sender address not valid."
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:690 mail/mail-ops.c:631
+#: camel/providers/smtp/camel-smtp-transport.c:691 mail/mail-ops.c:613
msgid "Sending message"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:705
+#: camel/providers/smtp/camel-smtp-transport.c:706
msgid "Cannot send message: no recipients defined."
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:714
+#: camel/providers/smtp/camel-smtp-transport.c:715
msgid "Cannot send message: one or more invalid recipients"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:879
+#: camel/providers/smtp/camel-smtp-transport.c:880
msgid "SMTP Greeting"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:928
+#: camel/providers/smtp/camel-smtp-transport.c:927
#, c-format
msgid "HELO request timed out: %s"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:950
+#: camel/providers/smtp/camel-smtp-transport.c:949
msgid "HELO response error"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1016
+#: camel/providers/smtp/camel-smtp-transport.c:1015
msgid "SMTP Authentication"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1022
+#: camel/providers/smtp/camel-smtp-transport.c:1021
msgid "Error creating SASL authentication object."
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1039
-#: camel/providers/smtp/camel-smtp-transport.c:1051
+#: camel/providers/smtp/camel-smtp-transport.c:1038
+#: camel/providers/smtp/camel-smtp-transport.c:1050
#, c-format
msgid "AUTH request timed out: %s"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1060
+#: camel/providers/smtp/camel-smtp-transport.c:1059
msgid "AUTH request failed."
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1121
+#: camel/providers/smtp/camel-smtp-transport.c:1120
msgid "Bad authentication response from server.\n"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1146
+#: camel/providers/smtp/camel-smtp-transport.c:1145
#, c-format
msgid "MAIL FROM request timed out: %s: mail not sent"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1166
+#: camel/providers/smtp/camel-smtp-transport.c:1165
msgid "MAIL FROM response error"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1190
+#: camel/providers/smtp/camel-smtp-transport.c:1189
#, c-format
msgid "RCPT TO request timed out: %s: mail not sent"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1212
+#: camel/providers/smtp/camel-smtp-transport.c:1211
#, c-format
msgid "RCPT TO <%s> failed"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1251
+#: camel/providers/smtp/camel-smtp-transport.c:1250
#, c-format
msgid "DATA request timed out: %s: mail not sent"
msgstr ""
@@ -10278,66 +10107,67 @@ msgstr ""
#. we should have gotten instructions on how to use the DATA command:
#. * 354 Enter mail, end with "." on a line by itself
#.
-#: camel/providers/smtp/camel-smtp-transport.c:1271
+#: camel/providers/smtp/camel-smtp-transport.c:1270
msgid "DATA response error"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1312
-#: camel/providers/smtp/camel-smtp-transport.c:1335
+#: camel/providers/smtp/camel-smtp-transport.c:1311
+#: camel/providers/smtp/camel-smtp-transport.c:1334
#, c-format
msgid "DATA send timed out: message termination: %s: mail not sent"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1355
+#: camel/providers/smtp/camel-smtp-transport.c:1354
msgid "DATA termination response error"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1378
+#: camel/providers/smtp/camel-smtp-transport.c:1377
#, c-format
msgid "RSET request timed out: %s"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1398
+#: camel/providers/smtp/camel-smtp-transport.c:1397
msgid "RSET response error"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1421
+#: camel/providers/smtp/camel-smtp-transport.c:1420
#, c-format
msgid "QUIT request timed out: %s"
msgstr ""
-#: camel/providers/smtp/camel-smtp-transport.c:1441
+#: camel/providers/smtp/camel-smtp-transport.c:1440
msgid "QUIT response error"
msgstr ""
-#: composer/e-msg-composer-attachment-bar.c:103
+#: composer/e-msg-composer-attachment-bar.c:102
#, c-format
msgid "%.0fK"
msgstr ""
-#: composer/e-msg-composer-attachment-bar.c:106
+#: composer/e-msg-composer-attachment-bar.c:105
#, c-format
msgid "%.0fM"
msgstr ""
-#: composer/e-msg-composer-attachment-bar.c:109
+#: composer/e-msg-composer-attachment-bar.c:108
#, c-format
msgid "%.0fG"
msgstr ""
-#: composer/e-msg-composer-attachment-bar.c:300
+#. This is a filename. Translators take note.
+#: composer/e-msg-composer-attachment-bar.c:370 mail/mail-display.c:227
msgid "attachment"
msgstr ""
-#: composer/e-msg-composer-attachment-bar.c:445
+#: composer/e-msg-composer-attachment-bar.c:508
msgid "Remove selected items from the attachment list"
msgstr ""
-#: composer/e-msg-composer-attachment-bar.c:475
+#: composer/e-msg-composer-attachment-bar.c:538
msgid "Add attachment..."
msgstr ""
-#: composer/e-msg-composer-attachment-bar.c:476
+#: composer/e-msg-composer-attachment-bar.c:539
msgid "Attach a file to the message"
msgstr ""
@@ -10370,75 +10200,150 @@ msgstr "የmime ዓይነት"
msgid "Suggest automatic display of attachment"
msgstr ""
-#: composer/e-msg-composer.c:562
+#: composer/e-msg-composer-hdrs.c:290
+msgid "Hey you, dunce. You need an account to send mail doncha know."
+msgstr ""
+
+#: composer/e-msg-composer-hdrs.c:483
+msgid "Click here for the address book"
+msgstr ""
+
+#.
+#. * Reply-To:
+#. *
+#. * Create this before we call create_from_optionmenu,
+#. * because that causes from_changed to be called, which
+#. * expects the reply_to fields to be initialized.
+#.
+#: composer/e-msg-composer-hdrs.c:514
+msgid "Reply-To:"
+msgstr ""
+
+#.
+#. * From
+#.
+#: composer/e-msg-composer-hdrs.c:520
+msgid "From:"
+msgstr "ከ፦"
+
+#.
+#. * Subject
+#.
+#: composer/e-msg-composer-hdrs.c:526
+msgid "Subject:"
+msgstr "ጉዳዩ፦"
+
+#: composer/e-msg-composer-hdrs.c:535
+msgid "To:"
+msgstr "ወደ፦"
+
+#: composer/e-msg-composer-hdrs.c:536
+msgid "Enter the recipients of the message"
+msgstr ""
+
+#: composer/e-msg-composer-hdrs.c:539
+msgid "Cc:"
+msgstr "Cc፦"
+
+#: composer/e-msg-composer-hdrs.c:540
+msgid "Enter the addresses that will receive a carbon copy of the message"
+msgstr ""
+
+#: composer/e-msg-composer-hdrs.c:543
+msgid "Bcc:"
+msgstr "Bcc፦"
+
+#: composer/e-msg-composer-hdrs.c:544
+msgid ""
+"Enter the addresses that will receive a carbon copy of the message without "
+"appearing in the recipient list of the message."
+msgstr ""
+
+#.
+#. * Post-To
+#.
+#: composer/e-msg-composer-hdrs.c:551
+msgid "Post To:"
+msgstr ""
+
+#: composer/e-msg-composer-hdrs.c:553
+msgid "Posting destination"
+msgstr ""
+
+#: composer/e-msg-composer-select-file.c:102
+#: composer/e-msg-composer-select-file.c:119
+msgid "Attach file(s)"
+msgstr ""
+
+#: composer/e-msg-composer.c:535
msgid "Could not create a PGP signature context"
msgstr ""
-#: composer/e-msg-composer.c:841
+#: composer/e-msg-composer.c:814
#, c-format
msgid ""
"Error while reading file %s:\n"
"%s"
msgstr ""
-#: composer/e-msg-composer.c:1206
+#: composer/e-msg-composer.c:1177
msgid "File exists, overwrite?"
msgstr ""
-#: composer/e-msg-composer.c:1217 composer/e-msg-composer.c:1233
+#: composer/e-msg-composer.c:1195
#, c-format
msgid "Error saving file: %s"
msgstr ""
-#: composer/e-msg-composer.c:1256
+#: composer/e-msg-composer.c:1218
#, c-format
msgid "Error loading file: %s"
msgstr ""
-#: composer/e-msg-composer.c:1294
+#: composer/e-msg-composer.c:1256
#, c-format
msgid "Error accessing file: %s"
msgstr ""
-#: composer/e-msg-composer.c:1302
+#: composer/e-msg-composer.c:1264
msgid "Unable to retrieve message from editor"
msgstr ""
-#: composer/e-msg-composer.c:1309
+#: composer/e-msg-composer.c:1271
#, c-format
msgid ""
"Unable to seek on file: %s\n"
"%s"
msgstr ""
-#: composer/e-msg-composer.c:1316
+#: composer/e-msg-composer.c:1278
#, c-format
msgid ""
"Unable to truncate file: %s\n"
"%s"
msgstr ""
-#: composer/e-msg-composer.c:1325
+#: composer/e-msg-composer.c:1287
#, c-format
msgid ""
"Unable to copy file descriptor: %s\n"
"%s"
msgstr ""
-#: composer/e-msg-composer.c:1334
+#: composer/e-msg-composer.c:1296
#, c-format
msgid ""
"Error autosaving message: %s\n"
" %s"
msgstr ""
-#: composer/e-msg-composer.c:1431
+#: composer/e-msg-composer.c:1390
msgid ""
"Ximian Evolution has found unsaved files from a previous session.\n"
"Would you like to try to recover them?"
msgstr ""
-#: composer/e-msg-composer.c:1594
+#: composer/e-msg-composer.c:1552
#, c-format
msgid ""
"The message \"%s\" has not been sent.\n"
@@ -10446,34 +10351,34 @@ msgid ""
"Do you wish to save your changes?"
msgstr ""
-#: composer/e-msg-composer.c:1603
+#: composer/e-msg-composer.c:1561
msgid "Warning: Modified Message"
msgstr ""
-#: composer/e-msg-composer.c:1635
+#: composer/e-msg-composer.c:1593
msgid "Open file"
msgstr "ፋይል ክፈት"
-#: composer/e-msg-composer.c:2054
+#: composer/e-msg-composer.c:2017
msgid "Signature:"
msgstr ""
-#: composer/e-msg-composer.c:2094 mail/mail-account-gui.c:1261
+#: composer/e-msg-composer.c:2057 mail/mail-account-gui.c:1261
msgid "Autogenerated"
msgstr ""
-#: composer/e-msg-composer.c:2274 composer/e-msg-composer.c:2970
-#: composer/e-msg-composer.c:2971
+#: composer/e-msg-composer.c:2233 composer/e-msg-composer.c:2902
+#: composer/e-msg-composer.c:2903
msgid "Compose a message"
msgstr ""
-#: composer/e-msg-composer.c:3002
+#: composer/e-msg-composer.c:2934
msgid ""
"Could not create composer window:\n"
"Unable to activate address selector control."
msgstr ""
-#: composer/e-msg-composer.c:3030
+#: composer/e-msg-composer.c:2962
msgid ""
"Could not create composer window:\n"
"Unable to activate HTML editor component.\n"
@@ -10481,92 +10386,18 @@ msgid ""
"of gtkhtml and libgtkhtml installed.\n"
msgstr ""
-#: composer/e-msg-composer.c:3100
+#: composer/e-msg-composer.c:3029
msgid ""
"Could not create composer window:\n"
"Unable to activate HTML editor component."
msgstr ""
-#: composer/e-msg-composer.c:4110
+#: composer/e-msg-composer.c:4045
msgid ""
"<b>(The composer contains a non-text message body, which cannot be edited.)"
"<b>"
msgstr ""
-#: composer/e-msg-composer-hdrs.c:290
-msgid "You need to configure an account before you can compose mail."
-msgstr ""
-
-#: composer/e-msg-composer-hdrs.c:483
-msgid "Click here for the address book"
-msgstr ""
-
-#.
-#. * Reply-To:
-#. *
-#. * Create this before we call create_from_optionmenu,
-#. * because that causes from_changed to be called, which
-#. * expects the reply_to fields to be initialized.
-#.
-#: composer/e-msg-composer-hdrs.c:514
-msgid "Reply-To:"
-msgstr ""
-
-#.
-#. * From
-#.
-#: composer/e-msg-composer-hdrs.c:520
-msgid "From:"
-msgstr "ከ፦"
-
-#.
-#. * Subject
-#.
-#: composer/e-msg-composer-hdrs.c:526
-msgid "Subject:"
-msgstr "ጉዳዩ፦"
-
-#: composer/e-msg-composer-hdrs.c:535
-msgid "To:"
-msgstr "ወደ፦"
-
-#: composer/e-msg-composer-hdrs.c:536
-msgid "Enter the recipients of the message"
-msgstr ""
-
-#: composer/e-msg-composer-hdrs.c:539
-msgid "Cc:"
-msgstr "Cc፦"
-
-#: composer/e-msg-composer-hdrs.c:540
-msgid "Enter the addresses that will receive a carbon copy of the message"
-msgstr ""
-
-#: composer/e-msg-composer-hdrs.c:543
-msgid "Bcc:"
-msgstr "Bcc፦"
-
-#: composer/e-msg-composer-hdrs.c:544
-msgid ""
-"Enter the addresses that will receive a carbon copy of the message without "
-"appearing in the recipient list of the message."
-msgstr ""
-
-#.
-#. * Post-To
-#.
-#: composer/e-msg-composer-hdrs.c:551
-msgid "Post To:"
-msgstr ""
-
-#: composer/e-msg-composer-hdrs.c:553
-msgid "Posting destination"
-msgstr ""
-
-#: composer/e-msg-composer-select-file.c:119
-msgid "Attach file(s)"
-msgstr ""
-
#: data/evolution.desktop.in.h:1
msgid "The Evolution groupware suite"
msgstr ""
@@ -10721,7 +10552,7 @@ msgid ""
"Overwrite it?"
msgstr ""
-#: e-util/e-dialog-utils.c:249
+#: e-util/e-dialog-utils.c:249 mail/mail-display.c:200
msgid "Overwrite file?"
msgstr ""
@@ -10743,209 +10574,90 @@ msgstr ""
#. strptime format of a weekday, a date and a time,
#. in 12-hour format, without seconds.
-#: e-util/e-time-utils.c:185 e-util/e-time-utils.c:398
+#: e-util/e-time-utils.c:172 e-util/e-time-utils.c:385
msgid "%a %m/%d/%Y %I:%M %p"
msgstr "d"
#. strptime format of a weekday, a date and a time,
#. in 24-hour format, without seconds.
-#: e-util/e-time-utils.c:190 e-util/e-time-utils.c:389
+#: e-util/e-time-utils.c:177 e-util/e-time-utils.c:376
msgid "%a %m/%d/%Y %H:%M"
msgstr "d"
#. strptime format of a weekday, a date and a time,
#. in 12-hour format, without minutes or seconds.
-#: e-util/e-time-utils.c:195
+#: e-util/e-time-utils.c:182
msgid "%a %m/%d/%Y %I %p"
msgstr "d"
#. strptime format of a weekday, a date and a time,
#. in 24-hour format, without minutes or seconds.
-#: e-util/e-time-utils.c:200
+#: e-util/e-time-utils.c:187
msgid "%a %m/%d/%Y %H"
msgstr "d"
#. strptime format of a date and a time, in 12-hour format.
-#: e-util/e-time-utils.c:211
+#: e-util/e-time-utils.c:198
msgid "%m/%d/%Y %I:%M:%S %p"
msgstr ""
#. strptime format of a date and a time, in 24-hour format.
-#: e-util/e-time-utils.c:215
+#: e-util/e-time-utils.c:202
msgid "%m/%d/%Y %H:%M:%S"
msgstr ""
#. strptime format of a date and a time, in 12-hour format,
#. without seconds.
-#: e-util/e-time-utils.c:220
+#: e-util/e-time-utils.c:207
msgid "%m/%d/%Y %I:%M %p"
msgstr "d"
#. strptime format of a date and a time, in 24-hour format,
#. without seconds.
-#: e-util/e-time-utils.c:225
+#: e-util/e-time-utils.c:212
msgid "%m/%d/%Y %H:%M"
msgstr "d"
#. strptime format of a date and a time, in 12-hour format,
#. without minutes or seconds.
-#: e-util/e-time-utils.c:230
+#: e-util/e-time-utils.c:217
msgid "%m/%d/%Y %I %p"
msgstr "d"
#. strptime format of a date and a time, in 24-hour format,
#. without minutes or seconds.
-#: e-util/e-time-utils.c:235
+#: e-util/e-time-utils.c:222
msgid "%m/%d/%Y %H"
msgstr "d"
#. strptime format for a time of day, in 12-hour format.
-#: e-util/e-time-utils.c:339 e-util/e-time-utils.c:438
+#: e-util/e-time-utils.c:326 e-util/e-time-utils.c:425
msgid "%I:%M:%S %p"
msgstr "i p,"
#. strptime format for a time of day, in 24-hour format.
-#: e-util/e-time-utils.c:343 e-util/e-time-utils.c:430
+#: e-util/e-time-utils.c:330 e-util/e-time-utils.c:417
msgid "%H:%M:%S"
msgstr "%H:%M:%S"
#. strptime format for time of day, without seconds,
#. in 12-hour format.
-#: e-util/e-time-utils.c:348 e-util/e-time-utils.c:435
-#: widgets/misc/e-dateedit.c:1417 widgets/misc/e-dateedit.c:1642
+#: e-util/e-time-utils.c:335 e-util/e-time-utils.c:422
+#: widgets/misc/e-dateedit.c:1404 widgets/misc/e-dateedit.c:1617
msgid "%I:%M %p"
msgstr "i p,"
#. strptime format for time of day, without seconds 24-hour format.
-#: e-util/e-time-utils.c:352 e-util/e-time-utils.c:427
-#: widgets/misc/e-dateedit.c:1414 widgets/misc/e-dateedit.c:1639
+#: e-util/e-time-utils.c:339 e-util/e-time-utils.c:414
+#: widgets/misc/e-dateedit.c:1401 widgets/misc/e-dateedit.c:1614
msgid "%H:%M"
msgstr "h"
#. strptime format for hour and AM/PM, 12-hour format.
-#: e-util/e-time-utils.c:356
+#: e-util/e-time-utils.c:343
msgid "%I %p"
msgstr "%I %p"
-#: executive-summary/component/component-factory.c:151
-msgid "Cannot initialize Evolution's Executive Summary component."
-msgstr ""
-
-#: executive-summary/component/e-summary.c:925
-#, fuzzy, c-format
-msgid ""
-"Cannot open the HTML file:\n"
-"%s"
-msgstr ""
-"ፋይል `%s'ን መክፈት አልቻለም፦\n"
-"%s"
-
-#: executive-summary/component/e-summary.c:939
-#, c-format
-msgid ""
-"Error reading data:\n"
-"%s"
-msgstr ""
-
-#: executive-summary/component/e-summary.c:957
-msgid "File does not have a place for the services.\n"
-msgstr ""
-
-#: executive-summary/component/e-summary-callbacks.c:125
-#, fuzzy
-msgid "Select a service"
-msgstr "ፋይል ምረጡ"
-
-#: executive-summary/component/e-summary-callbacks.c:289
-msgid ""
-"You can select a different HTML page for the background of the Executive "
-"Summary.\n"
-"\n"
-"Just leave it blank for the default"
-msgstr ""
-
-#: executive-summary/component/e-summary-url.c:69
-#: executive-summary/component/e-summary-url.c:74
-#: executive-summary/component/e-summary-url.c:81
-#, c-format
-msgid "Open %s with the default GNOME application"
-msgstr ""
-
-#: executive-summary/component/e-summary-url.c:70
-#, c-format
-msgid "Open %s with the default GNOME web browser"
-msgstr ""
-
-#: executive-summary/component/e-summary-url.c:71
-#, c-format
-msgid "Send an email to %s"
-msgstr ""
-
-#: executive-summary/component/e-summary-url.c:72
-#, c-format
-msgid "Change the view to %s"
-msgstr ""
-
-#: executive-summary/component/e-summary-url.c:73
-#, fuzzy, c-format
-msgid "Run %s"
-msgstr "URL፦ %s"
-
-#: executive-summary/component/e-summary-url.c:75
-#, fuzzy, c-format
-msgid "Close %s"
-msgstr "ዝጋ"
-
-#: executive-summary/component/e-summary-url.c:76
-#, c-format
-msgid "Move %s to the left"
-msgstr ""
-
-#: executive-summary/component/e-summary-url.c:77
-#, c-format
-msgid "Move %s to the right"
-msgstr ""
-
-#: executive-summary/component/e-summary-url.c:78
-#, c-format
-msgid "Move %s into the previous row"
-msgstr ""
-
-#: executive-summary/component/e-summary-url.c:79
-#, c-format
-msgid "Move %s into the next row"
-msgstr ""
-
-#: executive-summary/component/e-summary-url.c:80
-#, fuzzy, c-format
-msgid "Configure %s"
-msgstr "ምርጫዎች"
-
-#: executive-summary/component/e-summary-url.c:553
-#, fuzzy
-msgid "page"
-msgstr "ገጽ"
-
-#: executive-summary/test-service/rdf-summary.c:512
-#: executive-summary/test-service/rdf-summary.c:549
-#: executive-summary/test-service/rdf-summary.c:594
-msgid "Error"
-msgstr "ስህተት"
-
-#: executive-summary/test-service/rdf-summary.c:775
-msgid "Update automatically"
-msgstr ""
-
-#: executive-summary/test-service/rdf-summary.c:785
-#, fuzzy
-msgid "Update now"
-msgstr "አሻሽል"
-
-#: executive-summary/test-service/rdf-summary.c:795
-#, fuzzy
-msgid "Update every "
-msgstr "አሻሽል"
-
#: filter/filter-datespec.c:65
#, fuzzy
msgid "1 second ago"
@@ -11067,6 +10779,82 @@ msgstr ""
msgid "Select Folder"
msgstr "ዶሴ ምረጡ"
+#: filter/filter-input.c:191
+#, c-format
+msgid ""
+"Error in regular expression '%s':\n"
+"%s"
+msgstr ""
+
+#: filter/filter-label.c:121 filter/libfilter-i18n.h:26 mail/mail-config.c:65
+#: mail/mail-config.glade.h:62 shell/e-config-upgrade.c:1411
+msgid "Important"
+msgstr "አስፈላጊ"
+
+#. red
+#: filter/filter-label.c:122 mail/mail-config.c:66
+#: mail/mail-config.glade.h:129 shell/e-config-upgrade.c:1412
+msgid "Work"
+msgstr "መሥራት"
+
+#. orange
+#: filter/filter-label.c:123 mail/mail-config.c:67 mail/mail-config.glade.h:84
+#: shell/e-config-upgrade.c:1413
+msgid "Personal"
+msgstr "የግል"
+
+#. forest green
+#: filter/filter-label.c:124 mail/mail-config.c:68
+#: mail/mail-config.glade.h:120 shell/e-config-upgrade.c:1414
+msgid "To Do"
+msgstr ""
+
+#. blue
+#: filter/filter-label.c:125 mail/mail-config.c:69 mail/mail-config.glade.h:66
+#: shell/e-config-upgrade.c:1415
+msgid "Later"
+msgstr ""
+
+#: filter/filter-part.c:531 shell/evolution-test-component.c:63
+msgid "Test"
+msgstr "ፈተና"
+
+#: filter/filter-rule.c:219
+msgid "You must name this filter."
+msgstr ""
+
+#: filter/filter-rule.c:751
+msgid "Rule name: "
+msgstr ""
+
+#: filter/filter-rule.c:755
+msgid "Untitled"
+msgstr "ያልተሰየመ"
+
+#: filter/filter-rule.c:772
+msgid "If"
+msgstr ""
+
+#: filter/filter-rule.c:791
+msgid "Execute actions"
+msgstr ""
+
+#: filter/filter-rule.c:795
+msgid "if all criteria are met"
+msgstr ""
+
+#: filter/filter-rule.c:800
+msgid "if any criteria are met"
+msgstr ""
+
+#: filter/filter-rule.c:895
+msgid "incoming"
+msgstr ""
+
+#: filter/filter-rule.c:895
+msgid "outgoing"
+msgstr ""
+
#: filter/filter.glade.h:1
msgid "Compare against"
msgstr ""
@@ -11161,82 +10949,6 @@ msgstr ""
msgid "years"
msgstr "ዓመታት"
-#: filter/filter-input.c:191
-#, c-format
-msgid ""
-"Error in regular expression '%s':\n"
-"%s"
-msgstr ""
-
-#: filter/filter-label.c:121 filter/libfilter-i18n.h:17 mail/mail-config.c:65
-#: mail/mail-config.glade.h:62 shell/e-config-upgrade.c:1454
-msgid "Important"
-msgstr "አስፈላጊ"
-
-#. red
-#: filter/filter-label.c:122 mail/mail-config.c:66
-#: mail/mail-config.glade.h:129 shell/e-config-upgrade.c:1455
-msgid "Work"
-msgstr "መሥራት"
-
-#. orange
-#: filter/filter-label.c:123 mail/mail-config.c:67 mail/mail-config.glade.h:84
-#: shell/e-config-upgrade.c:1456
-msgid "Personal"
-msgstr "የግል"
-
-#. forest green
-#: filter/filter-label.c:124 mail/mail-config.c:68
-#: mail/mail-config.glade.h:120 shell/e-config-upgrade.c:1457
-msgid "To Do"
-msgstr ""
-
-#. blue
-#: filter/filter-label.c:125 mail/mail-config.c:69 mail/mail-config.glade.h:66
-#: shell/e-config-upgrade.c:1458
-msgid "Later"
-msgstr ""
-
-#: filter/filter-part.c:531 shell/evolution-test-component.c:63
-msgid "Test"
-msgstr "ፈተና"
-
-#: filter/filter-rule.c:219
-msgid "You must name this filter."
-msgstr ""
-
-#: filter/filter-rule.c:751
-msgid "Rule name: "
-msgstr ""
-
-#: filter/filter-rule.c:755
-msgid "Untitled"
-msgstr "ያልተሰየመ"
-
-#: filter/filter-rule.c:772
-msgid "If"
-msgstr ""
-
-#: filter/filter-rule.c:791
-msgid "Execute actions"
-msgstr ""
-
-#: filter/filter-rule.c:795
-msgid "if all criteria are met"
-msgstr ""
-
-#: filter/filter-rule.c:800
-msgid "if any criteria are met"
-msgstr ""
-
-#: filter/filter-rule.c:895
-msgid "incoming"
-msgstr ""
-
-#: filter/filter-rule.c:895
-msgid "outgoing"
-msgstr ""
-
#. Automatically generated. Do not edit.
#: filter/libfilter-i18n.h:2
msgid "Adjust Score"
@@ -11259,217 +10971,217 @@ msgid "Beep"
msgstr ""
#: filter/libfilter-i18n.h:7
-msgid "Copy to Folder"
+msgid "contains"
msgstr ""
#: filter/libfilter-i18n.h:8
-msgid "Date received"
+msgid "Copy to Folder"
msgstr ""
#: filter/libfilter-i18n.h:9
+msgid "Date received"
+msgstr ""
+
+#: filter/libfilter-i18n.h:10
msgid "Date sent"
msgstr ""
-#: filter/libfilter-i18n.h:11
+#: filter/libfilter-i18n.h:12
msgid "Deleted"
msgstr "የጠፋ"
-#: filter/libfilter-i18n.h:12
-msgid "Do Not Exist"
-msgstr ""
-
#: filter/libfilter-i18n.h:13
-msgid "Draft"
-msgstr "ንድፍ"
+msgid "does not contain"
+msgstr ""
#: filter/libfilter-i18n.h:14
-msgid "Exist"
+msgid "does not end with"
msgstr ""
#: filter/libfilter-i18n.h:15
-msgid "Expression"
+msgid "does not exist"
msgstr ""
#: filter/libfilter-i18n.h:16
-msgid "Follow Up"
+msgid "does not return"
+msgstr ""
+
+#: filter/libfilter-i18n.h:17
+msgid "does not sound like"
msgstr ""
#: filter/libfilter-i18n.h:18
-msgid "Label"
-msgstr "መለያ"
+msgid "does not start with"
+msgstr ""
#: filter/libfilter-i18n.h:19
-msgid "Mailing list"
+msgid "Do Not Exist"
msgstr ""
#: filter/libfilter-i18n.h:20
-msgid "Message Body"
-msgstr ""
+msgid "Draft"
+msgstr "ንድፍ"
#: filter/libfilter-i18n.h:21
-msgid "Message Header"
+msgid "ends with"
msgstr ""
#: filter/libfilter-i18n.h:22
-msgid "Move to Folder"
+msgid "Exist"
msgstr ""
#: filter/libfilter-i18n.h:23
-msgid "Pipe Message to Shell Command"
+msgid "exists"
msgstr ""
#: filter/libfilter-i18n.h:24
-msgid "Play Sound"
-msgstr "ድምፅ አጫውት"
-
-#: filter/libfilter-i18n.h:25 mail/message-tag-followup.c:68
-msgid "Read"
-msgstr "አንብብ"
+msgid "Expression"
+msgstr ""
-#: filter/libfilter-i18n.h:26
-msgid "Recipients"
+#: filter/libfilter-i18n.h:25
+msgid "Follow Up"
msgstr ""
#: filter/libfilter-i18n.h:27
-msgid "Regex Match"
-msgstr ""
+msgid "is"
+msgstr "ነው"
#: filter/libfilter-i18n.h:28
-msgid "Replied to"
+msgid "is after"
msgstr ""
-#: filter/libfilter-i18n.h:29 filter/score-rule.c:184 filter/score-rule.c:186
-#: mail/message-list.etspec.h:10
-msgid "Score"
-msgstr "ነጥብ"
+#: filter/libfilter-i18n.h:29
+msgid "is before"
+msgstr ""
#: filter/libfilter-i18n.h:30
-msgid "Sender"
+msgid "is Flagged"
msgstr ""
#: filter/libfilter-i18n.h:31
-msgid "Set Status"
+msgid "is greater than"
msgstr ""
#: filter/libfilter-i18n.h:32
-msgid "Shell Command"
-msgstr "የሼሉን ትእዛዝ"
+msgid "is less than"
+msgstr ""
#: filter/libfilter-i18n.h:33
-msgid "Size (kB)"
-msgstr "መጠን kb"
+msgid "is not"
+msgstr "አይደለም"
#: filter/libfilter-i18n.h:34
-msgid "Source Account"
+msgid "is not Flagged"
msgstr ""
-#: filter/libfilter-i18n.h:35
-msgid "Specific header"
+#: filter/libfilter-i18n.h:35 mail/folder-browser.c:1800
+msgid "Label"
+msgstr "መለያ"
+
+#: filter/libfilter-i18n.h:36
+msgid "Mailing list"
msgstr ""
#: filter/libfilter-i18n.h:37
-msgid "Stop Processing"
+msgid "Message Body"
msgstr ""
-#: filter/libfilter-i18n.h:38 mail/message-list.etspec.h:13
-#: mail/message-tag-followup.c:305
-msgid "Subject"
-msgstr "ጉዳዩ"
+#: filter/libfilter-i18n.h:38
+msgid "Message Header"
+msgstr ""
#: filter/libfilter-i18n.h:39
-msgid "Unset Status"
+msgid "Move to Folder"
msgstr ""
#: filter/libfilter-i18n.h:40
-msgid "contains"
+msgid "Pipe Message to Shell Command"
msgstr ""
#: filter/libfilter-i18n.h:41
-msgid "does not contain"
-msgstr ""
+msgid "Play Sound"
+msgstr "ድምፅ አጫውት"
-#: filter/libfilter-i18n.h:42
-msgid "does not end with"
-msgstr ""
+#: filter/libfilter-i18n.h:42 mail/message-tag-followup.c:68
+msgid "Read"
+msgstr "አንብብ"
#: filter/libfilter-i18n.h:43
-msgid "does not exist"
+msgid "Recipients"
msgstr ""
#: filter/libfilter-i18n.h:44
-msgid "does not return"
+msgid "Regex Match"
msgstr ""
#: filter/libfilter-i18n.h:45
-msgid "does not sound like"
+msgid "Replied to"
msgstr ""
#: filter/libfilter-i18n.h:46
-msgid "does not start with"
+msgid "returns"
msgstr ""
#: filter/libfilter-i18n.h:47
-msgid "ends with"
+msgid "returns greater than"
msgstr ""
#: filter/libfilter-i18n.h:48
-msgid "exists"
+msgid "returns less than"
msgstr ""
-#: filter/libfilter-i18n.h:49
-msgid "is Flagged"
-msgstr ""
+#: filter/libfilter-i18n.h:49 filter/score-rule.c:184 filter/score-rule.c:186
+#: mail/message-list.etspec.h:10
+msgid "Score"
+msgstr "ነጥብ"
-#: filter/libfilter-i18n.h:50
-msgid "is after"
+#: filter/libfilter-i18n.h:50 mail/mail-callbacks.c:1820
+msgid "Sender"
msgstr ""
#: filter/libfilter-i18n.h:51
-msgid "is before"
+msgid "Set Status"
msgstr ""
#: filter/libfilter-i18n.h:52
-msgid "is greater than"
-msgstr ""
+msgid "Shell Command"
+msgstr "የሼሉን ትእዛዝ"
#: filter/libfilter-i18n.h:53
-msgid "is less than"
-msgstr ""
+msgid "Size (kB)"
+msgstr "መጠን kb"
#: filter/libfilter-i18n.h:54
-msgid "is not Flagged"
+msgid "sounds like"
msgstr ""
#: filter/libfilter-i18n.h:55
-msgid "is not"
-msgstr "አይደለም"
+msgid "Source Account"
+msgstr ""
#: filter/libfilter-i18n.h:56
-msgid "is"
-msgstr "ነው"
-
-#: filter/libfilter-i18n.h:57
-msgid "returns greater than"
+msgid "Specific header"
msgstr ""
-#: filter/libfilter-i18n.h:58
-msgid "returns less than"
+#: filter/libfilter-i18n.h:57
+msgid "starts with"
msgstr ""
#: filter/libfilter-i18n.h:59
-msgid "returns"
+msgid "Stop Processing"
msgstr ""
-#: filter/libfilter-i18n.h:60
-msgid "sounds like"
-msgstr ""
+#: filter/libfilter-i18n.h:60 mail/mail-format.c:934
+#: mail/message-list.etspec.h:13 mail/message-tag-followup.c:305
+msgid "Subject"
+msgstr "ጉዳዩ"
#: filter/libfilter-i18n.h:61
-msgid "starts with"
+msgid "Unset Status"
msgstr ""
-#: filter/rule-context.c:684 filter/rule-editor.c:241 filter/rule-editor.c:326
-#: mail/mail-vfolder.c:916
+#: filter/rule-context.c:664 filter/rule-editor.c:241 filter/rule-editor.c:326
+#: mail/mail-vfolder.c:917
#, c-format
msgid "Rule name '%s' is not unique, choose another."
msgstr ""
@@ -11537,9 +11249,10 @@ msgid "Scanning %s"
msgstr ""
#: importers/elm-importer.c:525 importers/netscape-importer.c:2128
-#: importers/pine-importer.c:637 mail/component-factory.c:116
-#: mail/importers/elm-importer.c:526 mail/importers/netscape-importer.c:2085
-#: mail/importers/pine-importer.c:572 my-evolution/my-evolution.glade.h:4
+#: importers/pine-importer.c:637 mail/component-factory.c:117
+#: mail/folder-browser-ui.c:360 mail/importers/elm-importer.c:526
+#: mail/importers/netscape-importer.c:2085 mail/importers/pine-importer.c:572
+#: my-evolution/my-evolution.glade.h:4
msgid "Mail"
msgstr "ፖስታ"
@@ -11602,7 +11315,7 @@ msgstr ""
#. Fill in the new fields
#: importers/netscape-importer.c:1872 mail/importers/netscape-importer.c:1842
-#: mail/mail-ops.c:1106 shell/e-local-storage.c:184
+#: mail/mail-ops.c:1092 shell/e-local-storage.c:184
msgid "Trash"
msgstr "የማይፈለግ"
@@ -11616,7 +11329,7 @@ msgid "Scanning directory"
msgstr ""
#: importers/netscape-importer.c:2047 mail/importers/netscape-importer.c:2015
-#: shell/e-shell-startup-wizard.c:556
+#: shell/e-shell-startup-wizard.c:541
msgid "Starting import"
msgstr ""
@@ -11648,143 +11361,328 @@ msgstr ""
msgid "Pine"
msgstr ""
-#: mail/component-factory.c:116
-msgid "Folder containing mail"
+#: mail/GNOME_Evolution_Mail.server.in.in.h:1
+msgid "Composer Preferences"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:2
+msgid ""
+"Configure mail preferences, including security and message display, here"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:3
+msgid "Configure spell-checking, signatures, and the message composer here"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:4
+msgid "Configure your email accounts here"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:5
+msgid "Evolution Mail"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:6
+msgid "Evolution Mail accounts configuration control"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:7
+msgid "Evolution Mail component"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:8
+msgid "Evolution Mail composer"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:9
+msgid "Evolution Mail composer configuration control"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:10
+msgid "Evolution Mail configuration interface"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:11
+msgid "Evolution Mail folder viewer"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:12
+msgid "Evolution Mail preferences control"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:13
+msgid "Mail Accounts"
+msgstr ""
+
+#: mail/GNOME_Evolution_Mail.server.in.in.h:14 mail/mail-config.glade.h:69
+msgid "Mail Preferences"
msgstr ""
#: mail/component-factory.c:117
+msgid "Folder containing mail"
+msgstr ""
+
+#: mail/component-factory.c:118
msgid "Public Mail"
msgstr ""
-#: mail/component-factory.c:117
+#: mail/component-factory.c:118
msgid "Public folder containing mail"
msgstr ""
-#: mail/component-factory.c:118
+#: mail/component-factory.c:119
msgid "Virtual Trash"
msgstr ""
-#: mail/component-factory.c:118
+#: mail/component-factory.c:119
msgid "Virtual Trash folder"
msgstr ""
-#: mail/component-factory.c:146
+#: mail/component-factory.c:147
msgid "This folder cannot contain messages."
msgstr ""
-#: mail/component-factory.c:444
+#: mail/component-factory.c:441
msgid "Properties..."
msgstr "ምርጫዎች..."
-#: mail/component-factory.c:444
+#: mail/component-factory.c:441
msgid "Change this folder's properties"
msgstr ""
-#: mail/component-factory.c:826
+#: mail/component-factory.c:819
msgid ""
"Some of your mail settings seem corrupt, please check that everything is in "
"order."
msgstr ""
-#: mail/component-factory.c:1008
+#: mail/component-factory.c:1000
msgid "You have not set a mail transport method"
msgstr ""
-#: mail/component-factory.c:1031
+#: mail/component-factory.c:1023
msgid "You have unsent messages, do you wish to quit anyway?"
msgstr ""
-#: mail/component-factory.c:1071
+#: mail/component-factory.c:1063
msgid "New Mail Message"
msgstr ""
-#: mail/component-factory.c:1071
+#: mail/component-factory.c:1063
msgid "_Mail Message"
msgstr ""
-#: mail/component-factory.c:1072
+#: mail/component-factory.c:1064
msgid "Compose a new mail message"
msgstr ""
-#: mail/component-factory.c:1080
+#: mail/component-factory.c:1072
msgid "New Message Post"
msgstr ""
-#: mail/component-factory.c:1080
+#: mail/component-factory.c:1072
msgid "_Post Message"
msgstr ""
-#: mail/component-factory.c:1081
+#: mail/component-factory.c:1073
msgid "Post a new mail message"
msgstr ""
-#: mail/component-factory.c:1373
+#: mail/component-factory.c:1365
msgid "Connecting..."
msgstr ""
-#: mail/component-factory.c:1384
+#: mail/component-factory.c:1376
msgid "Cannot register storage with shell"
msgstr ""
-#: mail/folder-info.c:70
-msgid "Getting Folder Information"
+#: mail/folder-browser-ui.c:486
+#, c-format
+msgid "Properties for \"%s\""
+msgstr "ለ \"%s\"ን ምርጫዎች"
+
+#: mail/folder-browser-ui.c:488
+msgid "Properties"
+msgstr "ምርጫዎች"
+
+#: mail/folder-browser.c:327 mail/mail-display.c:394 mail/mail-display.c:942
+#, c-format
+msgid "Could not create temporary directory: %s"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:1
-msgid "Composer Preferences"
+#: mail/folder-browser.c:782
+#, c-format
+msgid "%d new"
+msgstr "%d አዲስ"
+
+#: mail/folder-browser.c:785 mail/folder-browser.c:793
+#: mail/folder-browser.c:796
+msgid ", "
+msgstr "፣ "
+
+#: mail/folder-browser.c:787
+#, c-format
+msgid "%d hidden"
+msgstr "%d የተደበቀ"
+
+#: mail/folder-browser.c:789
+#, c-format
+msgid "%d visible"
+msgstr "%d የሚታይ"
+
+#: mail/folder-browser.c:794
+#, c-format
+msgid "%d selected"
+msgstr "%d ተመርጠዋል"
+
+#: mail/folder-browser.c:799
+#, c-format
+msgid "%d unsent"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:2
-msgid ""
-"Configure mail preferences, including security and message display, here"
+#: mail/folder-browser.c:801
+#, c-format
+msgid "%d sent"
+msgstr "%d ተልኳል"
+
+#: mail/folder-browser.c:803
+#, c-format
+msgid "%d total"
+msgstr "%d አጠቃላይ"
+
+#: mail/folder-browser.c:1182
+msgid "Create _Virtual Folder From Search..."
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:3
-msgid "Configure spell-checking, signatures, and the message composer here"
+#: mail/folder-browser.c:1736
+msgid "VFolder on _Subject"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:4
-msgid "Configure your email accounts here"
+#: mail/folder-browser.c:1737
+msgid "VFolder on Se_nder"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:5
-msgid "Evolution Mail"
+#: mail/folder-browser.c:1738
+msgid "VFolder on _Recipients"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:6
-msgid "Evolution Mail accounts configuration control"
+#: mail/folder-browser.c:1739
+msgid "VFolder on Mailing _List"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:7
-msgid "Evolution Mail component"
+#: mail/folder-browser.c:1743
+msgid "Filter on Sub_ject"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:8
-msgid "Evolution Mail composer"
+#: mail/folder-browser.c:1744
+msgid "Filter on Sen_der"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:9
-msgid "Evolution Mail composer configuration control"
+#: mail/folder-browser.c:1745
+msgid "Filter on Re_cipients"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:10
-msgid "Evolution Mail configuration interface"
+#: mail/folder-browser.c:1746 mail/folder-browser.c:2070
+msgid "Filter on _Mailing List"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:11
-msgid "Evolution Mail folder viewer"
+#: mail/folder-browser.c:1764
+msgid "_Edit as New Message..."
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:12
-msgid "Evolution Mail preferences control"
+#: mail/folder-browser.c:1766
+msgid "_Print"
+msgstr "አትም"
+
+#: mail/folder-browser.c:1770 ui/evolution-mail-message.xml.h:110
+msgid "_Reply to Sender"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:13
-msgid "Mail Accounts"
+#: mail/folder-browser.c:1771 ui/evolution-mail-message.xml.h:75
+msgid "Reply to _List"
msgstr ""
-#: mail/GNOME_Evolution_Mail.server.in.in.h:14 mail/mail-config.glade.h:69
-msgid "Mail Preferences"
+#: mail/folder-browser.c:1772 ui/evolution-mail-message.xml.h:74
+msgid "Reply to _All"
+msgstr ""
+
+#: mail/folder-browser.c:1773
+msgid "_Forward"
+msgstr "ወደፊት፦"
+
+#: mail/folder-browser.c:1777
+msgid "Follo_w Up..."
+msgstr ""
+
+#: mail/folder-browser.c:1778
+msgid "Fla_g Completed"
+msgstr ""
+
+#: mail/folder-browser.c:1779
+msgid "Cl_ear Flag"
+msgstr ""
+
+#. separator here?
+#: mail/folder-browser.c:1783 ui/evolution-mail-message.xml.h:43
+msgid "Mar_k as Read"
+msgstr ""
+
+#: mail/folder-browser.c:1784
+msgid "Mark as _Unread"
+msgstr ""
+
+#: mail/folder-browser.c:1785
+msgid "Mark as _Important"
+msgstr ""
+
+#: mail/folder-browser.c:1786
+msgid "_Mark as Unimportant"
+msgstr ""
+
+#: mail/folder-browser.c:1791
+msgid "U_ndelete"
+msgstr "አታጥፋ"
+
+#: mail/folder-browser.c:1795
+msgid "Mo_ve to Folder..."
+msgstr ""
+
+#: mail/folder-browser.c:1796 ui/evolution-addressbook.xml.h:31
+msgid "_Copy to Folder..."
+msgstr ""
+
+#: mail/folder-browser.c:1804
+msgid "Add Sender to Address_book"
+msgstr ""
+
+#: mail/folder-browser.c:1808
+msgid "Appl_y Filters"
+msgstr ""
+
+#: mail/folder-browser.c:1812
+msgid "Crea_te Rule From Message"
+msgstr ""
+
+#: mail/folder-browser.c:2071
+msgid "VFolder on M_ailing List"
+msgstr ""
+
+#: mail/folder-browser.c:2073
+#, c-format
+msgid "Filter on _Mailing List (%s)"
+msgstr ""
+
+#: mail/folder-browser.c:2074
+#, c-format
+msgid "VFolder on M_ailing List (%s)"
+msgstr ""
+
+#: mail/folder-browser.h:26 mail/mail-config.glade.h:39
+msgid "Default"
+msgstr "የነበረው"
+
+#: mail/folder-info.c:70
+msgid "Getting Folder Information"
msgstr ""
#: mail/importers/GNOME_Evolution_Mail_Elm_Intelligent_Importer.server.in.in.h:1
@@ -11867,7 +11765,7 @@ msgstr "የተጠቃሚ ስም"
msgid "_Path:"
msgstr "መተላለፊያ"
-#: mail/mail-account-gui.c:1886
+#: mail/mail-account-gui.c:1887
msgid "You may not create two accounts with the same name."
msgstr ""
@@ -11898,16 +11796,16 @@ msgstr "የነበረው"
#. FIXME: This routine should just be a "toggled" event handler on the checkbox cell renderer which
#. has "activatable" set.
-#: mail/mail-accounts.c:481 mail/mail-composer-prefs.c:708
-#: mail/mail-composer-prefs.c:854
+#: mail/mail-accounts.c:481 mail/mail-accounts.etspec.h:2
+#: mail/mail-composer-prefs.c:708 mail/mail-composer-prefs.c:854
msgid "Enabled"
msgstr "ያስችላል"
-#: mail/mail-accounts.c:487
+#: mail/mail-accounts.c:487 mail/mail-accounts.etspec.h:1
msgid "Account name"
msgstr ""
-#: mail/mail-accounts.c:489
+#: mail/mail-accounts.c:489 mail/mail-accounts.etspec.h:3
msgid "Protocol"
msgstr ""
@@ -11947,6 +11845,182 @@ msgid ""
"And have been updated."
msgstr ""
+#. Add the "Don't show this message again." checkbox
+#: mail/mail-callbacks.c:101 widgets/misc/e-messagebox.c:226
+msgid "Don't show this message again."
+msgstr ""
+
+#: mail/mail-callbacks.c:190
+msgid ""
+"You have not configured the mail client.\n"
+"You need to do this before you can send,\n"
+"receive or compose mail.\n"
+"Would you like to configure it now?"
+msgstr ""
+
+#: mail/mail-callbacks.c:212
+msgid ""
+"You need to configure an account\n"
+"before you can compose mail."
+msgstr ""
+
+#: mail/mail-callbacks.c:226
+msgid ""
+"You need to configure an identity\n"
+"before you can compose mail."
+msgstr ""
+
+#: mail/mail-callbacks.c:233
+msgid ""
+"You need to configure a mail transport\n"
+"before you can compose mail."
+msgstr ""
+
+#. FIXME: this wording sucks
+#: mail/mail-callbacks.c:255
+msgid ""
+"You are sending an HTML-formatted message. Please make sure that\n"
+"the following recipients are willing and able to receive HTML mail:\n"
+msgstr ""
+
+#: mail/mail-callbacks.c:267
+msgid "Send anyway?"
+msgstr ""
+
+#: mail/mail-callbacks.c:288
+msgid ""
+"This message has no subject.\n"
+"Really send?"
+msgstr ""
+
+#: mail/mail-callbacks.c:314
+msgid ""
+"Since the contact list you are sending to is configured to hide the list's "
+"addresses, this message will contain only Bcc recipients."
+msgstr ""
+
+#: mail/mail-callbacks.c:318
+msgid "This message contains only Bcc recipients."
+msgstr ""
+
+#: mail/mail-callbacks.c:323
+msgid ""
+"It is possible that the mail server may reveal the recipients by adding an "
+"Apparently-To header.\n"
+"Send anyway?"
+msgstr ""
+
+#: mail/mail-callbacks.c:472
+msgid "You must specify recipients in order to send this message."
+msgstr ""
+
+#: mail/mail-callbacks.c:724
+msgid ""
+"Unable to open the drafts folder for this account.\n"
+"Would you like to use the default drafts folder?"
+msgstr ""
+
+#: mail/mail-callbacks.c:1189
+msgid "an unknown sender"
+msgstr ""
+
+#: mail/mail-callbacks.c:1193
+msgid "On %a, %Y-%m-%d at %H:%M, %%s wrote:"
+msgstr ""
+
+#: mail/mail-callbacks.c:1700 mail/message-browser.c:132
+msgid "Move message(s) to"
+msgstr ""
+
+#: mail/mail-callbacks.c:1702 mail/message-browser.c:134
+msgid "Copy message(s) to"
+msgstr ""
+
+#: mail/mail-callbacks.c:2344
+#, c-format
+msgid "Are you sure you want to edit all %d messages?"
+msgstr ""
+
+#: mail/mail-callbacks.c:2360
+msgid ""
+"You may only edit messages saved\n"
+"in the Drafts folder."
+msgstr ""
+
+#: mail/mail-callbacks.c:2393
+msgid ""
+"You may only resend messages\n"
+"in the Sent folder."
+msgstr ""
+
+#: mail/mail-callbacks.c:2403
+#, c-format
+msgid "Are you sure you want to resend all %d messages?"
+msgstr ""
+
+#: mail/mail-callbacks.c:2424
+msgid "No Message Selected"
+msgstr ""
+
+#: mail/mail-callbacks.c:2465
+#, c-format
+msgid ""
+"Cannot save to `%s'\n"
+" %s"
+msgstr ""
+
+#: mail/mail-callbacks.c:2470
+#, c-format
+msgid ""
+"`%s' already exists.\n"
+"Overwrite it?"
+msgstr ""
+
+#: mail/mail-callbacks.c:2511
+msgid "Save Message As..."
+msgstr ""
+
+#: mail/mail-callbacks.c:2513
+msgid "Save Messages As..."
+msgstr ""
+
+#: mail/mail-callbacks.c:2686
+msgid ""
+"This operation will permanently erase all messages marked as\n"
+"deleted. If you continue, you will not be able to recover these messages.\n"
+"\n"
+"Really erase these messages?"
+msgstr ""
+
+#: mail/mail-callbacks.c:2781
+#, c-format
+msgid ""
+"Error loading filter information:\n"
+"%s"
+msgstr ""
+
+#: mail/mail-callbacks.c:2789
+msgid "Filters"
+msgstr "አጣራዎች"
+
+#: mail/mail-callbacks.c:2830
+#, c-format
+msgid "Page %d of %d"
+msgstr ""
+
+#: mail/mail-callbacks.c:2886
+msgid "Print Message"
+msgstr ""
+
+#: mail/mail-callbacks.c:2954
+msgid "Printing of message failed"
+msgstr ""
+
+#: mail/mail-callbacks.c:3147
+#, c-format
+msgid "Are you sure you want to open all %d messages in separate windows?"
+msgstr ""
+
#: mail/mail-composer-prefs.c:226 mail/mail-composer-prefs.c:349
#: mail/mail-config.c:1376
msgid "Unnamed"
@@ -11972,55 +12046,47 @@ msgstr ""
msgid "Signature(s)"
msgstr ""
-#: mail/mail-config.c:1080
-msgid "Checking Service"
-msgstr ""
-
-#: mail/mail-config.c:1158 mail/mail-config.c:1162
-msgid "Connecting to server..."
-msgstr ""
-
-#: mail/mail-config-druid.c:367 mail/mail-config.glade.h:61
+#: mail/mail-config-druid.c:380 mail/mail-config.glade.h:61
msgid "Identity"
msgstr ""
-#: mail/mail-config-druid.c:369
+#: mail/mail-config-druid.c:382
msgid ""
"Please enter your name and email address below. The \"optional\" fields "
"below do not need to be filled in, unless you wish to include this "
"information in email you send."
msgstr ""
-#: mail/mail-config-druid.c:375 mail/mail-config-druid.c:382
+#: mail/mail-config-druid.c:388 mail/mail-config-druid.c:395
msgid "Receiving Mail"
msgstr ""
-#: mail/mail-config-druid.c:377
+#: mail/mail-config-druid.c:390
msgid ""
"Please enter information about your incoming mail server below. If you are "
"not sure, ask your system administrator or Internet Service Provider."
msgstr ""
-#: mail/mail-config-druid.c:384
+#: mail/mail-config-druid.c:397
msgid "Please select among the following options"
msgstr ""
-#: mail/mail-config-druid.c:387
+#: mail/mail-config-druid.c:400
#, fuzzy
msgid "Sending Mail"
msgstr "ሴኔጋል"
-#: mail/mail-config-druid.c:389
+#: mail/mail-config-druid.c:402
msgid ""
"Please enter information about the way you will send mail. If you are not "
"sure, ask your system administrator or Internet Service Provider."
msgstr ""
-#: mail/mail-config-druid.c:394 mail/mail-config.glade.h:10
+#: mail/mail-config-druid.c:407 mail/mail-config.glade.h:10
msgid "Account Management"
msgstr ""
-#: mail/mail-config-druid.c:396
+#: mail/mail-config-druid.c:409
msgid ""
"You are almost done with the mail configuration process. The identity, "
"incoming mail server and outgoing mail transport method which you provided "
@@ -12029,6 +12095,14 @@ msgid ""
"purposes only."
msgstr ""
+#: mail/mail-config.c:1080
+msgid "Checking Service"
+msgstr ""
+
+#: mail/mail-config.c:1158 mail/mail-config.c:1162
+msgid "Connecting to server..."
+msgstr ""
+
#: mail/mail-config.glade.h:3
msgid " _Check for supported types "
msgstr ""
@@ -12143,10 +12217,6 @@ msgstr ""
msgid "De_fault"
msgstr "የነበረው (_F)"
-#: mail/mail-config.glade.h:39
-msgid "Default"
-msgstr "የነበረው"
-
#: mail/mail-config.glade.h:40
msgid "Default Behavior"
msgstr ""
@@ -12581,293 +12651,495 @@ msgstr ""
msgid "_Use the same fonts as other applications"
msgstr ""
+#: mail/mail-config.glade.h:171
+msgid "color"
+msgstr "ቀለም"
+
#: mail/mail-config.glade.h:172
msgid "description"
msgstr "መግለጫ"
-#: mail/mail-folder-cache.c:832
+#: mail/mail-crypto.c:84
+msgid "Could not create a S/MIME signature context."
+msgstr ""
+
+#: mail/mail-crypto.c:116
+msgid "Could not create a S/MIME certsonly context."
+msgstr ""
+
+#: mail/mail-crypto.c:148
+msgid "Could not create a S/MIME encryption context."
+msgstr ""
+
+#: mail/mail-crypto.c:180
+msgid "Could not create a S/MIME envelope context."
+msgstr ""
+
+#: mail/mail-crypto.c:211
+msgid "Could not create a S/MIME decode context."
+msgstr ""
+
+#: mail/mail-display.c:197
+#, c-format
+msgid ""
+"File `%s' already exists.\n"
+"Overwrite it?"
+msgstr ""
+
+#: mail/mail-display.c:336
+msgid "Save Attachment"
+msgstr ""
+
+#: mail/mail-display.c:409
+#, c-format
+msgid "Could not create temporary file '%s': %s"
+msgstr ""
+
+#: mail/mail-display.c:457
+msgid "Save Attachment..."
+msgstr ""
+
+#: mail/mail-display.c:458
+msgid "View Inline"
+msgstr ""
+
+#: mail/mail-display.c:459
+#, c-format
+msgid "Open in %s..."
+msgstr ""
+
+#: mail/mail-display.c:515
+#, c-format
+msgid "View Inline (via %s)"
+msgstr ""
+
+#: mail/mail-display.c:519
+msgid "Hide"
+msgstr "ደብቅ"
+
+#: mail/mail-display.c:539
+msgid "External Viewer"
+msgstr ""
+
+#: mail/mail-display.c:1368
+msgid "Downloading images"
+msgstr ""
+
+#: mail/mail-display.c:1545
+msgid "Loading message content"
+msgstr ""
+
+#: mail/mail-display.c:1887
+msgid "Overdue:"
+msgstr ""
+
+#: mail/mail-display.c:1891
+msgid "by %B %d, %Y, %l:%M %P"
+msgstr ""
+
+#: mail/mail-display.c:2255
+msgid "Open Link in Browser"
+msgstr ""
+
+#: mail/mail-display.c:2256
+msgid "Copy Link Location"
+msgstr "አያያዝ ቦታ ቅጂ"
+
+#: mail/mail-display.c:2258
+msgid "Save Link as (FIXME)"
+msgstr ""
+
+#: mail/mail-display.c:2260
+msgid "Save Image as..."
+msgstr "ምስሉን በሌላ ስም አስቀምጥ"
+
+#: mail/mail-folder-cache.c:745
#, c-format
msgid "Pinging %s"
msgstr ""
+#: mail/mail-format.c:665
+#, c-format
+msgid "%s attachment"
+msgstr ""
+
+#: mail/mail-format.c:707 mail/mail-format.c:1370 mail/mail-format.c:1439
+#: mail/mail-format.c:1559 mail/mail-format.c:1683 mail/mail-format.c:1708
+msgid "Could not parse MIME message. Displaying as source."
+msgstr ""
+
+#: mail/mail-format.c:785 mail/message-list.etspec.h:2
+msgid "Date"
+msgstr "ቀን"
+
+#: mail/mail-format.c:871
+msgid "Bad Address"
+msgstr ""
+
+#: mail/mail-format.c:912 mail/message-list.etspec.h:7
+#: mail/message-tag-followup.c:301
+msgid "From"
+msgstr "ከ"
+
+#: mail/mail-format.c:916
+msgid "Reply-To"
+msgstr ""
+
+#: mail/mail-format.c:921 mail/message-list.etspec.h:14
+msgid "To"
+msgstr "ወደ"
+
+#: mail/mail-format.c:926
+msgid "Cc"
+msgstr "Cc"
+
+#: mail/mail-format.c:931
+msgid "Bcc"
+msgstr "Bcc"
+
+#: mail/mail-format.c:1482
+msgid ""
+"This message is digitally signed. Click the lock icon for more information."
+msgstr ""
+
+#: mail/mail-format.c:1510
+msgid "Could not create a PGP verfication context"
+msgstr ""
+
+#: mail/mail-format.c:1518
+msgid "This message is digitally signed and has been found to be authentic."
+msgstr ""
+
+#: mail/mail-format.c:1525
+msgid "This message is digitally signed but can not be proven to be authentic."
+msgstr ""
+
+#: mail/mail-format.c:1789
+#, c-format
+msgid "Pointer to FTP site (%s)"
+msgstr ""
+
+#: mail/mail-format.c:1800
+#, c-format
+msgid "Pointer to local file (%s) valid at site \"%s\""
+msgstr ""
+
+#: mail/mail-format.c:1803
+#, c-format
+msgid "Pointer to local file (%s)"
+msgstr ""
+
+#: mail/mail-format.c:1830
+#, c-format
+msgid "Pointer to remote data (%s)"
+msgstr ""
+
+#: mail/mail-format.c:1836
+#, c-format
+msgid "Pointer to unknown external data (\"%s\" type)"
+msgstr ""
+
+#: mail/mail-format.c:1838
+msgid "Malformed external-body part."
+msgstr ""
+
#: mail/mail-local.c:541 mail/mail-local.c:543
#, c-format
msgid "Local folders/%s"
msgstr ""
-#: mail/mail-local.c:711
+#: mail/mail-local.c:671
msgid "Reconfiguring folder"
msgstr ""
-#: mail/mail-local.c:792
+#: mail/mail-local.c:752
#, c-format
msgid ""
"Cannot save folder metainfo; you may find you can't\n"
"open this folder anymore: %s: %s"
msgstr ""
-#: mail/mail-local.c:848
+#: mail/mail-local.c:808
#, c-format
msgid "Cannot save folder metainfo to %s: %s"
msgstr ""
-#: mail/mail-local.c:900
+#: mail/mail-local.c:860
#, c-format
msgid "Cannot delete folder metadata %s: %s"
msgstr ""
-#: mail/mail-local.c:1363
+#: mail/mail-local.c:1323
#, c-format
msgid "Changing folder \"%s\" to \"%s\" format"
msgstr ""
-#: mail/mail-local.c:1388
+#: mail/mail-local.c:1348
msgid ""
"If you can no longer open this mailbox, then\n"
"you may need to repair it manually."
msgstr ""
-#: mail/mail-local.c:1488
+#: mail/mail-local.c:1448
#, c-format
msgid "Reconfigure /%s"
msgstr ""
-#: mail/mail-local.c:1552
+#: mail/mail-local.c:1512
msgid "You cannot change the format of a non-local folder."
msgstr ""
-#: mail/mail-mt.c:259
+#: mail/mail-mt.c:257
#, c-format
msgid ""
"Error while '%s':\n"
"%s"
msgstr ""
-#: mail/mail-mt.c:262
+#: mail/mail-mt.c:260
#, c-format
msgid ""
"Error while performing operation:\n"
"%s"
msgstr ""
-#: mail/mail-mt.c:913
+#: mail/mail-mt.c:904
msgid "Working"
msgstr ""
-#: mail/mail-ops.c:87
+#: mail/mail-ops.c:86
msgid "Filtering Folder"
msgstr ""
-#: mail/mail-ops.c:260
+#: mail/mail-ops.c:264
msgid "Fetching Mail"
msgstr ""
-#: mail/mail-ops.c:557
-#, c-format
-msgid "Failed to apply outgoing filters: %s"
-msgstr ""
-
-#: mail/mail-ops.c:578
-#, c-format
-msgid ""
-"Failed to append to %s: %s\n"
-"Appending to local `Sent' folder instead."
+#: mail/mail-ops.c:550 mail/mail-ops.c:579
+msgid "However, the message was successfully sent."
msgstr ""
-#: mail/mail-ops.c:587
-#, c-format
-msgid "Failed to append to local `Sent' folder: %s"
-msgstr ""
-
-#: mail/mail-ops.c:629
+#: mail/mail-ops.c:611
#, c-format
msgid "Sending \"%s\""
msgstr ""
-#: mail/mail-ops.c:747
+#: mail/mail-ops.c:729
#, c-format
msgid "Sending message %d of %d"
msgstr ""
-#: mail/mail-ops.c:766
+#: mail/mail-ops.c:748
#, c-format
msgid "Failed on message %d of %d"
msgstr ""
-#: mail/mail-ops.c:768
+#: mail/mail-ops.c:750 mail/mail-send-recv.c:581
msgid "Complete."
msgstr ""
-#: mail/mail-ops.c:862
+#: mail/mail-ops.c:844
msgid "Saving message to folder"
msgstr ""
-#: mail/mail-ops.c:943
+#: mail/mail-ops.c:925
#, c-format
msgid "Moving messages to %s"
msgstr ""
-#: mail/mail-ops.c:943
+#: mail/mail-ops.c:925
#, c-format
msgid "Copying messages to %s"
msgstr ""
-#: mail/mail-ops.c:1056
+#: mail/mail-ops.c:1042
#, c-format
msgid "Scanning folders in \"%s\""
msgstr ""
-#: mail/mail-ops.c:1244
+#: mail/mail-ops.c:1225
msgid "Forwarded messages"
msgstr ""
-#: mail/mail-ops.c:1287
+#: mail/mail-ops.c:1268
#, c-format
msgid "Opening folder %s"
msgstr ""
-#: mail/mail-ops.c:1359
+#: mail/mail-ops.c:1340
#, c-format
msgid "Opening store %s"
msgstr ""
-#: mail/mail-ops.c:1437
+#: mail/mail-ops.c:1413
#, c-format
msgid "Removing folder %s"
msgstr ""
-#: mail/mail-ops.c:1531
+#: mail/mail-ops.c:1507
#, c-format
msgid "Storing folder '%s'"
msgstr ""
-#: mail/mail-ops.c:1582
+#: mail/mail-ops.c:1558
msgid "Refreshing folder"
msgstr ""
-#: mail/mail-ops.c:1618 mail/mail-ops.c:1669
+#: mail/mail-ops.c:1594 mail/mail-ops.c:1645
msgid "Expunging folder"
msgstr ""
-#: mail/mail-ops.c:1666
+#: mail/mail-ops.c:1642
#, c-format
msgid "Emptying trash in '%s'"
msgstr ""
-#: mail/mail-ops.c:1667 my-evolution/e-summary-mail.c:483
+#: mail/mail-ops.c:1643 my-evolution/e-summary-mail.c:483
#: shell/e-local-storage.c:1151
msgid "Local Folders"
msgstr ""
-#: mail/mail-ops.c:1742
+#: mail/mail-ops.c:1718
#, c-format
msgid "Retrieving message %s"
msgstr ""
-#: mail/mail-ops.c:1814
+#: mail/mail-ops.c:1790
#, c-format
msgid "Retrieving %d message(s)"
msgstr ""
-#: mail/mail-ops.c:1898
+#: mail/mail-ops.c:1876
#, c-format
msgid "Saving %d messsage(s)"
msgstr ""
-#: mail/mail-ops.c:1946
+#: mail/mail-ops.c:1924
#, c-format
msgid ""
"Unable to create output file: %s\n"
" %s"
msgstr ""
-#: mail/mail-ops.c:1974
+#: mail/mail-ops.c:1952
#, c-format
msgid ""
"Error saving messages to: %s:\n"
" %s"
msgstr ""
-#: mail/mail-ops.c:2045
+#: mail/mail-ops.c:2026
msgid "Saving attachment"
msgstr ""
-#: mail/mail-ops.c:2062
+#: mail/mail-ops.c:2043
#, c-format
msgid ""
"Cannot create output file: %s:\n"
" %s"
msgstr ""
-#: mail/mail-ops.c:2092
+#: mail/mail-ops.c:2073
#, c-format
msgid "Could not write data: %s"
msgstr ""
-#: mail/mail-ops.c:2240
+#: mail/mail-ops.c:2221
#, c-format
msgid "Disconnecting from %s"
msgstr ""
-#: mail/mail-ops.c:2240
+#: mail/mail-ops.c:2221
#, c-format
msgid "Reconnecting to %s"
msgstr ""
-#: mail/mail-send-recv.c:147
+#: mail/mail-search.c:154
+msgid "(Untitled Message)"
+msgstr ""
+
+#: mail/mail-search.c:236
+msgid "Untitled Message"
+msgstr ""
+
+#: mail/mail-search.c:238
+msgid "Empty Message"
+msgstr ""
+
+#: mail/mail-search.c:287
+msgid "Find in Message"
+msgstr ""
+
+#: mail/mail-search.c:320
+msgid "Case Sensitive"
+msgstr ""
+
+#: mail/mail-search.c:322
+msgid "Search Forward"
+msgstr ""
+
+#: mail/mail-search.c:342
+msgid "Find:"
+msgstr "ፈልግ"
+
+#: mail/mail-search.c:346
+msgid "Matches:"
+msgstr ""
+
+#: mail/mail-send-recv.c:146
msgid "Cancelling..."
msgstr ""
-#: mail/mail-send-recv.c:255
+#: mail/mail-send-recv.c:254
#, c-format
msgid "Server: %s, Type: %s"
msgstr ""
-#: mail/mail-send-recv.c:257
+#: mail/mail-send-recv.c:256
#, c-format
msgid "Path: %s, Type: %s"
msgstr ""
-#: mail/mail-send-recv.c:259
+#: mail/mail-send-recv.c:258
#, c-format
msgid "Type: %s"
msgstr "ዓይነት፦ %s"
-#: mail/mail-send-recv.c:308
+#: mail/mail-send-recv.c:306
msgid "Send & Receive Mail"
msgstr ""
-#: mail/mail-send-recv.c:309
+#: mail/mail-send-recv.c:307
#, fuzzy
msgid "Cancel _All"
msgstr "ተወው"
-#: mail/mail-send-recv.c:390
+#: mail/mail-send-recv.c:389
msgid "Updating..."
msgstr ""
-#: mail/mail-send-recv.c:390 mail/mail-send-recv.c:442
+#: mail/mail-send-recv.c:390 mail/mail-send-recv.c:446
msgid "Waiting..."
msgstr ""
-#: mail/mail-session.c:229
+#: mail/mail-session.c:226
msgid "User canceled operation."
msgstr ""
-#: mail/mail-session.c:262
+#: mail/mail-session.c:259
#, c-format
msgid "Enter Password for %s"
msgstr ""
-#: mail/mail-session.c:264
+#: mail/mail-session.c:261
msgid "Enter Password"
msgstr "ሚስጢራዊ ቃል አስገቡ"
-#: mail/mail-session.c:287
+#: mail/mail-session.c:284
msgid "_Remember this password"
msgstr "ይህንን ሚስጢራዊ ቃል አስታውሱ (_R)"
-#: mail/mail-session.c:288
+#: mail/mail-session.c:285
msgid "_Remember this password for the remainder of this session"
msgstr ""
@@ -12912,17 +13184,21 @@ msgstr ""
msgid "Forwarded message"
msgstr ""
-#: mail/mail-vfolder.c:91
+#: mail/mail-tools.c:438
+msgid "Forwarded Message"
+msgstr ""
+
+#: mail/mail-vfolder.c:92
#, c-format
msgid "Setting up vfolder: %s"
msgstr ""
-#: mail/mail-vfolder.c:209
+#: mail/mail-vfolder.c:210
#, c-format
msgid "Updating vfolders for uri: %s"
msgstr ""
-#: mail/mail-vfolder.c:467
+#: mail/mail-vfolder.c:468
#, c-format
msgid ""
"The following vFolder(s):\n"
@@ -12931,95 +13207,100 @@ msgid ""
"And have been updated."
msgstr ""
-#: mail/mail-vfolder.c:776
+#: mail/mail-vfolder.c:777
msgid "VFolders"
msgstr ""
-#: mail/mail-vfolder.c:834
+#: mail/mail-vfolder.c:835
msgid "vFolders"
msgstr ""
-#: mail/mail-vfolder.c:873
+#: mail/mail-vfolder.c:874
msgid "Edit VFolder"
msgstr ""
-#: mail/mail-vfolder.c:893
+#: mail/mail-vfolder.c:894
#, c-format
msgid "Trying to edit a vfolder '%s' which doesn't exist."
msgstr ""
-#: mail/mail-vfolder.c:965
+#: mail/mail-vfolder.c:966
msgid "New VFolder"
msgstr ""
-#: mail/message-list.c:900
+#: mail/message-browser.c:233
+msgid "(No subject)"
+msgstr ""
+
+#: mail/message-browser.c:235
+#, c-format
+msgid "%s - Message"
+msgstr "%s - መልዕክት"
+
+#: mail/message-list.c:741
msgid "Unseen"
msgstr ""
-#: mail/message-list.c:901
+#: mail/message-list.c:742
msgid "Seen"
msgstr ""
-#: mail/message-list.c:902
+#: mail/message-list.c:743
msgid "Answered"
msgstr ""
-#: mail/message-list.c:903
+#: mail/message-list.c:744
msgid "Multiple Unseen Messages"
msgstr ""
-#: mail/message-list.c:904
+#: mail/message-list.c:745
msgid "Multiple Messages"
msgstr ""
-#: mail/message-list.c:908
+#: mail/message-list.c:749
msgid "Lowest"
msgstr ""
-#: mail/message-list.c:909
+#: mail/message-list.c:750
msgid "Lower"
msgstr "ዝቅተኛ"
-#: mail/message-list.c:913
+#: mail/message-list.c:754
msgid "Higher"
msgstr ""
-#: mail/message-list.c:914
+#: mail/message-list.c:755
msgid "Highest"
msgstr ""
-#: mail/message-list.c:1231
+#: mail/message-list.c:1072
msgid "?"
msgstr "?"
-#: mail/message-list.c:1238
+#: mail/message-list.c:1079
msgid "Today %l:%M %p"
msgstr "ዛሬ %l:%M %p"
-#: mail/message-list.c:1247
+#: mail/message-list.c:1088
msgid "Yesterday %l:%M %p"
msgstr "ትናንት %l:%M %p"
-#: mail/message-list.c:1259
+#: mail/message-list.c:1100
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
-#: mail/message-list.c:1267
+#: mail/message-list.c:1108
msgid "%b %d %l:%M %p"
msgstr "%b %d %l:%M %p"
-#: mail/message-list.c:1269
+#: mail/message-list.c:1110
msgid "%b %d %Y"
msgstr "%b %d %Y"
-#: mail/message-list.c:3062
+#: mail/message-list.c:2649
msgid "Generating message list"
msgstr ""
-#: mail/message-list.etspec.h:2
-msgid "Date"
-msgstr "ቀን"
-
#: mail/message-list.etspec.h:3
msgid "Due By"
msgstr ""
@@ -13036,10 +13317,6 @@ msgstr ""
msgid "Follow Up Flag"
msgstr ""
-#: mail/message-list.etspec.h:7 mail/message-tag-followup.c:301
-msgid "From"
-msgstr "ከ"
-
#: mail/message-list.etspec.h:8
msgid "Original Location"
msgstr ""
@@ -13052,10 +13329,6 @@ msgstr ""
msgid "Size"
msgstr "መጠን"
-#: mail/message-list.etspec.h:14
-msgid "To"
-msgstr "ወደ"
-
#: mail/message-tag-followup.c:62
msgid "Call"
msgstr ""
@@ -13072,7 +13345,7 @@ msgstr ""
msgid "For Your Information"
msgstr ""
-#: mail/message-tag-followup.c:66 ui/evolution-mail-message.xml.h:40
+#: mail/message-tag-followup.c:66 ui/evolution-mail-message.xml.h:36
msgid "Forward"
msgstr "ወደፊት"
@@ -13080,11 +13353,11 @@ msgstr "ወደፊት"
msgid "No Response Necessary"
msgstr ""
-#: mail/message-tag-followup.c:69 ui/evolution-mail-message.xml.h:77
+#: mail/message-tag-followup.c:69 ui/evolution-mail-message.xml.h:72
msgid "Reply"
msgstr ""
-#: mail/message-tag-followup.c:70 ui/evolution-mail-message.xml.h:78
+#: mail/message-tag-followup.c:70 ui/evolution-mail-message.xml.h:73
msgid "Reply to All"
msgstr ""
@@ -13114,138 +13387,64 @@ msgstr ""
msgid "_Flag:"
msgstr "ባንዲራ"
-#: mail/subscribe-dialog.glade.h:1
-#, fuzzy
-msgid "Folder Subscriptions"
-msgstr "መግለጫ"
-
-#: mail/subscribe-dialog.glade.h:2
-#, fuzzy
-msgid "None Selected"
-msgstr "ተመርጠዋል"
-
-#: mail/subscribe-dialog.glade.h:3
-#, fuzzy
-msgid "S_erver:"
-msgstr "_የሰርቨር ስም፦"
-
-#: mail/subscribe-dialog.glade.h:4
-msgid "_Subscribe"
-msgstr ""
-
-#: mail/subscribe-dialog.glade.h:5
-msgid "_Unsubscribe"
+#: mail/subscribe-dialog.c:230
+#, c-format
+msgid "Scanning folders under %s on \"%s\""
msgstr ""
-#: my-evolution/component-factory.c:56
-msgid "Folder containing the Evolution Summary"
+#: mail/subscribe-dialog.c:232
+#, c-format
+msgid "Scanning root-level folders on \"%s\""
msgstr ""
-#: my-evolution/e-summary.c:204
-msgid "%A, %B %e %Y"
-msgstr "%A, %B %e %Y"
-
-#: my-evolution/e-summary.c:533
-msgid "Please wait..."
+#: mail/subscribe-dialog.c:329
+#, c-format
+msgid "Subscribing to folder \"%s\""
msgstr ""
-#: my-evolution/e-summary.c:622 ui/my-evolution.xml.h:2
-msgid "Print Summary"
+#: mail/subscribe-dialog.c:331
+#, c-format
+msgid "Unsubscribing to folder \"%s\""
msgstr ""
-#: my-evolution/e-summary.c:655
-msgid "Printing of Summary failed"
-msgstr ""
+#: mail/subscribe-dialog.c:1270 mail/subscribe-dialog.etspec.h:1
+#: shell/e-storage-set-view.etspec.h:2
+msgid "Folder"
+msgstr "ዶሴ"
-#: my-evolution/e-summary-calendar.c:384
-msgid "Appointments"
+#: mail/subscribe-dialog.c:1499
+msgid "No server has been selected"
msgstr ""
-#: my-evolution/e-summary-calendar.c:392
-msgid "No appointments."
+#: mail/subscribe-dialog.c:1598
+msgid "Please select a server."
msgstr ""
-#: my-evolution/e-summary-calendar.c:409
-msgid "%k:%M %d %B"
-msgstr "%k:%M %d %B"
-
-#: my-evolution/e-summary-calendar.c:411
+#: mail/subscribe-dialog.glade.h:1
#, fuzzy
-msgid "%l:%M%p %d %B"
-msgstr "%l:%M %d %B"
-
-#: my-evolution/e-summary-calendar.c:429
-msgid "No description"
-msgstr "መግለጫ የለም"
-
-#: my-evolution/e-summary-mail.c:189
-msgid "Mail summary"
-msgstr ""
-
-#: my-evolution/e-summary-preferences.c:355
-msgid "Dictionary.com Word of the Day"
-msgstr ""
-
-#: my-evolution/e-summary-preferences.c:373
-msgid "Quotes of the Day"
-msgstr ""
-
-#: my-evolution/e-summary-preferences.c:565
-msgid "New News Feed"
-msgstr ""
+msgid "Folder Subscriptions"
+msgstr "መግለጫ"
-#: my-evolution/e-summary-preferences.c:581
+#: mail/subscribe-dialog.glade.h:2
#, fuzzy
-msgid "_URL:"
-msgstr "url"
-
-#: my-evolution/e-summary-rdf.c:315
-msgid "Error downloading RDF"
-msgstr ""
-
-#: my-evolution/e-summary-rdf.c:453
-msgid "News Feed"
-msgstr ""
-
-#: my-evolution/e-summary-shown.c:496
-msgid "All"
-msgstr "ሁሉም"
-
-#: my-evolution/e-summary-shown.c:521 my-evolution/e-summary-table.c:58
-msgid "Shown"
-msgstr ""
-
-#: my-evolution/e-summary-tasks.c:349
-msgid "No tasks"
-msgstr ""
+msgid "None Selected"
+msgstr "ተመርጠዋል"
-#: my-evolution/e-summary-tasks.c:387
+#: mail/subscribe-dialog.glade.h:3
#, fuzzy
-msgid "blue"
-msgstr "አስቻለ"
-
-#: my-evolution/e-summary-tasks.c:387
-msgid "(No Description)"
-msgstr "መግለጫ የለም"
-
-#: my-evolution/e-summary-weather.c:72
-msgid "My Weather"
-msgstr ""
+msgid "S_erver:"
+msgstr "_የሰርቨር ስም፦"
-#: my-evolution/e-summary-weather.c:261
-msgid "There was an error downloading data for"
+#: mail/subscribe-dialog.glade.h:4
+msgid "Scanning folders ..."
msgstr ""
-#: my-evolution/e-summary-weather.c:478 my-evolution/my-evolution.glade.h:16
-msgid "Weather"
+#: mail/subscribe-dialog.glade.h:5
+msgid "_Subscribe"
msgstr ""
-#. translators: Put here a list of codes for locations you want to
-#. see in My Evolution by default. You can find the list of all
-#. stations and their codes in Evolution sources
-#. (evolution/my-evolution/Locations)
-#: my-evolution/e-summary-weather.c:582
-msgid "KBOS"
+#: mail/subscribe-dialog.glade.h:6
+msgid "_Unsubscribe"
msgstr ""
#: my-evolution/GNOME_Evolution_Summary.server.in.in.h:1
@@ -23053,6 +23252,112 @@ msgstr ""
msgid "Zurich"
msgstr ""
+#: my-evolution/component-factory.c:56
+msgid "Folder containing the Evolution Summary"
+msgstr ""
+
+#: my-evolution/e-summary-calendar.c:381
+msgid "Appointments"
+msgstr ""
+
+#: my-evolution/e-summary-calendar.c:389
+msgid "No appointments."
+msgstr ""
+
+#: my-evolution/e-summary-calendar.c:406
+msgid "%k:%M %d %B"
+msgstr "%k:%M %d %B"
+
+#: my-evolution/e-summary-calendar.c:408
+#, fuzzy
+msgid "%l:%M%P %d %B"
+msgstr "%l:%M %d %B"
+
+#: my-evolution/e-summary-calendar.c:426
+msgid "No description"
+msgstr "መግለጫ የለም"
+
+#: my-evolution/e-summary-mail.c:189
+msgid "Mail summary"
+msgstr ""
+
+#: my-evolution/e-summary-preferences.c:355
+msgid "Dictionary.com Word of the Day"
+msgstr ""
+
+#: my-evolution/e-summary-preferences.c:373
+msgid "Quotes of the Day"
+msgstr ""
+
+#: my-evolution/e-summary-preferences.c:565
+msgid "New News Feed"
+msgstr ""
+
+#: my-evolution/e-summary-preferences.c:581
+#, fuzzy
+msgid "_URL:"
+msgstr "url"
+
+#: my-evolution/e-summary-rdf.c:315
+msgid "Error downloading RDF"
+msgstr ""
+
+#: my-evolution/e-summary-rdf.c:453
+msgid "News Feed"
+msgstr ""
+
+#: my-evolution/e-summary-shown.c:496
+msgid "All"
+msgstr "ሁሉም"
+
+#: my-evolution/e-summary-shown.c:521 my-evolution/e-summary-table.c:58
+msgid "Shown"
+msgstr ""
+
+#: my-evolution/e-summary-tasks.c:330
+msgid "No tasks"
+msgstr ""
+
+#: my-evolution/e-summary-tasks.c:364
+msgid "(No Description)"
+msgstr "መግለጫ የለም"
+
+#: my-evolution/e-summary-weather.c:73
+msgid "My Weather"
+msgstr ""
+
+#: my-evolution/e-summary-weather.c:262
+msgid "There was an error downloading data for"
+msgstr ""
+
+#: my-evolution/e-summary-weather.c:479 my-evolution/my-evolution.glade.h:16
+msgid "Weather"
+msgstr ""
+
+#. translators: Put here a list of codes for locations you want to
+#. see in My Evolution by default. You can find the list of all
+#. stations and their codes in Evolution sources
+#. (evolution/my-evolution/Locations)
+#: my-evolution/e-summary-weather.c:583
+msgid "KBOS"
+msgstr ""
+
+#: my-evolution/e-summary.c:204
+msgid "%A, %B %e %Y"
+msgstr "%A, %B %e %Y"
+
+#: my-evolution/e-summary.c:533
+msgid "Please wait..."
+msgstr ""
+
+#: my-evolution/e-summary.c:622 ui/my-evolution.xml.h:2
+msgid "Print Summary"
+msgstr ""
+
+#: my-evolution/e-summary.c:655
+msgid "Printing of Summary failed"
+msgstr ""
+
#: my-evolution/metar.c:30
msgid " F"
msgstr " F"
@@ -24314,26 +24619,21 @@ msgstr ""
msgid "_Show full path for folders"
msgstr ""
-#: notes/component-factory.c:27
-#: shell/e-shell-user-creatable-items-handler.c:587
-#: shell/e-shell-user-creatable-items-handler.c:643
-#: widgets/misc/e-charset-picker.c:109
-msgid "New"
-msgstr "አዲስ"
+#: shell/GNOME_Evolution_Shell.server.in.in.h:1
+msgid "Configure special folders and offline folder behavior here"
+msgstr ""
-#: notes/component-factory.c:27
-#, fuzzy
-msgid "Create a new note"
-msgstr "አዲስ ዶሴ ፍጠር"
+#: shell/GNOME_Evolution_Shell.server.in.in.h:2
+msgid "Evolution Shell"
+msgstr ""
-#: notes/component-factory.c:152
-msgid "Cannot initialize Evolution's notes component."
+#: shell/GNOME_Evolution_Shell.server.in.in.h:3
+msgid "Evolution folder settings configuration control"
msgstr ""
-#: notes/main.c:30
-#, fuzzy
-msgid "Notes Component: Could not initialize bonobo"
-msgstr "bonobo ማስጀመር አልቻልኩም!"
+#: shell/GNOME_Evolution_Shell.server.in.in.h:4
+msgid "Folder Settings"
+msgstr ""
#: shell/e-activity-handler.c:164
msgid "Show Details"
@@ -24415,43 +24715,6 @@ msgstr ""
msgid "Brought to you by"
msgstr ""
-#: shell/e-shell.c:175
-#, c-format
-msgid ""
-"Cannot activate component %s :\n"
-"The error from the activation system is:\n"
-"%s"
-msgstr ""
-
-#: shell/e-shell.c:741
-#, c-format
-msgid "Cannot set up local storage -- %s"
-msgstr ""
-
-#: shell/e-shell.c:1804
-#, c-format
-msgid ""
-"The Evolution component that handles folders of type \"%s\"\n"
-"has unexpectedly quit. You will need to quit Evolution and restart\n"
-"in order to access that data again."
-msgstr ""
-
-#: shell/e-shell.c:2069
-msgid "Invalid arguments"
-msgstr ""
-
-#: shell/e-shell.c:2071
-msgid "Cannot register on OAF"
-msgstr ""
-
-#: shell/e-shell.c:2073
-msgid "Configuration Database not found"
-msgstr ""
-
-#: shell/e-shell.c:2075 shell/e-storage.c:568
-msgid "Generic error"
-msgstr "አጠቃላይ ስህተት"
-
#: shell/e-shell-config-autocompletion.c:110
msgid "Extra Completion folders"
msgstr ""
@@ -24538,32 +24801,27 @@ msgid ""
"%s"
msgstr ""
-#: shell/e-shell-folder-commands.c:534
+#: shell/e-shell-folder-commands.c:538
#, c-format
msgid "Rename the \"%s\" folder to:"
msgstr ""
-#: shell/e-shell-folder-commands.c:541
+#: shell/e-shell-folder-commands.c:544
#, fuzzy
msgid "Rename Folder"
msgstr "ዶሴን እንደገና ሰይም"
-#: shell/e-shell-folder-commands.c:547
+#: shell/e-shell-folder-commands.c:553
#: shell/e-shell-folder-creation-dialog.c:180
#, c-format
msgid "The specified folder name is not valid: %s"
msgstr ""
-#: shell/e-shell-folder-commands.c:554
-#, c-format
-msgid "A folder named \"%s\" already exists. Please use a different name."
-msgstr ""
-
-#: shell/e-shell-folder-commands.c:584
+#: shell/e-shell-folder-commands.c:587
msgid "Selected folder does not belong to another user"
msgstr ""
-#: shell/e-shell-folder-commands.c:587
+#: shell/e-shell-folder-commands.c:590
#, c-format
msgid ""
"Cannot remove folder:\n"
@@ -24598,126 +24856,115 @@ msgid ""
"to work it out."
msgstr ""
-#: shell/e-shell-importer.c:148 shell/e-shell-startup-wizard.c:724
+#: shell/e-shell-importer.c:148 shell/e-shell-startup-wizard.c:709
msgid "Please select the information that you would like to import:"
msgstr ""
-#: shell/e-shell-importer.c:151
-msgid ""
-"Evolution checked for settings to import from the following\n"
-"applications: Pine, Netscape, Elm, iCalendar. No settings\n"
-"that could be imported where found. If you would like to\n"
-"try again, please click the \"Back\" button.\n"
-msgstr ""
-
-#: shell/e-shell-importer.c:219 shell/e-shell-importer.c:250
+#: shell/e-shell-importer.c:213 shell/e-shell-importer.c:244
#, c-format
msgid ""
"Importing %s\n"
"Importing item %d."
msgstr ""
-#: shell/e-shell-importer.c:323
+#: shell/e-shell-importer.c:317
msgid "Select importer"
msgstr ""
-#: shell/e-shell-importer.c:464
+#: shell/e-shell-importer.c:458
#, c-format
msgid "File %s does not exist"
msgstr ""
-#: shell/e-shell-importer.c:465 shell/e-shell-importer.c:482
-#: shell/e-shell-importer.c:524
+#: shell/e-shell-importer.c:459 shell/e-shell-importer.c:476
+#: shell/e-shell-importer.c:518
msgid "Evolution Error"
msgstr ""
-#: shell/e-shell-importer.c:481
+#: shell/e-shell-importer.c:475
#, c-format
msgid ""
"There is no importer that is able to handle\n"
"%s"
msgstr ""
-#: shell/e-shell-importer.c:490
+#: shell/e-shell-importer.c:484
msgid "Importing"
msgstr ""
-#: shell/e-shell-importer.c:497
+#: shell/e-shell-importer.c:491
#, c-format
msgid ""
"Importing %s.\n"
"Starting %s"
msgstr ""
-#: shell/e-shell-importer.c:509
+#: shell/e-shell-importer.c:503
#, c-format
msgid "Error starting %s"
msgstr ""
-#: shell/e-shell-importer.c:523
+#: shell/e-shell-importer.c:517
#, c-format
msgid "Error loading %s"
msgstr ""
-#: shell/e-shell-importer.c:540
+#: shell/e-shell-importer.c:534
#, c-format
msgid ""
"Importing %s\n"
"Importing item 1."
msgstr ""
-#: shell/e-shell-importer.c:594
+#: shell/e-shell-importer.c:588
msgid "Automatic"
msgstr "አውቶማቲክ"
-#: shell/e-shell-importer.c:643
-#, fuzzy
-msgid "_Filename:"
+#: shell/e-shell-importer.c:637
+msgid "Filename:"
msgstr "የፋይል ስም፦"
-#: shell/e-shell-importer.c:648
+#: shell/e-shell-importer.c:642
msgid "Select a file"
msgstr "ፋይል ምረጡ"
-#: shell/e-shell-importer.c:658
-#, fuzzy
-msgid "File _type:"
+#: shell/e-shell-importer.c:651
+msgid "File type:"
msgstr "የፋይሉ ዓይነት፦"
-#: shell/e-shell-importer.c:684
-msgid "Import data and settings from _older programs"
+#: shell/e-shell-importer.c:676
+msgid "Import data and settings from older programs"
msgstr ""
-#: shell/e-shell-importer.c:687
-msgid "Import a _single file"
+#: shell/e-shell-importer.c:680
+msgid "Import a single file"
msgstr ""
-#: shell/e-shell-importer.c:755 shell/e-shell-startup-wizard.c:553
+#: shell/e-shell-importer.c:746 shell/e-shell-startup-wizard.c:538
msgid ""
"Please wait...\n"
"Scanning for existing setups"
msgstr ""
-#: shell/e-shell-importer.c:758
+#: shell/e-shell-importer.c:749
msgid "Starting Intelligent Importers"
msgstr ""
-#: shell/e-shell-importer.c:884 shell/e-shell-startup-wizard.c:679
+#: shell/e-shell-importer.c:873 shell/e-shell-startup-wizard.c:664
#, c-format
msgid "From %s:"
msgstr "ከ %s፦"
-#: shell/e-shell-importer.c:1061
+#: shell/e-shell-importer.c:1047
msgid "Select folder"
msgstr "ዶሴ ምረጡ"
-#: shell/e-shell-importer.c:1062
+#: shell/e-shell-importer.c:1048
msgid "Select a destination folder for importing this data"
msgstr ""
-#: shell/e-shell-importer.c:1193
-#, fuzzy
-msgid "_Import"
+#: shell/e-shell-importer.c:1178 shell/importer/intelligent.c:191
+msgid "Import"
msgstr "ከውጭ አስገባ"
#: shell/e-shell-offline-handler.c:592
@@ -24775,18 +25022,11 @@ msgstr ""
msgid "Cannot find the specified shared folder."
msgstr ""
-#: shell/e-shell-startup-wizard.c:771
-msgid ""
-"If you quit the Evolution Setup Assistant now, all of the information that "
-"you have entered will be forgotten. You will need to run this assistant "
-"again before using Evolution.\n"
-"\n"
-"Do you want to quit using the Assistant now?"
-msgstr ""
-
-#: shell/e-shell-startup-wizard.c:782
-msgid "Quit Assistant"
-msgstr ""
+#: shell/e-shell-user-creatable-items-handler.c:586
+#: shell/e-shell-user-creatable-items-handler.c:642
+#: widgets/misc/e-charset-picker.c:109
+msgid "New"
+msgstr "አዲስ"
#: shell/e-shell-utils.c:116
msgid "No folder name specified."
@@ -24808,33 +25048,6 @@ msgstr ""
msgid "'.' and '..' are reserved folder names."
msgstr ""
-#: shell/e-shell-view.c:264
-msgid "(No folder displayed)"
-msgstr ""
-
-#: shell/e-shell-view.c:2040
-#, c-format
-msgid "%s (%d)"
-msgstr "%s (%d)"
-
-#: shell/e-shell-view.c:2042
-msgid "(None)"
-msgstr "(ምንም)"
-
-#: shell/e-shell-view.c:2083
-msgid ""
-"Ximian Evolution is currently online. Click on this button to work offline."
-msgstr ""
-
-#: shell/e-shell-view.c:2090
-msgid "Ximian Evolution is in the process of going offline."
-msgstr ""
-
-#: shell/e-shell-view.c:2096
-msgid ""
-"Ximian Evolution is currently offline. Click on this button to work online."
-msgstr ""
-
#: shell/e-shell-view-menu.c:89
msgid "The GNOME Pilot tools do not appear to be installed on this system."
msgstr ""
@@ -24884,13 +25097,69 @@ msgstr ""
msgid "Work Offline"
msgstr ""
-#: shell/e-shortcuts.c:649
-msgid "Error saving shortcuts."
+#: shell/e-shell-view.c:264
+msgid "(No folder displayed)"
msgstr ""
-#: shell/e-shortcuts.c:1096
-msgid "Shortcuts"
-msgstr "አቋራጮች"
+#: shell/e-shell-view.c:2040
+#, c-format
+msgid "%s (%d)"
+msgstr "%s (%d)"
+
+#: shell/e-shell-view.c:2042
+msgid "(None)"
+msgstr "(ምንም)"
+
+#: shell/e-shell-view.c:2083
+msgid ""
+"Ximian Evolution is currently online. Click on this button to work offline."
+msgstr ""
+
+#: shell/e-shell-view.c:2090
+msgid "Ximian Evolution is in the process of going offline."
+msgstr ""
+
+#: shell/e-shell-view.c:2096
+msgid ""
+"Ximian Evolution is currently offline. Click on this button to work online."
+msgstr ""
+
+#: shell/e-shell.c:175
+#, c-format
+msgid ""
+"Cannot activate component %s :\n"
+"The error from the activation system is:\n"
+"%s"
+msgstr ""
+
+#: shell/e-shell.c:741
+#, c-format
+msgid "Cannot set up local storage -- %s"
+msgstr ""
+
+#: shell/e-shell.c:1804
+#, c-format
+msgid ""
+"The Evolution component that handles folders of type \"%s\"\n"
+"has unexpectedly quit. You will need to quit Evolution and restart\n"
+"in order to access that data again."
+msgstr ""
+
+#: shell/e-shell.c:2069
+msgid "Invalid arguments"
+msgstr ""
+
+#: shell/e-shell.c:2071
+msgid "Cannot register on OAF"
+msgstr ""
+
+#: shell/e-shell.c:2073
+msgid "Configuration Database not found"
+msgstr ""
+
+#: shell/e-shell.c:2075 shell/e-storage.c:568
+msgid "Generic error"
+msgstr "አጠቃላይ ስህተት"
#: shell/e-shortcuts-view.c:80
#, fuzzy
@@ -25008,6 +25277,18 @@ msgstr "አስወግድ"
msgid "Remove this shortcut from the shortcut bar"
msgstr ""
+#: shell/e-shortcuts.c:649
+msgid "Error saving shortcuts."
+msgstr ""
+
+#: shell/e-shortcuts.c:1096
+msgid "Shortcuts"
+msgstr "አቋራጮች"
+
+#: shell/e-storage-set-view.etspec.h:1
+msgid "Checkbox"
+msgstr ""
+
#: shell/e-storage.c:566
msgid "No error"
msgstr "ስህተት የለም"
@@ -25064,14 +25345,6 @@ msgstr ""
msgid "This operation cannot be performed in off-line mode"
msgstr ""
-#: shell/e-storage-set-view.etspec.h:1
-msgid "Checkbox"
-msgstr ""
-
-#: shell/e-storage-set-view.etspec.h:2
-msgid "Folder"
-msgstr "ዶሴ"
-
#: shell/e-task-widget.c:211
#, c-format
msgid "%s (...)"
@@ -25086,95 +25359,95 @@ msgstr ""
msgid "<click here to select a folder>"
msgstr ""
-#: shell/evolution-shell-component.c:1187
+#: shell/evolution-shell-component-utils.c:124
+#, c-format
+msgid ""
+"%s\n"
+"\n"
+"Unknown error."
+msgstr ""
+"%s\n"
+"\n"
+"ያልታወቀ ስህተት።"
+
+#: shell/evolution-shell-component-utils.c:127
+#, c-format
+msgid ""
+"%s\n"
+"\n"
+"The error from the component system is:\n"
+"%s"
+msgstr ""
+
+#: shell/evolution-shell-component-utils.c:134
+#, c-format
+msgid ""
+"%s\n"
+"\n"
+"The error from the activation system is:\n"
+"%s"
+msgstr ""
+
+#: shell/evolution-shell-component.c:1184
msgid "CORBA error"
msgstr "የCORBA ብልሽት"
-#: shell/evolution-shell-component.c:1189
+#: shell/evolution-shell-component.c:1186
msgid "Interrupted"
msgstr ""
-#: shell/evolution-shell-component.c:1191
+#: shell/evolution-shell-component.c:1188
msgid "Invalid argument"
msgstr ""
-#: shell/evolution-shell-component.c:1193
+#: shell/evolution-shell-component.c:1190
msgid "Already has an owner"
msgstr ""
-#: shell/evolution-shell-component.c:1195
+#: shell/evolution-shell-component.c:1192
msgid "No owner"
msgstr "ባለቤት የለም"
-#: shell/evolution-shell-component.c:1197
+#: shell/evolution-shell-component.c:1194
msgid "Not found"
msgstr "አልተገኘም"
-#: shell/evolution-shell-component.c:1199
+#: shell/evolution-shell-component.c:1196
msgid "Unsupported type"
msgstr ""
-#: shell/evolution-shell-component.c:1201
+#: shell/evolution-shell-component.c:1198
msgid "Unsupported schema"
msgstr ""
-#: shell/evolution-shell-component.c:1203
+#: shell/evolution-shell-component.c:1200
msgid "Unsupported operation"
msgstr ""
-#: shell/evolution-shell-component.c:1205
+#: shell/evolution-shell-component.c:1202
msgid "Internal error"
msgstr "የውስጥ ብልሽት"
-#: shell/evolution-shell-component.c:1209
+#: shell/evolution-shell-component.c:1206
msgid "Exists"
msgstr ""
-#: shell/evolution-shell-component.c:1211
+#: shell/evolution-shell-component.c:1208
msgid "Invalid URI"
msgstr "የማይሰራ URI"
-#: shell/evolution-shell-component.c:1215
+#: shell/evolution-shell-component.c:1212
msgid "Has subfolders"
msgstr ""
-#: shell/evolution-shell-component.c:1217
+#: shell/evolution-shell-component.c:1214
msgid "No space left"
msgstr ""
-#: shell/evolution-shell-component.c:1219
+#: shell/evolution-shell-component.c:1216
msgid "Old owner has died"
msgstr ""
-#: shell/evolution-shell-component-utils.c:124
-#, c-format
-msgid ""
-"%s\n"
-"\n"
-"Unknown error."
-msgstr ""
-"%s\n"
-"\n"
-"ያልታወቀ ስህተት።"
-
-#: shell/evolution-shell-component-utils.c:127
-#, c-format
-msgid ""
-"%s\n"
-"\n"
-"The error from the component system is:\n"
-"%s"
-msgstr ""
-
-#: shell/evolution-shell-component-utils.c:134
-#, c-format
-msgid ""
-"%s\n"
-"\n"
-"The error from the activation system is:\n"
-"%s"
-msgstr ""
-
#: shell/evolution-test-component.c:63
msgid "Test type"
msgstr ""
@@ -25274,22 +25547,6 @@ msgid ""
"Click the \"Apply\" button to save your settings. "
msgstr ""
-#: shell/GNOME_Evolution_Shell.server.in.in.h:1
-msgid "Configure special folders and offline folder behavior here"
-msgstr ""
-
-#: shell/GNOME_Evolution_Shell.server.in.in.h:2
-msgid "Evolution Shell"
-msgstr ""
-
-#: shell/GNOME_Evolution_Shell.server.in.in.h:3
-msgid "Evolution folder settings configuration control"
-msgstr ""
-
-#: shell/GNOME_Evolution_Shell.server.in.in.h:4
-msgid "Folder Settings"
-msgstr ""
-
#: shell/importer/import.glade.h:1
msgid "Click \"Import\" to begin importing the file into Evolution. "
msgstr ""
@@ -25325,10 +25582,6 @@ msgstr ""
msgid "Importers"
msgstr ""
-#: shell/importer/intelligent.c:191
-msgid "Import"
-msgstr "ከውጭ አስገባ"
-
#: shell/importer/intelligent.c:195
msgid "Don't import"
msgstr ""
@@ -25495,7 +25748,7 @@ msgstr ""
msgid "Move to Folder..."
msgstr ""
-#: ui/evolution-addressbook.xml.h:14 ui/evolution-calendar.xml.h:18
+#: ui/evolution-addressbook.xml.h:14 ui/evolution-calendar.xml.h:17
msgid "Paste the clipboard"
msgstr "ክሊፕቦርዱን ለጥፍ"
@@ -25503,9 +25756,9 @@ msgstr "ክሊፕቦርዱን ለጥፍ"
msgid "Previews the contacts to be printed"
msgstr ""
-#: ui/evolution-addressbook.xml.h:17 ui/evolution-calendar.xml.h:20
-#: ui/evolution-comp-editor.xml.h:9 ui/evolution-mail-message.xml.h:73
-#: ui/evolution-tasks.xml.h:13
+#: ui/evolution-addressbook.xml.h:17 ui/evolution-calendar.xml.h:19
+#: ui/evolution-comp-editor.xml.h:9 ui/evolution-mail-message.xml.h:68
+#: ui/evolution-tasks.xml.h:12
msgid "Print Pre_view"
msgstr "የቅድመ ህትመት ዕይታ"
@@ -25549,21 +25802,17 @@ msgstr ""
msgid "View the current contact"
msgstr ""
-#: ui/evolution-addressbook.xml.h:29 ui/evolution-calendar.xml.h:32
-#: ui/evolution-comp-editor.xml.h:16 ui/evolution-contact-editor.xml.h:13
-#: ui/evolution-contact-list-editor.xml.h:11
+#: ui/evolution-addressbook.xml.h:29 ui/evolution-calendar.xml.h:28
+#: ui/evolution-comp-editor.xml.h:17 ui/evolution-contact-editor.xml.h:11
+#: ui/evolution-contact-list-editor.xml.h:10
#: ui/evolution-event-editor.xml.h:11 ui/evolution-mail-global.xml.h:17
-#: ui/evolution-mail-list.xml.h:23 ui/evolution-mail-messagedisplay.xml.h:4
-#: ui/evolution-mail-message.xml.h:99 ui/evolution-task-editor.xml.h:9
-#: ui/evolution-tasks.xml.h:16 ui/evolution.xml.h:42
+#: ui/evolution-mail-list.xml.h:23 ui/evolution-mail-message.xml.h:93
+#: ui/evolution-mail-messagedisplay.xml.h:4 ui/evolution-task-editor.xml.h:9
+#: ui/evolution-tasks.xml.h:14 ui/evolution.xml.h:42
msgid "_Actions"
msgstr "ትግባሮች (_A)"
-#: ui/evolution-addressbook.xml.h:31
-msgid "_Copy to Folder..."
-msgstr ""
-
-#: ui/evolution-addressbook.xml.h:34 ui/evolution-contact-editor.xml.h:16
+#: ui/evolution-addressbook.xml.h:34 ui/evolution-contact-editor.xml.h:13
msgid "_Forward Contact..."
msgstr ""
@@ -25631,59 +25880,46 @@ msgstr ""
msgid "Go to today"
msgstr ""
-#: ui/evolution-calendar.xml.h:17
+#: ui/evolution-calendar.xml.h:16
msgid "Month"
msgstr "ወር"
-#: ui/evolution-calendar.xml.h:19
+#: ui/evolution-calendar.xml.h:18
msgid "Previews the calendar to be printed"
msgstr ""
-#: ui/evolution-calendar.xml.h:21
+#: ui/evolution-calendar.xml.h:20
msgid "Print this calendar"
msgstr ""
-#: ui/evolution-calendar.xml.h:22
+#: ui/evolution-calendar.xml.h:21
msgid "Publish Free/Busy information for this calendar"
msgstr ""
-#: ui/evolution-calendar.xml.h:23 ui/evolution-tasks.xml.h:15
-#, fuzzy
-msgid "Purg_e"
-msgstr "ገጽ"
-
-#: ui/evolution-calendar.xml.h:24
-msgid "Purge old appointments and meetings"
-msgstr ""
-
-#: ui/evolution-calendar.xml.h:25
-msgid "Show as list"
-msgstr ""
-
-#: ui/evolution-calendar.xml.h:26
+#: ui/evolution-calendar.xml.h:22
msgid "Show one day"
msgstr ""
-#: ui/evolution-calendar.xml.h:27
+#: ui/evolution-calendar.xml.h:23
msgid "Show one month"
msgstr ""
-#: ui/evolution-calendar.xml.h:28
+#: ui/evolution-calendar.xml.h:24
msgid "Show one week"
msgstr ""
-#: ui/evolution-calendar.xml.h:29
+#: ui/evolution-calendar.xml.h:25
msgid "Show the working week"
msgstr ""
-#: ui/evolution-calendar.xml.h:30
+#: ui/evolution-calendar.xml.h:26
msgid "Week"
msgstr "ሳመንት"
-#: ui/evolution-comp-editor.xml.h:2 ui/evolution-contact-editor.xml.h:2
-#: ui/evolution-contact-list-editor.xml.h:2
+#: ui/evolution-comp-editor.xml.h:2 ui/evolution-contact-editor.xml.h:1
+#: ui/evolution-contact-list-editor.xml.h:1
#: ui/evolution-mail-messagedisplay.xml.h:1
-#: ui/evolution-message-composer.xml.h:3 ui/evolution-signature-editor.xml.h:2
+#: ui/evolution-message-composer.xml.h:3 ui/evolution-signature-editor.xml.h:1
#: ui/evolution.xml.h:5
msgid "Close"
msgstr "ዝጋ"
@@ -25692,7 +25928,7 @@ msgstr "ዝጋ"
msgid "Close this item"
msgstr ""
-#: ui/evolution-comp-editor.xml.h:5 ui/evolution-contact-editor.xml.h:4
+#: ui/evolution-comp-editor.xml.h:5 ui/evolution-contact-editor.xml.h:3
msgid "Delete this item"
msgstr ""
@@ -25705,58 +25941,48 @@ msgstr "ዋናው ቱልባር"
msgid "Preview the printed item"
msgstr ""
-#: ui/evolution-comp-editor.xml.h:10 ui/evolution-contact-editor.xml.h:7
+#: ui/evolution-comp-editor.xml.h:10 ui/evolution-contact-editor.xml.h:6
msgid "Print this item"
msgstr ""
-#: ui/evolution-comp-editor.xml.h:11 ui/evolution-contact-editor.xml.h:8
-#: ui/evolution-contact-list-editor.xml.h:5
-#: ui/evolution-message-composer.xml.h:18
-msgid "Save _As..."
-msgstr "በሌላ ስም አስቀምጥ... (_A)"
+#: ui/evolution-comp-editor.xml.h:12 ui/evolution-message-composer.xml.h:16
+#: ui/evolution-signature-editor.xml.h:5
+msgid "Save"
+msgstr "አስቀምጥ"
+
+#: ui/evolution-comp-editor.xml.h:13
+msgid "Save As..."
+msgstr "በሌላ ስም አስቀምጥ..."
-#: ui/evolution-comp-editor.xml.h:12 ui/evolution-contact-editor.xml.h:9
+#: ui/evolution-comp-editor.xml.h:14 ui/evolution-contact-editor.xml.h:8
#: ui/evolution-contact-list-editor.xml.h:6
-#: ui/evolution-signature-editor.xml.h:7
+#: ui/evolution-signature-editor.xml.h:6
msgid "Save and Close"
msgstr ""
-#: ui/evolution-comp-editor.xml.h:13 ui/evolution-contact-editor.xml.h:10
-#: ui/evolution-contact-list-editor.xml.h:7
-#: ui/evolution-signature-editor.xml.h:8
-msgid "Save and _Close"
-msgstr ""
-
-#: ui/evolution-comp-editor.xml.h:14
+#: ui/evolution-comp-editor.xml.h:15
msgid "Save the item and close the dialog box"
msgstr ""
-#: ui/evolution-comp-editor.xml.h:15
+#: ui/evolution-comp-editor.xml.h:16
msgid "Save this item to disk"
msgstr ""
-#: ui/evolution-comp-editor.xml.h:18 ui/evolution-contact-editor.xml.h:15
-#: ui/evolution-contact-list-editor.xml.h:13
+#: ui/evolution-comp-editor.xml.h:18 ui/evolution-contact-editor.xml.h:12
+#: ui/evolution-contact-list-editor.xml.h:11
#: ui/evolution-mail-messagedisplay.xml.h:7
#: ui/evolution-message-composer.xml.h:42
-#: ui/evolution-signature-editor.xml.h:13 ui/evolution-subscribe.xml.h:11
+#: ui/evolution-signature-editor.xml.h:12 ui/evolution-subscribe.xml.h:11
#: ui/evolution.xml.h:46
msgid "_File"
msgstr "ፋይል (_F)"
-#: ui/evolution-comp-editor.xml.h:20 ui/evolution-contact-editor.xml.h:18
-#: ui/evolution-contact-list-editor.xml.h:14
-#: ui/evolution-message-composer.xml.h:47
-#: ui/evolution-signature-editor.xml.h:15
-msgid "_Save"
-msgstr "አስቀምጥ"
-
#: ui/evolution-composer-entries.xml.h:1
#, fuzzy
msgid "Copy selected text to the clipboard"
msgstr "ክሊፕቦርዱን ለጥፍ"
-#: ui/evolution-composer-entries.xml.h:2 ui/evolution-mail-message.xml.h:21
+#: ui/evolution-composer-entries.xml.h:2 ui/evolution-mail-list.xml.h:3
msgid "Cu_t"
msgstr "ቁረጥ (_T)"
@@ -25780,39 +26006,51 @@ msgstr "ሁሉንም ምረጡ (_A)"
msgid "Select all text"
msgstr "ሁሉንም ምረጡ"
-#: ui/evolution-contact-editor.xml.h:6
+#: ui/evolution-contact-editor.xml.h:5
msgid "Print En_velope..."
msgstr ""
-#: ui/evolution-contact-editor.xml.h:11
+#: ui/evolution-contact-editor.xml.h:7
+#: ui/evolution-contact-list-editor.xml.h:5
+#: ui/evolution-message-composer.xml.h:18
+msgid "Save _As..."
+msgstr "በሌላ ስም አስቀምጥ... (_A)"
+
+#: ui/evolution-contact-editor.xml.h:9
msgid "Save the contact and close the dialog box"
msgstr ""
-#: ui/evolution-contact-editor.xml.h:12
+#: ui/evolution-contact-editor.xml.h:10
msgid "Send _Message to Contact..."
msgstr ""
-#: ui/evolution-contact-list-editor.xml.h:4
+#: ui/evolution-contact-editor.xml.h:15
+#: ui/evolution-contact-list-editor.xml.h:12
+#: ui/evolution-message-composer.xml.h:47
+#: ui/evolution-signature-editor.xml.h:14
+msgid "_Save"
+msgstr "አስቀምጥ"
+
+#: ui/evolution-contact-list-editor.xml.h:3
msgid "Delete this list"
msgstr ""
-#: ui/evolution-contact-list-editor.xml.h:8
+#: ui/evolution-contact-list-editor.xml.h:4
+msgid "Delete..."
+msgstr "አጥፉ..."
+
+#: ui/evolution-contact-list-editor.xml.h:7
msgid "Save the list and close the dialog box"
msgstr ""
-#: ui/evolution-contact-list-editor.xml.h:9
+#: ui/evolution-contact-list-editor.xml.h:8
msgid "Se_nd list to other..."
msgstr ""
-#: ui/evolution-contact-list-editor.xml.h:10
+#: ui/evolution-contact-list-editor.xml.h:9
msgid "Send _message to list..."
msgstr ""
-#: ui/evolution-contact-list-editor.xml.h:12
-#, fuzzy
-msgid "_Delete..."
-msgstr "አጥፉ..."
-
#: ui/evolution-event-editor.xml.h:1
msgid "Cancel Mee_ting"
msgstr ""
@@ -25886,9 +26124,8 @@ msgid "Permanently remove all deleted messages from all folders"
msgstr ""
#: ui/evolution-mail-global.xml.h:11
-#, fuzzy
-msgid "Post Ne_w Message"
-msgstr "%s - መልዕክት"
+msgid "Post New Message"
+msgstr ""
#: ui/evolution-mail-global.xml.h:12
msgid "Post a message to a Public folder"
@@ -25922,16 +26159,12 @@ msgstr ""
msgid "Change the properties of this folder"
msgstr ""
-#: ui/evolution-mail-list.xml.h:2 ui/evolution-mail-message.xml.h:10
+#: ui/evolution-mail-list.xml.h:2
msgid "Copy selected message(s) to the clipboard"
msgstr ""
-#: ui/evolution-mail-list.xml.h:3 ui/evolution-mail-message.xml.h:22
-msgid "Cut selected message(s) to the clipboard"
-msgstr ""
-
#: ui/evolution-mail-list.xml.h:4
-msgid "E_xpunge"
+msgid "Cut selected message(s) to the clipboard"
msgstr ""
#: ui/evolution-mail-list.xml.h:5
@@ -25952,14 +26185,14 @@ msgid ""
msgstr ""
#: ui/evolution-mail-list.xml.h:9
-msgid "Mark All as _Read"
+msgid "Mark All as R_ead"
msgstr ""
#: ui/evolution-mail-list.xml.h:10
msgid "Mark all visible messages as read"
msgstr ""
-#: ui/evolution-mail-list.xml.h:11 ui/evolution-mail-message.xml.h:66
+#: ui/evolution-mail-list.xml.h:11
msgid "Paste message(s) from the clipboard"
msgstr ""
@@ -26003,37 +26236,26 @@ msgstr ""
msgid "Threaded Message list"
msgstr ""
-#: ui/evolution-mail-list.xml.h:25 ui/evolution.xml.h:47
+#: ui/evolution-mail-list.xml.h:26 ui/evolution-tasks.xml.h:18
+msgid "_Expunge"
+msgstr ""
+
+#: ui/evolution-mail-list.xml.h:27 ui/evolution.xml.h:47
msgid "_Folder"
msgstr "ዶሴ (_F)"
-#: ui/evolution-mail-list.xml.h:26 ui/evolution-subscribe.xml.h:12
+#: ui/evolution-mail-list.xml.h:28 ui/evolution-subscribe.xml.h:12
msgid "_Invert Selection"
msgstr ""
-#: ui/evolution-mail-list.xml.h:27
+#: ui/evolution-mail-list.xml.h:30
msgid "_Properties..."
msgstr "ምርጫዎች"
-#: ui/evolution-mail-list.xml.h:28
+#: ui/evolution-mail-list.xml.h:31
msgid "_Threaded Message List"
msgstr ""
-#: ui/evolution-mail-messagedisplay.xml.h:2 ui/evolution.xml.h:6
-msgid "Close this window"
-msgstr "ይሄንን መስኮት ዝጋ"
-
-#: ui/evolution-mail-messagedisplay.xml.h:5
-#: ui/evolution-message-composer.xml.h:39 ui/evolution-subscribe.xml.h:9
-#: ui/evolution.xml.h:43
-msgid "_Close"
-msgstr "ዝጋ (_C)"
-
-#: ui/evolution-mail-messagedisplay.xml.h:8
-#: ui/evolution-message-composer.xml.h:49 ui/evolution.xml.h:64
-msgid "_View"
-msgstr "ተመልከት (_V)"
-
#: ui/evolution-mail-message.xml.h:1
msgid "A_dd Sender to Addressbook"
msgstr ""
@@ -26051,409 +26273,401 @@ msgid "Apply filter rules to the selected messages"
msgstr ""
#: ui/evolution-mail-message.xml.h:5
-msgid "Caret _Mode"
-msgstr ""
-
-#: ui/evolution-mail-message.xml.h:6
msgid "Compose a reply to all of the recipients of the selected message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:7
+#: ui/evolution-mail-message.xml.h:6
msgid "Compose a reply to the mailing list of the selected message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:8
+#: ui/evolution-mail-message.xml.h:7
msgid "Compose a reply to the sender of the selected message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:11
+#: ui/evolution-mail-message.xml.h:9
msgid "Copy selected messages to another folder"
msgstr ""
-#: ui/evolution-mail-message.xml.h:12
+#: ui/evolution-mail-message.xml.h:10
msgid "Create _Virtual Folder From Message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:13
+#: ui/evolution-mail-message.xml.h:11
msgid "Create a rule to filter messages from this sender"
msgstr ""
-#: ui/evolution-mail-message.xml.h:14
+#: ui/evolution-mail-message.xml.h:12
msgid "Create a rule to filter messages to these recipients"
msgstr ""
-#: ui/evolution-mail-message.xml.h:15
+#: ui/evolution-mail-message.xml.h:13
msgid "Create a rule to filter messages to this mailing list"
msgstr ""
-#: ui/evolution-mail-message.xml.h:16
+#: ui/evolution-mail-message.xml.h:14
msgid "Create a rule to filter messages with this subject"
msgstr ""
-#: ui/evolution-mail-message.xml.h:17
+#: ui/evolution-mail-message.xml.h:15
msgid "Create a virtual folder for these recipients"
msgstr ""
-#: ui/evolution-mail-message.xml.h:18
+#: ui/evolution-mail-message.xml.h:16
msgid "Create a virtual folder for this mailing list"
msgstr ""
-#: ui/evolution-mail-message.xml.h:19
+#: ui/evolution-mail-message.xml.h:17
msgid "Create a virtual folder for this sender"
msgstr ""
-#: ui/evolution-mail-message.xml.h:20
+#: ui/evolution-mail-message.xml.h:18
msgid "Create a virtual folder for this subject"
msgstr ""
-#: ui/evolution-mail-message.xml.h:23
+#: ui/evolution-mail-message.xml.h:19
msgid "Decrease the text size"
msgstr ""
-#: ui/evolution-mail-message.xml.h:25
+#: ui/evolution-mail-message.xml.h:21
msgid "Display the next important message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:26
+#: ui/evolution-mail-message.xml.h:22
msgid "Display the next message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:27
+#: ui/evolution-mail-message.xml.h:23
msgid "Display the next unread message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:28
+#: ui/evolution-mail-message.xml.h:24
msgid "Display the next unread thread"
msgstr ""
-#: ui/evolution-mail-message.xml.h:29
+#: ui/evolution-mail-message.xml.h:25
msgid "Display the previous important message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:30
+#: ui/evolution-mail-message.xml.h:26
msgid "Display the previous message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:31
+#: ui/evolution-mail-message.xml.h:27
msgid "Display the previous unread message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:32
+#: ui/evolution-mail-message.xml.h:28
msgid "F_orward"
msgstr "ወደፊት (_O)"
-#: ui/evolution-mail-message.xml.h:33
+#: ui/evolution-mail-message.xml.h:29
msgid "Filter on Mailing _List..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:34
+#: ui/evolution-mail-message.xml.h:30
msgid "Filter on Se_nder..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:35
+#: ui/evolution-mail-message.xml.h:31
msgid "Filter on _Recipients..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:36
+#: ui/evolution-mail-message.xml.h:32
msgid "Filter on _Subject..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:37
+#: ui/evolution-mail-message.xml.h:33
msgid "Flag selected message(s) for follow-up"
msgstr ""
-#: ui/evolution-mail-message.xml.h:38
+#: ui/evolution-mail-message.xml.h:34
msgid "Follow _Up..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:39
+#: ui/evolution-mail-message.xml.h:35
msgid "Force images in HTML mail to be loaded"
msgstr ""
-#: ui/evolution-mail-message.xml.h:41
+#: ui/evolution-mail-message.xml.h:37
msgid "Forward the selected message in the body of a new message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:42
+#: ui/evolution-mail-message.xml.h:38
msgid "Forward the selected message quoted like a reply"
msgstr ""
-#: ui/evolution-mail-message.xml.h:43
+#: ui/evolution-mail-message.xml.h:39
msgid "Forward the selected message to someone"
msgstr ""
-#: ui/evolution-mail-message.xml.h:44
+#: ui/evolution-mail-message.xml.h:40
msgid "Forward the selected message to someone as an attachment"
msgstr ""
-#: ui/evolution-mail-message.xml.h:45
+#: ui/evolution-mail-message.xml.h:41
msgid "Increase the text size"
msgstr ""
-#: ui/evolution-mail-message.xml.h:46
+#: ui/evolution-mail-message.xml.h:42
msgid "Load _Images"
msgstr ""
-#: ui/evolution-mail-message.xml.h:47
-msgid "Mar_k as Read"
-msgstr ""
-
-#: ui/evolution-mail-message.xml.h:48
+#: ui/evolution-mail-message.xml.h:44
msgid "Mark as I_mportant"
msgstr ""
-#: ui/evolution-mail-message.xml.h:49
+#: ui/evolution-mail-message.xml.h:45
msgid "Mark as U_nread"
msgstr ""
-#: ui/evolution-mail-message.xml.h:50
+#: ui/evolution-mail-message.xml.h:46
msgid "Mark as Unimp_ortant"
msgstr ""
-#: ui/evolution-mail-message.xml.h:51
+#: ui/evolution-mail-message.xml.h:47
msgid "Mark the selected message(s) as having been read"
msgstr ""
-#: ui/evolution-mail-message.xml.h:52
+#: ui/evolution-mail-message.xml.h:48
msgid "Mark the selected message(s) as important"
msgstr ""
-#: ui/evolution-mail-message.xml.h:53
+#: ui/evolution-mail-message.xml.h:49
msgid "Mark the selected message(s) as not having been read"
msgstr ""
-#: ui/evolution-mail-message.xml.h:54
+#: ui/evolution-mail-message.xml.h:50
msgid "Mark the selected message(s) as unimportant"
msgstr ""
-#: ui/evolution-mail-message.xml.h:55
+#: ui/evolution-mail-message.xml.h:51
msgid "Mark the selected messages for deletion"
msgstr ""
-#: ui/evolution-mail-message.xml.h:56
+#: ui/evolution-mail-message.xml.h:52
msgid "Move"
msgstr "መንቀሳቅስ"
-#: ui/evolution-mail-message.xml.h:57
+#: ui/evolution-mail-message.xml.h:53
msgid "Move selected message(s) to another folder"
msgstr ""
-#: ui/evolution-mail-message.xml.h:58
+#: ui/evolution-mail-message.xml.h:54
msgid "Next"
msgstr "የሚቀጥለው"
-#: ui/evolution-mail-message.xml.h:59
+#: ui/evolution-mail-message.xml.h:55
msgid "Next _Important Message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:60
+#: ui/evolution-mail-message.xml.h:56
msgid "Next _Thread"
msgstr ""
-#: ui/evolution-mail-message.xml.h:61
+#: ui/evolution-mail-message.xml.h:57
msgid "Next _Unread Message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:62
+#: ui/evolution-mail-message.xml.h:58
msgid "Open the selected message in a new window"
msgstr ""
-#: ui/evolution-mail-message.xml.h:63
+#: ui/evolution-mail-message.xml.h:59
msgid "Open the selected message in the composer to re-send it"
msgstr ""
-#: ui/evolution-mail-message.xml.h:64
+#: ui/evolution-mail-message.xml.h:60
msgid "Original Si_ze"
msgstr "የመጀመሪያው መጠን (_Z)"
-#: ui/evolution-mail-message.xml.h:65
+#: ui/evolution-mail-message.xml.h:61
msgid "P_revious Unread Message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:67
-msgid "Post a Repl_y"
+#: ui/evolution-mail-message.xml.h:62
+msgid "Post a Reply"
msgstr ""
-#: ui/evolution-mail-message.xml.h:68
+#: ui/evolution-mail-message.xml.h:63
msgid "Post a reply to a message in a Public folder"
msgstr ""
-#: ui/evolution-mail-message.xml.h:69
+#: ui/evolution-mail-message.xml.h:64
msgid "Pr_evious Important Message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:70
+#: ui/evolution-mail-message.xml.h:65
msgid "Preview the message to be printed"
msgstr ""
-#: ui/evolution-mail-message.xml.h:71
+#: ui/evolution-mail-message.xml.h:66
msgid "Previous"
msgstr "የቀድሞው"
-#: ui/evolution-mail-message.xml.h:74
+#: ui/evolution-mail-message.xml.h:69
msgid "Print this message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:75
+#: ui/evolution-mail-message.xml.h:70
msgid "Re_direct"
msgstr ""
-#: ui/evolution-mail-message.xml.h:76
+#: ui/evolution-mail-message.xml.h:71
msgid "Redirect (bounce) the selected message to someone"
msgstr ""
-#: ui/evolution-mail-message.xml.h:79
-msgid "Reply to _All"
-msgstr ""
-
-#: ui/evolution-mail-message.xml.h:80
-msgid "Reply to _List"
-msgstr ""
-
-#: ui/evolution-mail-message.xml.h:81
+#: ui/evolution-mail-message.xml.h:76
msgid "Reset the text to its original size"
msgstr ""
-#: ui/evolution-mail-message.xml.h:82
-msgid "S_earch in Message..."
+#: ui/evolution-mail-message.xml.h:77
+msgid "S_earch Message..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:83
+#: ui/evolution-mail-message.xml.h:78
msgid "S_maller"
msgstr "አነስተኛ (_M)"
-#: ui/evolution-mail-message.xml.h:84
+#: ui/evolution-mail-message.xml.h:79
msgid "Save the message as a text file"
msgstr ""
-#: ui/evolution-mail-message.xml.h:85
+#: ui/evolution-mail-message.xml.h:80
msgid "Search for text in the body of the displayed message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:86
+#: ui/evolution-mail-message.xml.h:81
msgid "Set up the page settings for your current printer"
msgstr ""
-#: ui/evolution-mail-message.xml.h:87
+#: ui/evolution-mail-message.xml.h:82
msgid "Show Email _Source"
msgstr ""
-#: ui/evolution-mail-message.xml.h:88
+#: ui/evolution-mail-message.xml.h:83
msgid "Show Full _Headers"
msgstr ""
-#: ui/evolution-mail-message.xml.h:89
-msgid "Show a blinking cursor in the body of displayed messages"
-msgstr ""
-
-#: ui/evolution-mail-message.xml.h:90
+#: ui/evolution-mail-message.xml.h:84
msgid "Show message in the normal style"
msgstr ""
-#: ui/evolution-mail-message.xml.h:91
+#: ui/evolution-mail-message.xml.h:85
msgid "Show message with all email headers"
msgstr ""
-#: ui/evolution-mail-message.xml.h:92
+#: ui/evolution-mail-message.xml.h:86
msgid "Show the raw email source of the message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:93
+#: ui/evolution-mail-message.xml.h:87
msgid "Text Si_ze"
msgstr ""
-#: ui/evolution-mail-message.xml.h:94
+#: ui/evolution-mail-message.xml.h:88
msgid "Un-delete the selected messages"
msgstr ""
-#: ui/evolution-mail-message.xml.h:95
+#: ui/evolution-mail-message.xml.h:89
msgid "VFolder on Mailing _List..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:96
+#: ui/evolution-mail-message.xml.h:90
msgid "VFolder on Se_nder..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:97
+#: ui/evolution-mail-message.xml.h:91
msgid "VFolder on _Recipients..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:98
+#: ui/evolution-mail-message.xml.h:92
msgid "VFolder on _Subject..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:100
+#: ui/evolution-mail-message.xml.h:94
msgid "_Attached"
msgstr ""
-#: ui/evolution-mail-message.xml.h:102
+#: ui/evolution-mail-message.xml.h:95
msgid "_Copy to Folder"
msgstr ""
-#: ui/evolution-mail-message.xml.h:103
+#: ui/evolution-mail-message.xml.h:96
msgid "_Create Filter From Message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:105
+#: ui/evolution-mail-message.xml.h:98
msgid "_Forward Message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:106
+#: ui/evolution-mail-message.xml.h:99
msgid "_Go To"
msgstr "ሂድ ወደ (_G)"
-#: ui/evolution-mail-message.xml.h:107
+#: ui/evolution-mail-message.xml.h:100
msgid "_Inline"
msgstr ""
-#: ui/evolution-mail-message.xml.h:108
+#: ui/evolution-mail-message.xml.h:101
msgid "_Larger"
msgstr ""
-#: ui/evolution-mail-message.xml.h:109
+#: ui/evolution-mail-message.xml.h:102
msgid "_Message Display"
msgstr ""
-#: ui/evolution-mail-message.xml.h:110
+#: ui/evolution-mail-message.xml.h:103
msgid "_Move to Folder"
msgstr ""
-#: ui/evolution-mail-message.xml.h:111
+#: ui/evolution-mail-message.xml.h:104
msgid "_Next Message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:112
+#: ui/evolution-mail-message.xml.h:105
msgid "_Normal Display"
msgstr ""
-#: ui/evolution-mail-message.xml.h:113
+#: ui/evolution-mail-message.xml.h:106
msgid "_Open Message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:115
+#: ui/evolution-mail-message.xml.h:107
msgid "_Previous Message"
msgstr ""
-#: ui/evolution-mail-message.xml.h:117
+#: ui/evolution-mail-message.xml.h:109
msgid "_Quoted"
msgstr ""
-#: ui/evolution-mail-message.xml.h:118
-msgid "_Reply to Sender"
-msgstr ""
-
-#: ui/evolution-mail-message.xml.h:119
+#: ui/evolution-mail-message.xml.h:111
msgid "_Resend..."
msgstr ""
-#: ui/evolution-mail-message.xml.h:121 ui/evolution.xml.h:63
+#: ui/evolution-mail-message.xml.h:113 ui/evolution.xml.h:63
msgid "_Tools"
msgstr "መሣሪያዎች (_T)"
-#: ui/evolution-mail-message.xml.h:122
+#: ui/evolution-mail-message.xml.h:114
msgid "_Undelete"
msgstr "አታጥፋ (_U)"
+#: ui/evolution-mail-messagedisplay.xml.h:2 ui/evolution.xml.h:6
+msgid "Close this window"
+msgstr "ይሄንን መስኮት ዝጋ"
+
+#: ui/evolution-mail-messagedisplay.xml.h:5
+#: ui/evolution-message-composer.xml.h:39
+#: ui/evolution-signature-editor.xml.h:10 ui/evolution-subscribe.xml.h:9
+#: ui/evolution.xml.h:43
+msgid "_Close"
+msgstr "ዝጋ (_C)"
+
+#: ui/evolution-mail-messagedisplay.xml.h:8
+#: ui/evolution-message-composer.xml.h:49 ui/evolution.xml.h:64
+msgid "_View"
+msgstr "ተመልከት (_V)"
+
#: ui/evolution-message-composer.xml.h:1
msgid "Attach"
msgstr ""
@@ -26462,7 +26676,7 @@ msgstr ""
msgid "Attach a file"
msgstr ""
-#: ui/evolution-message-composer.xml.h:4 ui/evolution-signature-editor.xml.h:3
+#: ui/evolution-message-composer.xml.h:4 ui/evolution-signature-editor.xml.h:2
msgid "Close the current file"
msgstr "የአሁኑን ፋይል ዝጋ"
@@ -26478,7 +26692,7 @@ msgstr ""
msgid "Encrypt this message with your S/MIME Encryption Cetificate"
msgstr ""
-#: ui/evolution-message-composer.xml.h:8 ui/evolution-signature-editor.xml.h:4
+#: ui/evolution-message-composer.xml.h:8 ui/evolution-signature-editor.xml.h:3
msgid "For_mat"
msgstr "ፎርማት (_M)"
@@ -26510,11 +26724,6 @@ msgstr ""
msgid "S/MIME Sign"
msgstr ""
-#: ui/evolution-message-composer.xml.h:16
-#: ui/evolution-signature-editor.xml.h:6
-msgid "Save"
-msgstr "አስቀምጥ"
-
#: ui/evolution-message-composer.xml.h:17
msgid "Save As"
msgstr "በሌላ ስም አስቀምጥ"
@@ -26528,7 +26737,7 @@ msgid "Save in folder..."
msgstr ""
#: ui/evolution-message-composer.xml.h:21
-#: ui/evolution-signature-editor.xml.h:9
+#: ui/evolution-signature-editor.xml.h:7
msgid "Save the current file"
msgstr "የአሁኑን ፋይል አስቀምጥ"
@@ -26545,7 +26754,7 @@ msgid "Send"
msgstr "ላክ"
#: ui/evolution-message-composer.xml.h:25
-#: ui/evolution-signature-editor.xml.h:11
+#: ui/evolution-signature-editor.xml.h:9
msgid "Send the mail in HTML format"
msgstr ""
@@ -26610,7 +26819,7 @@ msgid "_From Field"
msgstr ""
#: ui/evolution-message-composer.xml.h:44
-#: ui/evolution-signature-editor.xml.h:14
+#: ui/evolution-signature-editor.xml.h:13
msgid "_Insert"
msgstr "አስገባ (_I)"
@@ -26626,11 +26835,11 @@ msgstr ""
msgid "_Security"
msgstr "_ደህነት"
-#: ui/evolution-signature-editor.xml.h:5
+#: ui/evolution-signature-editor.xml.h:4
msgid "H_TML"
msgstr "H_TML"
-#: ui/evolution-signature-editor.xml.h:10
+#: ui/evolution-signature-editor.xml.h:8
msgid "Save the current file and close the window"
msgstr ""
@@ -26706,19 +26915,15 @@ msgstr ""
msgid "Mar_k as Complete"
msgstr ""
-#: ui/evolution-tasks.xml.h:9
-msgid "Mark selected tasks as complete"
-msgstr ""
-
-#: ui/evolution-tasks.xml.h:11
+#: ui/evolution-tasks.xml.h:10
msgid "Paste task from the clipboard"
msgstr ""
-#: ui/evolution-tasks.xml.h:12
+#: ui/evolution-tasks.xml.h:11
msgid "Previews the list of tasks to be printed"
msgstr ""
-#: ui/evolution-tasks.xml.h:14
+#: ui/evolution-tasks.xml.h:13
msgid "Print the list of tasks"
msgstr ""
@@ -26968,31 +27173,27 @@ msgid "_Work Week View"
msgstr ""
#: views/mail/galview.xml.h:1
-#, fuzzy
-msgid "As _Sent Folder"
-msgstr "ዶሴ ምረጡ"
+msgid "As Sent Folder"
+msgstr ""
#: views/mail/galview.xml.h:2
-#, fuzzy
-msgid "By S_tatus"
-msgstr "በሁኔታ"
+msgid "By Follow Up Flag"
+msgstr ""
#: views/mail/galview.xml.h:3
-msgid "By Se_nder"
+msgid "By Sender"
msgstr ""
#: views/mail/galview.xml.h:4
-#, fuzzy
-msgid "By Su_bject"
-msgstr "በጉዳዩ"
+msgid "By Status"
+msgstr "በሁኔታ"
#: views/mail/galview.xml.h:5
-msgid "By _Follow Up Flag"
-msgstr ""
+msgid "By Subject"
+msgstr "በጉዳዩ"
#: views/mail/galview.xml.h:6
-#, fuzzy
-msgid "_Messages"
+msgid "Messages"
msgstr "መልዕክቶች"
#: views/tasks/galview.xml.h:1
@@ -27048,20 +27249,20 @@ msgstr ""
#. Translators: These are the first characters of each day of the
#. week, 'M' for 'Monday', 'T' for Tuesday etc.
-#: widgets/misc/e-calendar-item.c:456
+#: widgets/misc/e-calendar-item.c:427
msgid "MTWTFSS"
msgstr "ሳማረሐዓቅእ"
#. This is a strftime() format. %B = Month name, %Y = Year.
-#: widgets/misc/e-calendar-item.c:1174
+#: widgets/misc/e-calendar-item.c:1127
msgid "%B %Y"
msgstr "%B %Y"
-#: widgets/misc/e-cell-date-edit.c:241 widgets/misc/e-dateedit.c:431
+#: widgets/misc/e-cell-date-edit.c:241 widgets/misc/e-dateedit.c:428
msgid "Now"
msgstr "አሁኑኑ"
-#: widgets/misc/e-cell-date-edit.c:249 widgets/misc/e-dateedit.c:437
+#: widgets/misc/e-cell-date-edit.c:249 widgets/misc/e-dateedit.c:434
msgid "Today"
msgstr "ዛሬ"
@@ -27178,6 +27379,22 @@ msgstr ""
msgid "_Advanced..."
msgstr "ጠለቅ... (_A)"
+#: widgets/misc/e-messagebox.c:154
+msgid "Information"
+msgstr "መረጃ"
+
+#: widgets/misc/e-messagebox.c:168
+msgid "Error"
+msgstr "ስህተት"
+
+#: widgets/misc/e-messagebox.c:175
+msgid "Question"
+msgstr "ጥያቄ"
+
+#: widgets/misc/e-messagebox.c:182
+msgid "Message"
+msgstr "መልዕክት"
+
#: widgets/misc/e-search-bar.c:531
msgid "_Search"
msgstr "ፈልግ"
@@ -27223,98 +27440,6 @@ msgstr ""
msgid "Evolution Addressbook local file backend"
msgstr ""
-#~ msgid "Group"
-#~ msgstr "የውይይት መድረክ"
-
-#~ msgid "%d new"
-#~ msgstr "%d አዲስ"
-
-#~ msgid ", "
-#~ msgstr "፣ "
-
-#~ msgid "%d hidden"
-#~ msgstr "%d የተደበቀ"
-
-#~ msgid "%d visible"
-#~ msgstr "%d የሚታይ"
-
-#~ msgid "%d selected"
-#~ msgstr "%d ተመርጠዋል"
-
-#~ msgid "%d sent"
-#~ msgstr "%d ተልኳል"
-
-#~ msgid "%d total"
-#~ msgstr "%d አጠቃላይ"
-
-#~ msgid "_Print"
-#~ msgstr "አትም"
-
-#~ msgid "_Forward"
-#~ msgstr "ወደፊት፦"
-
-#~ msgid "U_ndelete"
-#~ msgstr "አታጥፋ"
-
-#~ msgid "Properties for \"%s\""
-#~ msgstr "ለ \"%s\"ን ምርጫዎች"
-
-#~ msgid "Properties"
-#~ msgstr "ምርጫዎች"
-
-#~ msgid "Filters"
-#~ msgstr "አጣራዎች"
-
-#, fuzzy
-#~ msgid "Save all attachments..."
-#~ msgstr "ምስሉን በሌላ ስም አስቀምጥ"
-
-#~ msgid "Hide"
-#~ msgstr "ደብቅ"
-
-#, fuzzy
-#~ msgid "by %B %d, %Y, %l:%M %p"
-#~ msgstr "%b %d %l:%M %p"
-
-#~ msgid "Copy Link Location"
-#~ msgstr "አያያዝ ቦታ ቅጂ"
-
-#~ msgid "Save Image as..."
-#~ msgstr "ምስሉን በሌላ ስም አስቀምጥ"
-
-#~ msgid "Cc"
-#~ msgstr "Cc"
-
-#~ msgid "Bcc"
-#~ msgstr "Bcc"
-
-#~ msgid "Find:"
-#~ msgstr "ፈልግ"
-
-#~ msgid "%s - Message"
-#~ msgstr "%s - መልዕክት"
-
-#~ msgid "URL:"
-#~ msgstr "url"
-
-#~ msgid "_Save as..."
-#~ msgstr "በሌላ ስም አስቀምጥ"
-
-#~ msgid "Print..."
-#~ msgstr "አትም"
-
-#~ msgid "Save As..."
-#~ msgstr "በሌላ ስም አስቀምጥ..."
-
-#~ msgid "Information"
-#~ msgstr "መረጃ"
-
-#~ msgid "Question"
-#~ msgstr "ጥያቄ"
-
-#~ msgid "Message"
-#~ msgstr "መልዕክት"
-
#~ msgid "Search"
#~ msgstr "&ፈልግ"
diff --git a/po/az.po b/po/az.po
index e97597558a..8676f7589b 100644
--- a/po/az.po
+++ b/po/az.po
@@ -5,210 +5,59 @@
msgid ""
msgstr ""
"Project-Id-Version: evolution 0.99.2\n"
-"POT-Creation-Date: 2003-10-15 23:45+0200\n"
+"POT-Creation-Date: 2003-06-25 13:24-0400\n"
"PO-Revision-Date: 2001-12-19 19:21GMT+0200\n"
"Last-Translator: Vasif İsmayıloğlu MD <azerb_linux@hotmail.com>\n"
"Language-Team: Azerbaijani Turkic <linuxaz@azerimail.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Report-Msgid-Bugs-To: \n"
"X-Generator: KBabel 0.9.5\n"
-#: addressbook/backend/ebook/e-card.c:1306
+#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in.h:1
+#, fuzzy
+msgid "Evolution LDIF importer"
+msgstr "Evolution İdxalçı Yardımçısı"
+
+#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in.h:2
+msgid "LDAP Data Interchange Format (.ldif)"
+msgstr ""
+
+#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in.h:1
+#, fuzzy
+msgid "Evolution VCard Importer"
+msgstr "Evolutionun ePoçt yazıçısı."
+
+#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in.h:2
+#, fuzzy
+msgid "Evolution VCard importer"
+msgstr "Evolutionun ePoçt yazıçısı."
+
+#: addressbook/backend/ebook/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in.h:3
+msgid "VCard (.vcf, .gcrd)"
+msgstr ""
+
#: addressbook/backend/ebook/e-card-simple.c:60
+#: addressbook/backend/ebook/e-card.c:1306
#: addressbook/gui/widgets/e-addressbook-view.etspec.h:15
msgid "File As"
msgstr "Fərqli Qeyd Et"
-#: addressbook/backend/ebook/e-card.c:1313
-#: addressbook/gui/contact-editor/fullname.glade.h:4
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:17
-msgid "Full Name"
-msgstr "Tam Ad"
-
-#: addressbook/backend/ebook/e-card.c:1320
#: addressbook/backend/ebook/e-card-simple.c:61
-#: addressbook/gui/component/select-names/e-select-names.etspec.h:1
+#: addressbook/backend/ebook/e-card.c:1320
#: addressbook/gui/component/select-names/e-select-names-section.etspec.h:1
+#: addressbook/gui/component/select-names/e-select-names.etspec.h:1
#: addressbook/gui/contact-editor/e-contact-editor-fullname.c:89
#: my-evolution/e-summary-table.c:59
msgid "Name"
msgstr "Ad"
-#: addressbook/backend/ebook/e-card.c:1326
-#: addressbook/gui/contact-editor/e-contact-editor-address.c:96
-#, fuzzy
-msgid "Address"
-msgstr "_Ünvan :"
-
-#: addressbook/backend/ebook/e-card.c:1333
-#, fuzzy
-msgid "Address Label"
-msgstr "Ünvan Kartları"
-
-#: addressbook/backend/ebook/e-card.c:1340
-#, fuzzy
-msgid "Phone"
-msgstr "Yoxdur"
-
-#: addressbook/backend/ebook/e-card.c:1347
#: addressbook/backend/ebook/e-card-simple.c:62
+#: addressbook/backend/ebook/e-card.c:1347
#: addressbook/gui/widgets/e-addressbook-view.etspec.h:12
msgid "Email"
msgstr "ePoçt"
-#: addressbook/backend/ebook/e-card.c:1354
-#, fuzzy
-msgid "Birth date"
-msgstr "Ad Günü"
-
-#: addressbook/backend/ebook/e-card.c:1360
-#: calendar/gui/e-calendar-table.etspec.h:18
-msgid "URL"
-msgstr "URL"
-
-#: addressbook/backend/ebook/e-card.c:1367
-#: addressbook/backend/ebook/e-card-simple.c:69
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:28
-msgid "Organization"
-msgstr "Quruluş"
-
-#: addressbook/backend/ebook/e-card.c:1374
-#, fuzzy
-msgid "Organizational Unit"
-msgstr "Quruluş"
-
-#: addressbook/backend/ebook/e-card.c:1381
-#: addressbook/backend/ebook/e-card-simple.c:90
-#: addressbook/gui/widgets/e-addressbook-view.etspec.h:27
-msgid "Office"