diff --git a/cmake/modules/FindIntltool.cmake b/cmake/modules/FindIntltool.cmake index 8e223e9..2cda254 100644 --- a/cmake/modules/FindIntltool.cmake +++ b/cmake/modules/FindIntltool.cmake @@ -176,18 +176,9 @@ macro(intltool_merge _in_filename _out_filename) DEPENDS ${_in} ) else(_has_no_translations) - if(NOT TARGET intltool-merge-cache) - add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/po/.intltool-merge-cache - COMMAND ${INTLTOOL_MERGE} ${_args} --quiet --cache="${CMAKE_BINARY_DIR}/po/.intltool-merge-cache" "${GETTEXT_PO_DIR}" "${_in}" "${_out}" - DEPENDS ${_in} - ) - add_custom_target(intltool-merge-cache ALL - DEPENDS ${CMAKE_BINARY_DIR}/po/.intltool-merge-cache) - endif(NOT TARGET intltool-merge-cache) - add_custom_command(OUTPUT ${_out} COMMAND ${INTLTOOL_MERGE} ${_args} --quiet --cache="${CMAKE_BINARY_DIR}/po/.intltool-merge-cache" "${GETTEXT_PO_DIR}" "${_in}" "${_out}" - DEPENDS ${_in} intltool-merge-cache + DEPENDS ${_in} ) endif(_has_no_translations) endmacro(intltool_merge) diff --git a/cmake/modules/FindIntltool.cmake.intltool-cache b/cmake/modules/FindIntltool.cmake.intltool-cache deleted file mode 100644 index 2cda254..0000000 --- a/cmake/modules/FindIntltool.cmake.intltool-cache +++ /dev/null @@ -1,209 +0,0 @@ -# FindIntltool.cmake -# -# Searches for intltool and gettext. It aborts, if anything cannot be found. -# Requires GETTEXT_PO_DIR to be set to full path of the po/ directory. -# -# Output is: -# INTLTOOL_UPDATE - an intltool-update executable path, as found -# INTLTOOL_EXTRACT - an intltool-extract executable path, as found -# INTLTOOL_MERGE - an intltool-merge executable path, as found -# -# and anything from the FindGettext module. -# -# The below provided macros require GETTEXT_PACKAGE to be set. -# -# intltool_add_check_potfiles_target() -# Adds a check-potfiles target, which verifies that all files with translations -# are added in the POTFILES.in file inside GETTEXT_PO_DIR. This macro can be called -# only inside GETTEXT_PO_DIR. -# -# intltool_add_pot_file_target() -# Creates a new target pot-file, which generates ${GETTEXT_PACKAGE}.pot file into -# the CMAKE_CURERNT_BINARY_DIR. This target is not part of ALL. -# This can be called only inside GETTEXT_PO_DIR. -# -# intltool_process_po_files() -# Processes all files in the GETTEXT_PO_DIR and generates .gmo files for them -# in CMAKE_CURRENT_BINARY_DIR. These are added into a new target gmo-files. -# It also installs them into proper location under LOCALE_INSTALL_DIR. -# This can be called only inside GETTEXT_PO_DIR. -# -# intltool_setup_po_dir() -# Shortcut to setup intltool's po/ directory by adding all custom targets -# and such. this can be called only inside GETTEXT_PO_DIR. -# -# intltool_merge(_in_filename _out_filename ...args) -# Adds rule to call intltool-merge. The args are optional arguments. -# This can be called in any folder, only the GETTEXT_PO_DIR should -# be properly set, otherwise the call will fail. -# -# add_appdata_file(_infilename _outfilename) -# A shortcut to call intltool-merge() for an appdata file and install it -# to ${SHARE_INSTALL_PREFIX}/metainfo - -include(FindGettext) - -if(NOT GETTEXT_FOUND) - message(FATAL_ERROR "gettext not found, please install at least 0.18.3 version") -endif(NOT GETTEXT_FOUND) - -if(NOT GETTEXT_FOUND) - message(FATAL_ERROR "gettext not found, please install at least 0.18.3 version") -endif(NOT GETTEXT_FOUND) - -if(GETTEXT_VERSION_STRING VERSION_LESS "0.18.3") - message(FATAL_ERROR "gettext version 0.18.3+ required, but version '${GETTEXT_VERSION_STRING}' found instead. Please update your gettext") -endif(GETTEXT_VERSION_STRING VERSION_LESS "0.18.3") - -find_program(XGETTEXT xgettext) -if(NOT XGETTEXT) - message(FATAL_ERROR "xgettext executable not found. Please install or update your gettext to at least 0.18.3 version") -endif(NOT XGETTEXT) - -find_program(INTLTOOL_UPDATE intltool-update) -if(NOT INTLTOOL_UPDATE) - message(FATAL_ERROR "intltool-update not found. Please install it (usually part of an 'intltool' package)") -endif(NOT INTLTOOL_UPDATE) - -find_program(INTLTOOL_EXTRACT intltool-extract) -if(NOT INTLTOOL_EXTRACT) - message(FATAL_ERROR "intltool-extract not found. Please install it (usually part of an 'intltool' package)") -endif(NOT INTLTOOL_EXTRACT) - -find_program(INTLTOOL_MERGE intltool-merge) -if(NOT INTLTOOL_MERGE) - message(FATAL_ERROR "intltool-merge not found. Please install it (usually part of an 'intltool' package)") -endif(NOT INTLTOOL_MERGE) - -macro(intltool_add_check_potfiles_target) - if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL GETTEXT_PO_DIR) - message(FATAL_ERROR "intltool_add_pot_file_target() can be called only inside GETTEXT_PO_DIR ('${GETTEXT_PO_DIR}'), but it is called inside '${CMAKE_CURRENT_SOURCE_DIR}' instead") - endif(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL GETTEXT_PO_DIR) - - add_custom_target(check-potfiles - COMMAND ${INTLTOOL_UPDATE} -m - WORKING_DIRECTORY ${GETTEXT_PO_DIR} - ) -endmacro(intltool_add_check_potfiles_target) - -macro(intltool_add_pot_file_target) - if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL GETTEXT_PO_DIR) - message(FATAL_ERROR "intltool_add_pot_file_target() can be called only inside GETTEXT_PO_DIR ('${GETTEXT_PO_DIR}'), but it is called inside '${CMAKE_CURRENT_SOURCE_DIR}' instead") - endif(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL GETTEXT_PO_DIR) - - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${GETTEXT_PACKAGE}.pot - COMMAND ${CMAKE_COMMAND} -E env INTLTOOL_EXTRACT="${INTLTOOL_EXTRACT}" XGETTEXT="${XGETTEXT}" srcdir=${CMAKE_CURRENT_SOURCE_DIR} ${INTLTOOL_UPDATE} --gettext-package ${GETTEXT_PACKAGE} --pot - ) - - add_custom_target(pot-file - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${GETTEXT_PACKAGE}.pot - ) -endmacro(intltool_add_pot_file_target) - -macro(intltool_process_po_files) - if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL GETTEXT_PO_DIR) - message(FATAL_ERROR "intltool_process_po_files() can be called only inside GETTEXT_PO_DIR ('${GETTEXT_PO_DIR}'), but it is called inside '${CMAKE_CURRENT_SOURCE_DIR}' instead") - endif(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL GETTEXT_PO_DIR) - - file(GLOB po_files ${GETTEXT_PO_DIR}/*.po) - - set(LINGUAS) - set(LINGUAS_GMO) - - foreach(file IN LISTS po_files) - get_filename_component(lang ${file} NAME_WE) - list(APPEND LINGUAS ${lang}) - list(APPEND LINGUAS_GMO ${lang}.gmo) - - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${lang}.gmo - COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${CMAKE_CURRENT_BINARY_DIR}/${lang}.gmo ${CMAKE_CURRENT_SOURCE_DIR}/${lang}.po - DEPENDS ${lang}.po - ) - - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${lang}.gmo - DESTINATION ${LOCALE_INSTALL_DIR}/${lang}/LC_MESSAGES/ - RENAME ${GETTEXT_PACKAGE}.mo - ) - if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${lang}.gmo.m) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${lang}.gmo.m - DESTINATION ${LOCALE_INSTALL_DIR}/${lang}/LC_MESSAGES/ - RENAME ${GETTEXT_PACKAGE}.mo.m - ) - endif(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${lang}.gmo.m) - endforeach(file) - - add_custom_target(gmo-files ALL - DEPENDS ${LINGUAS_GMO} - ) -endmacro(intltool_process_po_files) - -macro(intltool_setup_po_dir) - if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL GETTEXT_PO_DIR) - message(FATAL_ERROR "intltool_setup_po_dir() can be called only inside GETTEXT_PO_DIR ('${GETTEXT_PO_DIR}'), but it is called inside '${CMAKE_CURRENT_SOURCE_DIR}' instead") - endif(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL GETTEXT_PO_DIR) - - intltool_add_check_potfiles_target() - intltool_add_pot_file_target() - intltool_process_po_files() -endmacro(intltool_setup_po_dir) - -macro(intltool_merge _in_filename _out_filename) - set(_in ${_in_filename}) - set(_out ${_out_filename}) - - get_filename_component(_path ${_in} DIRECTORY) - if(_path STREQUAL "") - set(_in ${CMAKE_CURRENT_SOURCE_DIR}/${_in}) - endif(_path STREQUAL "") - - get_filename_component(_path ${_out} DIRECTORY) - if(_path STREQUAL "") - set(_out ${CMAKE_CURRENT_BINARY_DIR}/${_out}) - endif(_path STREQUAL "") - - set(_has_no_translations OFF) - set(_args) - foreach(_arg ${ARGN}) - list(APPEND _args "${_arg}") - if(_arg STREQUAL "--no-translations") - set(_has_no_translations ON) - endif(_arg STREQUAL "--no-translations") - endforeach(_arg) - - if(_has_no_translations) - add_custom_command(OUTPUT ${_out} - COMMAND ${INTLTOOL_MERGE} ${_args} --quiet "${_in}" "${_out}" - DEPENDS ${_in} - ) - else(_has_no_translations) - add_custom_command(OUTPUT ${_out} - COMMAND ${INTLTOOL_MERGE} ${_args} --quiet --cache="${CMAKE_BINARY_DIR}/po/.intltool-merge-cache" "${GETTEXT_PO_DIR}" "${_in}" "${_out}" - DEPENDS ${_in} - ) - endif(_has_no_translations) -endmacro(intltool_merge) - -macro(add_appdata_file _infilename _outfilename) - if(NOT TARGET appdata-files) - add_custom_target(appdata-files ALL) - endif(NOT TARGET appdata-files) - - set(_out ${_outfilename}) - get_filename_component(_outtarget ${_out} NAME) - get_filename_component(_path ${_out} DIRECTORY) - if(_path STREQUAL "") - set(_out ${CMAKE_CURRENT_BINARY_DIR}/${_out}) - endif(_path STREQUAL "") - - intltool_merge(${_infilename} ${_out} --xml-style --utf8) - - add_custom_target(appdata-${_outtarget} - DEPENDS ${_out} - ) - - add_dependencies(appdata-files appdata-${_outtarget}) - - install(FILES ${_out} - DESTINATION ${SHARE_INSTALL_PREFIX}/metainfo - ) -endmacro(add_appdata_file) diff --git a/src/calendar/gui/e-comp-editor.c b/src/calendar/gui/e-comp-editor.c index 0f00f58..4c01d1d 100644 --- a/src/calendar/gui/e-comp-editor.c +++ b/src/calendar/gui/e-comp-editor.c @@ -2610,7 +2610,6 @@ e_comp_editor_fill_component (ECompEditor *comp_editor, icalcomponent *component) { ECompEditorClass *comp_editor_class; - GtkWidget *focused_widget; gboolean is_valid; g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); @@ -2620,30 +2619,8 @@ e_comp_editor_fill_component (ECompEditor *comp_editor, g_return_val_if_fail (comp_editor_class != NULL, FALSE); g_return_val_if_fail (comp_editor_class->fill_component != NULL, FALSE); - focused_widget = gtk_window_get_focus (GTK_WINDOW (comp_editor)); - if (focused_widget) { - GtkWidget *parent, *ce_widget = GTK_WIDGET (comp_editor); - - /* When a cell-renderer is focused and editing the cell content, - then unfocus it may mean to free the currently focused widget, - thus get the GtkTreeView in such cases. */ - parent = focused_widget; - while (parent = gtk_widget_get_parent (parent), parent && parent != ce_widget) { - if (GTK_IS_TREE_VIEW (parent)) { - focused_widget = parent; - break; - } - } - - /* Save any pending changes */ - gtk_window_set_focus (GTK_WINDOW (comp_editor), NULL); - } - is_valid = comp_editor_class->fill_component (comp_editor, component); - if (focused_widget) - gtk_window_set_focus (GTK_WINDOW (comp_editor), focused_widget); - if (is_valid && comp_editor->priv->validation_alert) { e_alert_response (comp_editor->priv->validation_alert, GTK_RESPONSE_CLOSE); g_clear_object (&comp_editor->priv->validation_alert); diff --git a/src/calendar/gui/e-comp-editor.c.crash-empty-attendee b/src/calendar/gui/e-comp-editor.c.crash-empty-attendee deleted file mode 100644 index 4c01d1d..0000000 --- a/src/calendar/gui/e-comp-editor.c.crash-empty-attendee +++ /dev/null @@ -1,3428 +0,0 @@ -/* - * Copyright (C) 2015 Red Hat, Inc. (www.redhat.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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#include "evolution-config.h" - -#include -#include - -#include -#include -#include - -#include "calendar-config.h" -#include "comp-util.h" -#include "e-cal-dialogs.h" -#include "itip-utils.h" -#include "print.h" - -#include "e-comp-editor-page-general.h" -#include "e-comp-editor-page-attachments.h" -#include "e-comp-editor-event.h" -#include "e-comp-editor-memo.h" -#include "e-comp-editor-task.h" - -#include "e-comp-editor.h" - -struct _ECompEditorPrivate { - EAlertBar *alert_bar; /* not referenced */ - EActivityBar *activity_bar; /* not referenced */ - GtkNotebook *content; /* not referenced */ - - EAlert *validation_alert; - - EShell *shell; - GSettings *calendar_settings; - ESource *origin_source; - icalcomponent *component; - guint32 flags; - - EFocusTracker *focus_tracker; - GtkUIManager *ui_manager; - - GSList *pages; /* ECompEditorPage * */ - gulong show_attendees_handler_id; - - ECompEditorPageGeneral *page_general; /* special page, can be added only once; not referenced */ - - EActivity *target_client_opening; - - ECalClient *source_client; - ECalClient *target_client; - gchar *cal_email_address; - gchar *alarm_email_address; - gboolean changed; - guint updating; - gchar *title_suffix; - - ECompEditorPropertyPart *dtstart_part; - ECompEditorPropertyPart *dtend_part; - - GtkWidget *restore_focus; -}; - -enum { - PROP_0, - PROP_ALARM_EMAIL_ADDRESS, - PROP_CAL_EMAIL_ADDRESS, - PROP_CHANGED, - PROP_COMPONENT, - PROP_FLAGS, - PROP_ORIGIN_SOURCE, - PROP_SHELL, - PROP_SOURCE_CLIENT, - PROP_TARGET_CLIENT, - PROP_TITLE_SUFFIX -}; - -enum { - TIMES_CHANGED, - OBJECT_CREATED, - EDITOR_CLOSED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -static GSList *opened_editors = NULL; - -static void e_comp_editor_alert_sink_iface_init (EAlertSinkInterface *iface); - -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ECompEditor, e_comp_editor, GTK_TYPE_WINDOW, - G_IMPLEMENT_INTERFACE (E_TYPE_ALERT_SINK, e_comp_editor_alert_sink_iface_init) - G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL)) - -static void -ece_restore_focus (ECompEditor *comp_editor) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (comp_editor->priv->restore_focus) { - gtk_widget_grab_focus (comp_editor->priv->restore_focus); - - if (GTK_IS_ENTRY (comp_editor->priv->restore_focus)) - gtk_editable_set_position (GTK_EDITABLE (comp_editor->priv->restore_focus), 0); - - comp_editor->priv->restore_focus = NULL; - } -} - -static void -e_comp_editor_enable (ECompEditor *comp_editor, - gboolean enable) -{ - GtkActionGroup *group; - GtkWidget *current_focus; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - current_focus = gtk_window_get_focus (GTK_WINDOW (comp_editor)); - - gtk_widget_set_sensitive (GTK_WIDGET (comp_editor->priv->content), enable); - - group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_set_sensitive (group, enable); - - group = e_comp_editor_get_action_group (comp_editor, "core"); - gtk_action_group_set_sensitive (group, enable); - - group = e_comp_editor_get_action_group (comp_editor, "editable"); - gtk_action_group_set_sensitive (group, enable); - - if (enable) { - e_comp_editor_sensitize_widgets (comp_editor); - ece_restore_focus (comp_editor); - } else { - comp_editor->priv->restore_focus = current_focus; - } -} - -static void -ece_set_attendees_for_delegation (ECalComponent *comp, - const gchar *address) -{ - icalproperty *prop; - icalparameter *param; - icalcomponent *icalcomp; - gboolean again; - - icalcomp = e_cal_component_get_icalcomponent (comp); - - for (prop = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY); - prop; - prop = again ? icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY) : - icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY)) { - const gchar *attendee = icalproperty_get_attendee (prop); - const gchar *delfrom = NULL; - - again = FALSE; - param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDFROM_PARAMETER); - if (param) - delfrom = icalparameter_get_delegatedfrom (param); - if (!(g_str_equal (itip_strip_mailto (attendee), address) || - ((delfrom && *delfrom) && g_str_equal (itip_strip_mailto (delfrom), address)))) { - icalcomponent_remove_property (icalcomp, prop); - icalproperty_free (prop); - again = TRUE; - } - - } -} - -/* Utility function to get the mime-attachment list from the attachment - * bar for sending the comp via itip. The list and its contents must - * be freed by the caller. - */ -static GSList * -ece_get_mime_attach_list (ECompEditor *comp_editor) -{ - ECompEditorPage *page_attachments; - EAttachmentStore *store; - GtkTreeModel *model; - GtkTreeIter iter; - struct CalMimeAttach *cal_mime_attach; - GSList *attach_list = NULL; - gboolean valid; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - page_attachments = e_comp_editor_get_page (comp_editor, E_TYPE_COMP_EDITOR_PAGE_ATTACHMENTS); - if (!page_attachments) - return NULL; - - store = e_comp_editor_page_attachments_get_store (E_COMP_EDITOR_PAGE_ATTACHMENTS (page_attachments)); - if (!store) - return NULL; - - model = GTK_TREE_MODEL (store); - valid = gtk_tree_model_get_iter_first (model, &iter); - - while (valid) { - EAttachment *attachment; - CamelDataWrapper *wrapper; - CamelMimePart *mime_part; - CamelStream *stream; - GByteArray *byte_array; - guchar *buffer = NULL; - const gchar *description; - const gchar *disposition; - gint column_id; - - column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT; - gtk_tree_model_get (model, &iter, column_id, &attachment, -1); - mime_part = e_attachment_ref_mime_part (attachment); - g_object_unref (attachment); - - valid = gtk_tree_model_iter_next (model, &iter); - - if (mime_part == NULL) - continue; - - cal_mime_attach = g_malloc0 (sizeof (struct CalMimeAttach)); - wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); - - byte_array = g_byte_array_new (); - stream = camel_stream_mem_new_with_byte_array (byte_array); - - camel_data_wrapper_decode_to_stream_sync ( - wrapper, stream, NULL, NULL); - buffer = g_memdup (byte_array->data, byte_array->len); - - camel_mime_part_set_content_id (mime_part, NULL); - - cal_mime_attach->encoded_data = (gchar *) buffer; - cal_mime_attach->length = byte_array->len; - cal_mime_attach->filename = - g_strdup (camel_mime_part_get_filename (mime_part)); - description = camel_mime_part_get_description (mime_part); - if (description == NULL || *description == '\0') - description = _("attachment"); - cal_mime_attach->description = g_strdup (description); - cal_mime_attach->content_type = camel_data_wrapper_get_mime_type (wrapper); - cal_mime_attach->content_id = g_strdup ( - camel_mime_part_get_content_id (mime_part)); - - disposition = camel_mime_part_get_disposition (mime_part); - cal_mime_attach->disposition = - (disposition != NULL) && - (g_ascii_strcasecmp (disposition, "inline") == 0); - - attach_list = g_slist_append (attach_list, cal_mime_attach); - - g_object_unref (mime_part); - g_object_unref (stream); - - } - - return attach_list; -} - -static void -e_comp_editor_set_component (ECompEditor *comp_editor, - const icalcomponent *component) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (component != NULL); - - if (comp_editor->priv->component) - icalcomponent_free (comp_editor->priv->component); - comp_editor->priv->component = icalcomponent_new_clone ((icalcomponent *) component); - - g_warn_if_fail (comp_editor->priv->component != NULL); -} - -typedef struct _SaveData { - ECompEditor *comp_editor; - ECalClient *source_client; - ECalClient *target_client; - icalcomponent *component; - gboolean with_send; - gboolean close_after_save; - ECalObjModType recur_mod; - gboolean success; - GError *error; - gchar *alert_ident; - gchar *alert_arg_0; - - gboolean object_created; - ECalComponentItipMethod first_send; - ECalComponentItipMethod second_send; - ECalComponent *send_comp; - EActivity *send_activity; - gboolean strip_alarms; - gboolean only_new_attendees; - GSList *mime_attach_list; -} SaveData; - -static void -save_data_free (SaveData *sd) -{ - if (sd) { - e_comp_editor_enable (sd->comp_editor, TRUE); - - if (sd->success) { - if (sd->close_after_save) { - g_signal_emit (sd->comp_editor, signals[EDITOR_CLOSED], 0, TRUE, NULL); - gtk_widget_destroy (GTK_WIDGET (sd->comp_editor)); - } else { - e_comp_editor_set_component (sd->comp_editor, sd->component); - - e_comp_editor_fill_widgets (sd->comp_editor, sd->component); - - g_clear_object (&sd->comp_editor->priv->source_client); - sd->comp_editor->priv->source_client = g_object_ref (sd->target_client); - - sd->comp_editor->priv->flags = sd->comp_editor->priv->flags & (~E_COMP_EDITOR_FLAG_IS_NEW); - - e_comp_editor_sensitize_widgets (sd->comp_editor); - e_comp_editor_set_changed (sd->comp_editor, FALSE); - } - } else if (sd->alert_ident) { - e_alert_submit ( - E_ALERT_SINK (sd->comp_editor), sd->alert_ident, sd->alert_arg_0, - sd->error ? sd->error->message : _("Unknown error"), NULL); - } - - if (sd->send_activity && e_activity_get_state (sd->send_activity) != E_ACTIVITY_CANCELLED) - e_activity_set_state (sd->send_activity, E_ACTIVITY_COMPLETED); - - g_clear_object (&sd->comp_editor); - g_clear_object (&sd->source_client); - g_clear_object (&sd->target_client); - g_clear_object (&sd->send_comp); - g_clear_object (&sd->send_activity); - g_clear_error (&sd->error); - if (sd->component) - icalcomponent_free (sd->component); - g_slist_free_full (sd->mime_attach_list, itip_cal_mime_attach_free); - g_free (sd->alert_ident); - g_free (sd->alert_arg_0); - g_free (sd); - } -} - -static gboolean -ece_send_process_method (SaveData *sd, - ECalComponentItipMethod send_method, - ECalComponent *send_comp, - ESourceRegistry *registry, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSList *mime_attach_list = NULL; - - g_return_val_if_fail (sd != NULL, FALSE); - g_return_val_if_fail (E_IS_CAL_COMPONENT (send_comp), FALSE); - g_return_val_if_fail (send_method != E_CAL_COMPONENT_METHOD_NONE, FALSE); - - if (e_cal_component_has_attachments (send_comp) && - e_client_check_capability (E_CLIENT (sd->target_client), CAL_STATIC_CAPABILITY_CREATE_MESSAGES)) { - /* Clone the component with attachments set to CID:... */ - GSList *attach_list = NULL; - GSList *attach; - - /* mime_attach_list is freed by itip_send_component() */ - mime_attach_list = sd->mime_attach_list; - sd->mime_attach_list = NULL; - - for (attach = mime_attach_list; attach; attach = attach->next) { - struct CalMimeAttach *cma = (struct CalMimeAttach *) attach->data; - - attach_list = g_slist_append ( - attach_list, g_strconcat ( - "cid:", cma->content_id, NULL)); - } - - if (attach_list) { - e_cal_component_set_attachment_list (send_comp, attach_list); - - g_slist_free_full (attach_list, g_free); - } - } - - itip_send_component ( - registry, send_method, send_comp, sd->target_client, - NULL, mime_attach_list, NULL, sd->strip_alarms, - sd->only_new_attendees, FALSE, - cancellable, callback, user_data); - - return TRUE; -} - -static void -ecep_second_send_processed_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - SaveData *sd = user_data; - - g_return_if_fail (sd != NULL); - - sd->success = itip_send_component_finish (result, &sd->error); - - save_data_free (sd); -} - -static void -ecep_first_send_processed_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - SaveData *sd = user_data; - - g_return_if_fail (sd != NULL); - - sd->success = itip_send_component_finish (result, &sd->error); - if (!sd->success || sd->second_send == E_CAL_COMPONENT_METHOD_NONE) { - save_data_free (sd); - } else { - sd->success = ece_send_process_method (sd, sd->second_send, sd->send_comp, - e_shell_get_registry (sd->comp_editor->priv->shell), - e_activity_get_cancellable (sd->send_activity), - ecep_second_send_processed_cb, sd); - if (!sd->success) - save_data_free (sd); - } -} - -static void -ece_prepare_send_component_done (gpointer ptr) -{ - SaveData *sd = ptr; - - g_return_if_fail (sd != NULL); - g_return_if_fail (E_IS_COMP_EDITOR (sd->comp_editor)); - g_return_if_fail (sd->send_activity != NULL); - - sd->success = ece_send_process_method (sd, sd->first_send, sd->send_comp, - e_shell_get_registry (sd->comp_editor->priv->shell), - e_activity_get_cancellable (sd->send_activity), - ecep_first_send_processed_cb, sd); - if (!sd->success) - save_data_free (sd); -} - -static void -ece_prepare_send_component_thread (EAlertSinkThreadJobData *job_data, - gpointer user_data, - GCancellable *cancellable, - GError **error) -{ - SaveData *sd = user_data; - const gchar *alert_ident; - ECalComponent *send_comp = NULL; - guint32 flags; - ESourceRegistry *registry; - - g_return_if_fail (sd != NULL); - g_return_if_fail (E_IS_CAL_CLIENT (sd->target_client)); - g_return_if_fail (sd->component != NULL); - - while (!sd->send_activity) { - /* Give the main thread a chance to set this object - and give it a 50 milliseconds delay too */ - g_thread_yield (); - g_usleep (50000); - } - - switch (icalcomponent_isa (sd->component)) { - case ICAL_VEVENT_COMPONENT: - alert_ident = "calendar:failed-send-event"; - break; - case ICAL_VJOURNAL_COMPONENT: - alert_ident = "calendar:failed-send-memo"; - break; - case ICAL_VTODO_COMPONENT: - alert_ident = "calendar:failed-send-task"; - break; - default: - g_warning ("%s: Cannot send component of kind %d", G_STRFUNC, icalcomponent_isa (sd->component)); - sd->success = FALSE; - sd->alert_ident = g_strdup ("calendar:failed-send-event"); - return; - } - - g_free (sd->alert_ident); - sd->alert_ident = g_strdup (alert_ident); - - e_alert_sink_thread_job_set_alert_ident (job_data, alert_ident); - - flags = e_comp_editor_get_flags (sd->comp_editor); - registry = e_shell_get_registry (sd->comp_editor->priv->shell); - - if (sd->recur_mod == E_CAL_OBJ_MOD_ALL && e_cal_component_is_instance (sd->send_comp)) { - /* Ensure we send the master object, not the instance only */ - icalcomponent *icalcomp = NULL; - const gchar *uid = NULL; - - e_cal_component_get_uid (sd->send_comp, &uid); - if (e_cal_client_get_object_sync (sd->target_client, uid, NULL, &icalcomp, cancellable, NULL) && - icalcomp != NULL) { - send_comp = e_cal_component_new_from_icalcomponent (icalcomp); - } - } - - if (!send_comp) - send_comp = e_cal_component_clone (sd->send_comp); - - cal_comp_util_copy_new_attendees (send_comp, sd->send_comp); - - /* The user updates the delegated status to the Organizer, - * so remove all other attendees. */ - if ((flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0) { - gchar *address; - - address = itip_get_comp_attendee (registry, send_comp, sd->target_client); - - if (address) { - ece_set_attendees_for_delegation (send_comp, address); - g_free (address); - } - } - - g_clear_object (&sd->send_comp); - sd->send_comp = send_comp; -} - -static void -ece_save_component_done (gpointer ptr) -{ - SaveData *sd = ptr; - - g_return_if_fail (sd != NULL); - g_return_if_fail (E_IS_COMP_EDITOR (sd->comp_editor)); - - if (sd->success) { - ECalComponent *comp; - gboolean delegated, is_new_meeting; - gboolean only_new_attendees = FALSE; - gboolean strip_alarms = TRUE; - guint32 flags; - - if (sd->object_created) - g_signal_emit (sd->comp_editor, signals[OBJECT_CREATED], 0, NULL); - - comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (sd->component)); - if (sd->comp_editor->priv->page_general) { - GSList *added_attendees; - - added_attendees = e_comp_editor_page_general_get_added_attendees (sd->comp_editor->priv->page_general); - cal_comp_util_set_added_attendees_mails (comp, added_attendees); - } - - flags = e_comp_editor_get_flags (sd->comp_editor); - is_new_meeting = (flags & E_COMP_EDITOR_FLAG_WITH_ATTENDEES) == 0 || - (flags & E_COMP_EDITOR_FLAG_IS_NEW) != 0; - delegated = (flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0 && - e_cal_client_check_save_schedules (sd->target_client); - - if (delegated || (sd->with_send && e_cal_dialogs_send_component ( - GTK_WINDOW (sd->comp_editor), sd->target_client, comp, - is_new_meeting, &strip_alarms, &only_new_attendees))) { - ESourceRegistry *registry; - EActivity *activity; - - registry = e_shell_get_registry (sd->comp_editor->priv->shell); - - if (delegated) - only_new_attendees = FALSE; - - if ((itip_organizer_is_user (registry, comp, sd->target_client) || - itip_sentby_is_user (registry, comp, sd->target_client))) { - if (e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_JOURNAL) - sd->first_send = E_CAL_COMPONENT_METHOD_PUBLISH; - else - sd->first_send = E_CAL_COMPONENT_METHOD_REQUEST; - } else { - sd->first_send = E_CAL_COMPONENT_METHOD_REQUEST; - - if ((flags & E_COMP_EDITOR_FLAG_DELEGATE) != 0) - sd->second_send = E_CAL_COMPONENT_METHOD_REPLY; - } - - sd->mime_attach_list = ece_get_mime_attach_list (sd->comp_editor); - sd->strip_alarms = strip_alarms; - sd->only_new_attendees = only_new_attendees; - sd->send_comp = comp; - sd->success = FALSE; - sd->alert_ident = g_strdup ("calendar:failed-send-event"); - sd->alert_arg_0 = e_util_get_source_full_name (registry, e_client_get_source (E_CLIENT (sd->target_client))); - - activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (sd->comp_editor), - _("Sending notifications to attendees..."), sd->alert_ident, sd->alert_arg_0, - ece_prepare_send_component_thread, sd, ece_prepare_send_component_done); - - if (activity) - e_activity_bar_set_activity (sd->comp_editor->priv->activity_bar, activity); - - /* The thread is waiting for this to be set first */ - sd->send_activity = activity; - - return; - } - - g_clear_object (&comp); - } - - save_data_free (sd); -} - -static gboolean -ece_save_component_attachments_sync (ECalClient *cal_client, - icalcomponent *component, - GCancellable *cancellable, - GError **error) -{ - icalproperty *prop; - const gchar *local_store; - gchar *target_filename_prefix, *filename_prefix, *tmp; - gboolean success = TRUE; - - g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client), FALSE); - g_return_val_if_fail (component != NULL, FALSE); - - tmp = g_strdup (icalcomponent_get_uid (component)); - e_filename_make_safe (tmp); - filename_prefix = g_strconcat (tmp, "-", NULL); - g_free (tmp); - - local_store = e_cal_client_get_local_attachment_store (cal_client); - if (local_store && *local_store && - g_mkdir_with_parents (local_store, 0700) < 0) { - g_debug ("%s: Failed to create local store directory '%s'", G_STRFUNC, local_store); - } - - target_filename_prefix = g_build_filename (local_store, filename_prefix, NULL); - - g_free (filename_prefix); - - for (prop = icalcomponent_get_first_property (component, ICAL_ATTACH_PROPERTY); - prop && success; - prop = icalcomponent_get_next_property (component, ICAL_ATTACH_PROPERTY)) { - icalattach *attach; - gchar *uri = NULL; - - attach = icalproperty_get_attach (prop); - if (!attach) - continue; - - if (icalattach_get_is_url (attach)) { - const gchar *data; - gsize buf_size; - - data = icalattach_get_url (attach); - buf_size = strlen (data); - uri = g_malloc0 (buf_size + 1); - - icalvalue_decode_ical_string (data, uri, buf_size); - } - - if (uri) { - if (g_ascii_strncasecmp (uri, "file://", 7) == 0 && - !g_str_has_prefix (uri + 7, target_filename_prefix)) { - GFile *source, *destination; - gchar *decoded_filename; - gchar *target_filename; - - decoded_filename = g_uri_unescape_string (strrchr (uri, '/') + 1, NULL); - target_filename = g_strconcat (target_filename_prefix, decoded_filename, NULL); - g_free (decoded_filename); - - source = g_file_new_for_uri (uri); - destination = g_file_new_for_path (target_filename); - - if (source && destination) { - success = g_file_copy (source, destination, G_FILE_COPY_OVERWRITE, cancellable, NULL, NULL, error); - if (success) { - g_free (uri); - uri = g_file_get_uri (destination); - - if (uri) { - icalattach *new_attach; - gsize buf_size; - gchar *buf; - - buf_size = 2 * strlen (uri) + 1; - buf = g_malloc0 (buf_size); - - icalvalue_encode_ical_string (uri, buf, buf_size); - new_attach = icalattach_new_from_url (buf); - - icalproperty_set_attach (prop, new_attach); - - icalattach_unref (new_attach); - g_free (buf); - } - } - } - - g_clear_object (&source); - g_clear_object (&destination); - g_free (target_filename); - } - - g_free (uri); - } - - success = success & !g_cancellable_set_error_if_cancelled (cancellable, error); - } - - g_free (target_filename_prefix); - - return success; -} - -static void -ece_gather_tzids_cb (icalparameter *param, - gpointer user_data) -{ - GHashTable *tzids = user_data; - const gchar *tzid; - - g_return_if_fail (param != NULL); - g_return_if_fail (tzids != NULL); - - tzid = icalparameter_get_tzid (param); - if (tzid && *tzid && g_ascii_strcasecmp (tzid, "UTC") != 0) - g_hash_table_insert (tzids, g_strdup (tzid), NULL); -} - -static gboolean -ece_save_component_add_timezones_sync (SaveData *sd, - GCancellable *cancellable, - GError **error) -{ - GHashTable *tzids; - GHashTableIter iter; - gpointer key, value; - gboolean source_is_target; - - g_return_val_if_fail (sd != NULL, FALSE); - g_return_val_if_fail (sd->component != NULL, FALSE); - g_return_val_if_fail (sd->target_client != NULL, FALSE); - - sd->success = TRUE; - - tzids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - source_is_target = !sd->source_client || - e_source_equal (e_client_get_source (E_CLIENT (sd->target_client)), - e_client_get_source (E_CLIENT (sd->source_client))); - - icalcomponent_foreach_tzid (sd->component, ece_gather_tzids_cb, tzids); - - g_hash_table_iter_init (&iter, tzids); - while (sd->success && g_hash_table_iter_next (&iter, &key, &value)) { - const gchar *tzid = key; - icaltimezone *zone = NULL; - GError *local_error = NULL; - - if (!e_cal_client_get_timezone_sync (source_is_target ? sd->target_client : sd->source_client, - tzid, &zone, cancellable, &local_error)) { - zone = icaltimezone_get_builtin_timezone_from_tzid (tzid); - if (!zone) - zone = icaltimezone_get_builtin_timezone (tzid); - if (!zone) { - g_propagate_error (error, local_error); - local_error = NULL; - sd->success = FALSE; - break; - } - } - - sd->success = e_cal_client_add_timezone_sync (sd->target_client, zone, cancellable, error); - - g_clear_error (&local_error); - } - - g_hash_table_destroy (tzids); - - return sd->success; -} - -static void -ece_save_component_thread (EAlertSinkThreadJobData *job_data, - gpointer user_data, - GCancellable *cancellable, - GError **error) -{ - SaveData *sd = user_data; - const gchar *create_alert_ident, *modify_alert_ident, *remove_alert_ident, *get_alert_ident; - gchar *orig_uid, *new_uid = NULL; - - g_return_if_fail (sd != NULL); - g_return_if_fail (E_IS_CAL_CLIENT (sd->target_client)); - g_return_if_fail (sd->component != NULL); - - switch (icalcomponent_isa (sd->component)) { - case ICAL_VEVENT_COMPONENT: - create_alert_ident = "calendar:failed-create-event"; - modify_alert_ident = "calendar:failed-modify-event"; - remove_alert_ident = "calendar:failed-remove-event"; - get_alert_ident = "calendar:failed-get-event"; - break; - case ICAL_VJOURNAL_COMPONENT: - create_alert_ident = "calendar:failed-create-memo"; - modify_alert_ident = "calendar:failed-modify-memo"; - remove_alert_ident = "calendar:failed-remove-memo"; - get_alert_ident = "calendar:failed-get-memo"; - break; - case ICAL_VTODO_COMPONENT: - create_alert_ident = "calendar:failed-create-task"; - modify_alert_ident = "calendar:failed-modify-task"; - remove_alert_ident = "calendar:failed-remove-task"; - get_alert_ident = "calendar:failed-get-task"; - break; - default: - g_warning ("%s: Cannot save component of kind %d", G_STRFUNC, icalcomponent_isa (sd->component)); - return; - } - - sd->success = ece_save_component_add_timezones_sync (sd, cancellable, error); - if (!sd->success) { - e_alert_sink_thread_job_set_alert_ident (job_data, "calendar:failed-add-timezone"); - return; - } - - sd->success = ece_save_component_attachments_sync (sd->target_client, sd->component, cancellable, error); - if (!sd->success) { - e_alert_sink_thread_job_set_alert_ident (job_data, "calendar:failed-save-attachments"); - return; - } - - orig_uid = g_strdup (icalcomponent_get_uid (sd->component)); - - if (cal_comp_is_icalcomp_on_server_sync (sd->component, sd->target_client, cancellable, error)) { - ECalComponent *comp; - gboolean has_recurrences; - - e_alert_sink_thread_job_set_alert_ident (job_data, modify_alert_ident); - - comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (sd->component)); - g_return_if_fail (comp != NULL); - - has_recurrences = e_cal_util_component_has_recurrences (sd->component); - - if (has_recurrences && sd->recur_mod == E_CAL_OBJ_MOD_ALL) - sd->success = comp_util_sanitize_recurrence_master_sync (comp, sd->target_client, cancellable, error); - else - sd->success = TRUE; - - if (sd->recur_mod == E_CAL_OBJ_MOD_THIS) { - e_cal_component_set_rdate_list (comp, NULL); - e_cal_component_set_rrule_list (comp, NULL); - e_cal_component_set_exdate_list (comp, NULL); - e_cal_component_set_exrule_list (comp, NULL); - } - - sd->success = sd->success && e_cal_client_modify_object_sync ( - sd->target_client, e_cal_component_get_icalcomponent (comp), sd->recur_mod, cancellable, error); - - g_clear_object (&comp); - } else { - e_alert_sink_thread_job_set_alert_ident (job_data, create_alert_ident); - - sd->success = e_cal_client_create_object_sync (sd->target_client, sd->component, &new_uid, cancellable, error); - - if (sd->success) - sd->object_created = TRUE; - } - - if (sd->success && sd->source_client && - !e_source_equal (e_client_get_source (E_CLIENT (sd->target_client)), - e_client_get_source (E_CLIENT (sd->source_client))) && - cal_comp_is_icalcomp_on_server_sync (sd->component, sd->source_client, cancellable, NULL)) { - ECalObjModType recur_mod = E_CAL_OBJ_MOD_THIS; - - /* Comp found a new home. Remove it from old one. */ - if (e_cal_util_component_is_instance (sd->component) || - e_cal_util_component_has_recurrences (sd->component)) - recur_mod = E_CAL_OBJ_MOD_ALL; - - sd->success = e_cal_client_remove_object_sync ( - sd->source_client, orig_uid, - NULL, recur_mod, cancellable, error); - - if (!sd->success) { - gchar *source_display_name; - - source_display_name = e_util_get_source_full_name (e_shell_get_registry (sd->comp_editor->priv->shell), - e_client_get_source (E_CLIENT (sd->source_client))); - - e_alert_sink_thread_job_set_alert_ident (job_data, remove_alert_ident); - e_alert_sink_thread_job_set_alert_arg_0 (job_data, source_display_name); - - g_free (source_display_name); - } - } - - if (new_uid) { - icalcomponent_set_uid (sd->component, new_uid); - g_free (new_uid); - } - - g_free (orig_uid); - - if (sd->success && !sd->close_after_save) { - icalcomponent *comp = NULL; - gchar *uid, *rid = NULL; - - uid = g_strdup (icalcomponent_get_uid (sd->component)); - if (icalcomponent_get_first_property (sd->component, ICAL_RECURRENCEID_PROPERTY)) { - struct icaltimetype ridtt; - - ridtt = icalcomponent_get_recurrenceid (sd->component); - if (icaltime_is_valid_time (ridtt) && !icaltime_is_null_time (ridtt)) { - rid = icaltime_as_ical_string_r (ridtt); - } - } - - sd->success = e_cal_client_get_object_sync (sd->target_client, uid, rid, &comp, cancellable, error); - if (sd->success && comp) { - icalcomponent_free (sd->component); - sd->component = comp; - } else { - e_alert_sink_thread_job_set_alert_ident (job_data, get_alert_ident); - } - - g_free (uid); - g_free (rid); - } -} - -static void -ece_save_component (ECompEditor *comp_editor, - icalcomponent *component, - gboolean with_send, - gboolean close_after_save) -{ - EActivity *activity; - const gchar *summary; - ECalObjModType recur_mod = E_CAL_OBJ_MOD_THIS; - SaveData *sd; - gchar *source_display_name; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (component != NULL); - - summary = icalcomponent_get_summary (component); - if (!summary || !*summary) { - if (!e_cal_dialogs_send_component_prompt_subject (GTK_WINDOW (comp_editor), component)) { - return; - } - } - - if (e_cal_util_component_is_instance (component)) { - if (!e_cal_dialogs_recur_icalcomp (comp_editor->priv->target_client, - component, &recur_mod, GTK_WINDOW (comp_editor), FALSE)) { - return; - } - } else if (e_cal_util_component_has_recurrences (component)) { - recur_mod = E_CAL_OBJ_MOD_ALL; - } - - e_comp_editor_enable (comp_editor, FALSE); - - sd = g_new0 (SaveData, 1); - sd->comp_editor = g_object_ref (comp_editor); - sd->source_client = comp_editor->priv->source_client ? g_object_ref (comp_editor->priv->source_client) : NULL; - sd->target_client = g_object_ref (comp_editor->priv->target_client); - sd->component = icalcomponent_new_clone (component); - sd->with_send = with_send; - sd->close_after_save = close_after_save; - sd->recur_mod = recur_mod; - sd->first_send = E_CAL_COMPONENT_METHOD_NONE; - sd->second_send = E_CAL_COMPONENT_METHOD_NONE; - sd->success = FALSE; - - source_display_name = e_util_get_source_full_name (e_shell_get_registry (comp_editor->priv->shell), - e_client_get_source (E_CLIENT (sd->target_client))); - - activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (comp_editor), - _("Saving changes..."), "calendar:failed-create-event", source_display_name, - ece_save_component_thread, sd, ece_save_component_done); - - if (activity) - e_activity_bar_set_activity (comp_editor->priv->activity_bar, activity); - - g_clear_object (&activity); - g_free (source_display_name); -} - -typedef struct _OpenTargetClientData { - ECompEditor *comp_editor; - ESource *source; - gchar *extension_name; - EClient *client; - gchar *cal_email_address; - gchar *alarm_email_address; - gboolean is_target_client_change; - EActivity *activity; -} OpenTargetClientData; - -static void -open_target_client_data_free (gpointer ptr) -{ - OpenTargetClientData *otc = ptr; - - if (otc) { - if (otc->comp_editor) { - if (otc->client) { - gboolean previous_changed = e_comp_editor_get_changed (otc->comp_editor); - - e_comp_editor_set_alarm_email_address (otc->comp_editor, otc->alarm_email_address); - e_comp_editor_set_cal_email_address (otc->comp_editor, otc->cal_email_address); - e_comp_editor_set_target_client (otc->comp_editor, E_CAL_CLIENT (otc->client)); - - if (otc->is_target_client_change) - e_comp_editor_set_changed (otc->comp_editor, TRUE); - else - e_comp_editor_set_changed (otc->comp_editor, previous_changed); - } - - if (otc->comp_editor->priv->activity_bar && otc->activity) { - if (otc->activity == e_activity_bar_get_activity (otc->comp_editor->priv->activity_bar)) - e_activity_bar_set_activity (otc->comp_editor->priv->activity_bar, NULL); - - if (otc->activity == otc->comp_editor->priv->target_client_opening) - g_clear_object (&otc->comp_editor->priv->target_client_opening); - } - - if (otc->source) { - EShell *shell; - ECredentialsPrompter *credentials_prompter; - - shell = e_comp_editor_get_shell (otc->comp_editor); - credentials_prompter = e_shell_get_credentials_prompter (shell); - - e_credentials_prompter_set_auto_prompt_disabled_for (credentials_prompter, otc->source, TRUE); - } - - e_comp_editor_sensitize_widgets (otc->comp_editor); - } - - g_clear_object (&otc->comp_editor); - g_clear_object (&otc->source); - g_clear_object (&otc->client); - g_clear_object (&otc->activity); - g_free (otc->extension_name); - g_free (otc->cal_email_address); - g_free (otc->alarm_email_address); - g_free (otc); - } -} - -static void -comp_editor_open_target_client_thread (EAlertSinkThreadJobData *job_data, - gpointer user_data, - GCancellable *cancellable, - GError **error) -{ - OpenTargetClientData *otc = user_data; - EClientCache *client_cache; - - g_return_if_fail (otc != NULL); - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return; - - g_return_if_fail (E_IS_COMP_EDITOR (otc->comp_editor)); - g_return_if_fail (E_IS_SOURCE (otc->source)); - g_return_if_fail (otc->extension_name != NULL); - - client_cache = e_shell_get_client_cache (e_comp_editor_get_shell (otc->comp_editor)); - - otc->client = e_client_cache_get_client_sync (client_cache, otc->source, otc->extension_name, - 30, cancellable, error); - - if (otc->client) { - /* Cache some properties which require remote calls */ - - if (!g_cancellable_is_cancelled (cancellable)) { - e_client_get_capabilities (otc->client); - } - - if (!g_cancellable_is_cancelled (cancellable)) { - e_client_get_backend_property_sync (otc->client, - CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS, - &otc->cal_email_address, - cancellable, error); - } - - if (!g_cancellable_is_cancelled (cancellable)) { - e_client_get_backend_property_sync (otc->client, - CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS, - &otc->alarm_email_address, - cancellable, error); - } - - if (g_cancellable_is_cancelled (cancellable)) - g_clear_object (&otc->client); - } -} - -typedef struct _UpdateActivityBarData { - ECompEditor *comp_editor; - EActivity *activity; -} UpdateActivityBarData; - -static void -update_activity_bar_data_free (gpointer ptr) -{ - UpdateActivityBarData *uab = ptr; - - if (uab) { - g_clear_object (&uab->comp_editor); - g_clear_object (&uab->activity); - g_free (uab); - } -} - -static gboolean -update_activity_bar_cb (gpointer user_data) -{ - UpdateActivityBarData *uab = user_data; - - g_return_val_if_fail (uab != NULL, FALSE); - g_return_val_if_fail (E_IS_COMP_EDITOR (uab->comp_editor), FALSE); - g_return_val_if_fail (E_IS_ACTIVITY (uab->activity), FALSE); - - if (uab->comp_editor->priv->target_client_opening == uab->activity && - e_activity_get_state (uab->activity) != E_ACTIVITY_CANCELLED && - e_activity_get_state (uab->activity) != E_ACTIVITY_COMPLETED) { - e_activity_bar_set_activity (uab->comp_editor->priv->activity_bar, uab->activity); - } - - return FALSE; -} - -static void -e_comp_editor_open_target_client (ECompEditor *comp_editor) -{ - OpenTargetClientData *otc; - ESource *source; - EActivity *activity; - ECredentialsPrompter *credentials_prompter; - gchar *source_display_name, *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL; - gboolean is_target_client_change; - const gchar *extension_name; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (comp_editor->priv->page_general != NULL); - - source = e_comp_editor_page_general_ref_selected_source (comp_editor->priv->page_general); - if (!source) - return; - - if (comp_editor->priv->target_client && - e_client_get_source (E_CLIENT (comp_editor->priv->target_client)) == source) { - g_clear_object (&source); - return; - } - - if (comp_editor->priv->target_client_opening) { - e_activity_cancel (comp_editor->priv->target_client_opening); - g_clear_object (&comp_editor->priv->target_client_opening); - } - - is_target_client_change = comp_editor->priv->target_client != NULL; - g_clear_object (&comp_editor->priv->target_client); - - extension_name = e_comp_editor_page_general_get_source_extension_name (comp_editor->priv->page_general); - source_display_name = e_util_get_source_full_name ( - e_shell_get_registry (e_comp_editor_get_shell (comp_editor)), - source); - - g_return_if_fail (e_util_get_open_source_job_info (extension_name, source_display_name, - &description, &alert_ident, &alert_arg_0)); - - credentials_prompter = e_shell_get_credentials_prompter (e_comp_editor_get_shell (comp_editor)); - e_credentials_prompter_set_auto_prompt_disabled_for (credentials_prompter, source, FALSE); - - otc = g_new0 (OpenTargetClientData, 1); - otc->extension_name = g_strdup (extension_name); - otc->comp_editor = g_object_ref (comp_editor); - otc->source = g_object_ref (source); - otc->is_target_client_change = is_target_client_change; - - activity = e_alert_sink_submit_thread_job ( - E_ALERT_SINK (comp_editor), description, alert_ident, alert_arg_0, - comp_editor_open_target_client_thread, otc, - open_target_client_data_free); - - otc->activity = g_object_ref (activity); - comp_editor->priv->target_client_opening = g_object_ref (activity); - - /* Close all alerts */ - while (e_alert_bar_close_alert (comp_editor->priv->alert_bar)) { - ; - } - - if (comp_editor->priv->activity_bar) { - UpdateActivityBarData *uab; - - uab = g_new0 (UpdateActivityBarData, 1); - uab->comp_editor = g_object_ref (comp_editor); - uab->activity = g_object_ref (activity); - - /* To avoid UI flickering when the source can be opened quickly */ - g_timeout_add_seconds_full (G_PRIORITY_LOW, 1, - update_activity_bar_cb, uab, update_activity_bar_data_free); - } - - g_free (description); - g_free (alert_ident); - g_free (alert_arg_0); - g_free (source_display_name); - g_clear_object (&source); - g_clear_object (&activity); -} - -static void -e_comp_editor_update_window_title (ECompEditor *comp_editor) -{ - ECompEditorClass *comp_editor_class; - gboolean with_attendees = FALSE; - const gchar *format, *title_suffix; - gchar *title; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (comp_editor->priv->page_general) - with_attendees = e_comp_editor_page_general_get_show_attendees (comp_editor->priv->page_general); - - comp_editor_class = E_COMP_EDITOR_GET_CLASS (comp_editor); - if (with_attendees) - format = comp_editor_class->title_format_with_attendees; - else - format = comp_editor_class->title_format_without_attendees; - - title_suffix = e_comp_editor_get_title_suffix (comp_editor); - - title = g_strdup_printf (format, title_suffix && *title_suffix ? title_suffix : _("No Summary")); - - gtk_window_set_icon_name (GTK_WINDOW (comp_editor), comp_editor_class->icon_name); - gtk_window_set_title (GTK_WINDOW (comp_editor), title); - - g_free (title); -} - -static void -e_comp_editor_close (ECompEditor *comp_editor) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - g_signal_emit (comp_editor, signals[EDITOR_CLOSED], 0, FALSE, NULL); - - gtk_widget_destroy (GTK_WIDGET (comp_editor)); -} - -static void -e_comp_editor_save_and_close (ECompEditor *comp_editor, - gboolean can_close) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (comp_editor->priv->component) { - icalcomponent *component = icalcomponent_new_clone (comp_editor->priv->component); - if (component && e_comp_editor_fill_component (comp_editor, component)) { - ece_save_component (comp_editor, component, TRUE, can_close); - icalcomponent_free (component); - } - } -} - -static GtkResponseType -ece_save_component_dialog (ECompEditor *comp_editor) -{ - const icalcomponent *component; - GtkWindow *parent; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), GTK_RESPONSE_NO); - g_return_val_if_fail (e_comp_editor_get_component (comp_editor) != NULL, GTK_RESPONSE_NO); - - parent = GTK_WINDOW (comp_editor); - component = e_comp_editor_get_component (comp_editor); - switch (icalcomponent_isa (component)) { - case ICAL_VEVENT_COMPONENT: - if (e_comp_editor_page_general_get_show_attendees (comp_editor->priv->page_general)) - return e_alert_run_dialog_for_args (parent, "calendar:prompt-save-meeting", NULL); - else - return e_alert_run_dialog_for_args (parent, "calendar:prompt-save-appointment", NULL); - case ICAL_VTODO_COMPONENT: - return e_alert_run_dialog_for_args (parent, "calendar:prompt-save-task", NULL); - case ICAL_VJOURNAL_COMPONENT: - return e_alert_run_dialog_for_args (parent, "calendar:prompt-save-memo", NULL); - default: - return GTK_RESPONSE_NO; - } -} - -static gboolean -e_comp_editor_prompt_and_save_changes (ECompEditor *comp_editor, - gboolean with_send) -{ - icalcomponent *component; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); - - if (!e_comp_editor_get_changed (comp_editor)) - return TRUE; - - switch (ece_save_component_dialog (comp_editor)) { - case GTK_RESPONSE_YES: /* Save */ - if (e_client_is_readonly (E_CLIENT (comp_editor->priv->target_client))) { - e_alert_submit ( - E_ALERT_SINK (comp_editor), - "calendar:prompt-read-only-cal-editor", - e_source_get_display_name ( - e_client_get_source (E_CLIENT (comp_editor->priv->target_client))), - NULL); - /* don't discard changes when selected readonly calendar */ - return FALSE; - } - - if (comp_editor->priv->component && - e_comp_editor_page_general_get_show_attendees (comp_editor->priv->page_general) && - icalcomponent_isa (comp_editor->priv->component) == ICAL_VTODO_COMPONENT - && e_client_check_capability (E_CLIENT (comp_editor->priv->target_client), CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT)) { - e_alert_submit ( - E_ALERT_SINK (comp_editor), - "calendar:prompt-no-task-assignment-editor", - e_source_get_display_name ( - e_client_get_source (E_CLIENT (comp_editor->priv->target_client))), - NULL); - return FALSE; - } - - component = icalcomponent_new_clone (comp_editor->priv->component); - if (!e_comp_editor_fill_component (comp_editor, component)) { - icalcomponent_free (component); - return FALSE; - } - - ece_save_component (comp_editor, component, with_send, TRUE); - - return FALSE; - case GTK_RESPONSE_NO: /* Discard */ - return TRUE; - case GTK_RESPONSE_CANCEL: /* Cancel */ - default: - return FALSE; - } - - return FALSE; -} - -static void -action_close_cb (GtkAction *action, - ECompEditor *comp_editor) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (e_comp_editor_prompt_and_save_changes (comp_editor, TRUE)) - e_comp_editor_close (comp_editor); -} - -static void -action_help_cb (GtkAction *action, - ECompEditor *comp_editor) -{ - ECompEditorClass *klass; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - klass = E_COMP_EDITOR_GET_CLASS (comp_editor); - g_return_if_fail (klass->help_section != NULL); - - e_display_help (GTK_WINDOW (comp_editor), klass->help_section); -} - -static void -ece_print_or_preview (ECompEditor *comp_editor, - GtkPrintOperationAction print_action) -{ - icalcomponent *component; - ECalComponent *comp; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (e_comp_editor_get_component (comp_editor) != NULL); - - component = icalcomponent_new_clone (e_comp_editor_get_component (comp_editor)); - if (!e_comp_editor_fill_component (comp_editor, component)) { - icalcomponent_free (component); - return; - } - - comp = e_cal_component_new_from_icalcomponent (component); - g_return_if_fail (comp != NULL); - - print_comp (comp, - e_comp_editor_get_target_client (comp_editor), - calendar_config_get_icaltimezone (), - calendar_config_get_24_hour_format (), - print_action); - - g_object_unref (comp); -} - -static void -action_print_cb (GtkAction *action, - ECompEditor *comp_editor) -{ - ece_print_or_preview (comp_editor, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG); -} - -static void -action_print_preview_cb (GtkAction *action, - ECompEditor *comp_editor) -{ - ece_print_or_preview (comp_editor, GTK_PRINT_OPERATION_ACTION_PREVIEW); -} - -static void -action_save_cb (GtkAction *action, - ECompEditor *comp_editor) -{ - e_comp_editor_save_and_close (comp_editor, FALSE); -} - -static void -action_save_and_close_cb (GtkAction *action, - ECompEditor *comp_editor) -{ - e_comp_editor_save_and_close (comp_editor, TRUE); -} - -static gboolean -ece_organizer_email_address_is_user (ECompEditor *comp_editor, - EClient *client, - const gchar *email_address, - gboolean is_organizer) -{ - ESourceRegistry *registry; - const gchar *cal_email_address; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); - g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE); - - email_address = itip_strip_mailto (email_address); - - if (!email_address || !*email_address) - return FALSE; - - cal_email_address = e_comp_editor_get_cal_email_address (comp_editor); - if (cal_email_address && *cal_email_address && - g_ascii_strcasecmp (cal_email_address, email_address) == 0) { - return TRUE; - } - - if (is_organizer && e_client_check_capability (client, CAL_STATIC_CAPABILITY_ORGANIZER_NOT_EMAIL_ADDRESS)) - return FALSE; - - registry = e_shell_get_registry (e_comp_editor_get_shell (comp_editor)); - - return itip_address_is_user (registry, email_address); -} - -static gboolean -ece_organizer_is_user (ECompEditor *comp_editor, - icalcomponent *component, - EClient *client) -{ - icalproperty *prop; - const gchar *organizer; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); - g_return_val_if_fail (component != NULL, FALSE); - g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE); - - prop = icalcomponent_get_first_property (component, ICAL_ORGANIZER_PROPERTY); - if (!prop || e_client_check_capability (client, CAL_STATIC_CAPABILITY_NO_ORGANIZER)) - return FALSE; - - organizer = itip_strip_mailto (icalproperty_get_organizer (prop)); - if (!organizer || !*organizer) - return FALSE; - - return ece_organizer_email_address_is_user (comp_editor, client, organizer, TRUE); -} - -static gboolean -ece_sentby_is_user (ECompEditor *comp_editor, - icalcomponent *component, - EClient *client) -{ - icalproperty *prop; - icalparameter *param; - const gchar *sentby; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); - g_return_val_if_fail (component != NULL, FALSE); - g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE); - - prop = icalcomponent_get_first_property (component, ICAL_ORGANIZER_PROPERTY); - if (!prop || e_client_check_capability (client, CAL_STATIC_CAPABILITY_NO_ORGANIZER)) - return FALSE; - - param = icalproperty_get_first_parameter (prop, ICAL_SENTBY_PARAMETER); - if (!param) - return FALSE; - - sentby = icalparameter_get_sentby (param); - - return ece_organizer_email_address_is_user (comp_editor, client, sentby, FALSE); -} - -static void -ece_emit_times_changed_cb (ECompEditor *comp_editor) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - g_signal_emit (comp_editor, signals[TIMES_CHANGED], 0, NULL); -} - -static void -ece_connect_time_parts (ECompEditor *comp_editor, - ECompEditorPropertyPart *dtstart_part, - ECompEditorPropertyPart *dtend_part) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - -#define update_part(x) G_STMT_START { \ - if (x) \ - g_object_ref (x); \ - if (comp_editor->priv->x) { \ - g_signal_handlers_disconnect_by_func (comp_editor->priv->x, G_CALLBACK (ece_emit_times_changed_cb), comp_editor); \ - g_clear_object (&comp_editor->priv->x); \ - } \ - if (x) { \ - comp_editor->priv->x = x; \ - g_signal_connect_swapped (comp_editor->priv->x, "changed", \ - G_CALLBACK (ece_emit_times_changed_cb), comp_editor); \ - } \ - } G_STMT_END - - update_part (dtstart_part); - update_part (dtend_part); - -#undef update_part -} - -static void -ece_sensitize_widgets (ECompEditor *comp_editor, - gboolean force_insensitive) -{ - GtkActionGroup *group; - GSList *link; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - for (link = comp_editor->priv->pages; link; link = g_slist_next (link)) { - ECompEditorPage *page = link->data; - - g_warn_if_fail (E_IS_COMP_EDITOR_PAGE (page)); - if (!E_IS_COMP_EDITOR_PAGE (page)) - continue; - - e_comp_editor_page_sensitize_widgets (page, force_insensitive); - } - - group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_set_sensitive (group, !force_insensitive); - - group = e_comp_editor_get_action_group (comp_editor, "editable"); - gtk_action_group_set_sensitive (group, !force_insensitive); -} - -static void -ece_fill_widgets (ECompEditor *comp_editor, - icalcomponent *component) -{ - GSList *link; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (component != NULL); - - for (link = comp_editor->priv->pages; link; link = g_slist_next (link)) { - ECompEditorPage *page = link->data; - - g_warn_if_fail (E_IS_COMP_EDITOR_PAGE (page)); - if (!E_IS_COMP_EDITOR_PAGE (page)) - continue; - - e_comp_editor_page_fill_widgets (page, component); - } -} - -static gboolean -ece_fill_component (ECompEditor *comp_editor, - icalcomponent *component) -{ - GSList *link; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); - g_return_val_if_fail (component != NULL, FALSE); - - for (link = comp_editor->priv->pages; link; link = g_slist_next (link)) { - ECompEditorPage *page = link->data; - - g_warn_if_fail (E_IS_COMP_EDITOR_PAGE (page)); - if (!E_IS_COMP_EDITOR_PAGE (page)) - continue; - - if (!e_comp_editor_page_fill_component (page, component)) - return FALSE; - } - - return TRUE; -} - -static void -comp_editor_realize_cb (ECompEditor *comp_editor) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (comp_editor->priv->component) { - e_comp_editor_fill_widgets (comp_editor, comp_editor->priv->component); - e_comp_editor_set_changed (comp_editor, FALSE); - } - - e_comp_editor_update_window_title (comp_editor); - e_comp_editor_sensitize_widgets (comp_editor); - - if (comp_editor->priv->page_general && comp_editor->priv->origin_source) { - e_comp_editor_page_general_set_selected_source ( - comp_editor->priv->page_general, - comp_editor->priv->origin_source); - e_comp_editor_set_changed (comp_editor, FALSE); - } - - if (comp_editor->priv->page_general) { - e_comp_editor_page_general_update_view (comp_editor->priv->page_general); - - if (!comp_editor->priv->show_attendees_handler_id) { - comp_editor->priv->show_attendees_handler_id = - e_signal_connect_notify_swapped (comp_editor->priv->page_general, - "notify::show-attendees", - G_CALLBACK (e_comp_editor_update_window_title), comp_editor); - } - } - - if (!comp_editor->priv->target_client) - e_comp_editor_open_target_client (comp_editor); -} - -static void -comp_editor_unrealize_cb (ECompEditor *comp_editor) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (comp_editor->priv->page_general) { - e_signal_disconnect_notify_handler (comp_editor->priv->page_general, - &comp_editor->priv->show_attendees_handler_id); - } -} - -static gboolean -comp_editor_delete_event (GtkWidget *widget, - GdkEventAny *event) -{ - ECompEditor *comp_editor; - - g_return_val_if_fail (E_IS_COMP_EDITOR (widget), FALSE); - - comp_editor = E_COMP_EDITOR (widget); - - /* It's disabled when the component is being saved */ - if (gtk_widget_get_sensitive (GTK_WIDGET (comp_editor->priv->content))) - action_close_cb (NULL, comp_editor); - - return TRUE; -} - -static gboolean -comp_editor_key_press_event (GtkWidget *widget, - GdkEventKey *event) -{ - ECompEditor *comp_editor; - - g_return_val_if_fail (E_IS_COMP_EDITOR (widget), FALSE); - - comp_editor = E_COMP_EDITOR (widget); - - if (event->keyval == GDK_KEY_Escape && - !e_alert_bar_close_alert (comp_editor->priv->alert_bar)) { - GtkAction *action; - - action = e_comp_editor_get_action (comp_editor, "close"); - gtk_action_activate (action); - - return TRUE; - } - - /* Chain up to parent's method. */ - return GTK_WIDGET_CLASS (e_comp_editor_parent_class)->key_press_event (widget, event); -} - -static void -comp_editor_selected_source_notify_cb (ECompEditorPageGeneral *page_general, - GParamSpec *param, - ECompEditor *comp_editor) -{ - g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general)); - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (comp_editor->priv->page_general == page_general); - - e_comp_editor_open_target_client (comp_editor); -} - -static void -e_comp_editor_submit_alert (EAlertSink *alert_sink, - EAlert *alert) -{ - ECompEditor *comp_editor; - - g_return_if_fail (E_IS_COMP_EDITOR (alert_sink)); - g_return_if_fail (E_IS_ALERT (alert)); - - comp_editor = E_COMP_EDITOR (alert_sink); - - e_alert_bar_submit_alert (comp_editor->priv->alert_bar, alert); -} - -static void -e_comp_editor_set_origin_source (ECompEditor *comp_editor, - ESource *origin_source) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - if (origin_source) - g_return_if_fail (E_IS_SOURCE (origin_source)); - - g_clear_object (&comp_editor->priv->origin_source); - if (origin_source) - comp_editor->priv->origin_source = g_object_ref (origin_source); -} - -static void -e_comp_editor_set_shell (ECompEditor *comp_editor, - EShell *shell) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (E_IS_SHELL (shell)); - - g_clear_object (&comp_editor->priv->shell); - comp_editor->priv->shell = g_object_ref (shell); -} - -static void -e_comp_editor_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_ALARM_EMAIL_ADDRESS: - e_comp_editor_set_alarm_email_address ( - E_COMP_EDITOR (object), - g_value_get_string (value)); - return; - - case PROP_CAL_EMAIL_ADDRESS: - e_comp_editor_set_cal_email_address ( - E_COMP_EDITOR (object), - g_value_get_string (value)); - return; - - case PROP_CHANGED: - e_comp_editor_set_changed ( - E_COMP_EDITOR (object), - g_value_get_boolean (value)); - return; - - case PROP_COMPONENT: - e_comp_editor_set_component ( - E_COMP_EDITOR (object), - g_value_get_pointer (value)); - return; - - case PROP_FLAGS: - e_comp_editor_set_flags ( - E_COMP_EDITOR (object), - g_value_get_uint (value)); - return; - - case PROP_ORIGIN_SOURCE: - e_comp_editor_set_origin_source ( - E_COMP_EDITOR (object), - g_value_get_object (value)); - return; - - case PROP_SHELL: - e_comp_editor_set_shell ( - E_COMP_EDITOR (object), - g_value_get_object (value)); - return; - - case PROP_SOURCE_CLIENT: - e_comp_editor_set_source_client ( - E_COMP_EDITOR (object), - g_value_get_object (value)); - return; - - case PROP_TARGET_CLIENT: - e_comp_editor_set_target_client ( - E_COMP_EDITOR (object), - g_value_get_object (value)); - return; - - case PROP_TITLE_SUFFIX: - e_comp_editor_set_title_suffix ( - E_COMP_EDITOR (object), - g_value_get_string (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -e_comp_editor_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_ALARM_EMAIL_ADDRESS: - g_value_set_string ( - value, - e_comp_editor_get_alarm_email_address ( - E_COMP_EDITOR (object))); - return; - - case PROP_CAL_EMAIL_ADDRESS: - g_value_set_string ( - value, - e_comp_editor_get_cal_email_address ( - E_COMP_EDITOR (object))); - return; - - case PROP_CHANGED: - g_value_set_boolean ( - value, - e_comp_editor_get_changed ( - E_COMP_EDITOR (object))); - return; - - case PROP_COMPONENT: - g_value_set_pointer ( - value, - e_comp_editor_get_component ( - E_COMP_EDITOR (object))); - return; - - case PROP_FLAGS: - g_value_set_uint ( - value, - e_comp_editor_get_flags ( - E_COMP_EDITOR (object))); - return; - - case PROP_ORIGIN_SOURCE: - g_value_set_object ( - value, - e_comp_editor_get_origin_source ( - E_COMP_EDITOR (object))); - return; - - case PROP_SHELL: - g_value_set_object ( - value, - e_comp_editor_get_shell ( - E_COMP_EDITOR (object))); - return; - - case PROP_SOURCE_CLIENT: - g_value_set_object ( - value, - e_comp_editor_get_source_client ( - E_COMP_EDITOR (object))); - return; - - case PROP_TARGET_CLIENT: - g_value_set_object ( - value, - e_comp_editor_get_target_client ( - E_COMP_EDITOR (object))); - return; - - case PROP_TITLE_SUFFIX: - g_value_set_string ( - value, - e_comp_editor_get_title_suffix ( - E_COMP_EDITOR (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -e_comp_editor_constructed (GObject *object) -{ - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " \n" - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - - GtkActionEntry core_entries[] = { - - { "close", - "window-close", - N_("_Close"), - "w", - N_("Close the current window"), - G_CALLBACK (action_close_cb) }, - - { "copy-clipboard", - "edit-copy", - N_("_Copy"), - "c", - N_("Copy the selection"), - NULL }, /* Handled by EFocusTracker */ - - { "cut-clipboard", - "edit-cut", - N_("Cu_t"), - "x", - N_("Cut the selection"), - NULL }, /* Handled by EFocusTracker */ - - { "delete-selection", - "edit-delete", - N_("_Delete"), - NULL, - N_("Delete the selection"), - NULL }, /* Handled by EFocusTracker */ - - { "help", - "help-browser", - N_("_Help"), - "F1", - N_("View help"), - G_CALLBACK (action_help_cb) }, - - { "paste-clipboard", - "edit-paste", - N_("_Paste"), - "v", - N_("Paste the clipboard"), - NULL }, /* Handled by EFocusTracker */ - - { "print", - "document-print", - N_("_Print..."), - "p", - NULL, - G_CALLBACK (action_print_cb) }, - - { "print-preview", - "document-print-preview", - N_("Pre_view..."), - NULL, - NULL, - G_CALLBACK (action_print_preview_cb) }, - - { "select-all", - "edit-select-all", - N_("Select _All"), - "a", - N_("Select all text"), - NULL }, /* Handled by EFocusTracker */ - - { "undo", - "edit-undo", - N_("_Undo"), - "z", - N_("Undo"), - NULL }, /* Handled by EFocusTracker */ - - { "redo", - "edit-redo", - N_("_Redo"), - "y", - N_("Redo"), - NULL }, /* Handled by EFocusTracker */ - - /* Menus */ - - { "classification-menu", - NULL, - N_("_Classification"), - NULL, - NULL, - NULL }, - - { "edit-menu", - NULL, - N_("_Edit"), - NULL, - NULL, - NULL }, - - { "file-menu", - NULL, - N_("_File"), - NULL, - NULL, - NULL }, - - { "help-menu", - NULL, - N_("_Help"), - NULL, - NULL, - NULL }, - - { "insert-menu", - NULL, - N_("_Insert"), - NULL, - NULL, - NULL }, - - { "options-menu", - NULL, - N_("_Options"), - NULL, - NULL, - NULL }, - - { "view-menu", - NULL, - N_("_View"), - NULL, - NULL, - NULL } - }; - - GtkActionEntry editable_entries[] = { - - { "save", - "document-save", - N_("_Save"), - "s", - N_("Save current changes"), - G_CALLBACK (action_save_cb) }, - - { "save-and-close", - NULL, - N_("Save and Close"), - NULL, - N_("Save current changes and close editor"), - G_CALLBACK (action_save_and_close_cb) } - }; - - ECompEditor *comp_editor = E_COMP_EDITOR (object); - GtkWidget *widget; - GtkBox *vbox; - GtkAction *action; - GtkActionGroup *action_group; - EFocusTracker *focus_tracker; - GError *error = NULL; - - G_OBJECT_CLASS (e_comp_editor_parent_class)->constructed (object); - - g_signal_connect (comp_editor, "key-press-event", - G_CALLBACK (e_util_check_gtk_bindings_in_key_press_event_cb), NULL); - - comp_editor->priv->calendar_settings = e_util_ref_settings ("org.gnome.evolution.calendar"); - comp_editor->priv->ui_manager = gtk_ui_manager_new (); - - gtk_window_add_accel_group ( - GTK_WINDOW (comp_editor), - gtk_ui_manager_get_accel_group (comp_editor->priv->ui_manager)); - - /* Setup Action Groups */ - - action_group = gtk_action_group_new ("individual"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_ui_manager_insert_action_group ( - comp_editor->priv->ui_manager, action_group, 0); - g_object_unref (action_group); - - action_group = gtk_action_group_new ("core"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions ( - action_group, core_entries, - G_N_ELEMENTS (core_entries), comp_editor); - gtk_ui_manager_insert_action_group ( - comp_editor->priv->ui_manager, action_group, 0); - g_object_unref (action_group); - - action_group = gtk_action_group_new ("editable"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions ( - action_group, editable_entries, - G_N_ELEMENTS (editable_entries), comp_editor); - gtk_ui_manager_insert_action_group ( - comp_editor->priv->ui_manager, action_group, 0); - g_object_unref (action_group); - - action = gtk_action_group_get_action (action_group, "save-and-close"); - if (action) { - GtkAction *save_action; - GIcon *icon; - GIcon *emblemed_icon; - GEmblem *emblem; - - icon = g_themed_icon_new ("window-close"); - emblemed_icon = g_themed_icon_new ("document-save"); - emblem = g_emblem_new (emblemed_icon); - g_object_unref (emblemed_icon); - - emblemed_icon = g_emblemed_icon_new (icon, emblem); - g_object_unref (emblem); - g_object_unref (icon); - - gtk_action_set_gicon (action, emblemed_icon); - - g_object_unref (emblemed_icon); - - save_action = gtk_action_group_get_action (action_group, "save"); - e_binding_bind_property ( - save_action, "sensitive", - action, "sensitive", - G_BINDING_SYNC_CREATE); - } - - gtk_ui_manager_add_ui_from_string (comp_editor->priv->ui_manager, ui, -1, &error); - if (error != NULL) { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } - - widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - g_object_set (G_OBJECT (widget), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", TRUE, - "valign", GTK_ALIGN_FILL, - NULL); - gtk_widget_show (widget); - - vbox = GTK_BOX (widget); - - gtk_container_add (GTK_CONTAINER (comp_editor), widget); - - widget = e_comp_editor_get_managed_widget (comp_editor, "/main-menu"); - gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); - gtk_widget_set_visible (widget, TRUE); - - widget = e_comp_editor_get_managed_widget (comp_editor, "/main-toolbar"); - gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - gtk_style_context_add_class ( - gtk_widget_get_style_context (widget), - GTK_STYLE_CLASS_PRIMARY_TOOLBAR); - - widget = e_alert_bar_new (); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_FILL, - "vexpand", FALSE, - "valign", GTK_ALIGN_START, - NULL); - - comp_editor->priv->alert_bar = E_ALERT_BAR (widget); - - gtk_box_pack_start (vbox, widget, FALSE, FALSE, 0); - - widget = e_activity_bar_new (); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_FILL, - "vexpand", FALSE, - "valign", GTK_ALIGN_START, - NULL); - - comp_editor->priv->activity_bar = E_ACTIVITY_BAR (widget); - - gtk_box_pack_start (vbox, widget, FALSE, FALSE, 0); - - widget = gtk_notebook_new (); - g_object_set (G_OBJECT (widget), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", TRUE, - "valign", GTK_ALIGN_FILL, - "show-tabs", TRUE, - "show-border", FALSE, - NULL); - gtk_widget_show (widget); - - comp_editor->priv->content = GTK_NOTEBOOK (widget); - - gtk_box_pack_start (vbox, widget, TRUE, TRUE, 0); - - /* Configure an EFocusTracker to manage selection actions. */ - - focus_tracker = e_focus_tracker_new (GTK_WINDOW (comp_editor)); - - action = e_comp_editor_get_action (comp_editor, "cut-clipboard"); - e_focus_tracker_set_cut_clipboard_action (focus_tracker, action); - - action = e_comp_editor_get_action (comp_editor, "copy-clipboard"); - e_focus_tracker_set_copy_clipboard_action (focus_tracker, action); - - action = e_comp_editor_get_action (comp_editor, "paste-clipboard"); - e_focus_tracker_set_paste_clipboard_action (focus_tracker, action); - - action = e_comp_editor_get_action (comp_editor, "delete-selection"); - e_focus_tracker_set_delete_selection_action (focus_tracker, action); - - action = e_comp_editor_get_action (comp_editor, "select-all"); - e_focus_tracker_set_select_all_action (focus_tracker, action); - - action = e_comp_editor_get_action (comp_editor, "undo"); - e_focus_tracker_set_undo_action (focus_tracker, action); - - action = e_comp_editor_get_action (comp_editor, "redo"); - e_focus_tracker_set_redo_action (focus_tracker, action); - - comp_editor->priv->focus_tracker = focus_tracker; - - /* Desensitize the "save" action. */ - action = e_comp_editor_get_action (comp_editor, "save"); - gtk_action_set_sensitive (action, FALSE); - - e_binding_bind_property (comp_editor, "changed", action, "sensitive", 0); - - g_signal_connect (comp_editor, "realize", G_CALLBACK (comp_editor_realize_cb), NULL); - g_signal_connect (comp_editor, "unrealize", G_CALLBACK (comp_editor_unrealize_cb), NULL); - - gtk_application_add_window (GTK_APPLICATION (comp_editor->priv->shell), GTK_WINDOW (comp_editor)); - - e_extensible_load_extensions (E_EXTENSIBLE (comp_editor)); -} - -static void -e_comp_editor_dispose (GObject *object) -{ - ECompEditor *comp_editor = E_COMP_EDITOR (object); - - if (comp_editor->priv->page_general) { - g_signal_handlers_disconnect_by_func (comp_editor->priv->page_general, - G_CALLBACK (comp_editor_selected_source_notify_cb), comp_editor); - comp_editor->priv->page_general = NULL; - } - - if (comp_editor->priv->target_client_opening) { - e_activity_cancel (comp_editor->priv->target_client_opening); - g_clear_object (&comp_editor->priv->target_client_opening); - } - - g_slist_free_full (comp_editor->priv->pages, g_object_unref); - comp_editor->priv->pages = NULL; - - g_free (comp_editor->priv->alarm_email_address); - comp_editor->priv->alarm_email_address = NULL; - - g_free (comp_editor->priv->cal_email_address); - comp_editor->priv->cal_email_address = NULL; - - g_free (comp_editor->priv->title_suffix); - comp_editor->priv->title_suffix = NULL; - - if (comp_editor->priv->component) { - icalcomponent_free (comp_editor->priv->component); - comp_editor->priv->component = NULL; - } - - ece_connect_time_parts (comp_editor, NULL, NULL); - - g_clear_object (&comp_editor->priv->origin_source); - g_clear_object (&comp_editor->priv->shell); - g_clear_object (&comp_editor->priv->focus_tracker); - g_clear_object (&comp_editor->priv->ui_manager); - g_clear_object (&comp_editor->priv->source_client); - g_clear_object (&comp_editor->priv->target_client); - g_clear_object (&comp_editor->priv->calendar_settings); - g_clear_object (&comp_editor->priv->validation_alert); - - comp_editor->priv->activity_bar = NULL; - - opened_editors = g_slist_remove (opened_editors, comp_editor); - - G_OBJECT_CLASS (e_comp_editor_parent_class)->dispose (object); -} - -static void -e_comp_editor_init (ECompEditor *comp_editor) -{ - comp_editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (comp_editor, E_TYPE_COMP_EDITOR, ECompEditorPrivate); -} - -static void -e_comp_editor_alert_sink_iface_init (EAlertSinkInterface *iface) -{ - iface->submit_alert = e_comp_editor_submit_alert; -} - -static void -e_comp_editor_class_init (ECompEditorClass *klass) -{ - GtkWidgetClass *widget_class; - GObjectClass *object_class; - - g_type_class_add_private (klass, sizeof (ECompEditorPrivate)); - - klass->sensitize_widgets = ece_sensitize_widgets; - klass->fill_widgets = ece_fill_widgets; - klass->fill_component = ece_fill_component; - - widget_class = GTK_WIDGET_CLASS (klass); - widget_class->delete_event = comp_editor_delete_event; - widget_class->key_press_event = comp_editor_key_press_event; - - object_class = G_OBJECT_CLASS (klass); - object_class->set_property = e_comp_editor_set_property; - object_class->get_property = e_comp_editor_get_property; - object_class->constructed = e_comp_editor_constructed; - object_class->dispose = e_comp_editor_dispose; - - g_object_class_install_property ( - object_class, - PROP_ALARM_EMAIL_ADDRESS, - g_param_spec_string ( - "alarm-email-address", - "Alarm Email Address", - "Target client's alarm email address", - NULL, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_CAL_EMAIL_ADDRESS, - g_param_spec_string ( - "cal-email-address", - "Calendar Email Address", - "Target client's calendar email address", - NULL, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_CHANGED, - g_param_spec_boolean ( - "changed", - "Changed", - "Whether the editor content changed", - FALSE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_COMPONENT, - g_param_spec_pointer ( - "component", - "Component", - "icalcomponent currently edited", - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_FLAGS, - g_param_spec_uint ( - "flags", - "Flags", - "Editor flags", - 0, G_MAXUINT, 0, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_ORIGIN_SOURCE, - g_param_spec_object ( - "origin-source", - "Origin Source", - "ESource of an ECalClient the component is stored in", - E_TYPE_SOURCE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_SHELL, - g_param_spec_object ( - "shell", - "Shell", - "EShell", - E_TYPE_SHELL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_SOURCE_CLIENT, - g_param_spec_object ( - "source-client", - "Source Client", - "ECalClient, the source calendar for the component", - E_TYPE_CAL_CLIENT, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_TARGET_CLIENT, - g_param_spec_object ( - "target-client", - "Target Client", - "ECalClient currently set as the target calendar for the component", - E_TYPE_CAL_CLIENT, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_TITLE_SUFFIX, - g_param_spec_string ( - "title-suffix", - "Title Suffix", - "Window title suffix, usually summary of the component", - NULL, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - signals[TIMES_CHANGED] = g_signal_new ( - "times-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (ECompEditorClass, times_changed), - NULL, NULL, NULL, - G_TYPE_NONE, 0, - G_TYPE_NONE); - - signals[OBJECT_CREATED] = g_signal_new ( - "object-created", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (ECompEditorClass, object_created), - NULL, NULL, NULL, - G_TYPE_NONE, 0, - G_TYPE_NONE); - - signals[EDITOR_CLOSED] = g_signal_new ( - "editor-closed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ECompEditorClass, editor_closed), - NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, 1, G_TYPE_BOOLEAN); -} - -void -e_comp_editor_sensitize_widgets (ECompEditor *comp_editor) -{ - ECompEditorClass *comp_editor_class; - gboolean force_insensitive; - GtkWidget *current_focus; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - comp_editor_class = E_COMP_EDITOR_GET_CLASS (comp_editor); - g_return_if_fail (comp_editor_class != NULL); - g_return_if_fail (comp_editor_class->sensitize_widgets != NULL); - - current_focus = gtk_window_get_focus (GTK_WINDOW (comp_editor)); - - force_insensitive = !comp_editor->priv->component; - - if (!force_insensitive) { - ECalClient *target_client; - - target_client = e_comp_editor_get_target_client (comp_editor); - if (target_client) { - EClient *client = E_CLIENT (target_client); - - if (e_client_is_readonly (client)) { - force_insensitive = TRUE; - } else { - if (!e_cal_util_component_has_organizer (comp_editor->priv->component) || - ece_organizer_is_user (comp_editor, comp_editor->priv->component, client) || - ece_sentby_is_user (comp_editor, comp_editor->priv->component, client)) { - comp_editor->priv->flags = comp_editor->priv->flags | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER; - } else { - comp_editor->priv->flags = comp_editor->priv->flags & (~E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER); - } - } - } else { - force_insensitive = TRUE; - } - } - - comp_editor_class->sensitize_widgets (comp_editor, force_insensitive); - - if (force_insensitive) - comp_editor->priv->restore_focus = current_focus; - else - ece_restore_focus (comp_editor); -} - -void -e_comp_editor_fill_widgets (ECompEditor *comp_editor, - icalcomponent *component) -{ - ECompEditorClass *comp_editor_class; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (component != NULL); - - comp_editor_class = E_COMP_EDITOR_GET_CLASS (comp_editor); - g_return_if_fail (comp_editor_class != NULL); - g_return_if_fail (comp_editor_class->fill_widgets != NULL); - - e_comp_editor_set_updating (comp_editor, TRUE); - - comp_editor_class->fill_widgets (comp_editor, component); - - e_comp_editor_set_updating (comp_editor, FALSE); -} - -gboolean -e_comp_editor_fill_component (ECompEditor *comp_editor, - icalcomponent *component) -{ - ECompEditorClass *comp_editor_class; - gboolean is_valid; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); - g_return_val_if_fail (component != NULL, FALSE); - - comp_editor_class = E_COMP_EDITOR_GET_CLASS (comp_editor); - g_return_val_if_fail (comp_editor_class != NULL, FALSE); - g_return_val_if_fail (comp_editor_class->fill_component != NULL, FALSE); - - is_valid = comp_editor_class->fill_component (comp_editor, component); - - if (is_valid && comp_editor->priv->validation_alert) { - e_alert_response (comp_editor->priv->validation_alert, GTK_RESPONSE_CLOSE); - g_clear_object (&comp_editor->priv->validation_alert); - } - - if (is_valid) { - ECalClient *target_client; - EClient *client = NULL; - - target_client = e_comp_editor_get_target_client (comp_editor); - if (target_client) - client = E_CLIENT (target_client); - - if (!e_cal_util_component_has_organizer (component) || (client && ( - ece_organizer_is_user (comp_editor, component, client) || - ece_sentby_is_user (comp_editor, component, client)))) { - gint sequence; - - sequence = icalcomponent_get_sequence (component); - icalcomponent_set_sequence (component, sequence + 1); - } - } - - return is_valid; -} - -void -e_comp_editor_set_validation_error (ECompEditor *comp_editor, - ECompEditorPage *error_page, - GtkWidget *error_widget, - const gchar *error_message) -{ - EAlert *alert, *previous_alert; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (error_message != NULL); - - /* Ignore validation errors when the inner editor is currently updating. */ - if (e_comp_editor_get_updating (comp_editor)) - return; - - alert = e_alert_new ("calendar:comp-editor-failed-validate", error_message, NULL); - - e_alert_bar_add_alert (comp_editor->priv->alert_bar, alert); - - previous_alert = comp_editor->priv->validation_alert; - comp_editor->priv->validation_alert = alert; - - if (previous_alert) { - e_alert_response (previous_alert, GTK_RESPONSE_CLOSE); - g_clear_object (&previous_alert); - } - - if (error_page) - e_comp_editor_select_page (comp_editor, error_page); - - if (error_widget) - gtk_widget_grab_focus (error_widget); -} - -EShell * -e_comp_editor_get_shell (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->shell; -} - -GSettings * -e_comp_editor_get_settings (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->calendar_settings; -} - -ESource * -e_comp_editor_get_origin_source (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->origin_source; -} - -icalcomponent * -e_comp_editor_get_component (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->component; -} - -guint32 -e_comp_editor_get_flags (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), 0); - - return comp_editor->priv->flags; -} - -void -e_comp_editor_set_flags (ECompEditor *comp_editor, - guint32 flags) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (comp_editor->priv->flags == flags) - return; - - comp_editor->priv->flags = flags; - - g_object_notify (G_OBJECT (comp_editor), "flags"); -} - -EFocusTracker * -e_comp_editor_get_focus_tracker (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->focus_tracker; -} - -GtkUIManager * -e_comp_editor_get_ui_manager (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->ui_manager; -} - -GtkAction * -e_comp_editor_get_action (ECompEditor *comp_editor, - const gchar *action_name) -{ - GtkUIManager *ui_manager; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - g_return_val_if_fail (action_name != NULL, NULL); - - ui_manager = e_comp_editor_get_ui_manager (comp_editor); - - return e_lookup_action (ui_manager, action_name); -} - -GtkActionGroup * -e_comp_editor_get_action_group (ECompEditor *comp_editor, - const gchar *group_name) -{ - GtkUIManager *ui_manager; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - g_return_val_if_fail (group_name != NULL, NULL); - - ui_manager = e_comp_editor_get_ui_manager (comp_editor); - - return e_lookup_action_group (ui_manager, group_name); -} - -GtkWidget * -e_comp_editor_get_managed_widget (ECompEditor *comp_editor, - const gchar *widget_path) -{ - GtkUIManager *ui_manager; - GtkWidget *widget; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - g_return_val_if_fail (widget_path != NULL, NULL); - - ui_manager = e_comp_editor_get_ui_manager (comp_editor); - widget = gtk_ui_manager_get_widget (ui_manager, widget_path); - g_return_val_if_fail (widget != NULL, NULL); - - return widget; -} - -const gchar * -e_comp_editor_get_alarm_email_address (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->alarm_email_address; -} - -void -e_comp_editor_set_alarm_email_address (ECompEditor *comp_editor, - const gchar *alarm_email_address) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (g_strcmp0 (alarm_email_address, comp_editor->priv->alarm_email_address) == 0) - return; - - g_free (comp_editor->priv->alarm_email_address); - comp_editor->priv->alarm_email_address = g_strdup (alarm_email_address); - - g_object_notify (G_OBJECT (comp_editor), "alarm-email-address"); -} - -const gchar * -e_comp_editor_get_cal_email_address (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->cal_email_address; -} - -void -e_comp_editor_set_cal_email_address (ECompEditor *comp_editor, - const gchar *cal_email_address) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (g_strcmp0 (cal_email_address, comp_editor->priv->cal_email_address) == 0) - return; - - g_free (comp_editor->priv->cal_email_address); - comp_editor->priv->cal_email_address = g_strdup (cal_email_address); - - g_object_notify (G_OBJECT (comp_editor), "cal-email-address"); -} - -gboolean -e_comp_editor_get_changed (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); - - return comp_editor->priv->changed; -} - -void -e_comp_editor_set_changed (ECompEditor *comp_editor, - gboolean changed) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if ((changed ? 1 : 0) == (comp_editor->priv->changed ? 1 : 0)) - return; - - comp_editor->priv->changed = changed; - - g_object_notify (G_OBJECT (comp_editor), "changed"); -} - -void -e_comp_editor_ensure_changed (ECompEditor *comp_editor) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - e_comp_editor_set_changed (comp_editor, TRUE); -} - -gboolean -e_comp_editor_get_updating (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); - - return comp_editor->priv->updating > 0; -} - -void -e_comp_editor_set_updating (ECompEditor *comp_editor, - gboolean updating) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (updating) { - comp_editor->priv->updating++; - } else if (comp_editor->priv->updating > 0) { - comp_editor->priv->updating--; - } else { - g_warn_if_reached (); - } -} - -ECalClient * -e_comp_editor_get_source_client (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->source_client; -} - -void -e_comp_editor_set_source_client (ECompEditor *comp_editor, - ECalClient *client) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (client == comp_editor->priv->source_client) - return; - - if (client) - g_object_ref (client); - g_clear_object (&comp_editor->priv->source_client); - comp_editor->priv->source_client = client; - - g_object_notify (G_OBJECT (comp_editor), "source-client"); -} - -ECalClient * -e_comp_editor_get_target_client (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->target_client; -} - -void -e_comp_editor_set_target_client (ECompEditor *comp_editor, - ECalClient *client) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (client == comp_editor->priv->target_client) - return; - - if (client) - g_object_ref (client); - g_clear_object (&comp_editor->priv->target_client); - comp_editor->priv->target_client = client; - - g_object_notify (G_OBJECT (comp_editor), "target-client"); - - if (client && !comp_editor->priv->source_client && comp_editor->priv->origin_source && - e_source_equal (e_client_get_source (E_CLIENT (client)), comp_editor->priv->origin_source)) - e_comp_editor_set_source_client (comp_editor, client); - - e_comp_editor_sensitize_widgets (comp_editor); -} - -const gchar * -e_comp_editor_get_title_suffix (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return comp_editor->priv->title_suffix; -} - -void -e_comp_editor_set_title_suffix (ECompEditor *comp_editor, - const gchar *title_suffix) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (g_strcmp0 (title_suffix, comp_editor->priv->title_suffix) == 0) - return; - - g_free (comp_editor->priv->title_suffix); - comp_editor->priv->title_suffix = g_strdup (title_suffix); - - g_object_notify (G_OBJECT (comp_editor), "title-suffix"); - - e_comp_editor_update_window_title (comp_editor); -} - -void -e_comp_editor_set_time_parts (ECompEditor *comp_editor, - ECompEditorPropertyPart *dtstart_part, - ECompEditorPropertyPart *dtend_part) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (dtstart_part) - g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (dtstart_part)); - if (dtend_part) - g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (dtend_part)); - - ece_connect_time_parts (comp_editor, dtstart_part, dtend_part); -} - -void -e_comp_editor_get_time_parts (ECompEditor *comp_editor, - ECompEditorPropertyPart **out_dtstart_part, - ECompEditorPropertyPart **out_dtend_part) -{ - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - - if (out_dtstart_part) - *out_dtstart_part = comp_editor->priv->dtstart_part; - if (out_dtend_part) - *out_dtend_part = comp_editor->priv->dtend_part; -} - -/* This consumes the @page. */ -void -e_comp_editor_add_page (ECompEditor *comp_editor, - const gchar *label, - ECompEditorPage *page) -{ - ECompEditor *pages_comp_editor; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (label != NULL); - g_return_if_fail (E_IS_COMP_EDITOR_PAGE (page)); - - pages_comp_editor = e_comp_editor_page_ref_editor (page); - if (pages_comp_editor != comp_editor) { - g_warn_if_fail (pages_comp_editor == comp_editor); - g_clear_object (&pages_comp_editor); - return; - } - - g_clear_object (&pages_comp_editor); - - /* One reference uses the GtkNotebook, the other the pages GSList */ - gtk_notebook_append_page (comp_editor->priv->content, - GTK_WIDGET (page), - gtk_label_new_with_mnemonic (label)); - - comp_editor->priv->pages = g_slist_append (comp_editor->priv->pages, g_object_ref (page)); - - g_signal_connect_swapped (page, "changed", G_CALLBACK (e_comp_editor_ensure_changed), comp_editor); - - if (E_IS_COMP_EDITOR_PAGE_GENERAL (page)) { - ECompEditorPageGeneral *page_general; - - g_return_if_fail (comp_editor->priv->page_general == NULL); - - page_general = E_COMP_EDITOR_PAGE_GENERAL (page); - - g_signal_connect (page_general, "notify::selected-source", - G_CALLBACK (comp_editor_selected_source_notify_cb), comp_editor); - - comp_editor->priv->page_general = page_general; - - if ((comp_editor->priv->flags & E_COMP_EDITOR_FLAG_WITH_ATTENDEES) != 0) { - e_comp_editor_page_general_set_show_attendees (page_general, TRUE); - } - } -} - -/* The returned pointer is owned by the @comp_editor; returns the first instance, - in order of the addition. */ -ECompEditorPage * -e_comp_editor_get_page (ECompEditor *comp_editor, - GType page_type) -{ - GSList *link; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - g_return_val_if_fail (g_type_is_a (page_type, E_TYPE_COMP_EDITOR_PAGE), NULL); - g_return_val_if_fail (page_type != E_TYPE_COMP_EDITOR_PAGE, NULL); - - for (link = comp_editor->priv->pages; link; link = g_slist_next (link)) { - ECompEditorPage *page = link->data; - - if (G_TYPE_CHECK_INSTANCE_TYPE (page, page_type)) - return page; - } - - return NULL; -} - -/* Free the returned GSList with g_slist_free(), the memebers are owned by the comp_editor */ -GSList * -e_comp_editor_get_pages (ECompEditor *comp_editor) -{ - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - - return g_slist_copy (comp_editor->priv->pages); -} - -void -e_comp_editor_select_page (ECompEditor *comp_editor, - ECompEditorPage *page) -{ - gint page_num; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (E_IS_COMP_EDITOR_PAGE (page)); - - page_num = gtk_notebook_page_num (comp_editor->priv->content, GTK_WIDGET (page)); - g_return_if_fail (page_num != -1); - - gtk_notebook_set_current_page (comp_editor->priv->content, page_num); -} - -/* Unref returned pointer when done with it. */ -static EAlert * -e_comp_editor_add_alert (ECompEditor *comp_editor, - const gchar *alert_id, - const gchar *primary_text, - const gchar *secondary_text) -{ - EAlert *alert; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - g_return_val_if_fail (alert_id != NULL, NULL); - g_return_val_if_fail (primary_text != NULL || secondary_text != NULL, NULL); - - alert = e_alert_new (alert_id, - primary_text ? primary_text : "", - secondary_text ? secondary_text : "", - NULL); - - e_alert_bar_add_alert (comp_editor->priv->alert_bar, alert); - - return alert; -} - -/* Unref returned pointer when done with it. */ -EAlert * -e_comp_editor_add_information (ECompEditor *comp_editor, - const gchar *primary_text, - const gchar *secondary_text) -{ - return e_comp_editor_add_alert (comp_editor, "calendar:comp-editor-information", primary_text, secondary_text); -} - -/* Unref returned pointer when done with it. */ -EAlert * -e_comp_editor_add_warning (ECompEditor *comp_editor, - const gchar *primary_text, - const gchar *secondary_text) -{ - return e_comp_editor_add_alert (comp_editor, "calendar:comp-editor-warning", primary_text, secondary_text); -} - -/* Unref returned pointer when done with it. */ -EAlert * -e_comp_editor_add_error (ECompEditor *comp_editor, - const gchar *primary_text, - const gchar *secondary_text) -{ - return e_comp_editor_add_alert (comp_editor, "calendar:comp-editor-error", primary_text, secondary_text); -} - - -static gboolean -ece_check_start_before_end (ECompEditor *comp_editor, - struct icaltimetype *start_tt, - struct icaltimetype *end_tt, - gboolean adjust_end_time) -{ - struct icaltimetype end_tt_copy; - icaltimezone *start_zone, *end_zone; - gint duration = -1; - gint cmp; - - if ((e_comp_editor_get_flags (comp_editor) & E_COMP_EDITOR_FLAG_IS_NEW) == 0) { - icalcomponent *icomp; - - icomp = e_comp_editor_get_component (comp_editor); - if (icomp && - icalcomponent_get_first_property (icomp, ICAL_DTSTART_PROPERTY) && - (icalcomponent_get_first_property (icomp, ICAL_DTEND_PROPERTY) || - icalcomponent_get_first_property (icomp, ICAL_DUE_PROPERTY))) { - struct icaltimetype orig_start, orig_end; - - orig_start = icalcomponent_get_dtstart (icomp); - orig_end = icalcomponent_get_dtend (icomp); - - if (icaltime_is_valid_time (orig_start) && - icaltime_is_valid_time (orig_end)) { - duration = icaltime_as_timet (orig_end) - icaltime_as_timet (orig_start); - } - } - } - - start_zone = (icaltimezone *) start_tt->zone; - end_zone = (icaltimezone *) end_tt->zone; - - /* Convert the end time to the same timezone as the start time. */ - end_tt_copy = *end_tt; - - if (start_zone && end_zone && start_zone != end_zone) - icaltimezone_convert_time (&end_tt_copy, end_zone, start_zone); - - /* Now check if the start time is after the end time. If it is, - * we need to modify one of the times. */ - cmp = icaltime_compare (*start_tt, end_tt_copy); - if (cmp > 0) { - if (adjust_end_time) { - /* Try to switch only the date */ - end_tt->year = start_tt->year; - end_tt->month = start_tt->month; - end_tt->day = start_tt->day; - - end_tt_copy = *end_tt; - if (start_zone && end_zone && start_zone != end_zone) - icaltimezone_convert_time (&end_tt_copy, end_zone, start_zone); - - if (duration > 0) - icaltime_adjust (&end_tt_copy, 0, 0, 0, -duration); - - if (icaltime_compare (*start_tt, end_tt_copy) >= 0) { - *end_tt = *start_tt; - - if (duration >= 0) { - icaltime_adjust (end_tt, 0, 0, 0, duration); - } else { - /* Modify the end time, to be the start + 1 hour/day. */ - icaltime_adjust (end_tt, 0, start_tt->is_date ? 24 : 1, 0, 0); - } - - if (start_zone && end_zone && start_zone != end_zone) - icaltimezone_convert_time (end_tt, start_zone, end_zone); - } - } else { - /* Try to switch only the date */ - start_tt->year = end_tt->year; - start_tt->month = end_tt->month; - start_tt->day = end_tt->day; - - if (icaltime_compare (*start_tt, end_tt_copy) >= 0) { - *start_tt = *end_tt; - - if (duration >= 0) { - icaltime_adjust (start_tt, 0, 0, 0, -duration); - } else { - /* Modify the start time, to be the end - 1 hour/day. */ - icaltime_adjust (start_tt, 0, start_tt->is_date ? -24 : -1, 0, 0); - } - - if (start_zone && end_zone && start_zone != end_zone) - icaltimezone_convert_time (start_tt, end_zone, start_zone); - } - } - - return TRUE; - } - - return FALSE; -} - -void -e_comp_editor_ensure_start_before_end (ECompEditor *comp_editor, - ECompEditorPropertyPart *start_datetime, - ECompEditorPropertyPart *end_datetime, - gboolean change_end_datetime) -{ - ECompEditorPropertyPartDatetime *start_dtm, *end_dtm; - struct icaltimetype start_tt, end_tt; - gboolean set_dtstart = FALSE, set_dtend = FALSE; - - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); - g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (start_datetime)); - g_return_if_fail (E_IS_COMP_EDITOR_PROPERTY_PART_DATETIME (end_datetime)); - - start_dtm = E_COMP_EDITOR_PROPERTY_PART_DATETIME (start_datetime); - end_dtm = E_COMP_EDITOR_PROPERTY_PART_DATETIME (end_datetime); - - start_tt = e_comp_editor_property_part_datetime_get_value (start_dtm); - end_tt = e_comp_editor_property_part_datetime_get_value (end_dtm); - - if (icaltime_is_null_time (start_tt) || - icaltime_is_null_time (end_tt) || - !icaltime_is_valid_time (start_tt) || - !icaltime_is_valid_time (end_tt)) - return; - - if (start_tt.is_date || end_tt.is_date) { - /* All Day Events are simple. We just compare the dates and if - * start > end we copy one of them to the other. */ - gint cmp; - - start_tt.is_date = TRUE; - end_tt.is_date = TRUE; - - cmp = icaltime_compare_date_only (start_tt, end_tt); - - if (cmp > 0) { - if (change_end_datetime) { - end_tt = start_tt; - set_dtend = TRUE; - } else { - start_tt = end_tt; - set_dtstart = TRUE; - } - } - } else { - if (ece_check_start_before_end (comp_editor, &start_tt, &end_tt, change_end_datetime)) { - if (change_end_datetime) - set_dtend = TRUE; - else - set_dtstart = TRUE; - } - } - - if (set_dtstart || set_dtend) { - e_comp_editor_set_updating (comp_editor, TRUE); - - if (set_dtstart) - e_comp_editor_property_part_datetime_set_value (start_dtm, start_tt); - - if (set_dtend) - e_comp_editor_property_part_datetime_set_value (end_dtm, end_tt); - - e_comp_editor_set_updating (comp_editor, FALSE); - } -} - -static gboolean -e_comp_editor_holds_component (ECompEditor *comp_editor, - ESource *origin_source, - const icalcomponent *component) -{ - const gchar *component_uid, *editor_uid; - gboolean equal; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); - g_return_val_if_fail (component != NULL, FALSE); - - if (!origin_source || !comp_editor->priv->origin_source || - !e_source_equal (origin_source, comp_editor->priv->origin_source)) - return FALSE; - - component_uid = icalcomponent_get_uid ((icalcomponent *) component); - editor_uid = icalcomponent_get_uid (comp_editor->priv->component); - - if (!component_uid || !editor_uid) - return FALSE; - - equal = g_strcmp0 (component_uid, editor_uid) == 0; - if (equal) { - struct icaltimetype component_rid, editor_rid; - - component_rid = icalcomponent_get_recurrenceid ((icalcomponent *) component); - editor_rid = icalcomponent_get_recurrenceid (comp_editor->priv->component); - - if (icaltime_is_null_time (component_rid)) { - equal = icaltime_is_null_time (editor_rid); - } else if (!icaltime_is_null_time (editor_rid)) { - equal = icaltime_compare (component_rid, editor_rid) == 0; - } - } - - return equal; -} - -ECompEditor * -e_comp_editor_open_for_component (GtkWindow *parent, - EShell *shell, - ESource *origin_source, - const icalcomponent *component, - guint32 flags /* bit-or of ECompEditorFlags */) -{ - ECompEditor *comp_editor; - GType comp_editor_type; - - g_return_val_if_fail (E_IS_SHELL (shell), NULL); - if (origin_source) - g_return_val_if_fail (E_IS_SOURCE (origin_source), NULL); - g_return_val_if_fail (component != NULL, NULL); - - comp_editor = e_comp_editor_find_existing_for (origin_source, component); - if (comp_editor) { - gtk_window_present (GTK_WINDOW (comp_editor)); - return comp_editor; - } - - switch (icalcomponent_isa (component)) { - case ICAL_VEVENT_COMPONENT: - comp_editor_type = E_TYPE_COMP_EDITOR_EVENT; - break; - case ICAL_VTODO_COMPONENT: - comp_editor_type = E_TYPE_COMP_EDITOR_TASK; - break; - case ICAL_VJOURNAL_COMPONENT: - comp_editor_type = E_TYPE_COMP_EDITOR_MEMO; - break; - default: - g_warn_if_reached (); - return NULL; - } - - comp_editor = g_object_new (comp_editor_type, - "shell", shell, - "origin-source", origin_source, - "component", component, - "flags", flags, - NULL); - - opened_editors = g_slist_prepend (opened_editors, comp_editor); - - gtk_widget_show (GTK_WIDGET (comp_editor)); - - return comp_editor; -} - -ECompEditor * -e_comp_editor_find_existing_for (ESource *origin_source, - const icalcomponent *component) -{ - ECompEditor *comp_editor; - GSList *link; - - if (origin_source) - g_return_val_if_fail (E_IS_SOURCE (origin_source), NULL); - g_return_val_if_fail (component != NULL, NULL); - - for (link = opened_editors; link; link = g_slist_next (link)) { - comp_editor = link->data; - - if (!comp_editor) - continue; - - if (e_comp_editor_holds_component (comp_editor, origin_source, component)) { - gtk_window_present (GTK_WINDOW (comp_editor)); - return comp_editor; - } - } - - return NULL; -} diff --git a/src/e-util/e-collection-account-wizard.c b/src/e-util/e-collection-account-wizard.c index 84ccd3f..49b1ac4 100644 --- a/src/e-util/e-collection-account-wizard.c +++ b/src/e-util/e-collection-account-wizard.c @@ -1858,6 +1858,8 @@ collection_account_wizard_dispose (GObject *object) wizard->priv->store_passwords = NULL; } + g_warn_if_fail (wizard->priv->running_result == NULL); + if (wizard->priv->running_result) { e_simple_async_result_complete_idle (wizard->priv->running_result); g_clear_object (&wizard->priv->running_result); diff --git a/src/e-util/e-collection-account-wizard.c.config-lookup-crash b/src/e-util/e-collection-account-wizard.c.config-lookup-crash deleted file mode 100644 index 49b1ac4..0000000 --- a/src/e-util/e-collection-account-wizard.c.config-lookup-crash +++ /dev/null @@ -1,2358 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com) - * - * This library is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This library 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 Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -/** - * SECTION: e-collection-account-wizard - * @include: e-util/e-util.h - * @short_description: Collection account wizard - * - * #ECollectionAccountWizard is a configuration wizard which guides - * user through steps to created collection accounts. Such accounts - * provide multiple sources at once, being it address books, calendars, - * mail and others. - **/ - -#include "evolution-config.h" - -#include -#include -#include -#include - -#include "e-config-lookup.h" -#include "e-dialog-widgets.h" -#include "e-misc-utils.h" -#include "e-spinner.h" -#include "e-simple-async-result.h" - -#include "e-collection-account-wizard.h" - -/* There is no mail identity in the EConfigLookupResultKind enum, thus define a fake one */ -#define FAKE_E_CONFIG_LOOKUP_RESULT_MAIL_IDENTITY E_CONFIG_LOOKUP_RESULT_UNKNOWN - -struct _ECollectionAccountWizardPrivate { - ESourceRegistry *registry; - EConfigLookup *config_lookup; - GHashTable *store_passwords; /* gchar *source-uid ~> gchar *password */ - GHashTable *workers; /* EConfigLookupWorker * ~> WorkerData * */ - guint running_workers; - ESimpleAsyncResult *running_result; - gboolean changed; - - ESource *sources[E_CONFIG_LOOKUP_RESULT_LAST_KIND + 1]; - - /* Lookup page */ - GtkWidget *email_entry; - GtkWidget *advanced_expander; - GtkWidget *servers_entry; - GtkWidget *results_label; - - /* Parts page */ - GtkTreeView *parts_tree_view; - - /* Finish page */ - GtkWidget *display_name_entry; - GtkWidget *finish_running_box; - GtkWidget *finish_spinner; - GtkWidget *finish_label; - GtkWidget *finish_cancel_button; - GCancellable *finish_cancellable; -}; - -enum { - PROP_0, - PROP_REGISTRY, - PROP_CAN_RUN -}; - -enum { - DONE, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -G_DEFINE_TYPE (ECollectionAccountWizard, e_collection_account_wizard, GTK_TYPE_NOTEBOOK) - -enum { - PART_COLUMN_BOOL_ENABLED, /* G_TYPE_BOOLEAN */ - PART_COLUMN_BOOL_ENABLED_VISIBLE, /* G_TYPE_BOOLEAN */ - PART_COLUMN_BOOL_RADIO, /* G_TYPE_BOOLEAN */ - PART_COLUMN_BOOL_SENSITIVE, /* G_TYPE_BOOLEAN */ - PART_COLUMN_BOOL_IS_COLLECTION_GROUP, /* G_TYPE_BOOLEAN */ - PART_COLUMN_BOOL_ICON_VISIBLE, /* G_TYPE_BOOLEAN */ - PART_COLUMN_STRING_ICON_NAME, /* G_TYPE_STRING */ - PART_COLUMN_STRING_DESCRIPTION, /* G_TYPE_STRING */ - PART_COLUMN_STRING_PROTOCOL, /* G_TYPE_STRING */ - PART_COLUMN_OBJECT_RESULT, /* E_TYPE_CONFIG_LOOKUP_RESULT */ - PART_N_COLUMNS -}; - -typedef struct _WorkerData { - GtkWidget *enabled_check; - GtkWidget *running_box; - GtkWidget *spinner; - GtkWidget *running_label; - GtkWidget *cancel_button; - GCancellable *cancellable; - gulong status_id; - ENamedParameters *restart_params; - gchar *certificate_error; - gboolean remember_password; -} WorkerData; - -static void -worker_data_free (gpointer ptr) -{ - WorkerData *wd = ptr; - - if (wd) { - if (wd->cancellable) { - g_cancellable_cancel (wd->cancellable); - - if (wd->status_id) { - g_signal_handler_disconnect (wd->cancellable, wd->status_id); - wd->status_id = 0; - } - - g_clear_object (&wd->cancellable); - } - - g_clear_pointer (&wd->certificate_error, g_free); - g_clear_pointer (&wd->restart_params, e_named_parameters_free); - - g_free (wd); - } -} - -static void -collection_account_wizard_update_status_cb (CamelOperation *op, - const gchar *what, - gint pc, - gpointer user_data) -{ - GtkLabel *label = user_data; - - g_return_if_fail (GTK_IS_LABEL (label)); - - if (what) - gtk_label_set_label (label, what); -} - -static void -collection_account_wizard_notify_can_run (GObject *wizard) -{ - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - - g_object_notify (wizard, "can-run"); -} - -static void -collection_account_wizard_mark_changed (ECollectionAccountWizard *wizard) -{ - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - - wizard->priv->changed = TRUE; -} - -static void -collection_account_wizard_worker_cancel_clicked_cb (GtkWidget *button, - gpointer user_data) -{ - WorkerData *wd = user_data; - - g_return_if_fail (wd != NULL); - - if (wd->cancellable) - g_cancellable_cancel (wd->cancellable); -} - -static void -collection_account_wizard_worker_started_cb (EConfigLookup *config_lookup, - EConfigLookupWorker *worker, - GCancellable *cancellable, - gpointer user_data) -{ - ECollectionAccountWizard *wizard = user_data; - WorkerData *wd; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - - wd = g_hash_table_lookup (wizard->priv->workers, worker); - g_return_if_fail (wd != NULL); - - if (wizard->priv->changed) { - wizard->priv->changed = FALSE; - e_config_lookup_clear_results (wizard->priv->config_lookup); - } - - wizard->priv->running_workers++; - - g_warn_if_fail (wd->cancellable == NULL); - wd->cancellable = g_object_ref (cancellable); - - wd->status_id = 0; - if (CAMEL_IS_OPERATION (wd->cancellable)) { - wd->status_id = g_signal_connect (wd->cancellable, "status", - G_CALLBACK (collection_account_wizard_update_status_cb), wd->running_label); - } - - gtk_label_set_label (GTK_LABEL (wd->running_label), _("Looking up details, please wait…")); - e_spinner_start (E_SPINNER (wd->spinner)); - gtk_widget_show (wd->spinner); - gtk_widget_show (wd->cancel_button); - gtk_widget_show (wd->running_box); - - if (wizard->priv->running_workers == 1) { - GHashTableIter iter; - gpointer value; - - g_hash_table_iter_init (&iter, wizard->priv->workers); - while (g_hash_table_iter_next (&iter, NULL, &value)) { - WorkerData *wd2 = value; - - gtk_widget_set_sensitive (wd2->enabled_check, FALSE); - } - - g_object_notify (G_OBJECT (wizard), "can-run"); - - gtk_label_set_text (GTK_LABEL (wizard->priv->results_label), ""); - } -} - -static void -collection_account_wizard_worker_finished_cb (EConfigLookup *config_lookup, - EConfigLookupWorker *worker, - const ENamedParameters *restart_params, - const GError *error, - gpointer user_data) -{ - ECollectionAccountWizard *wizard = user_data; - WorkerData *wd; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - - wd = g_hash_table_lookup (wizard->priv->workers, worker); - g_return_if_fail (wd != NULL); - - wizard->priv->running_workers--; - - if (wd->status_id) { - g_signal_handler_disconnect (wd->cancellable, wd->status_id); - wd->status_id = 0; - } - g_clear_object (&wd->cancellable); - g_clear_pointer (&wd->certificate_error, g_free); - - e_spinner_stop (E_SPINNER (wd->spinner)); - gtk_widget_hide (wd->spinner); - gtk_widget_hide (wd->cancel_button); - - if (g_error_matches (error, E_CONFIG_LOOKUP_WORKER_ERROR, E_CONFIG_LOOKUP_WORKER_ERROR_REQUIRES_PASSWORD)) { - gchar *markup, *link; - - link = g_markup_printf_escaped ("%s", _("Enter password")); - - /* Translators: The %s is replaced with a clickable text "Enter password", thus it'll be "Requires password to continue. Enter password." at the end. */ - markup = g_strdup_printf (_("Requires password to continue. %s."), link); - - gtk_label_set_markup (GTK_LABEL (wd->running_label), markup); - - g_free (markup); - g_free (link); - } else if (g_error_matches (error, E_CONFIG_LOOKUP_WORKER_ERROR, E_CONFIG_LOOKUP_WORKER_ERROR_CERTIFICATE) && - restart_params && e_named_parameters_exists (restart_params, E_CONFIG_LOOKUP_PARAM_CERTIFICATE_PEM) && - e_named_parameters_exists (restart_params, E_CONFIG_LOOKUP_PARAM_CERTIFICATE_HOST)) { - gchar *markup, *link; - - wd->certificate_error = g_strdup (error->message); - - link = g_markup_printf_escaped ("%s", _("View certificate")); - - /* Translators: The first %s is replaced with actual error message about site certificate invalidity, - like "The signing certificate authority is not known.", the second %s is replaced with a link "View certificate". */ - markup = g_strdup_printf (C_("collection-account-wizard", "%s %s."), error->message, link); - - gtk_label_set_markup (GTK_LABEL (wd->running_label), markup); - - g_free (markup); - g_free (link); - } else if (error) { - gtk_label_set_text (GTK_LABEL (wd->running_label), error->message); - } else { - gtk_widget_hide (wd->running_box); - } - - e_named_parameters_free (wd->restart_params); - wd->restart_params = restart_params ? e_named_parameters_new_clone (restart_params) : NULL; - - if (!wizard->priv->running_workers) { - GHashTableIter iter; - gpointer value; - gint n_results; - gchar *str; - - g_hash_table_iter_init (&iter, wizard->priv->workers); - while (g_hash_table_iter_next (&iter, NULL, &value)) { - WorkerData *wd2 = value; - - gtk_widget_set_sensitive (wd2->enabled_check, TRUE); - } - - if (wizard->priv->running_result) { - e_simple_async_result_complete_idle (wizard->priv->running_result); - g_clear_object (&wizard->priv->running_result); - } - - g_object_notify (G_OBJECT (wizard), "can-run"); - - n_results = e_config_lookup_count_results (wizard->priv->config_lookup); - - if (!n_results) { - gtk_label_set_text (GTK_LABEL (wizard->priv->results_label), _("Found no candidates. It can also mean that the server doesn’t provide any information about its configuration using the selected lookup methods. Enter the account manually instead or change above settings.")); - } else { - str = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "Found one candidate", "Found %d candidates", n_results), n_results); - gtk_label_set_text (GTK_LABEL (wizard->priv->results_label), str); - g_free (str); - } - } -} - -typedef struct _PasswordPromptData { - ECollectionAccountWizard *wizard; - EConfigLookupWorker *worker; - GtkWidget *popover; - GtkWidget *password_entry; - GtkWidget *remember_check; -} PasswordPromptData; - -static PasswordPromptData * -password_prompt_data_new (ECollectionAccountWizard *wizard, - EConfigLookupWorker *worker, - GtkWidget *popover, - GtkWidget *password_entry, - GtkWidget *remember_check) -{ - PasswordPromptData *ppd; - - ppd = g_new0 (PasswordPromptData, 1); - ppd->wizard = wizard; - ppd->worker = worker; - ppd->popover = popover; - ppd->password_entry = password_entry; - ppd->remember_check = remember_check; - - return ppd; -} - -static void -password_prompt_data_free (gpointer data, - GClosure *closure) -{ - PasswordPromptData *ppd = data; - - if (ppd) { - /* Nothing to free inside the structure */ - g_free (ppd); - } -} - -static void -collection_account_wizard_try_again_clicked_cb (GtkButton *button, - gpointer user_data) -{ - PasswordPromptData *ppd = user_data; - ENamedParameters *params; - WorkerData *wd; - - g_return_if_fail (ppd != NULL); - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (ppd->wizard)); - g_return_if_fail (GTK_IS_ENTRY (ppd->password_entry)); - - wd = g_hash_table_lookup (ppd->wizard->priv->workers, ppd->worker); - g_return_if_fail (wd != NULL); - - params = e_named_parameters_new_clone (wd->restart_params); - g_return_if_fail (params != NULL); - - wd->remember_password = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ppd->remember_check)); - - e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_EMAIL_ADDRESS, gtk_entry_get_text (GTK_ENTRY (ppd->wizard->priv->email_entry))); - e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_SERVERS, gtk_entry_get_text (GTK_ENTRY (ppd->wizard->priv->servers_entry))); - e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_PASSWORD, gtk_entry_get_text (GTK_ENTRY (ppd->password_entry))); - e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_REMEMBER_PASSWORD, wd->remember_password ? "1" : NULL); - - e_config_lookup_run_worker (ppd->wizard->priv->config_lookup, ppd->worker, params, NULL); - - e_named_parameters_free (params); - - gtk_widget_hide (ppd->popover); -} - -static void -collection_account_wizard_show_password_prompt (ECollectionAccountWizard *wizard, - EConfigLookupWorker *worker, - WorkerData *wd) -{ - GtkWidget *widget, *label, *entry, *check, *button; - GtkGrid *grid; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - g_return_if_fail (E_IS_CONFIG_LOOKUP_WORKER (worker)); - g_return_if_fail (wd != NULL); - - widget = gtk_grid_new (); - grid = GTK_GRID (widget); - gtk_grid_set_column_spacing (grid, 6); - gtk_grid_set_row_spacing (grid, 6); - - widget = gtk_label_new_with_mnemonic (_("_Password:")); - gtk_widget_set_halign (widget, GTK_ALIGN_END); - gtk_grid_attach (grid, widget, 0, 0, 1, 1); - label = widget; - - widget = gtk_entry_new (); - gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget); - gtk_grid_attach (grid, widget, 1, 0, 1, 1); - entry = widget; - - widget = gtk_check_button_new_with_mnemonic (_("_Remember password")); - gtk_grid_attach (grid, widget, 0, 1, 2, 1); - check = widget; - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), wd->remember_password); - - widget = gtk_button_new_with_mnemonic (_("_Try Again")); - gtk_widget_set_halign (widget, GTK_ALIGN_END); - gtk_widget_set_can_default (widget, TRUE); - gtk_grid_attach (grid, widget, 0, 2, 2, 1); - button = widget; - - gtk_widget_show_all (GTK_WIDGET (grid)); - - widget = gtk_popover_new (wd->running_label); - gtk_popover_set_position (GTK_POPOVER (widget), GTK_POS_BOTTOM); - gtk_popover_set_default_widget (GTK_POPOVER (widget), button); - gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); - gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (grid)); - gtk_container_set_border_width (GTK_CONTAINER (widget), 6); - - g_signal_connect_data (button, "clicked", - G_CALLBACK (collection_account_wizard_try_again_clicked_cb), - password_prompt_data_new (wizard, worker, widget, entry, check), - password_prompt_data_free, 0); - - g_signal_connect (widget, "closed", - G_CALLBACK (gtk_widget_destroy), NULL); - - gtk_widget_show (widget); - - gtk_widget_grab_focus (entry); -} - -static void -collection_account_wizard_view_certificate (ECollectionAccountWizard *wizard, - EConfigLookupWorker *worker, - WorkerData *wd) -{ - ETrustPromptResponse response; - GtkWidget *toplevel; - GtkWindow *parent = NULL; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - g_return_if_fail (E_IS_CONFIG_LOOKUP_WORKER (worker)); - g_return_if_fail (wd != NULL); - g_return_if_fail (wd->restart_params != NULL); - g_return_if_fail (e_named_parameters_exists (wd->restart_params, E_CONFIG_LOOKUP_PARAM_CERTIFICATE_PEM)); - g_return_if_fail (e_named_parameters_exists (wd->restart_params, E_CONFIG_LOOKUP_PARAM_CERTIFICATE_HOST)); - - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (wizard)); - if (GTK_IS_WINDOW (toplevel)) - parent = GTK_WINDOW (toplevel); - - response = e_trust_prompt_run_modal (parent, NULL, NULL, - e_named_parameters_get (wd->restart_params, E_CONFIG_LOOKUP_PARAM_CERTIFICATE_HOST), - e_named_parameters_get (wd->restart_params, E_CONFIG_LOOKUP_PARAM_CERTIFICATE_PEM), - 0, wd->certificate_error); - - if (response != E_TRUST_PROMPT_RESPONSE_UNKNOWN) { - ENamedParameters *params; - - params = e_named_parameters_new_clone (wd->restart_params); - g_return_if_fail (params != NULL); - - e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_EMAIL_ADDRESS, gtk_entry_get_text (GTK_ENTRY (wizard->priv->email_entry))); - e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_SERVERS, gtk_entry_get_text (GTK_ENTRY (wizard->priv->servers_entry))); - e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_CERTIFICATE_TRUST, e_config_lookup_encode_certificate_trust (response)); - - e_config_lookup_run_worker (wizard->priv->config_lookup, worker, params, NULL); - - e_named_parameters_free (params); - } -} - -static gboolean -collection_account_wizard_activate_link_cb (GtkWidget *label, - const gchar *uri, - gpointer user_data) -{ - ECollectionAccountWizard *wizard = user_data; - EConfigLookupWorker *worker = NULL; - WorkerData *wd; - GHashTableIter iter; - gpointer key, value; - - g_return_val_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard), TRUE); - - g_hash_table_iter_init (&iter, wizard->priv->workers); - while (g_hash_table_iter_next (&iter, &key, &value)) { - worker = key; - wd = value; - - if (worker && wd && wd->running_label == label) - break; - - worker = NULL; - wd = NULL; - } - - if (worker && wd) { - if (g_strcmp0 (uri, "evo:enter-password") == 0) - collection_account_wizard_show_password_prompt (wizard, worker, wd); - else if (g_strcmp0 (uri, "evo:view-certificate") == 0) - collection_account_wizard_view_certificate (wizard, worker, wd); - else - g_warning ("%s: Do not know what to do with '%s'", G_STRFUNC, uri); - } - - return TRUE; -} - -static gboolean -collection_account_wizard_is_first_result_of_this_kind (GSList *known_results, - EConfigLookupResult *result) -{ - GSList *link; - gboolean known = FALSE; - - for (link = known_results; link && !known; link = g_slist_next (link)) { - EConfigLookupResult *result2 = link->data; - - if (!result2 || result2 == result) - continue; - - known = e_config_lookup_result_get_kind (result) == - e_config_lookup_result_get_kind (result2) && - g_strcmp0 (e_config_lookup_result_get_protocol (result), - e_config_lookup_result_get_protocol (result2)) == 0; - } - - return !known; -} - -static gboolean -collection_account_wizard_fill_results (ECollectionAccountWizard *wizard) -{ - struct _results_info { - EConfigLookupResultKind kind; - const gchar *display_name; - const gchar *icon_name; - GSList *results; /* EConfigLookupResult * */ - } results_info[] = { - { E_CONFIG_LOOKUP_RESULT_COLLECTION, N_("Collection"), "evolution", NULL }, - { E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE, N_("Mail Receive"), "evolution-mail", NULL }, - { E_CONFIG_LOOKUP_RESULT_MAIL_SEND, N_("Mail Send"), "mail-send", NULL }, - { E_CONFIG_LOOKUP_RESULT_ADDRESS_BOOK, N_("Address Book"), "x-office-address-book",NULL }, - { E_CONFIG_LOOKUP_RESULT_CALENDAR, N_("Calendar"), "x-office-calendar", NULL }, - { E_CONFIG_LOOKUP_RESULT_MEMO_LIST, N_("Memo List"), "evolution-memos", NULL }, - { E_CONFIG_LOOKUP_RESULT_TASK_LIST, N_("Task List"), "evolution-tasks", NULL } - }; - - GtkTreeStore *tree_store; - GtkTreeIter iter, parent; - gint ii; - gboolean found_any = FALSE; - - g_return_val_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard), FALSE); - - tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (wizard->priv->parts_tree_view)); - gtk_tree_store_clear (tree_store); - - for (ii = 0; ii < G_N_ELEMENTS (results_info); ii++) { - results_info[ii].results = e_config_lookup_dup_results (wizard->priv->config_lookup, results_info[ii].kind, NULL); - - if (results_info[ii].results) { - found_any = TRUE; - - results_info[ii].results = g_slist_sort (results_info[ii].results, e_config_lookup_result_compare); - } - } - - if (!found_any) - return FALSE; - - for (ii = 0; ii < G_N_ELEMENTS (results_info); ii++) { - GSList *results = results_info[ii].results, *link, *known_results = NULL, *klink; - gboolean is_collection_kind = results_info[ii].kind == E_CONFIG_LOOKUP_RESULT_COLLECTION; - GtkTreePath *path; - - /* Skip empty groups */ - if (!results) - continue; - - gtk_tree_store_append (tree_store, &parent, NULL); - gtk_tree_store_set (tree_store, &parent, - PART_COLUMN_BOOL_ENABLED, TRUE, - PART_COLUMN_BOOL_ENABLED_VISIBLE, TRUE, - PART_COLUMN_BOOL_RADIO, FALSE, - PART_COLUMN_BOOL_SENSITIVE, results != NULL, - PART_COLUMN_BOOL_IS_COLLECTION_GROUP, is_collection_kind, - PART_COLUMN_BOOL_ICON_VISIBLE, results_info[ii].icon_name != NULL, - PART_COLUMN_STRING_ICON_NAME, results_info[ii].icon_name, - PART_COLUMN_STRING_DESCRIPTION, _(results_info[ii].display_name), - -1); - - for (link = results; link; link = g_slist_next (link)) { - EConfigLookupResult *result = link->data; - const gchar *display_name, *description; - gchar *markup; - - if (!result) - continue; - - for (klink = known_results; klink; klink = g_slist_next (klink)) { - if (e_config_lookup_result_equal (result, klink->data)) - break; - } - - /* Found one such processed already. */ - if (klink) - continue; - - /* Just borrow it, no need to reference it. */ - known_results = g_slist_prepend (known_results, result); - - display_name = e_config_lookup_result_get_display_name (result); - description = e_config_lookup_result_get_description (result); - - if (description && *description) - markup = g_markup_printf_escaped ("%s\n%s", display_name, description); - else - markup = g_markup_printf_escaped ("%s", display_name); - - gtk_tree_store_append (tree_store, &iter, &parent); - gtk_tree_store_set (tree_store, &iter, - PART_COLUMN_BOOL_ENABLED, link == results || (is_collection_kind && collection_account_wizard_is_first_result_of_this_kind (known_results, result)), - PART_COLUMN_BOOL_ENABLED_VISIBLE, g_slist_next (results) != NULL, - PART_COLUMN_BOOL_RADIO, !is_collection_kind, - PART_COLUMN_BOOL_SENSITIVE, TRUE, - PART_COLUMN_BOOL_ICON_VISIBLE, NULL, - PART_COLUMN_STRING_ICON_NAME, NULL, - PART_COLUMN_STRING_DESCRIPTION, markup, - PART_COLUMN_STRING_PROTOCOL, e_config_lookup_result_get_protocol (result), - PART_COLUMN_OBJECT_RESULT, result, - -1); - - g_free (markup); - } - - g_slist_free (known_results); - - path = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_store), &parent); - if (path) { - gtk_tree_view_expand_to_path (wizard->priv->parts_tree_view, path); - gtk_tree_path_free (path); - } - } - - for (ii = 0; ii < G_N_ELEMENTS (results_info); ii++) { - g_slist_free_full (results_info[ii].results, g_object_unref); - results_info[ii].results = NULL; - } - - return TRUE; -} - -static void -collection_account_wizard_part_enabled_toggled_cb (GtkCellRendererToggle *cell_renderer, - const gchar *path_string, - gpointer user_data) -{ - ECollectionAccountWizard *wizard = user_data; - GtkTreeStore *tree_store; - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter, parent, child; - EConfigLookupResult *src_result = NULL, *cur_result = NULL; - gboolean set_enabled, is_radio = FALSE; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - - model = gtk_tree_view_get_model (wizard->priv->parts_tree_view); - tree_store = GTK_TREE_STORE (model); - - path = gtk_tree_path_new_from_string (path_string); - if (!gtk_tree_model_get_iter (model, &child, path)) { - g_warn_if_reached (); - gtk_tree_path_free (path); - - return; - } - - gtk_tree_path_free (path); - - set_enabled = !gtk_cell_renderer_toggle_get_active (cell_renderer); - - gtk_tree_model_get (model, &child, - PART_COLUMN_BOOL_RADIO, &is_radio, - PART_COLUMN_OBJECT_RESULT, &src_result, - -1); - - /* Reflect the change for other radio-s in this level */ - if (is_radio) { - GtkTreeIter sibling = child; - - iter = child; - - /* Move to the first sibling */ - if (gtk_tree_model_iter_parent (model, &parent, &child) && - gtk_tree_model_iter_nth_child (model, &iter, &parent, 0)) { - sibling = iter; - } else { - while (gtk_tree_model_iter_previous (model, &iter)) - sibling = iter; - } - - do { - is_radio = FALSE; - - gtk_tree_model_get (model, &sibling, - PART_COLUMN_BOOL_RADIO, &is_radio, - PART_COLUMN_OBJECT_RESULT, &cur_result, - -1); - - if (is_radio) { - gtk_tree_store_set (tree_store, &sibling, - PART_COLUMN_BOOL_ENABLED, cur_result == src_result, - -1); - } - - g_clear_object (&cur_result); - } while (gtk_tree_model_iter_next (model, &sibling)); - } else { - gtk_tree_store_set (tree_store, &child, - PART_COLUMN_BOOL_ENABLED, set_enabled, - -1); - } - - /* De/sensitize children of the group nodes */ - if (!gtk_tree_model_iter_parent (model, &parent, &child) && - gtk_tree_model_iter_nth_child (model, &iter, &child, 0)) { - do { - gtk_tree_store_set (tree_store, &iter, - PART_COLUMN_BOOL_SENSITIVE, set_enabled, - -1); - } while (gtk_tree_model_iter_next (model, &iter)); - } - - g_clear_object (&src_result); - - if (!is_radio) - g_object_notify (G_OBJECT (wizard), "can-run"); -} - -static ESource * -collection_account_wizard_create_child_source (ECollectionAccountWizard *wizard, - const gchar *add_extension_name) -{ - ESource *source; - - g_return_val_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard), NULL); - g_return_val_if_fail (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION] != NULL, NULL); - - source = e_source_new (NULL, NULL, NULL); - - e_source_set_parent (source, e_source_get_uid (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION])); - - if (add_extension_name) - e_source_get_extension (source, add_extension_name); - - return source; -} - -static ESource * -collection_account_wizard_get_source (ECollectionAccountWizard *wizard, - EConfigLookupResultKind kind) -{ - ESource *source = NULL; - const gchar *extension_name = NULL; - - g_return_val_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard), NULL); - - switch (kind) { - case E_CONFIG_LOOKUP_RESULT_COLLECTION: - source = wizard->priv->sources[kind]; - g_warn_if_fail (source != NULL); - break; - case E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE: - extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; - break; - case FAKE_E_CONFIG_LOOKUP_RESULT_MAIL_IDENTITY: /* E_CONFIG_LOOKUP_RESULT_UNKNOWN */ - extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; - break; - case E_CONFIG_LOOKUP_RESULT_MAIL_SEND: - extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT; - break; - case E_CONFIG_LOOKUP_RESULT_ADDRESS_BOOK: - extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK; - break; - case E_CONFIG_LOOKUP_RESULT_CALENDAR: - extension_name = E_SOURCE_EXTENSION_CALENDAR; - break; - case E_CONFIG_LOOKUP_RESULT_MEMO_LIST: - extension_name = E_SOURCE_EXTENSION_MEMO_LIST; - break; - case E_CONFIG_LOOKUP_RESULT_TASK_LIST: - extension_name = E_SOURCE_EXTENSION_TASK_LIST; - break; - } - - g_return_val_if_fail (kind >= 0 && kind <= E_CONFIG_LOOKUP_RESULT_LAST_KIND, NULL); - - source = wizard->priv->sources[kind]; - - if (!source && kind != E_CONFIG_LOOKUP_RESULT_COLLECTION) { - source = collection_account_wizard_create_child_source (wizard, extension_name); - wizard->priv->sources[kind] = source; - } - - return source; -} - -static ESource * -collection_account_wizard_get_source_cb (ECollectionAccountWizard *wizard, - EConfigLookupSourceKind kind) -{ - ESource *source = NULL; - - g_return_val_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard), NULL); - - switch (kind) { - case E_CONFIG_LOOKUP_SOURCE_UNKNOWN: - break; - case E_CONFIG_LOOKUP_SOURCE_COLLECTION: - source = collection_account_wizard_get_source (wizard, E_CONFIG_LOOKUP_RESULT_COLLECTION); - break; - case E_CONFIG_LOOKUP_SOURCE_MAIL_ACCOUNT: - source = collection_account_wizard_get_source (wizard, E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE); - break; - case E_CONFIG_LOOKUP_SOURCE_MAIL_IDENTITY: - source = collection_account_wizard_get_source (wizard, FAKE_E_CONFIG_LOOKUP_RESULT_MAIL_IDENTITY); - break; - case E_CONFIG_LOOKUP_SOURCE_MAIL_TRANSPORT: - source = collection_account_wizard_get_source (wizard, E_CONFIG_LOOKUP_RESULT_MAIL_SEND); - break; - } - - return source; -} - -static gboolean -collection_account_wizard_host_is_google_server (const gchar *host) -{ - if (!host || !*host) - return FALSE; - - return camel_strstrcase (host, "gmail.com") || - camel_strstrcase (host, "googlemail.com") || - camel_strstrcase (host, "google.com") || - camel_strstrcase (host, "googleusercontent.com"); -} - -static void -collection_account_wizard_write_changes_thread (ESimpleAsyncResult *result, - gpointer source_object, - GCancellable *cancellable) -{ - ECollectionAccountWizard *wizard = source_object; - ESourceCollection *collection_extension; - ESource *source; - gint ii; - const gchar *text; - GList *sources = NULL; - gboolean google_supported, any_is_google = FALSE; - GError *local_error = NULL; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - - /* Deal with LDAP addressbook first */ - source = wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_ADDRESS_BOOK]; - if (source && - e_source_has_extension (source, E_SOURCE_EXTENSION_LDAP_BACKEND) && - e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) { - ESourceAuthentication *auth_extension; - ESourceLDAP *ldap_extension; - const gchar *root_dn; - - auth_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); - ldap_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_LDAP_BACKEND); - root_dn = e_source_ldap_get_root_dn (ldap_extension); - - if (!root_dn || !*root_dn) { - gchar **root_dse = NULL; - - camel_operation_push_message (cancellable, "%s", _("Looking up LDAP server’s search base…")); - - if (e_util_query_ldap_root_dse_sync ( - e_source_authentication_get_host (auth_extension), - e_source_authentication_get_port (auth_extension), - &root_dse, cancellable, NULL)) { - if (root_dse && root_dse[0]) - e_source_ldap_set_root_dn (ldap_extension, root_dse[0]); - - g_strfreev (root_dse); - } - - camel_operation_pop_message (cancellable); - } - } - - if (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE]) { - ESourceMailAccount *mail_account_extension; - ESourceMailIdentity *mail_identity_extension; - ESourceMailTransport *mail_transport_extension; - ESourceMailSubmission *mail_submission_extension; - - mail_account_extension = e_source_get_extension (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE], E_SOURCE_EXTENSION_MAIL_ACCOUNT); - e_source_mail_account_set_identity_uid (mail_account_extension, e_source_get_uid (wizard->priv->sources[FAKE_E_CONFIG_LOOKUP_RESULT_MAIL_IDENTITY])); - - text = e_source_backend_get_backend_name (E_SOURCE_BACKEND (mail_account_extension)); - if (!text || !*text) - e_source_backend_set_backend_name (E_SOURCE_BACKEND (mail_account_extension), "none"); - - mail_identity_extension = e_source_get_extension (wizard->priv->sources[FAKE_E_CONFIG_LOOKUP_RESULT_MAIL_IDENTITY], E_SOURCE_EXTENSION_MAIL_IDENTITY); - text = e_source_mail_identity_get_name (mail_identity_extension); - if (!text || !*text) - e_source_mail_identity_set_name (mail_identity_extension, g_get_real_name ()); - - mail_submission_extension = e_source_get_extension (wizard->priv->sources[FAKE_E_CONFIG_LOOKUP_RESULT_MAIL_IDENTITY], E_SOURCE_EXTENSION_MAIL_SUBMISSION); - e_source_mail_submission_set_transport_uid (mail_submission_extension, e_source_get_uid (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_MAIL_SEND])); - - mail_transport_extension = e_source_get_extension (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_MAIL_SEND], E_SOURCE_EXTENSION_MAIL_TRANSPORT); - - text = e_source_backend_get_backend_name (E_SOURCE_BACKEND (mail_transport_extension)); - if (!text || !*text) - e_source_backend_set_backend_name (E_SOURCE_BACKEND (mail_transport_extension), "none"); - } - - if (!e_source_has_extension (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION], E_SOURCE_EXTENSION_AUTHENTICATION)) { - /* Make sure the collection source has the Authentication extension, - thus the credentials can be reused. It's fine when the extension - doesn't have set values. */ - e_source_get_extension (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION], E_SOURCE_EXTENSION_AUTHENTICATION); - } - - collection_extension = e_source_get_extension (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION], E_SOURCE_EXTENSION_COLLECTION); - - /* Collections with empty backend-name are skipped by ESourceRegistry */ - text = e_source_backend_get_backend_name (E_SOURCE_BACKEND (collection_extension)); - if (!text || !*text) - e_source_backend_set_backend_name (E_SOURCE_BACKEND (collection_extension), "none"); - - google_supported = e_oauth2_services_is_oauth2_alias (e_source_registry_get_oauth2_services (wizard->priv->registry), "Google"); - - for (ii = 0; ii <= E_CONFIG_LOOKUP_RESULT_LAST_KIND; ii++) { - source = wizard->priv->sources[ii]; - - if (!source) - continue; - - /* This is not great, to special-case the Google server, but there's nothing - better at the moment and it's the only OAuth2 right now anyway. */ - if (google_supported && ii != E_CONFIG_LOOKUP_RESULT_COLLECTION && - e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) { - ESourceAuthentication *authentication_extension; - - authentication_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); - if (collection_account_wizard_host_is_google_server (e_source_authentication_get_host (authentication_extension))) { - any_is_google = TRUE; - e_source_authentication_set_method (authentication_extension, "Google"); - } - } - - sources = g_list_prepend (sources, source); - } - - source = wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION]; - /* It is always true, but have the variables local in this place only */ - if (source) { - ESourceAuthentication *authentication_extension; - ESourceCollection *collection_extension; - const gchar *host; - - authentication_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); - collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION); - - host = e_source_collection_get_calendar_url (collection_extension); - if (collection_account_wizard_host_is_google_server (host)) { - any_is_google = TRUE; - if (strstr (host, "calendar.google.com")) { - e_source_backend_set_backend_name (E_SOURCE_BACKEND (collection_extension), "webdav"); - - if (google_supported) - e_source_collection_set_calendar_url (collection_extension, "https://apidata.googleusercontent.com/caldav/v2/"); - else - e_source_collection_set_calendar_url (collection_extension, "https://www.google.com/calendar/dav/"); - } - } - - if (any_is_google && google_supported) { - e_source_authentication_set_method (authentication_extension, "Google"); - e_source_backend_set_backend_name (E_SOURCE_BACKEND (collection_extension), "google"); - } - } - - /* First store passwords, thus the evolution-source-registry has them ready if needed. */ - if (g_hash_table_size (wizard->priv->store_passwords) > 0) { - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init (&iter, wizard->priv->store_passwords); - while (g_hash_table_iter_next (&iter, &key, &value)) { - const gchar *uid = key, *password = value; - - if (uid && *uid && password && *password) { - source = NULL; - - for (ii = 0; ii <= E_CONFIG_LOOKUP_RESULT_LAST_KIND; ii++) { - source = wizard->priv->sources[ii]; - - if (source && g_strcmp0 (uid, e_source_get_uid (source)) == 0) - break; - - source = NULL; - } - - if (source && !e_source_store_password_sync (source, password, TRUE, cancellable, &local_error)) { - e_simple_async_result_set_user_data (result, local_error, (GDestroyNotify) g_error_free); - break; - } - } - } - } - - if (!e_simple_async_result_get_user_data (result) && /* No error from password save */ - !e_source_registry_create_sources_sync (wizard->priv->registry, sources, cancellable, &local_error) && local_error) { - e_simple_async_result_set_user_data (result, local_error, (GDestroyNotify) g_error_free); - } - - g_list_free (sources); -} - -static void -collection_account_wizard_write_changes_done (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - ECollectionAccountWizard *wizard; - const GError *error; - gboolean is_cancelled = FALSE; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (source_object)); - - wizard = E_COLLECTION_ACCOUNT_WIZARD (source_object); - - g_clear_object (&wizard->priv->finish_cancellable); - g_hash_table_remove_all (wizard->priv->store_passwords); - - error = e_simple_async_result_get_user_data (E_SIMPLE_ASYNC_RESULT (result)); - if (error) { - is_cancelled = g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); - - gtk_label_set_text (GTK_LABEL (wizard->priv->finish_label), error->message); - } - - e_spinner_stop (E_SPINNER (wizard->priv->finish_spinner)); - - gtk_widget_set_visible (wizard->priv->finish_running_box, error && !is_cancelled); - gtk_widget_set_visible (wizard->priv->finish_spinner, FALSE); - gtk_widget_set_visible (wizard->priv->finish_label, !is_cancelled); - gtk_widget_set_visible (wizard->priv->finish_cancel_button, FALSE); - - g_object_notify (source_object, "can-run"); - - if (!error) { - ESource *source = wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION]; - - g_warn_if_fail (source != NULL); - - g_signal_emit (wizard, signals[DONE], 0, e_source_get_uid (source)); - } -} - -static void -collection_account_wizard_save_sources (ECollectionAccountWizard *wizard) -{ - GtkTreeModel *model; - GtkTreeIter iter; - ESimpleAsyncResult *simple_result; - ESource *source; - const gchar *display_name; - gint ii; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - - g_hash_table_remove_all (wizard->priv->store_passwords); - - model = gtk_tree_view_get_model (wizard->priv->parts_tree_view); - if (gtk_tree_model_get_iter_first (model, &iter)) { - do { - gboolean enabled = FALSE; - - gtk_tree_model_get (model, &iter, - PART_COLUMN_BOOL_ENABLED, &enabled, - -1); - - if (enabled) { - GtkTreeIter child; - - if (gtk_tree_model_iter_nth_child (model, &child, &iter, 0)) { - do { - enabled = FALSE; - - gtk_tree_model_get (model, &child, - PART_COLUMN_BOOL_ENABLED, &enabled, - -1); - - if (enabled) { - EConfigLookupResult *lookup_result = NULL; - - gtk_tree_model_get (model, &child, - PART_COLUMN_OBJECT_RESULT, &lookup_result, - -1); - - if (lookup_result) { - source = collection_account_wizard_get_source (wizard, e_config_lookup_result_get_kind (lookup_result)); - if (source) { - g_warn_if_fail (e_config_lookup_result_configure_source (lookup_result, wizard->priv->config_lookup, source)); - - if (e_config_lookup_result_get_password (lookup_result)) { - g_hash_table_insert (wizard->priv->store_passwords, e_source_dup_uid (source), - g_strdup (e_config_lookup_result_get_password (lookup_result))); - } - } - - g_clear_object (&lookup_result); - } - } - } while (gtk_tree_model_iter_next (model, &child)); - } - } - } while (gtk_tree_model_iter_next (model, &iter)); - } - - display_name = gtk_entry_get_text (GTK_ENTRY (wizard->priv->display_name_entry)); - - if (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE] || - wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_MAIL_SEND]) { - ESourceMailIdentity *identity_extension; - - /* Ensure all three exist */ - collection_account_wizard_get_source (wizard, E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE); - collection_account_wizard_get_source (wizard, E_CONFIG_LOOKUP_RESULT_MAIL_SEND); - - source = collection_account_wizard_get_source (wizard, FAKE_E_CONFIG_LOOKUP_RESULT_MAIL_IDENTITY); - identity_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_IDENTITY); - e_source_mail_identity_set_address (identity_extension, gtk_entry_get_text (GTK_ENTRY (wizard->priv->email_entry))); - } else { - g_clear_object (&wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE]); - g_clear_object (&wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_MAIL_SEND]); - g_clear_object (&wizard->priv->sources[FAKE_E_CONFIG_LOOKUP_RESULT_MAIL_IDENTITY]); - } - - for (ii = 0; ii <= E_CONFIG_LOOKUP_RESULT_LAST_KIND; ii++) { - source = wizard->priv->sources[ii]; - - if (source) { - if (ii == E_CONFIG_LOOKUP_RESULT_COLLECTION) { - ESourceAuthentication *authentication_extension; - ESourceCollection *collection_extension; - const gchar *user; - - authentication_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION); - collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION); - user = gtk_entry_get_text (GTK_ENTRY (wizard->priv->email_entry)); - - if (!e_source_authentication_get_user (authentication_extension)) - e_source_authentication_set_user (authentication_extension, user); - - if (!e_source_collection_get_identity (collection_extension)) - e_source_collection_set_identity (collection_extension, user); - } else { - e_source_set_parent (source, e_source_get_uid (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION])); - } - - e_source_set_display_name (source, display_name); - } - } - - g_warn_if_fail (wizard->priv->finish_cancellable == NULL); - - gtk_label_set_text (GTK_LABEL (wizard->priv->finish_label), _("Saving account settings, please wait…")); - gtk_widget_show (wizard->priv->finish_spinner); - gtk_widget_show (wizard->priv->finish_label); - gtk_widget_show (wizard->priv->finish_cancel_button); - gtk_widget_show (wizard->priv->finish_running_box); - - e_spinner_start (E_SPINNER (wizard->priv->finish_spinner)); - - wizard->priv->finish_cancellable = camel_operation_new (); - - g_signal_connect (wizard->priv->finish_cancellable, "status", - G_CALLBACK (collection_account_wizard_update_status_cb), wizard->priv->finish_label); - - simple_result = e_simple_async_result_new (G_OBJECT (wizard), - collection_account_wizard_write_changes_done, NULL, - collection_account_wizard_write_changes_done); - - e_simple_async_result_run_in_thread (simple_result, G_PRIORITY_HIGH_IDLE, - collection_account_wizard_write_changes_thread, wizard->priv->finish_cancellable); - - g_object_unref (simple_result); - - g_object_notify (G_OBJECT (wizard), "can-run"); -} - -static void -collection_account_wizard_finish_cancel_clicked_cb (GtkButton *button, - gpointer user_data) -{ - ECollectionAccountWizard *wizard = user_data; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - - if (wizard->priv->finish_cancellable) - g_cancellable_cancel (wizard->priv->finish_cancellable); -} - -static void -collection_account_wizard_set_registry (ECollectionAccountWizard *wizard, - ESourceRegistry *registry) -{ - g_return_if_fail (E_IS_SOURCE_REGISTRY (registry)); - g_return_if_fail (wizard->priv->registry == NULL); - - wizard->priv->registry = g_object_ref (registry); -} - -static void -collection_account_wizard_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_REGISTRY: - collection_account_wizard_set_registry ( - E_COLLECTION_ACCOUNT_WIZARD (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -collection_account_wizard_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_CAN_RUN: - g_value_set_boolean ( - value, - e_collection_account_wizard_get_can_run ( - E_COLLECTION_ACCOUNT_WIZARD (object))); - return; - - case PROP_REGISTRY: - g_value_set_object ( - value, - e_collection_account_wizard_get_registry ( - E_COLLECTION_ACCOUNT_WIZARD (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -collection_account_wizard_constructed (GObject *object) -{ - ECollectionAccountWizard *wizard = E_COLLECTION_ACCOUNT_WIZARD (object); - GtkBox *hbox, *vbox; - GtkGrid *grid; - GtkWidget *label, *widget, *expander, *scrolled_window; - GtkTreeStore *tree_store; - GSList *workers, *link; - GtkTreeViewColumn *column; - GtkCellRenderer *cell_renderer; - gchar *markup; - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_collection_account_wizard_parent_class)->constructed (object); - - g_object_set (object, - "show-border", FALSE, - "show-tabs", FALSE, - NULL); - - wizard->priv->config_lookup = e_config_lookup_new (wizard->priv->registry); - - g_signal_connect_swapped (wizard->priv->config_lookup, "get-source", - G_CALLBACK (collection_account_wizard_get_source_cb), wizard); - - g_signal_connect (wizard->priv->config_lookup, "worker-started", - G_CALLBACK (collection_account_wizard_worker_started_cb), wizard); - - g_signal_connect (wizard->priv->config_lookup, "worker-finished", - G_CALLBACK (collection_account_wizard_worker_finished_cb), wizard); - - /* Lookup page */ - - vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6)); - g_object_set (G_OBJECT (vbox), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", TRUE, - "valign", GTK_ALIGN_FILL, - "visible", TRUE, - NULL); - - grid = GTK_GRID (gtk_grid_new ()); - g_object_set (G_OBJECT (grid), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", TRUE, - "valign", GTK_ALIGN_FILL, - "visible", TRUE, - "border-width", 12, - "row-spacing", 6, - "column-spacing", 6, - NULL); - - widget = gtk_frame_new (_("User details")); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_CENTER, - "vexpand", FALSE, - "valign", GTK_ALIGN_START, - "visible", TRUE, - NULL); - - gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (grid)); - - gtk_box_pack_start (vbox, widget, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic (_("_Email Address or User name:")); - g_object_set (G_OBJECT (label), - "hexpand", FALSE, - "halign", GTK_ALIGN_END, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", TRUE, - NULL); - - widget = gtk_entry_new (); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", TRUE, - NULL); - wizard->priv->email_entry = widget; - - gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget); - - gtk_grid_attach (grid, label, 0, 0, 1, 1); - gtk_grid_attach (grid, widget, 1, 0, 1, 1); - - g_signal_connect_swapped (wizard->priv->email_entry, "changed", - G_CALLBACK (collection_account_wizard_notify_can_run), wizard); - - g_signal_connect_swapped (wizard->priv->email_entry, "changed", - G_CALLBACK (collection_account_wizard_mark_changed), wizard); - - expander = gtk_expander_new_with_mnemonic (_("_Advanced Options")); - gtk_widget_show (expander); - wizard->priv->advanced_expander = expander; - gtk_grid_attach (grid, expander, 0, 1, 2, 1); - - label = gtk_label_new_with_mnemonic (_("_Server:")); - g_object_set (G_OBJECT (label), - "hexpand", FALSE, - "halign", GTK_ALIGN_END, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", FALSE, - NULL); - - widget = gtk_entry_new (); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", FALSE, - NULL); - wizard->priv->servers_entry = widget; - gtk_widget_set_tooltip_text (widget, _("Semicolon (“;”) separated list of servers to look up information for, in addition to the domain of the e-mail address.")); - - g_signal_connect_swapped (wizard->priv->servers_entry, "changed", - G_CALLBACK (collection_account_wizard_mark_changed), wizard); - - gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget); - - gtk_grid_attach (grid, label, 0, 2, 1, 1); - gtk_grid_attach (grid, widget, 1, 2, 1, 1); - - e_binding_bind_property (expander, "expanded", label, "visible", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); - e_binding_bind_property (expander, "expanded", widget, "visible", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); - - widget = gtk_scrolled_window_new (NULL, NULL); - g_object_set (G_OBJECT (widget), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", TRUE, - "valign", GTK_ALIGN_FILL, - "visible", TRUE, - "hscrollbar-policy", GTK_POLICY_AUTOMATIC, - "vscrollbar-policy", GTK_POLICY_AUTOMATIC, - NULL); - - gtk_box_pack_start (vbox, widget, TRUE, TRUE, 0); - - label = gtk_label_new (""); - g_object_set (G_OBJECT (label), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "margin-start", 12, - "margin-top", 12, - "visible", TRUE, - "max-width-chars", 120, - "wrap", TRUE, - NULL); - - gtk_box_pack_start (vbox, label, FALSE, FALSE, 0); - - wizard->priv->results_label = label; - - gtk_notebook_append_page (GTK_NOTEBOOK (wizard), GTK_WIDGET (vbox), NULL); - - vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 4)); - g_object_set (G_OBJECT (vbox), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", FALSE, - "valign", GTK_ALIGN_START, - "visible", TRUE, - NULL); - - gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (vbox)); - - workers = e_config_lookup_dup_registered_workers (wizard->priv->config_lookup); - - for (link = workers; link; link = g_slist_next (link)) { - EConfigLookupWorker *worker = link->data; - WorkerData *wd; - - if (!worker) - continue; - - wd = g_new0 (WorkerData, 1); - wd->remember_password = TRUE; - - widget = gtk_check_button_new_with_label (e_config_lookup_worker_get_display_name (worker)); - g_object_set (G_OBJECT (widget), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "margin-start", 12, - "visible", TRUE, - "active", TRUE, - NULL); - wd->enabled_check = widget; - - g_signal_connect_swapped (wd->enabled_check, "toggled", - G_CALLBACK (collection_account_wizard_notify_can_run), wizard); - - g_signal_connect_swapped (wd->enabled_check, "toggled", - G_CALLBACK (collection_account_wizard_mark_changed), wizard); - - gtk_box_pack_start (vbox, widget, TRUE, TRUE, 0); - - widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_START, - "margin-start", 12, - "visible", TRUE, - NULL); - gtk_box_pack_start (vbox, widget, TRUE, TRUE, 0); - - e_binding_bind_property (wd->enabled_check, "active", widget, "visible", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); - - hbox = GTK_BOX (widget); - - /* spacer */ - widget = gtk_label_new (""); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_START, - "margin-start", 12, - "visible", TRUE, - NULL); - gtk_box_pack_start (hbox, widget, FALSE, FALSE, 0); - - widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_START, - "margin-start", 12, - "visible", FALSE, - NULL); - wd->running_box = widget; - - gtk_box_pack_start (hbox, widget, TRUE, TRUE, 0); - - hbox = GTK_BOX (widget); - - widget = e_spinner_new (); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", TRUE, - NULL); - wd->spinner = widget; - - gtk_box_pack_start (hbox, widget, FALSE, FALSE, 0); - - label = gtk_label_new (NULL); - g_object_set (G_OBJECT (label), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", TRUE, - "ellipsize", PANGO_ELLIPSIZE_END, - NULL); - wd->running_label = label; - - gtk_box_pack_start (hbox, label, FALSE, FALSE, 0); - - g_signal_connect (wd->running_label, "activate-link", - G_CALLBACK (collection_account_wizard_activate_link_cb), wizard); - - e_binding_bind_property (wd->enabled_check, "sensitive", wd->running_label, "sensitive", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); - - widget = e_dialog_button_new_with_icon ("process-stop", _("_Cancel")); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", TRUE, - NULL); - wd->cancel_button = widget; - - g_signal_connect (wd->cancel_button, "clicked", - G_CALLBACK (collection_account_wizard_worker_cancel_clicked_cb), wd); - - gtk_box_pack_start (hbox, widget, FALSE, FALSE, 0); - - g_hash_table_insert (wizard->priv->workers, g_object_ref (worker), wd); - } - - g_slist_free_full (workers, g_object_unref); - - /* Parts page */ - - vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6)); - g_object_set (G_OBJECT (vbox), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", TRUE, - "valign", GTK_ALIGN_FILL, - "visible", TRUE, - "margin-bottom", 12, - NULL); - - label = gtk_label_new (_("Select which parts should be configured:")); - g_object_set (G_OBJECT (label), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", TRUE, - NULL); - - gtk_box_pack_start (vbox, label, FALSE, FALSE, 0); - - widget = gtk_scrolled_window_new (NULL, NULL); - g_object_set (G_OBJECT (widget), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", TRUE, - "valign", GTK_ALIGN_FILL, - "visible", TRUE, - "margin-bottom", TRUE, - "hscrollbar-policy", GTK_POLICY_AUTOMATIC, - "vscrollbar-policy", GTK_POLICY_AUTOMATIC, - NULL); - - scrolled_window = widget; - - gtk_box_pack_start (vbox, widget, TRUE, TRUE, 0); - - tree_store = gtk_tree_store_new (PART_N_COLUMNS, - G_TYPE_BOOLEAN, /* PART_COLUMN_BOOL_ENABLED */ - G_TYPE_BOOLEAN, /* PART_COLUMN_BOOL_ENABLED_VISIBLE */ - G_TYPE_BOOLEAN, /* PART_COLUMN_BOOL_RADIO */ - G_TYPE_BOOLEAN, /* PART_COLUMN_BOOL_SENSITIVE */ - G_TYPE_BOOLEAN, /* PART_COLUMN_BOOL_IS_COLLECTION_GROUP */ - G_TYPE_BOOLEAN, /* PART_COLUMN_BOOL_ICON_VISIBLE */ - G_TYPE_STRING, /* PART_COLUMN_STRING_ICON_NAME */ - G_TYPE_STRING, /* PART_COLUMN_STRING_DESCRIPTION */ - G_TYPE_STRING, /* PART_COLUMN_STRING_PROTOCOL */ - E_TYPE_CONFIG_LOOKUP_RESULT); /* PART_COLUMN_OBJECT_RESULT */ - - widget = gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store)); - g_object_set (G_OBJECT (widget), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", TRUE, - "valign", GTK_ALIGN_FILL, - "visible", TRUE, - NULL); - g_object_unref (tree_store); - wizard->priv->parts_tree_view = GTK_TREE_VIEW (widget); - - gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget); - - gtk_container_add (GTK_CONTAINER (scrolled_window), widget); - - gtk_notebook_append_page (GTK_NOTEBOOK (wizard), GTK_WIDGET (vbox), NULL); - - /* Column: Description */ - - column = gtk_tree_view_column_new (); - gtk_tree_view_column_set_expand (column, TRUE); - gtk_tree_view_column_set_title (column, _("Description")); - - cell_renderer = gtk_cell_renderer_toggle_new (); - gtk_tree_view_column_pack_start (column, cell_renderer, FALSE); - - g_signal_connect (cell_renderer, "toggled", - G_CALLBACK (collection_account_wizard_part_enabled_toggled_cb), wizard); - - gtk_tree_view_column_set_attributes (column, cell_renderer, - "sensitive", PART_COLUMN_BOOL_SENSITIVE, - "active", PART_COLUMN_BOOL_ENABLED, - "visible", PART_COLUMN_BOOL_ENABLED_VISIBLE, - "radio", PART_COLUMN_BOOL_RADIO, - NULL); - - cell_renderer = gtk_cell_renderer_pixbuf_new (); - g_object_set (cell_renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL); - gtk_tree_view_column_pack_start (column, cell_renderer, FALSE); - - gtk_tree_view_column_set_attributes (column, cell_renderer, - "sensitive", PART_COLUMN_BOOL_SENSITIVE, - "icon-name", PART_COLUMN_STRING_ICON_NAME, - "visible", PART_COLUMN_BOOL_ICON_VISIBLE, - NULL); - - cell_renderer = gtk_cell_renderer_text_new (); - g_object_set (cell_renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); - gtk_tree_view_column_pack_start (column, cell_renderer, FALSE); - - gtk_tree_view_column_set_attributes (column, cell_renderer, - "sensitive", PART_COLUMN_BOOL_SENSITIVE, - "markup", PART_COLUMN_STRING_DESCRIPTION, - NULL); - - gtk_tree_view_append_column (wizard->priv->parts_tree_view, column); - gtk_tree_view_set_expander_column (wizard->priv->parts_tree_view, column); - - /* Column: Type */ - - column = gtk_tree_view_column_new (); - gtk_tree_view_column_set_expand (column, FALSE); - gtk_tree_view_column_set_title (column, _("Type")); - - cell_renderer = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (column, cell_renderer, TRUE); - - gtk_tree_view_column_set_attributes (column, cell_renderer, - "sensitive", PART_COLUMN_BOOL_SENSITIVE, - "text", PART_COLUMN_STRING_PROTOCOL, - NULL); - - gtk_tree_view_append_column (wizard->priv->parts_tree_view, column); - - /* Finish page */ - - grid = GTK_GRID (gtk_grid_new ()); - g_object_set (G_OBJECT (grid), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", TRUE, - "valign", GTK_ALIGN_FILL, - "visible", TRUE, - "column-spacing", 4, - NULL); - markup = g_markup_printf_escaped ("%s", _("Account Information")); - widget = gtk_label_new (markup); - gtk_label_set_use_markup (GTK_LABEL (widget), TRUE); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_widget_set_margin_bottom (widget, 12); - gtk_grid_attach (grid, widget, 0, 0, 2, 1); - gtk_widget_show (widget); - g_free (markup); - - label = gtk_label_new_with_mnemonic (_("_Name:")); - gtk_widget_set_margin_left (label, 12); - gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); - gtk_grid_attach (grid, label, 0, 1, 1, 1); - gtk_widget_show (label); - - widget = gtk_entry_new (); - gtk_widget_set_hexpand (widget, TRUE); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget); - gtk_grid_attach (grid, widget, 1, 1, 1, 1); - gtk_widget_show (widget); - - wizard->priv->display_name_entry = widget; - - g_signal_connect_swapped (wizard->priv->display_name_entry, "changed", - G_CALLBACK (collection_account_wizard_notify_can_run), wizard); - - widget = gtk_label_new ("The above name will be used to identify this account.\nUse for example, “Work” or “Personal”."); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_grid_attach (grid, widget, 1, 2, 1, 1); - gtk_widget_show (widget); - - vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6)); - g_object_set (G_OBJECT (vbox), - "hexpand", TRUE, - "halign", GTK_ALIGN_FILL, - "vexpand", FALSE, - "valign", GTK_ALIGN_START, - "visible", TRUE, - NULL); - - gtk_box_pack_end (vbox, GTK_WIDGET (grid), FALSE, FALSE, 0); - - hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4)); - g_object_set (G_OBJECT (hbox), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_START, - "margin-start", 12, - "visible", FALSE, - NULL); - wizard->priv->finish_running_box = GTK_WIDGET (hbox); - - widget = e_spinner_new (); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", TRUE, - NULL); - wizard->priv->finish_spinner = widget; - - gtk_box_pack_start (hbox, widget, FALSE, FALSE, 0); - - label = gtk_label_new (NULL); - g_object_set (G_OBJECT (label), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", TRUE, - "max-width-chars", 120, - "wrap", TRUE, - NULL); - wizard->priv->finish_label = label; - - gtk_box_pack_start (hbox, label, FALSE, FALSE, 0); - - widget = e_dialog_button_new_with_icon ("process-stop", _("_Cancel")); - g_object_set (G_OBJECT (widget), - "hexpand", FALSE, - "halign", GTK_ALIGN_START, - "vexpand", FALSE, - "valign", GTK_ALIGN_CENTER, - "visible", TRUE, - NULL); - wizard->priv->finish_cancel_button = widget; - - g_signal_connect (wizard->priv->finish_cancel_button, "clicked", - G_CALLBACK (collection_account_wizard_finish_cancel_clicked_cb), wizard); - - gtk_box_pack_start (hbox, widget, FALSE, FALSE, 0); - - gtk_notebook_append_page (GTK_NOTEBOOK (wizard), GTK_WIDGET (vbox), NULL); - - gtk_notebook_set_current_page (GTK_NOTEBOOK (wizard), 0); -} - -static void -collection_account_wizard_dispose (GObject *object) -{ - ECollectionAccountWizard *wizard = E_COLLECTION_ACCOUNT_WIZARD (object); - gint ii; - - g_clear_object (&wizard->priv->registry); - g_clear_object (&wizard->priv->config_lookup); - g_clear_object (&wizard->priv->finish_cancellable); - - if (wizard->priv->workers) { - g_hash_table_destroy (wizard->priv->workers); - wizard->priv->workers = NULL; - } - - if (wizard->priv->store_passwords) { - g_hash_table_destroy (wizard->priv->store_passwords); - wizard->priv->store_passwords = NULL; - } - - g_warn_if_fail (wizard->priv->running_result == NULL); - - if (wizard->priv->running_result) { - e_simple_async_result_complete_idle (wizard->priv->running_result); - g_clear_object (&wizard->priv->running_result); - } - - for (ii = 0; ii <= E_CONFIG_LOOKUP_RESULT_LAST_KIND; ii++) { - g_clear_object (&wizard->priv->sources[ii]); - } - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_collection_account_wizard_parent_class)->dispose (object); -} - -static void -e_collection_account_wizard_class_init (ECollectionAccountWizardClass *klass) -{ - GObjectClass *object_class; - - g_type_class_add_private (klass, sizeof (ECollectionAccountWizardPrivate)); - - object_class = G_OBJECT_CLASS (klass); - object_class->set_property = collection_account_wizard_set_property; - object_class->get_property = collection_account_wizard_get_property; - object_class->constructed = collection_account_wizard_constructed; - object_class->dispose = collection_account_wizard_dispose; - - /** - * ECollectionAccountWizard:registry: - * - * The #ESourceRegistry manages #ESource instances. - * - * Since: 3.28 - **/ - g_object_class_install_property ( - object_class, - PROP_REGISTRY, - g_param_spec_object ( - "registry", - "Registry", - "Data source registry", - E_TYPE_SOURCE_REGISTRY, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - /** - * ECollectionAccountWizard:can-run: - * - * Whether can call e_collection_account_wizard_run(). - * See e_collection_account_wizard_get_can_run() for more information. - * - * Since: 3.28 - **/ - g_object_class_install_property ( - object_class, - PROP_CAN_RUN, - g_param_spec_boolean ( - "can-run", - "Can Run", - NULL, - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - /** - * ECollectionAccountWizard::done: - * @uid: an #ESource UID which had been created - * - * Emitted to notify about the wizard being done. - * - * Since: 3.28 - **/ - signals[DONE] = g_signal_new ( - "done", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (ECollectionAccountWizardClass, done), - NULL, NULL, - NULL, - G_TYPE_NONE, 1, G_TYPE_STRING); -} - -static void -e_collection_account_wizard_init (ECollectionAccountWizard *wizard) -{ - gint ii; - - wizard->priv = G_TYPE_INSTANCE_GET_PRIVATE (wizard, E_TYPE_COLLECTION_ACCOUNT_WIZARD, ECollectionAccountWizardPrivate); - wizard->priv->workers = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, worker_data_free); - wizard->priv->store_passwords = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - wizard->priv->running_workers = 0; - - for (ii = 0; ii <= E_CONFIG_LOOKUP_RESULT_LAST_KIND; ii++) { - wizard->priv->sources[ii] = NULL; - } -} - -/** - * e_collection_account_wizard_new: - * @registry: an #ESourceRegistry - * - * Creates a new #ECollectionAccountWizard instance. - * - * Returns: (transfer full): a new #ECollectionAccountWizard - * - * Since: 3.28 - **/ -GtkWidget * -e_collection_account_wizard_new (ESourceRegistry *registry) -{ - g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); - - return g_object_new (E_TYPE_COLLECTION_ACCOUNT_WIZARD, - "registry", registry, - NULL); -} - -/** - * e_collection_account_wizard_get_registry: - * @wizard: an #ECollectionAccountWizard - * - * Returns the #ESourceRegistry passed to e_collection_account_wizard_new(). - * - * Returns: (transfer none): an #ESourceRegistry - * - * Since: 3.28 - **/ -ESourceRegistry * -e_collection_account_wizard_get_registry (ECollectionAccountWizard *wizard) -{ - g_return_val_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard), NULL); - - return wizard->priv->registry; -} - -/** - * e_collection_account_wizard_get_can_run: - * @wizard: an #ECollectionAccountWizard - * - * Returns whether e_collection_account_wizard_run() can be called, that is, - * whether at least one worker is enabled to run and the @wizard is not - * running. - * - * Returns: whether e_collection_account_wizard_run() can be called. - * - * Since: 3.28 - **/ -gboolean -e_collection_account_wizard_get_can_run (ECollectionAccountWizard *wizard) -{ - GHashTableIter iter; - gpointer value; - const gchar *email; - gint current_page; - - g_return_val_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard), FALSE); - - if (wizard->priv->running_workers || - wizard->priv->running_result || - wizard->priv->finish_cancellable) - return FALSE; - - email = gtk_entry_get_text (GTK_ENTRY (wizard->priv->email_entry)); - if (!email || !*email) - return FALSE; - - current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (wizard)); - - if (current_page == 1) { /* Parts page */ - GtkTreeModel *model; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (wizard->priv->parts_tree_view); - if (gtk_tree_model_get_iter_first (model, &iter)) { - do { - gboolean enabled = FALSE, is_collection_group = FALSE; - - gtk_tree_model_get (model, &iter, - PART_COLUMN_BOOL_ENABLED, &enabled, - PART_COLUMN_BOOL_IS_COLLECTION_GROUP, &is_collection_group, - -1); - - if (enabled && is_collection_group) { - /* Collection is not with radio, verify at least one child is selected */ - GtkTreeIter child; - - if (gtk_tree_model_iter_nth_child (model, &child, &iter, 0)) { - do { - enabled = FALSE; - - gtk_tree_model_get (model, &child, - PART_COLUMN_BOOL_ENABLED, &enabled, - -1); - - if (enabled) - return TRUE; - } while (gtk_tree_model_iter_next (model, &child)); - } - } else if (enabled) { - return TRUE; - } - } while (gtk_tree_model_iter_next (model, &iter)); - } - - return FALSE; - } else if (current_page == 2) { /* Finish page */ - gchar *display_name; - gboolean can_run; - - display_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (wizard->priv->display_name_entry))); - if (!display_name) - return FALSE; - - g_strstrip (display_name); - - can_run = display_name && *display_name; - - g_free (display_name); - - return can_run; - } - - /* Look up page */ - - g_hash_table_iter_init (&iter, wizard->priv->workers); - - while (g_hash_table_iter_next (&iter, NULL, &value)) { - WorkerData *wd = value; - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wd->enabled_check))) - return TRUE; - } - - return FALSE; -} - -/** - * e_collection_account_wizard_reset: - * @wizard: an #ECollectionAccountWizard - * - * Resets content of the @wizard to the initial state. This might be called - * whenever the widget is going to be shown. - * - * Since: 3.28 - **/ -void -e_collection_account_wizard_reset (ECollectionAccountWizard *wizard) -{ - GtkTreeModel *model; - GHashTableIter iter; - gpointer value; - gint ii; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - - e_collection_account_wizard_abort (wizard); - - g_hash_table_iter_init (&iter, wizard->priv->workers); - - while (g_hash_table_iter_next (&iter, NULL, &value)) { - WorkerData *wd = value; - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wd->enabled_check), TRUE); - gtk_widget_hide (wd->running_box); - e_named_parameters_free (wd->restart_params); - wd->restart_params = NULL; - wd->remember_password = TRUE; - } - - gtk_entry_set_text (GTK_ENTRY (wizard->priv->email_entry), ""); - gtk_entry_set_text (GTK_ENTRY (wizard->priv->servers_entry), ""); - gtk_label_set_text (GTK_LABEL (wizard->priv->results_label), ""); - gtk_entry_set_text (GTK_ENTRY (wizard->priv->display_name_entry), ""); - gtk_expander_set_expanded (GTK_EXPANDER (wizard->priv->advanced_expander), FALSE); - e_config_lookup_clear_results (wizard->priv->config_lookup); - - model = gtk_tree_view_get_model (wizard->priv->parts_tree_view); - gtk_tree_store_clear (GTK_TREE_STORE (model)); - - wizard->priv->changed = FALSE; - - for (ii = 0; ii <= E_CONFIG_LOOKUP_RESULT_LAST_KIND; ii++) { - g_clear_object (&wizard->priv->sources[ii]); - } - - gtk_notebook_set_current_page (GTK_NOTEBOOK (wizard), 0); - - g_object_notify (G_OBJECT (wizard), "can-run"); -} - -/** - * e_collection_account_wizard_next: - * @wizard: an #ECollectionAccountWizard - * - * Instructs the @wizard to advance to the next step. It does nothing - * when there is an ongoing lookup or when the current page cannot - * be advanced. - * - * This can influence e_collection_account_wizard_is_finish_page(). - * - * Returns: %TRUE, when the step had been changed, %FALSE otherwise. - * Note that when this is called on a finish page, then the %TRUE - * means that the @wizard finished all its settings and should be - * closed now. - * - * Since: 3.28 - **/ -gboolean -e_collection_account_wizard_next (ECollectionAccountWizard *wizard) -{ - gboolean changed = FALSE; - const gchar *text; - gint ii; - - g_return_val_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard), FALSE); - - switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (wizard))) { - case 0: /* Lookup page */ - if (wizard->priv->changed || - !e_config_lookup_count_results (wizard->priv->config_lookup)) { - for (ii = 0; ii <= E_CONFIG_LOOKUP_RESULT_LAST_KIND; ii++) { - g_clear_object (&wizard->priv->sources[ii]); - } - - wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION] = e_source_new (NULL, NULL, NULL); - e_source_get_extension (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION], E_SOURCE_EXTENSION_COLLECTION); - - e_collection_account_wizard_run (wizard, NULL, NULL); - changed = TRUE; - } else if (collection_account_wizard_fill_results (wizard)) { - gtk_notebook_set_current_page (GTK_NOTEBOOK (wizard), 1); - changed = TRUE; - } - break; - case 1: /* Parts page */ - g_warn_if_fail (wizard->priv->sources[E_CONFIG_LOOKUP_RESULT_COLLECTION] != NULL); - - text = gtk_entry_get_text (GTK_ENTRY (wizard->priv->display_name_entry)); - if (!text || !*text) { - gtk_entry_set_text (GTK_ENTRY (wizard->priv->display_name_entry), - gtk_entry_get_text (GTK_ENTRY (wizard->priv->email_entry))); - } - - gtk_notebook_set_current_page (GTK_NOTEBOOK (wizard), 2); - changed = TRUE; - break; - case 2: /* Finish page */ - /* It's an asynchronous operation, just fail or run it */ - collection_account_wizard_save_sources (wizard); - changed = FALSE; - break; - } - - return changed; -} - -/** - * e_collection_account_wizard_prev: - * @wizard: an #ECollectionAccountWizard - * - * Instructs the @wizard to go back to the previous step. - * - * This can influence e_collection_account_wizard_is_finish_page(). - * - * Returns: %TRUE, when the step had been changed, %FALSE otherwise. - * - * Since: 3.28 - **/ -gboolean -e_collection_account_wizard_prev (ECollectionAccountWizard *wizard) -{ - gint current_page; - - g_return_val_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard), FALSE); - - current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (wizard)); - - if (current_page < 1) - return FALSE; - - gtk_notebook_set_current_page (GTK_NOTEBOOK (wizard), current_page - 1); - - return TRUE; -} - -/** - * e_collection_account_wizard_is_finish_page: - * @wizard: an #ECollectionAccountWizard - * - * Returns: whether the @wizard is at the last page. - * - * Since: 3.28 - **/ -gboolean -e_collection_account_wizard_is_finish_page (ECollectionAccountWizard *wizard) -{ - g_return_val_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard), FALSE); - - return gtk_notebook_get_current_page (GTK_NOTEBOOK (wizard)) == gtk_notebook_get_n_pages (GTK_NOTEBOOK (wizard)) - 1; -} - -/** - * e_collection_account_wizard_run: - * @wizard: an #ECollectionAccountWizard - * @callback: a callback to call, when the run is finished - * @user_data: user data for the @callback - * - * Runs lookup for all enabled lookup workers. Finish the call - * with e_collection_account_wizard_run_finish() from the @callback. - * - * This function can be called only if e_collection_account_wizard_get_can_run() - * returns %TRUE. - * - * Since: 3.28 - **/ -void -e_collection_account_wizard_run (ECollectionAccountWizard *wizard, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GHashTableIter iter; - gpointer key, value; - gboolean any_worker = FALSE; - - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - g_return_if_fail (e_collection_account_wizard_get_can_run (wizard)); - - wizard->priv->running_result = e_simple_async_result_new (G_OBJECT (wizard), callback, user_data, e_collection_account_wizard_run); - - g_hash_table_iter_init (&iter, wizard->priv->workers); - while (g_hash_table_iter_next (&iter, &key, &value)) { - EConfigLookupWorker *worker = key; - WorkerData *wd = value; - - if (worker && wd && - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wd->enabled_check))) { - ENamedParameters *params; - - params = e_named_parameters_new_clone (wd->restart_params); - if (!params) - params = e_named_parameters_new (); - e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_EMAIL_ADDRESS, gtk_entry_get_text (GTK_ENTRY (wizard->priv->email_entry))); - e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_SERVERS, gtk_entry_get_text (GTK_ENTRY (wizard->priv->servers_entry))); - - any_worker = TRUE; - e_config_lookup_run_worker (wizard->priv->config_lookup, worker, params, NULL); - - e_named_parameters_free (params); - } - } - - if (!any_worker) { - e_simple_async_result_complete_idle (wizard->priv->running_result); - g_clear_object (&wizard->priv->running_result); - } -} - -/** - * e_collection_account_wizard_run_finish: - * @wizard: an #ECollectionAccountWizard - * @result: result of the operation - * - * Finishes the wizard run issued by e_collection_account_wizard_run(). - * It doesn't return anything, because everything is handled within - * the @wizard, thus it is provided mainly for consistency with asynchronous API. - * - * Since: 3.28 - **/ -void -e_collection_account_wizard_run_finish (ECollectionAccountWizard *wizard, - GAsyncResult *result) -{ - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - g_return_if_fail (G_IS_ASYNC_RESULT (result)); - g_return_if_fail (g_async_result_is_tagged (result, e_collection_account_wizard_run)); -} - -/** - * e_collection_account_wizard_abort: - * @wizard: an #ECollectionAccountWizard - * - * Aborts any ongoing operation the @wizard may run. If there is nothing - * running, then does nothing. - * - * Since: 3.28 - **/ -void -e_collection_account_wizard_abort (ECollectionAccountWizard *wizard) -{ - g_return_if_fail (E_IS_COLLECTION_ACCOUNT_WIZARD (wizard)); - - e_config_lookup_cancel_all (wizard->priv->config_lookup); - - if (wizard->priv->finish_cancellable) - g_cancellable_cancel (wizard->priv->finish_cancellable); -} diff --git a/src/e-util/e-config-lookup.c b/src/e-util/e-config-lookup.c index 3b68fa6..d0eff38 100644 --- a/src/e-util/e-config-lookup.c +++ b/src/e-util/e-config-lookup.c @@ -277,11 +277,6 @@ config_lookup_dispose (GObject *object) e_config_lookup_cancel_all (config_lookup); - if (config_lookup->priv->pool) { - g_thread_pool_free (config_lookup->priv->pool, TRUE, TRUE); - config_lookup->priv->pool = NULL; - } - g_mutex_lock (&config_lookup->priv->property_lock); g_clear_object (&config_lookup->priv->run_cancellable); @@ -310,6 +305,7 @@ config_lookup_finalize (GObject *object) EConfigLookup *config_lookup = E_CONFIG_LOOKUP (object); g_slist_free_full (config_lookup->priv->results, g_object_unref); + g_thread_pool_free (config_lookup->priv->pool, TRUE, FALSE); g_mutex_clear (&config_lookup->priv->property_lock); /* Chain up to parent's method. */ diff --git a/src/e-util/e-config-lookup.c.config-lookup-crash b/src/e-util/e-config-lookup.c.config-lookup-crash deleted file mode 100644 index d0eff38..0000000 --- a/src/e-util/e-config-lookup.c.config-lookup-crash +++ /dev/null @@ -1,996 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com) - * - * This library is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This library 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 Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -/** - * SECTION: e-config-lookup - * @include: e-util/e-util.h - * @short_description: Configuration lookup - * - * #EConfigLookup is used to search for configuration of an account, - * which is identified by an e-mail address, server address or such. - * It is an #EExtensible object, where the extensions connect to - * the #EConfigLookup::run signal to run the configuration lookup. - **/ - -#include "evolution-config.h" - -#include -#include -#include - -#include "e-config-lookup-result.h" -#include "e-config-lookup-worker.h" -#include "e-simple-async-result.h" -#include "e-util-enumtypes.h" - -#include "e-config-lookup.h" - -struct _EConfigLookupPrivate { - ESourceRegistry *registry; - - GMutex property_lock; - GSList *workers; /* EConfigLookupWorker * */ - GSList *results; /* EConfigLookupResult * */ - - ESimpleAsyncResult *run_result; - GCancellable *run_cancellable; - GSList *worker_cancellables; /* CamelOperation * */ - - GThreadPool *pool; -}; - -enum { - PROP_0, - PROP_REGISTRY, - PROP_BUSY -}; - -enum { - GET_SOURCE, - WORKER_STARTED, - WORKER_FINISHED, - RESULT_ADDED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -G_DEFINE_TYPE_WITH_CODE (EConfigLookup, e_config_lookup, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL)) - -enum { - EMIT_BUSY = 1 << 0, - EMIT_WORKER_STARTED = 1 << 1, - EMIT_WORKER_FINISHED = 1 << 2 -}; - -typedef struct _EmitData { - EConfigLookup *config_lookup; - EConfigLookupWorker *worker; - guint32 flags; - GCancellable *cancellable; - ENamedParameters *params; - GError *error; -} EmitData; - -static void -emit_data_free (gpointer ptr) -{ - EmitData *ed = ptr; - - if (ed) { - e_named_parameters_free (ed->params); - g_clear_object (&ed->config_lookup); - g_clear_object (&ed->worker); - g_clear_object (&ed->cancellable); - g_clear_error (&ed->error); - g_free (ed); - } -} - -static gboolean -config_lookup_emit_idle_cb (gpointer user_data) -{ - EmitData *ed = user_data; - - g_return_val_if_fail (ed != NULL, FALSE); - g_return_val_if_fail (E_IS_CONFIG_LOOKUP (ed->config_lookup), FALSE); - - if ((ed->flags & EMIT_WORKER_STARTED) != 0) - g_signal_emit (ed->config_lookup, signals[WORKER_STARTED], 0, ed->worker, ed->cancellable); - - if ((ed->flags & EMIT_WORKER_FINISHED) != 0) - g_signal_emit (ed->config_lookup, signals[WORKER_FINISHED], 0, ed->worker, ed->params, ed->error); - - if ((ed->flags & EMIT_BUSY) != 0) - g_object_notify (G_OBJECT (ed->config_lookup), "busy"); - - return FALSE; -} - -static void -config_lookup_schedule_emit_idle (EConfigLookup *config_lookup, - guint32 emit_flags, - EConfigLookupWorker *worker, - GCancellable *cancellable, - const ENamedParameters *params, - const GError *error) -{ - EmitData *ed; - - g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup)); - if (worker) - g_return_if_fail (E_IS_CONFIG_LOOKUP_WORKER (worker)); - - ed = g_new0 (EmitData, 1); - ed->config_lookup = g_object_ref (config_lookup); - ed->flags = emit_flags; - ed->worker = worker ? g_object_ref (worker) : NULL; - ed->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - ed->params = params ? e_named_parameters_new_clone (params) : NULL; - ed->error = error ? g_error_copy (error) : NULL; - - g_idle_add_full (G_PRIORITY_HIGH_IDLE, config_lookup_emit_idle_cb, ed, emit_data_free); -} - -typedef struct _ThreadData { - ENamedParameters *params; - EConfigLookupWorker *worker; - GCancellable *cancellable; -} ThreadData; - -static void -config_lookup_thread (gpointer data, - gpointer user_data) -{ - ThreadData *td = data; - EConfigLookup *config_lookup = user_data; - ESimpleAsyncResult *run_result = NULL; - guint32 emit_flags; - ENamedParameters *restart_params = NULL; - GError *error = NULL; - - g_return_if_fail (td != NULL); - g_return_if_fail (td->params != NULL); - g_return_if_fail (E_IS_CONFIG_LOOKUP_WORKER (td->worker)); - g_return_if_fail (G_IS_CANCELLABLE (td->cancellable)); - g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup)); - - e_config_lookup_worker_run (td->worker, config_lookup, td->params, &restart_params, td->cancellable, &error); - - g_mutex_lock (&config_lookup->priv->property_lock); - - emit_flags = EMIT_WORKER_FINISHED; - - if (g_slist_find (config_lookup->priv->worker_cancellables, td->cancellable)) { - config_lookup->priv->worker_cancellables = g_slist_remove (config_lookup->priv->worker_cancellables, td->cancellable); - g_object_unref (td->cancellable); - - if (!config_lookup->priv->worker_cancellables) - emit_flags |= EMIT_BUSY; - } - - config_lookup_schedule_emit_idle (config_lookup, emit_flags, td->worker, NULL, restart_params, error); - - if ((emit_flags & EMIT_BUSY) != 0) { - run_result = config_lookup->priv->run_result; - config_lookup->priv->run_result = NULL; - - g_clear_object (&config_lookup->priv->run_cancellable); - } - - g_mutex_unlock (&config_lookup->priv->property_lock); - - if (run_result) { - e_simple_async_result_complete_idle (run_result); - g_object_unref (run_result); - } - - e_named_parameters_free (restart_params); - e_named_parameters_free (td->params); - g_clear_object (&td->worker); - g_clear_object (&td->cancellable); - g_clear_error (&error); - g_free (td); -} - -static void -config_lookup_set_registry (EConfigLookup *config_lookup, - ESourceRegistry *registry) -{ - g_return_if_fail (E_IS_SOURCE_REGISTRY (registry)); - g_return_if_fail (config_lookup->priv->registry == NULL); - - config_lookup->priv->registry = g_object_ref (registry); -} - -static void -config_lookup_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_REGISTRY: - config_lookup_set_registry ( - E_CONFIG_LOOKUP (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -config_lookup_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_BUSY: - g_value_set_boolean ( - value, - e_config_lookup_get_busy ( - E_CONFIG_LOOKUP (object))); - return; - - case PROP_REGISTRY: - g_value_set_object ( - value, - e_config_lookup_get_registry ( - E_CONFIG_LOOKUP (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -config_lookup_constructed (GObject *object) -{ - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_config_lookup_parent_class)->constructed (object); - - e_extensible_load_extensions (E_EXTENSIBLE (object)); -} - -static void -config_lookup_dispose (GObject *object) -{ - EConfigLookup *config_lookup = E_CONFIG_LOOKUP (object); - gboolean had_running_workers; - - e_config_lookup_cancel_all (config_lookup); - - g_mutex_lock (&config_lookup->priv->property_lock); - - g_clear_object (&config_lookup->priv->run_cancellable); - - g_slist_free_full (config_lookup->priv->workers, g_object_unref); - config_lookup->priv->workers = NULL; - - had_running_workers = config_lookup->priv->worker_cancellables != NULL; - g_slist_free_full (config_lookup->priv->worker_cancellables, g_object_unref); - config_lookup->priv->worker_cancellables = NULL; - - g_mutex_unlock (&config_lookup->priv->property_lock); - - if (had_running_workers) - g_object_notify (object, "busy"); - - g_clear_object (&config_lookup->priv->registry); - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_config_lookup_parent_class)->dispose (object); -} - -static void -config_lookup_finalize (GObject *object) -{ - EConfigLookup *config_lookup = E_CONFIG_LOOKUP (object); - - g_slist_free_full (config_lookup->priv->results, g_object_unref); - g_thread_pool_free (config_lookup->priv->pool, TRUE, FALSE); - g_mutex_clear (&config_lookup->priv->property_lock); - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_config_lookup_parent_class)->finalize (object); -} - -static void -e_config_lookup_class_init (EConfigLookupClass *klass) -{ - GObjectClass *object_class; - - g_type_class_add_private (klass, sizeof (EConfigLookupPrivate)); - - object_class = G_OBJECT_CLASS (klass); - object_class->set_property = config_lookup_set_property; - object_class->get_property = config_lookup_get_property; - object_class->constructed = config_lookup_constructed; - object_class->dispose = config_lookup_dispose; - object_class->finalize = config_lookup_finalize; - - /** - * EConfigLookup:registry: - * - * The #ESourceRegistry manages #ESource instances. - * - * Since: 3.26 - **/ - g_object_class_install_property ( - object_class, - PROP_REGISTRY, - g_param_spec_object ( - "registry", - "Registry", - "Data source registry", - E_TYPE_SOURCE_REGISTRY, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - /** - * EConfigLookup:busy: - * - * Whether the EConfigLookup has any running workers. - * - * Since: 3.28 - **/ - g_object_class_install_property ( - object_class, - PROP_BUSY, - g_param_spec_boolean ( - "busy", - "Busy", - NULL, - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - /** - * EConfigLookup::get-source: - * @kind: an #EConfigLookupSourceKind - * - * Emitted to get an #ESource of the given @kind. Return %NULL, when not available. - * - * Since: 3.26 - **/ - signals[GET_SOURCE] = g_signal_new ( - "get-source", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (EConfigLookupClass, get_source), - NULL, NULL, - NULL, - G_TYPE_POINTER, 1, - E_TYPE_CONFIG_LOOKUP_SOURCE_KIND); - - /** - * EConfigLookup::worker-started: - * @worker: an #EConfigLookupWorker - * @cancellable: associated #GCancellable for this worker run - * - * Emitted when the @worker is about to start running. - * Corresponding @EConfigLookup::worker-finished is emitted when - * the run is finished. - * - * Note that this signal is always emitted in the main thread. - * - * Since: 3.28 - **/ - signals[WORKER_STARTED] = g_signal_new ( - "worker-started", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EConfigLookupClass, worker_started), - NULL, NULL, - NULL, - G_TYPE_NONE, 2, - E_TYPE_CONFIG_LOOKUP_WORKER, - G_TYPE_CANCELLABLE); - - /** - * EConfigLookup::worker-finished: - * @worker: an #EConfigLookupWorker - * @restart_params: an optional #ENamedParameters to use when the @worker might be restarted - * @error: an optional #GError with an overall result of the run - * - * Emitted when the @worker finished its running. - * - * Note that this signal is always emitted in the main thread. - * - * Since: 3.28 - **/ - signals[WORKER_FINISHED] = g_signal_new ( - "worker-finished", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EConfigLookupClass, worker_finished), - NULL, NULL, - NULL, - G_TYPE_NONE, 3, - E_TYPE_CONFIG_LOOKUP_WORKER, - E_TYPE_NAMED_PARAMETERS, - G_TYPE_ERROR); - - /** - * EConfigLookup::result-added: - * @result: an #EConfigLookupResult - * - * Emitted when a new @result is added to the config lookup. - * - * Note that this signal can be emitted in a worker's dedicated thread. - * - * Since: 3.28 - **/ - signals[RESULT_ADDED] = g_signal_new ( - "result-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EConfigLookupClass, result_added), - NULL, NULL, - NULL, - G_TYPE_NONE, 1, - E_TYPE_CONFIG_LOOKUP_RESULT); -} - -static void -e_config_lookup_init (EConfigLookup *config_lookup) -{ - config_lookup->priv = G_TYPE_INSTANCE_GET_PRIVATE (config_lookup, E_TYPE_CONFIG_LOOKUP, EConfigLookupPrivate); - - g_mutex_init (&config_lookup->priv->property_lock); - config_lookup->priv->pool = g_thread_pool_new (config_lookup_thread, config_lookup, 10, FALSE, NULL); -} - -/** - * e_config_lookup_new: - * @registry: an #ESourceRegistry - * - * Creates a new #EConfigLookup instance. - * - * Returns: (transfer full): a new #EConfigLookup - * - * Since: 3.26 - **/ -EConfigLookup * -e_config_lookup_new (ESourceRegistry *registry) -{ - g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); - - return g_object_new (E_TYPE_CONFIG_LOOKUP, - "registry", registry, - NULL); -} - -/** - * e_config_lookup_get_registry: - * @config_lookup: an #EConfigLookup - * - * Returns the #ESourceRegistry passed to e_config_lookup_new(). - * - * Returns: (transfer none): an #ESourceRegistry - * - * Since: 3.26 - **/ -ESourceRegistry * -e_config_lookup_get_registry (EConfigLookup *config_lookup) -{ - g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), NULL); - - return config_lookup->priv->registry; -} - -/** - * e_config_lookup_get_source: - * @config_lookup: an #EConfigLookup - * @kind: one of #EConfigLookupSourceKind, except of the %E_CONFIG_LOOKUP_SOURCE_UNKNOWN - * - * Emits the #EConfigLookup::get-source signal and any listener can provide - * the source. The function can return %NULL, when there are no listeners - * or when such source is not available. - * - * Returns: (transfer none) (nullable): an #ESource of the given @kind, or %NULL, if not found - * - * Since: 3.26 - **/ -ESource * -e_config_lookup_get_source (EConfigLookup *config_lookup, - EConfigLookupSourceKind kind) -{ - ESource *source = NULL; - - g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), NULL); - - g_signal_emit (config_lookup, signals[GET_SOURCE], 0, kind, &source); - - return source; -} - -/** - * e_config_lookup_get_busy: - * @config_lookup: an #EConfigLookup - * - * Returns whether there's any running worker. They can be cancelled - * with e_config_lookup_cancel_all(). - * - * Returns: whether there's any running worker - * - * Since: 3.28 - **/ -gboolean -e_config_lookup_get_busy (EConfigLookup *config_lookup) -{ - gboolean busy; - - g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), FALSE); - - g_mutex_lock (&config_lookup->priv->property_lock); - busy = config_lookup->priv->worker_cancellables != NULL; - g_mutex_unlock (&config_lookup->priv->property_lock); - - return busy; -} - -/** - * e_config_lookup_cancel_all: - * @config_lookup: an #EConfigLookup - * - * Cancels all pending workers. - * - * Since: 3.28 - **/ -void -e_config_lookup_cancel_all (EConfigLookup *config_lookup) -{ - GSList *cancellables; - GCancellable *run_cancellable; - - g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup)); - - g_mutex_lock (&config_lookup->priv->property_lock); - cancellables = g_slist_copy_deep (config_lookup->priv->worker_cancellables, (GCopyFunc) g_object_ref, NULL); - run_cancellable = config_lookup->priv->run_cancellable ? g_object_ref (config_lookup->priv->run_cancellable) : NULL; - g_mutex_unlock (&config_lookup->priv->property_lock); - - g_slist_foreach (cancellables, (GFunc) g_cancellable_cancel, NULL); - g_slist_free_full (cancellables, g_object_unref); - - if (run_cancellable) { - g_cancellable_cancel (run_cancellable); - g_object_unref (run_cancellable); - } -} - -/** - * e_config_lookup_register_worker: - * @config_lookup: an #EConfigLookup - * @worker: an #EConfigLookupWorker - * - * Registers a @worker as a worker, which can be run as part of e_config_lookup_run(). - * The function adds its own reference to @worker. - * - * Since: 3.28 - **/ -void -e_config_lookup_register_worker (EConfigLookup *config_lookup, - EConfigLookupWorker *worker) -{ - GSList *existing_worker; - - g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup)); - g_return_if_fail (E_IS_CONFIG_LOOKUP_WORKER (worker)); - - g_mutex_lock (&config_lookup->priv->property_lock); - - existing_worker = g_slist_find (config_lookup->priv->workers, worker); - - g_warn_if_fail (existing_worker == NULL); - - if (!existing_worker) - config_lookup->priv->workers = g_slist_prepend (config_lookup->priv->workers, g_object_ref (worker)); - - g_mutex_unlock (&config_lookup->priv->property_lock); -} - -/** - * e_config_lookup_unregister_worker: - * @config_lookup: an #EConfigLookup - * @worker: an #EConfigLookupWorker - * - * Removes a @worker previously registered with e_config_lookup_register_worker(). - * - * Since: 3.28 - **/ -void -e_config_lookup_unregister_worker (EConfigLookup *config_lookup, - EConfigLookupWorker *worker) -{ - GSList *existing_worker; - - g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup)); - g_return_if_fail (E_IS_CONFIG_LOOKUP_WORKER (worker)); - - g_mutex_lock (&config_lookup->priv->property_lock); - - existing_worker = g_slist_find (config_lookup->priv->workers, worker); - - g_warn_if_fail (existing_worker != NULL); - - if (existing_worker) { - config_lookup->priv->workers = g_slist_remove (config_lookup->priv->workers, worker); - g_object_unref (worker); - } - - g_mutex_unlock (&config_lookup->priv->property_lock); -} - -/** - * e_config_lookup_dup_registered_workers: - * @config_lookup: an #EConfigLookup - * - * Returns a list of all registered #EConfigLookupWorker objects. - * - * The returned #GSList should be freed with - * g_slist_free_full (workers, g_object_unref); - * when no longer needed. - * - * Returns: (transfer full) (element-type EConfigLookupWorker): a #GSList with all - * workers registered with e_config_lookup_register_worker(). - * - * Since: 3.28 - **/ -GSList * -e_config_lookup_dup_registered_workers (EConfigLookup *config_lookup) -{ - GSList *workers; - - g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), NULL); - - g_mutex_lock (&config_lookup->priv->property_lock); - workers = g_slist_copy_deep (config_lookup->priv->workers, (GCopyFunc) g_object_ref, NULL); - g_mutex_unlock (&config_lookup->priv->property_lock); - - return workers; -} - -/** - * e_config_lookup_run: - * @config_lookup: an #EConfigLookup - * @params: an #ENamedParameters with lookup parameters - * @cancellable: an optional #GCancellable, or %NULL - * @callback: a callback to call, when the run is finished - * @user_data: user data for the @callback - * - * Runs configuration lookup asynchronously. Once the run is done, the @callback is called, - * and the call can be finished with e_config_lookup_run_finish(). The @callback is always - * called from the main thread. - * - * Workers can be run individually using e_config_lookup_run_worker(). - * - * Note that there cannot be run two lookups at the same time, thus if it - * happens, then the @callback is called immediately with a %NULL result. - * - * Since: 3.26 - **/ -void -e_config_lookup_run (EConfigLookup *config_lookup, - const ENamedParameters *params, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSList *workers, *link; - - g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup)); - g_return_if_fail (params != NULL); - - g_mutex_lock (&config_lookup->priv->property_lock); - - if (config_lookup->priv->run_result) { - g_mutex_unlock (&config_lookup->priv->property_lock); - - if (callback) - callback (G_OBJECT (config_lookup), NULL, user_data); - return; - } - - g_slist_free_full (config_lookup->priv->results, g_object_unref); - config_lookup->priv->results = NULL; - - if (cancellable) - g_object_ref (cancellable); - else - cancellable = g_cancellable_new (); - - config_lookup->priv->run_result = e_simple_async_result_new (G_OBJECT (config_lookup), callback, user_data, e_config_lookup_run); - config_lookup->priv->run_cancellable = cancellable; - - workers = g_slist_copy_deep (config_lookup->priv->workers, (GCopyFunc) g_object_ref, NULL); - - g_mutex_unlock (&config_lookup->priv->property_lock); - - if (workers) { - for (link = workers; link; link = g_slist_next (link)) { - EConfigLookupWorker *worker = link->data; - - e_config_lookup_run_worker (config_lookup, worker, params, cancellable); - } - - g_slist_free_full (workers, g_object_unref); - } else { - ESimpleAsyncResult *run_result; - - g_mutex_lock (&config_lookup->priv->property_lock); - - run_result = config_lookup->priv->run_result; - config_lookup->priv->run_result = NULL; - - g_clear_object (&config_lookup->priv->run_cancellable); - - g_mutex_unlock (&config_lookup->priv->property_lock); - - if (run_result) { - e_simple_async_result_complete_idle (run_result); - g_object_unref (run_result); - } - } -} - -/** - * e_config_lookup_run_finish: - * @config_lookup: an #EConfigLookup - * @result: result of the operation - * - * Finishes the configuration lookup previously run by e_config_lookup_run(). - * It's expected that the extensions may fail, thus it doesn't return - * anything and is provided mainly for consistency with asynchronous API. - * - * Since: 3.26 - **/ -void -e_config_lookup_run_finish (EConfigLookup *config_lookup, - GAsyncResult *result) -{ - g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup)); - g_return_if_fail (G_IS_ASYNC_RESULT (result)); - g_return_if_fail (g_async_result_is_tagged (result, e_config_lookup_run)); -} - -/** - * e_config_lookup_run_worker: - * @config_lookup: an #EConfigLookup - * @worker: an #EConfigLookupWorker to run in a dedicated thread - * @params: an #ENamedParameters with lookup parameters - * @cancellable: an optional #GCancellable, or %NULL - * - * Creates a new thread and runs @worker in it. When the @cancellable is %NULL, - * then there's creates a new #CamelOperation, which either proxies currently - * running lookup or the newly created cancellable is completely independent. - * - * This function can be called while there's an ongoing configuration lookup, but - * also when the @worker is restarted. - * - * Since: 3.28 - **/ -void -e_config_lookup_run_worker (EConfigLookup *config_lookup, - EConfigLookupWorker *worker, - const ENamedParameters *params, - GCancellable *cancellable) -{ - ThreadData *td; - - g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup)); - g_return_if_fail (E_IS_CONFIG_LOOKUP_WORKER (worker)); - g_return_if_fail (params != NULL); - - td = g_new0 (ThreadData, 1); - td->params = e_named_parameters_new_clone (params); - td->worker = g_object_ref (worker); - - g_mutex_lock (&config_lookup->priv->property_lock); - - if (cancellable) - td->cancellable = camel_operation_new_proxy (cancellable); - else if (config_lookup->priv->run_cancellable) - td->cancellable = camel_operation_new_proxy (config_lookup->priv->run_cancellable); - else - td->cancellable = camel_operation_new (); - - camel_operation_push_message (td->cancellable, "%s", _("Running…")); - config_lookup->priv->worker_cancellables = g_slist_prepend (config_lookup->priv->worker_cancellables, g_object_ref (td->cancellable)); - - config_lookup_schedule_emit_idle (config_lookup, EMIT_WORKER_STARTED | - (!config_lookup->priv->worker_cancellables->next ? EMIT_BUSY : 0), - worker, td->cancellable, NULL, NULL); - - g_thread_pool_push (config_lookup->priv->pool, td, NULL); - - g_mutex_unlock (&config_lookup->priv->property_lock); -} - -/** - * e_config_lookup_add_result: - * @config_lookup: an #EConfigLookup - * @result: (transfer full): an #EConfigLookupResult - * - * Adds a new @result in a list of known configuration lookup results. - * The @config_lookup assumes ownership of the @result and frees it - * when no longer needed. - * - * The list of results can be obtained with e_config_lookup_dup_results(). - * - * Since: 3.26 - **/ -void -e_config_lookup_add_result (EConfigLookup *config_lookup, - EConfigLookupResult *result) -{ - g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup)); - g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT (result)); - - g_mutex_lock (&config_lookup->priv->property_lock); - - config_lookup->priv->results = g_slist_prepend (config_lookup->priv->results, result); - - g_mutex_unlock (&config_lookup->priv->property_lock); - - g_signal_emit (config_lookup, signals[RESULT_ADDED], 0, result); -} - -/** - * e_config_lookup_count_results: - * @config_lookup: an #EConfigLookup - * - * Returns: how many results had been added already. - * - * Since: 3.28 - **/ -gint -e_config_lookup_count_results (EConfigLookup *config_lookup) -{ - gint n_results; - - g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), -1); - - g_mutex_lock (&config_lookup->priv->property_lock); - - n_results = g_slist_length (config_lookup->priv->results); - - g_mutex_unlock (&config_lookup->priv->property_lock); - - return n_results; -} - -/** - * e_config_lookup_dup_results: - * @config_lookup: an #EConfigLookup - * @kind: an #EConfigLookupResultKind to filter the results with - * @protocol: (nullable): optional protocol to filter the results with, or %NULL - * - * Returns a #GSList with #EConfigLookupResult objects satisfying - * the @kind and @protocol filtering conditions. To receive all - * gathered results use %E_CONFIG_LOOKUP_RESULT_UNKNOWN for @kind - * and %NULL for the @protocol. - * - * Free the returned #GSList with - * g_slist_free_full (results, g_object_unref); - * when no longer needed. - * - * Returns: (transfer full) (element-type EConfigLookupResult): a #GSList - * with results satisfying the @kind and @protocol filtering conditions. - * - * Since: 3.28 - **/ -GSList * -e_config_lookup_dup_results (EConfigLookup *config_lookup, - EConfigLookupResultKind kind, - const gchar *protocol) -{ - GSList *results = NULL, *link; - - g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), NULL); - - g_mutex_lock (&config_lookup->priv->property_lock); - - for (link = config_lookup->priv->results; link; link = g_slist_next (link)) { - EConfigLookupResult *result = link->data; - - if (!E_IS_CONFIG_LOOKUP_RESULT (result)) - continue; - - if (kind != E_CONFIG_LOOKUP_RESULT_UNKNOWN && - kind != e_config_lookup_result_get_kind (result)) - continue; - - if (protocol && - g_strcmp0 (protocol, e_config_lookup_result_get_protocol (result)) != 0) - continue; - - results = g_slist_prepend (results, g_object_ref (result)); - } - - g_mutex_unlock (&config_lookup->priv->property_lock); - - return results; -} - -/** - * e_config_lookup_clear_results: - * @config_lookup: an #EConfigLookup - * - * Frees all gathered results. This might be usually called before - * starting new custom lookup. The e_config_lookup_run() frees - * all results automatically. - * - * Since: 3.28 - **/ -void -e_config_lookup_clear_results (EConfigLookup *config_lookup) -{ - g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup)); - - g_mutex_lock (&config_lookup->priv->property_lock); - - g_slist_free_full (config_lookup->priv->results, g_object_unref); - config_lookup->priv->results = NULL; - - g_mutex_unlock (&config_lookup->priv->property_lock); -} - -/** - * e_config_lookup_encode_certificate_trust: - * @response: an #ETrustPromptResponse to encode - * - * Encodes @response to a string. This can be decoded back to enum - * with e_config_lookup_decode_certificate_trust(). - * - * Returns: string representation of @response. - * - * Since: 3.28 - **/ -const gchar * -e_config_lookup_encode_certificate_trust (ETrustPromptResponse response) -{ - return e_enum_to_string (E_TYPE_TRUST_PROMPT_RESPONSE, response); -} - -/** - * e_config_lookup_decode_certificate_trust: - * @value: a text value to decode - * - * Decodes text @value to #ETrustPromptResponse, previously encoded - * with e_config_lookup_encode_certificate_trust(). - * - * Returns: an #ETrustPromptResponse corresponding to @value. - * - * Since: 3.28 - **/ -ETrustPromptResponse -e_config_lookup_decode_certificate_trust (const gchar *value) -{ - gint decoded; - - if (!value || - !e_enum_from_string (E_TYPE_TRUST_PROMPT_RESPONSE, value, &decoded)) - decoded = E_TRUST_PROMPT_RESPONSE_UNKNOWN; - - return decoded; -} diff --git a/src/e-util/e-misc-utils.c b/src/e-util/e-misc-utils.c index 3801337..c6f4e10 100644 --- a/src/e-util/e-misc-utils.c +++ b/src/e-util/e-misc-utils.c @@ -319,9 +319,7 @@ e_display_help (GtkWindow *parent, uri = g_string_new ("help:" PACKAGE); } else { uri = g_string_new ("https://help.gnome.org/users/" PACKAGE "/"); - /* Use '/stable/' until https://bugzilla.gnome.org/show_bug.cgi?id=785522 is fixed */ - g_string_append (uri, "stable/"); - /* g_string_append_printf (uri, "%d.%d", EDS_MAJOR_VERSION, EDS_MINOR_VERSION); */ + g_string_append_printf (uri, "%d.%d", EDS_MAJOR_VERSION, EDS_MINOR_VERSION); } timestamp = gtk_get_current_event_time (); @@ -329,6 +327,7 @@ e_display_help (GtkWindow *parent, if (parent != NULL) screen = gtk_widget_get_screen (GTK_WIDGET (parent)); + if (link_id != NULL) { g_string_append (uri, "/"); g_string_append (uri, link_id); diff --git a/src/e-util/e-misc-utils.c.help-contents-link b/src/e-util/e-misc-utils.c.help-contents-link deleted file mode 100644 index c6f4e10..0000000 --- a/src/e-util/e-misc-utils.c.help-contents-link +++ /dev/null @@ -1,4209 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - * - * Authors: - * Chris Lahey - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include "evolution-config.h" - -#include "e-misc-utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef G_OS_WIN32 -#include -#else -#include -#endif - -#include -#include - -#include - -#ifdef HAVE_LDAP -#include -#ifndef SUNLDAP -#include -#endif -#endif /* HAVE_LDAP */ - -#include "e-alert-dialog.h" -#include "e-alert-sink.h" -#include "e-client-cache.h" -#include "e-filter-option.h" -#include "e-mktemp.h" -#include "e-util-private.h" -#include "e-xml-utils.h" - -typedef struct _WindowData WindowData; - -struct _WindowData { - GtkWindow *window; - GSettings *settings; - ERestoreWindowFlags flags; - gint premax_width; - gint premax_height; - guint timeout_id; -}; - -static void -window_data_free (WindowData *data) -{ - if (data->settings != NULL) - g_object_unref (data->settings); - - if (data->timeout_id > 0) - g_source_remove (data->timeout_id); - - g_slice_free (WindowData, data); -} - -static gboolean -window_update_settings (gpointer user_data) -{ - WindowData *data = user_data; - GSettings *settings = data->settings; - - if (data->flags & E_RESTORE_WINDOW_SIZE) { - GdkWindowState state; - GdkWindow *window; - gboolean maximized; - - window = gtk_widget_get_window (GTK_WIDGET (data->window)); - state = gdk_window_get_state (window); - maximized = ((state & GDK_WINDOW_STATE_MAXIMIZED) != 0); - - g_settings_set_boolean (settings, "maximized", maximized); - - if (!maximized) { - gint width, height; - - gtk_window_get_size (data->window, &width, &height); - - g_settings_set_int (settings, "width", width); - g_settings_set_int (settings, "height", height); - } - } - - if (data->flags & E_RESTORE_WINDOW_POSITION) { - gint x, y; - - gtk_window_get_position (data->window, &x, &y); - - g_settings_set_int (settings, "x", x); - g_settings_set_int (settings, "y", y); - } - - data->timeout_id = 0; - - return FALSE; -} - -static void -window_delayed_update_settings (WindowData *data) -{ - if (data->timeout_id > 0) - g_source_remove (data->timeout_id); - - data->timeout_id = e_named_timeout_add_seconds ( - 1, window_update_settings, data); -} - -static gboolean -window_configure_event_cb (GtkWindow *window, - GdkEventConfigure *event, - WindowData *data) -{ - window_delayed_update_settings (data); - - return FALSE; -} - -static gboolean -window_state_event_cb (GtkWindow *window, - GdkEventWindowState *event, - WindowData *data) -{ - gboolean window_was_unmaximized; - - if (data->timeout_id > 0) { - g_source_remove (data->timeout_id); - data->timeout_id = 0; - } - - window_was_unmaximized = - ((event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) != 0) && - ((event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) == 0); - - if (window_was_unmaximized) { - gint width, height; - - width = data->premax_width; - data->premax_width = 0; - - height = data->premax_height; - data->premax_height = 0; - - /* This only applies when the window is initially restored - * as maximized and is then unmaximized. GTK+ handles the - * unmaximized window size thereafter. */ - if (width > 0 && height > 0) - gtk_window_resize (window, width, height); - } - - window_delayed_update_settings (data); - - return FALSE; -} - -static gboolean -window_unmap_cb (GtkWindow *window, - WindowData *data) -{ - if (data->timeout_id > 0) { - g_source_remove (data->timeout_id); - data->timeout_id = 0; - } - - /* Reset the flags so the window position and size are not - * accidentally reverted to their default value at the next run. */ - data->flags = 0; - - return FALSE; -} - -/** - * e_get_accels_filename: - * - * Returns the name of the user data file containing custom keyboard - * accelerator specifications. - * - * Returns: filename for accelerator specifications - **/ -const gchar * -e_get_accels_filename (void) -{ - static gchar *filename = NULL; - - if (G_UNLIKELY (filename == NULL)) { - const gchar *config_dir = e_get_user_config_dir (); - filename = g_build_filename (config_dir, "accels", NULL); - } - - return filename; -} - -/** - * e_show_uri: - * @parent: a parent #GtkWindow or %NULL - * @uri: the URI to show - * - * Launches the default application to show the given URI. The URI must - * be of a form understood by GIO. If the URI cannot be shown, it presents - * a dialog describing the error. The dialog is set as transient to @parent - * if @parent is non-%NULL. - **/ -void -e_show_uri (GtkWindow *parent, - const gchar *uri) -{ - GtkWidget *dialog; - GdkScreen *screen = NULL; - GError *error = NULL; - guint32 timestamp; - - g_return_if_fail (uri != NULL); - - timestamp = gtk_get_current_event_time (); - - if (parent != NULL) - screen = gtk_widget_get_screen (GTK_WIDGET (parent)); - - if (gtk_show_uri (screen, uri, timestamp, &error)) - return; - - dialog = gtk_message_dialog_new_with_markup ( - parent, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - "%s", - _("Could not open the link.")); - - gtk_message_dialog_format_secondary_text ( - GTK_MESSAGE_DIALOG (dialog), "%s", error->message); - - gtk_dialog_run (GTK_DIALOG (dialog)); - - gtk_widget_destroy (dialog); - g_error_free (error); -} - -static gboolean -e_misc_utils_is_help_package_installed (void) -{ - gboolean is_installed; - gchar *path; - - /* Viewing user documentation requires the evolution help - * files. Look for one of the files it installs. */ - path = g_build_filename (EVOLUTION_DATADIR, "help", "C", PACKAGE, "index.page", NULL); - - is_installed = g_file_test (path, G_FILE_TEST_IS_REGULAR); - - g_free (path); - - if (is_installed) { - GAppInfo *help_handler; - - help_handler = g_app_info_get_default_for_uri_scheme ("help"); - - is_installed = help_handler && g_app_info_get_commandline (help_handler); - - g_clear_object (&help_handler); - } - - return is_installed; -} - -/** - * e_display_help: - * @parent: a parent #GtkWindow or %NULL - * @link_id: help section to present or %NULL - * - * Opens the user documentation to the section given by @link_id, or to the - * table of contents if @link_id is %NULL. If the user documentation cannot - * be opened, it presents a dialog describing the error. The dialog is set - * as transient to @parent if @parent is non-%NULL. - **/ -void -e_display_help (GtkWindow *parent, - const gchar *link_id) -{ - GString *uri; - GtkWidget *dialog; - GdkScreen *screen = NULL; - GError *error = NULL; - guint32 timestamp; - - if (e_misc_utils_is_help_package_installed ()) { - uri = g_string_new ("help:" PACKAGE); - } else { - uri = g_string_new ("https://help.gnome.org/users/" PACKAGE "/"); - g_string_append_printf (uri, "%d.%d", EDS_MAJOR_VERSION, EDS_MINOR_VERSION); - } - - timestamp = gtk_get_current_event_time (); - - if (parent != NULL) - screen = gtk_widget_get_screen (GTK_WIDGET (parent)); - - - if (link_id != NULL) { - g_string_append (uri, "/"); - g_string_append (uri, link_id); - } - - if (gtk_show_uri (screen, uri->str, timestamp, &error)) - goto exit; - - dialog = gtk_message_dialog_new_with_markup ( - parent, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - "%s", - _("Could not display help for Evolution.")); - - gtk_message_dialog_format_secondary_text ( - GTK_MESSAGE_DIALOG (dialog), "%s", error->message); - - gtk_dialog_run (GTK_DIALOG (dialog)); - - gtk_widget_destroy (dialog); - g_error_free (error); - -exit: - g_string_free (uri, TRUE); -} - -/** - * e_restore_window: - * @window: a #GtkWindow - * @settings_path: a #GSettings path - * @flags: flags indicating which window features to restore - * - * This function can restore one of or both a window's size and position - * using #GSettings keys at @settings_path which conform to the relocatable - * schema "org.gnome.evolution.window". - * - * If #E_RESTORE_WINDOW_SIZE is present in @flags, restore @window's - * previously recorded size and maximize state. - * - * If #E_RESTORE_WINDOW_POSITION is present in @flags, move @window to - * the previously recorded screen coordinates. - * - * The respective #GSettings values will be updated when the window is - * resized and/or moved. - **/ -void -e_restore_window (GtkWindow *window, - const gchar *settings_path, - ERestoreWindowFlags flags) -{ - WindowData *data; - GSettings *settings; - const gchar *schema; - - g_return_if_fail (GTK_IS_WINDOW (window)); - g_return_if_fail (settings_path != NULL); - - schema = "org.gnome.evolution.window"; - settings = g_settings_new_with_path (schema, settings_path); - - data = g_slice_new0 (WindowData); - data->window = window; - data->settings = g_object_ref (settings); - data->flags = flags; - - if (flags & E_RESTORE_WINDOW_SIZE) { - gint width, height; - - width = g_settings_get_int (settings, "width"); - height = g_settings_get_int (settings, "height"); - - if (width > 0 && height > 0) - gtk_window_resize (window, width, height); - - if (g_settings_get_boolean (settings, "maximized")) { - GdkScreen *screen; - GdkRectangle monitor_area; - gint x, y, monitor; - - x = g_settings_get_int (settings, "x"); - y = g_settings_get_int (settings, "y"); - - screen = gtk_window_get_screen (window); - gtk_window_get_size (window, &width, &height); - - data->premax_width = width; - data->premax_height = height; - - monitor = gdk_screen_get_monitor_at_point (screen, x, y); - if (monitor < 0) - monitor = 0; - - if (monitor >= gdk_screen_get_n_monitors (screen)) - monitor = 0; - - gdk_screen_get_monitor_workarea ( - screen, monitor, &monitor_area); - - gtk_window_resize ( - window, - monitor_area.width, - monitor_area.height); - - gtk_window_maximize (window); - } - } - - if (flags & E_RESTORE_WINDOW_POSITION) { - gint x, y; - - x = g_settings_get_int (settings, "x"); - y = g_settings_get_int (settings, "y"); - - gtk_window_move (window, x, y); - } - - g_object_set_data_full ( - G_OBJECT (window), - "e-util-window-data", data, - (GDestroyNotify) window_data_free); - - g_signal_connect ( - window, "configure-event", - G_CALLBACK (window_configure_event_cb), data); - - g_signal_connect ( - window, "window-state-event", - G_CALLBACK (window_state_event_cb), data); - - g_signal_connect ( - window, "unmap", - G_CALLBACK (window_unmap_cb), data); - - g_object_unref (settings); -} - -/** - * e_lookup_action: - * @ui_manager: a #GtkUIManager - * @action_name: the name of an action - * - * Returns the first #GtkAction named @action_name by traversing the - * list of action groups in @ui_manager. If no such action exists, the - * function emits a critical warning before returning %NULL, since this - * probably indicates a programming error and most code is not prepared - * to deal with lookup failures. - * - * Returns: the first #GtkAction named @action_name - **/ -GtkAction * -e_lookup_action (GtkUIManager *ui_manager, - const gchar *action_name) -{ - GtkAction *action = NULL; - GList *iter; - - g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); - g_return_val_if_fail (action_name != NULL, NULL); - - iter = gtk_ui_manager_get_action_groups (ui_manager); - - while (iter != NULL) { - GtkActionGroup *action_group = iter->data; - - action = gtk_action_group_get_action ( - action_group, action_name); - if (action != NULL) - return action; - - iter = g_list_next (iter); - } - - g_critical ("%s: action '%s' not found", G_STRFUNC, action_name); - - return NULL; -} - -/** - * e_lookup_action_group: - * @ui_manager: a #GtkUIManager - * @group_name: the name of an action group - * - * Returns the #GtkActionGroup in @ui_manager named @group_name. If no - * such action group exists, the function emits a critical warnings before - * returning %NULL, since this probably indicates a programming error and - * most code is not prepared to deal with lookup failures. - * - * Returns: the #GtkActionGroup named @group_name - **/ -GtkActionGroup * -e_lookup_action_group (GtkUIManager *ui_manager, - const gchar *group_name) -{ - GList *iter; - - g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); - g_return_val_if_fail (group_name != NULL, NULL); - - iter = gtk_ui_manager_get_action_groups (ui_manager); - - while (iter != NULL) { - GtkActionGroup *action_group = iter->data; - const gchar *name; - - name = gtk_action_group_get_name (action_group); - if (strcmp (name, group_name) == 0) - return action_group; - - iter = g_list_next (iter); - } - - g_critical ("%s: action group '%s' not found", G_STRFUNC, group_name); - - return NULL; -} - -/** - * e_action_compare_by_label: - * @action1: a #GtkAction - * @action2: a #GtkAction - * - * Compares the labels for @action1 and @action2 using g_utf8_collate(). - * - * Returns: < 0 if @action1 compares before @action2, 0 if they - * compare equal, > 0 if @action1 compares after @action2 - **/ -gint -e_action_compare_by_label (GtkAction *action1, - GtkAction *action2) -{ - gchar *label1; - gchar *label2; - gint result; - - /* XXX This is horribly inefficient but will generally only be - * used on short lists of actions during UI construction. */ - - if (action1 == action2) - return 0; - - g_object_get (action1, "label", &label1, NULL); - g_object_get (action2, "label", &label2, NULL); - - result = g_utf8_collate (label1, label2); - - g_free (label1); - g_free (label2); - - return result; -} - -/** - * e_action_group_remove_all_actions: - * @action_group: a #GtkActionGroup - * - * Removes all actions from the action group. - **/ -void -e_action_group_remove_all_actions (GtkActionGroup *action_group) -{ - GList *list, *iter; - - /* XXX I've proposed this function for inclusion in GTK+. - * GtkActionGroup stores actions in an internal hash - * table and can do this more efficiently by calling - * g_hash_table_remove_all(). - * - * http://bugzilla.gnome.org/show_bug.cgi?id=550485 */ - - g_return_if_fail (GTK_IS_ACTION_GROUP (action_group)); - - list = gtk_action_group_list_actions (action_group); - for (iter = list; iter != NULL; iter = iter->next) - gtk_action_group_remove_action (action_group, iter->data); - g_list_free (list); -} - -/** - * e_radio_action_get_current_action: - * @radio_action: a #GtkRadioAction - * - * Returns the currently active member of the group to which @radio_action - * belongs. - * - * Returns: the currently active group member - **/ -GtkRadioAction * -e_radio_action_get_current_action (GtkRadioAction *radio_action) -{ - GSList *group; - gint current_value; - - g_return_val_if_fail (GTK_IS_RADIO_ACTION (radio_action), NULL); - - group = gtk_radio_action_get_group (radio_action); - current_value = gtk_radio_action_get_current_value (radio_action); - - while (group != NULL) { - gint value; - - radio_action = GTK_RADIO_ACTION (group->data); - g_object_get (radio_action, "value", &value, NULL); - - if (value == current_value) - return radio_action; - - group = g_slist_next (group); - } - - return NULL; -} - -/** - * e_action_group_add_actions_localized: - * @action_group: a #GtkActionGroup to add @entries to - * @translation_domain: a translation domain to use - * to translate label and tooltip strings in @entries - * @entries: (array length=n_entries): an array of action descriptions - * @n_entries: the number of entries - * @user_data: data to pass to the action callbacks - * - * Adds #GtkAction-s defined by @entries to @action_group, with action's - * label and tooltip localized in the given translation domain, instead - * of the domain set on the @action_group. - * - * Since: 3.4 - **/ -void -e_action_group_add_actions_localized (GtkActionGroup *action_group, - const gchar *translation_domain, - const GtkActionEntry *entries, - guint n_entries, - gpointer user_data) -{ - GtkActionGroup *tmp_group; - GList *list, *iter; - gint ii; - - g_return_if_fail (action_group != NULL); - g_return_if_fail (entries != NULL); - g_return_if_fail (n_entries > 0); - g_return_if_fail (translation_domain != NULL); - g_return_if_fail (*translation_domain); - - tmp_group = gtk_action_group_new ("temporary-group"); - gtk_action_group_set_translation_domain (tmp_group, translation_domain); - gtk_action_group_add_actions (tmp_group, entries, n_entries, user_data); - - list = gtk_action_group_list_actions (tmp_group); - for (iter = list; iter != NULL; iter = iter->next) { - GtkAction *action = GTK_ACTION (iter->data); - const gchar *action_name; - - g_object_ref (action); - - action_name = gtk_action_get_name (action); - - for (ii = 0; ii < n_entries; ii++) { - if (g_strcmp0 (entries[ii].name, action_name) == 0) { - gtk_action_group_remove_action ( - tmp_group, action); - gtk_action_group_add_action_with_accel ( - action_group, action, - entries[ii].accelerator); - break; - } - } - - g_object_unref (action); - } - - g_list_free (list); - g_object_unref (tmp_group); -} - -/** - * e_builder_get_widget: - * @builder: a #GtkBuilder - * @widget_name: name of a widget in @builder - * - * Gets the widget named @widget_name. Note that this function does not - * increment the reference count of the returned widget. If @widget_name - * could not be found in the @builder's object tree, a run-time - * warning is emitted since this usually indicates a programming error. - * - * This is a convenience function to work around the awkwardness of - * #GtkBuilder returning #GObject pointers, when the vast majority of - * the time you want a #GtkWidget pointer. - * - * If you need something from @builder other than a #GtkWidget, or you - * want to test for the existence of some widget name without incurring - * a run-time warning, use gtk_builder_get_object(). - * - * Returns: the widget named @widget_name, or %NULL - **/ -GtkWidget * -e_builder_get_widget (GtkBuilder *builder, - const gchar *widget_name) -{ - GObject *object; - - g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL); - g_return_val_if_fail (widget_name != NULL, NULL); - - object = gtk_builder_get_object (builder, widget_name); - if (object == NULL) { - g_warning ("Could not find widget '%s'", widget_name); - return NULL; - } - - return GTK_WIDGET (object); -} - -/** - * e_load_ui_builder_definition: - * @builder: a #GtkBuilder - * @basename: basename of the UI definition file - * - * Loads a UI definition into @builder from Evolution's UI directory. - * Failure here is fatal, since the application can't function without - * its UI definitions. - **/ -void -e_load_ui_builder_definition (GtkBuilder *builder, - const gchar *basename) -{ - gchar *filename; - GError *error = NULL; - - g_return_if_fail (GTK_IS_BUILDER (builder)); - g_return_if_fail (basename != NULL); - - filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL); - gtk_builder_add_from_file (builder, filename, &error); - g_free (filename); - - if (error != NULL) { - g_error ("%s: %s", basename, error->message); - g_warn_if_reached (); - } -} - -static gdouble -e_get_ui_manager_definition_file_version (const gchar *filename) -{ - xmlDocPtr doc; - xmlNode *root; - gdouble version = -1.0; - - g_return_val_if_fail (filename != NULL, version); - - doc = e_xml_parse_file (filename); - if (!doc) - return version; - - root = xmlDocGetRootElement (doc); - if (root && g_strcmp0 ((const gchar *) root->name, "ui") == 0) { - version = e_xml_get_double_prop_by_name_with_default (root, (const xmlChar *) "evolution-ui-version", -1.0); - } - - xmlFreeDoc (doc); - - return version; -} - -static gchar * -e_pick_ui_manager_definition_file (const gchar *basename) -{ - gchar *system_filename, *user_filename; - gdouble system_version, user_version; - - g_return_val_if_fail (basename != NULL, NULL); - - system_filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL); - user_filename = g_build_filename (e_get_user_config_dir (), "ui", basename, NULL); - - if (!g_file_test (user_filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { - g_free (user_filename); - - return system_filename; - } - - user_version = e_get_ui_manager_definition_file_version (user_filename); - system_version = e_get_ui_manager_definition_file_version (system_filename); - - /* Versions are equal and the system version is a positive number */ - if (user_version - system_version >= -1e-9 && - user_version - system_version <= 1e-9 && - system_version > 1e-9) { - g_free (system_filename); - - return user_filename; - } - - g_warning ("User's UI file '%s' version (%.1f) doesn't match expected version (%.1f), skipping it. Either correct the version or remove the file.", - user_filename, user_version, system_version); - - g_free (user_filename); - - return system_filename; -} - -/** - * e_load_ui_manager_definition: - * @ui_manager: a #GtkUIManager - * @basename: basename of the UI definition file - * - * Loads a UI definition into @ui_manager from Evolution's UI directory. - * Failure here is fatal, since the application can't function without - * its UI definitions. - * - * Returns: The merge ID for the merged UI. The merge ID can be used to - * unmerge the UI with gtk_ui_manager_remove_ui(). - **/ -guint -e_load_ui_manager_definition (GtkUIManager *ui_manager, - const gchar *basename) -{ - gchar *filename; - guint merge_id; - GError *error = NULL; - - g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), 0); - g_return_val_if_fail (basename != NULL, 0); - - filename = e_pick_ui_manager_definition_file (basename); - merge_id = gtk_ui_manager_add_ui_from_file ( - ui_manager, filename, &error); - g_free (filename); - - if (error != NULL) { - g_error ("%s: %s", basename, error->message); - g_warn_if_reached (); - } - - return merge_id; -} - -/* Helper for e_categories_add_change_hook() */ -static void -categories_changed_cb (GObject *useless_opaque_object, - GHookList *hook_list) -{ - /* e_categories_register_change_listener() is broken because - * it requires callbacks to allow for some opaque GObject as - * the first argument (not does it document this). */ - g_hook_list_invoke (hook_list, FALSE); -} - -/* Helper for e_categories_add_change_hook() */ -static void -categories_weak_notify_cb (GHookList *hook_list, - gpointer where_the_object_was) -{ - GHook *hook; - - /* This should not happen, but if we fail to find the hook for - * some reason, g_hook_destroy_link() will warn about the NULL - * pointer, which is all we would do anyway so no need to test - * for it ourselves. */ - hook = g_hook_find_data (hook_list, TRUE, where_the_object_was); - g_hook_destroy_link (hook_list, hook); -} - -/** - * e_categories_add_change_hook: - * @func: a hook function - * @object: a #GObject to be passed to @func, or %NULL - * - * A saner alternative to e_categories_register_change_listener(). - * - * Adds a hook function to be called when a category is added, removed or - * modified. If @object is not %NULL, the hook function is automatically - * removed when @object is finalized. - **/ -void -e_categories_add_change_hook (GHookFunc func, - gpointer object) -{ - static gboolean initialized = FALSE; - static GHookList hook_list; - GHook *hook; - - g_return_if_fail (func != NULL); - - if (object != NULL) - g_return_if_fail (G_IS_OBJECT (object)); - - if (!initialized) { - g_hook_list_init (&hook_list, sizeof (GHook)); - e_categories_register_change_listener ( - G_CALLBACK (categories_changed_cb), &hook_list); - initialized = TRUE; - } - - hook = g_hook_alloc (&hook_list); - - hook->func = func; - hook->data = object; - - if (object != NULL) - g_object_weak_ref ( - G_OBJECT (object), (GWeakNotify) - categories_weak_notify_cb, &hook_list); - - g_hook_append (&hook_list, hook); -} - -/** - * e_flexible_strtod: - * @nptr: the string to convert to a numeric value. - * @endptr: if non-NULL, it returns the character after - * the last character used in the conversion. - * - * Converts a string to a gdouble value. This function detects - * strings either in the standard C locale or in the current locale. - * - * This function is typically used when reading configuration files or - * other non-user input that should not be locale dependent, but may - * have been in the past. To handle input from the user you should - * normally use the locale-sensitive system strtod function. - * - * To convert from a double to a string in a locale-insensitive way, use - * @g_ascii_dtostr. - * - * Returns: the gdouble value - **/ -gdouble -e_flexible_strtod (const gchar *nptr, - gchar **endptr) -{ - gchar *fail_pos; - gdouble val; - struct lconv *locale_data; - const gchar *decimal_point; - gint decimal_point_len; - const gchar *p, *decimal_point_pos; - const gchar *end = NULL; /* Silence gcc */ - gchar *copy, *c; - - g_return_val_if_fail (nptr != NULL, 0); - - fail_pos = NULL; - - locale_data = localeconv (); - decimal_point = locale_data->decimal_point; - decimal_point_len = strlen (decimal_point); - - g_return_val_if_fail (decimal_point_len != 0, 0); - - decimal_point_pos = NULL; - if (!strcmp (decimal_point, ".")) - return strtod (nptr, endptr); - - p = nptr; - - /* Skip leading space */ - while (isspace ((guchar) * p)) - p++; - - /* Skip leading optional sign */ - if (*p == '+' || *p == '-') - p++; - - if (p[0] == '0' && - (p[1] == 'x' || p[1] == 'X')) { - p += 2; - /* HEX - find the (optional) decimal point */ - - while (isxdigit ((guchar) * p)) - p++; - - if (*p == '.') { - decimal_point_pos = p++; - - while (isxdigit ((guchar) * p)) - p++; - - if (*p == 'p' || *p == 'P') - p++; - if (*p == '+' || *p == '-') - p++; - while (isdigit ((guchar) * p)) - p++; - end = p; - } else if (strncmp (p, decimal_point, decimal_point_len) == 0) { - return strtod (nptr, endptr); - } - } else { - while (isdigit ((guchar) * p)) - p++; - - if (*p == '.') { - decimal_point_pos = p++; - - while (isdigit ((guchar) * p)) - p++; - - if (*p == 'e' || *p == 'E') - p++; - if (*p == '+' || *p == '-') - p++; - while (isdigit ((guchar) * p)) - p++; - end = p; - } else if (strncmp (p, decimal_point, decimal_point_len) == 0) { - return strtod (nptr, endptr); - } - } - /* For the other cases, we need not convert the decimal point */ - - if (!decimal_point_pos) - return strtod (nptr, endptr); - - /* We need to convert the '.' to the locale specific decimal point */ - copy = g_malloc (end - nptr + 1 + decimal_point_len); - - c = copy; - memcpy (c, nptr, decimal_point_pos - nptr); - c += decimal_point_pos - nptr; - memcpy (c, decimal_point, decimal_point_len); - c += decimal_point_len; - memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1)); - c += end - (decimal_point_pos + 1); - *c = 0; - - val = strtod (copy, &fail_pos); - - if (fail_pos) { - if (fail_pos > decimal_point_pos) - fail_pos = - (gchar *) nptr + (fail_pos - copy) - - (decimal_point_len - 1); - else - fail_pos = (gchar *) nptr + (fail_pos - copy); - } - - g_free (copy); - - if (endptr) - *endptr = fail_pos; - - return val; -} - -/** - * e_ascii_dtostr: - * @buffer: A buffer to place the resulting string in - * @buf_len: The length of the buffer. - * @format: The printf-style format to use for the - * code to use for converting. - * @d: The double to convert - * - * Converts a double to a string, using the '.' as - * decimal_point. To format the number you pass in - * a printf-style formating string. Allowed conversion - * specifiers are eEfFgG. - * - * If you want to generates enough precision that converting - * the string back using @g_strtod gives the same machine-number - * (on machines with IEEE compatible 64bit doubles) use the format - * string "%.17g". If you do this it is guaranteed that the size - * of the resulting string will never be larger than - * @G_ASCII_DTOSTR_BUF_SIZE bytes. - * - * Returns: the pointer to the buffer with the converted string - **/ -gchar * -e_ascii_dtostr (gchar *buffer, - gint buf_len, - const gchar *format, - gdouble d) -{ - struct lconv *locale_data; - const gchar *decimal_point; - gint decimal_point_len; - gchar *p; - gint rest_len; - gchar format_char; - - g_return_val_if_fail (buffer != NULL, NULL); - g_return_val_if_fail (format[0] == '%', NULL); - g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL); - - format_char = format[strlen (format) - 1]; - - g_return_val_if_fail (format_char == 'e' || format_char == 'E' || - format_char == 'f' || format_char == 'F' || - format_char == 'g' || format_char == 'G', - NULL); - - if (format[0] != '%') - return NULL; - - if (strpbrk (format + 1, "'l%")) - return NULL; - - if (!(format_char == 'e' || format_char == 'E' || - format_char == 'f' || format_char == 'F' || - format_char == 'g' || format_char == 'G')) - return NULL; - - g_snprintf (buffer, buf_len, format, d); - - locale_data = localeconv (); - decimal_point = locale_data->decimal_point; - decimal_point_len = strlen (decimal_point); - - g_return_val_if_fail (decimal_point_len != 0, NULL); - - if (strcmp (decimal_point, ".")) { - p = buffer; - - if (*p == '+' || *p == '-') - p++; - - while (isdigit ((guchar) * p)) - p++; - - if (strncmp (p, decimal_point, decimal_point_len) == 0) { - *p = '.'; - p++; - if (decimal_point_len > 1) { - rest_len = strlen (p + (decimal_point_len - 1)); - memmove ( - p, p + (decimal_point_len - 1), - rest_len); - p[rest_len] = 0; - } - } - } - - return buffer; -} - -/** - * e_str_without_underscores: - * @string: the string to strip underscores from - * - * Strips underscores from a string in the same way - * @gtk_label_new_with_mnemonics does. The returned string should be freed - * using g_free(). - * - * Returns: a newly-allocated string without underscores - */ -gchar * -e_str_without_underscores (const gchar *string) -{ - gchar *new_string; - const gchar *sp; - gchar *dp; - - new_string = g_malloc (strlen (string) + 1); - - dp = new_string; - for (sp = string; *sp != '\0'; sp++) { - if (*sp != '_') { - *dp = *sp; - dp++; - } else if (sp[1] == '_') { - /* Translate "__" in "_". */ - *dp = '_'; - dp++; - sp++; - } - } - *dp = 0; - - return new_string; -} - -/** - * e_str_replace_string - * @text: the string to replace - * @before: the string to be replaced - * @after: the string to replaced with - * - * Replaces every occurrence of the string @before with the string @after in - * the string @text and returns a #GString with result that should be freed - * with g_string_free(). - * - * Returns: a newly-allocated #GString - */ -GString * -e_str_replace_string (const gchar *text, - const gchar *before, - const gchar *after) -{ - const gchar *p, *next; - GString *str; - gint find_len; - - g_return_val_if_fail (text != NULL, NULL); - g_return_val_if_fail (before != NULL, NULL); - g_return_val_if_fail (*before, NULL); - - find_len = strlen (before); - str = g_string_new (""); - - p = text; - while (next = strstr (p, before), next) { - if (p < next) - g_string_append_len (str, p, next - p); - - if (after && *after) - g_string_append (str, after); - - p = next + find_len; - } - - g_string_append (str, p); - - return str; -} - -gint -e_str_compare (gconstpointer x, - gconstpointer y) -{ - if (x == NULL || y == NULL) { - if (x == y) - return 0; - else - return x ? -1 : 1; - } - - return strcmp (x, y); -} - -gint -e_str_case_compare (gconstpointer x, - gconstpointer y) -{ - gchar *cx, *cy; - gint res; - - if (x == NULL || y == NULL) { - if (x == y) - return 0; - else - return x ? -1 : 1; - } - - cx = g_utf8_casefold (x, -1); - cy = g_utf8_casefold (y, -1); - - res = g_utf8_collate (cx, cy); - - g_free (cx); - g_free (cy); - - return res; -} - -gint -e_collate_compare (gconstpointer x, - gconstpointer y) -{ - if (x == NULL || y == NULL) { - if (x == y) - return 0; - else - return x ? -1 : 1; - } - - return g_utf8_collate (x, y); -} - -gint -e_int_compare (gconstpointer x, - gconstpointer y) -{ - gint nx = GPOINTER_TO_INT (x); - gint ny = GPOINTER_TO_INT (y); - - return (nx == ny) ? 0 : (nx < ny) ? -1 : 1; -} - -/** - * e_color_to_value: - * @color: a #GdkColor - * - * Converts a #GdkColor to a 24-bit RGB color value. - * - * Returns: a 24-bit color value - **/ -guint32 -e_color_to_value (const GdkColor *color) -{ - GdkRGBA rgba; - - g_return_val_if_fail (color != NULL, 0); - - rgba.red = color->red / 65535.0; - rgba.green = color->green / 65535.0; - rgba.blue = color->blue / 65535.0; - rgba.alpha = 0.0; - - return e_rgba_to_value (&rgba); -} - -/** - * e_rgba_to_value: - * @rgba: a #GdkRGBA - * - * Converts #GdkRGBA to a 24-bit RGB color value - * - * Returns: a 24-bit color value - **/ -guint32 -e_rgba_to_value (const GdkRGBA *rgba) -{ - guint16 red; - guint16 green; - guint16 blue; - - g_return_val_if_fail (rgba != NULL, 0); - - red = 255 * rgba->red; - green = 255 * rgba->green; - blue = 255 * rgba->blue; - - return (guint32) - ((((red & 0xFF) << 16) | - ((green & 0xFF) << 8) | - (blue & 0xFF)) & 0xffffff); -} - -/** - * e_rgba_to_color: - * @rgba: a source #GdkRGBA - * @color: a destination #GdkColor - * - * Converts @rgba into @color, but loses the alpha channel from @rgba. - **/ -void -e_rgba_to_color (const GdkRGBA *rgba, - GdkColor *color) -{ - g_return_if_fail (rgba != NULL); - g_return_if_fail (color != NULL); - - color->pixel = 0; - color->red = rgba->red * 65535.0; - color->green = rgba->green * 65535.0; - color->blue = rgba->blue * 65535.0; -} - -/** - * e_utils_get_theme_color: - * @widget: a #GtkWidget instance - * @color_names: comma-separated theme color names - * @fallback_color_ident: fallback color identificator, in a format for gdk_rgba_parse() - * @rgba: where to store the read color - * - * Reads named theme color from a #GtkStyleContext of @widget. - * The @color_names are read one after another from left to right, - * the next are meant as fallbacks, in case the theme doesn't - * define the previous color. If none is found then the @fallback_color_ident - * is set to @rgba. - **/ -void -e_utils_get_theme_color (GtkWidget *widget, - const gchar *color_names, - const gchar *fallback_color_ident, - GdkRGBA *rgba) -{ - GtkStyleContext *style_context; - gchar **names; - gint ii; - - g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (color_names != NULL); - g_return_if_fail (fallback_color_ident != NULL); - g_return_if_fail (rgba != NULL); - - style_context = gtk_widget_get_style_context (widget); - - names = g_strsplit (color_names, ",", -1); - for (ii = 0; names && names[ii]; ii++) { - if (gtk_style_context_lookup_color (style_context, names[ii], rgba)) { - g_strfreev (names); - return; - } - } - - g_strfreev (names); - - g_warn_if_fail (gdk_rgba_parse (rgba, fallback_color_ident)); -} - -/** - * e_utils_get_theme_color_color: - * @widget: a #GtkWidget instance - * @color_names: comma-separated theme color names - * @fallback_color_ident: fallback color identificator, in a format for gdk_rgba_parse() - * @color: where to store the read color - * - * The same as e_utils_get_theme_color(), only populates #GdkColor, - * instead of #GdkRGBA. - **/ -void -e_utils_get_theme_color_color (GtkWidget *widget, - const gchar *color_names, - const gchar *fallback_color_ident, - GdkColor *color) -{ - GdkRGBA rgba; - - g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (color_names != NULL); - g_return_if_fail (fallback_color_ident != NULL); - g_return_if_fail (color != NULL); - - e_utils_get_theme_color (widget, color_names, fallback_color_ident, &rgba); - - e_rgba_to_color (&rgba, color); -} - -/* This is copied from gtk+ sources */ -static void -rgb_to_hls (gdouble *r, - gdouble *g, - gdouble *b) -{ - gdouble min; - gdouble max; - gdouble red; - gdouble green; - gdouble blue; - gdouble h, l, s; - gdouble delta; - - red = *r; - green = *g; - blue = *b; - - if (red > green) { - if (red > blue) - max = red; - else - max = blue; - - if (green < blue) - min = green; - else - min = blue; - } else { - if (green > blue) - max = green; - else - max = blue; - - if (red < blue) - min = red; - else - min = blue; - } - - l = (max + min) / 2; - s = 0; - h = 0; - - if (max != min) { - if (l <= 0.5) - s = (max - min) / (max + min); - else - s = (max - min) / (2 - max - min); - - delta = max -min; - if (red == max) - h = (green - blue) / delta; - else if (green == max) - h = 2 + (blue - red) / delta; - else if (blue == max) - h = 4 + (red - green) / delta; - - h *= 60; - if (h < 0.0) - h += 360; - } - - *r = h; - *g = l; - *b = s; -} - -/* This is copied from gtk+ sources */ -static void -hls_to_rgb (gdouble *h, - gdouble *l, - gdouble *s) -{ - gdouble hue; - gdouble lightness; - gdouble saturation; - gdouble m1, m2; - gdouble r, g, b; - - lightness = *l; - saturation = *s; - - if (lightness <= 0.5) - m2 = lightness * (1 + saturation); - else - m2 = lightness + saturation - lightness * saturation; - m1 = 2 * lightness - m2; - - if (saturation == 0) { - *h = lightness; - *l = lightness; - *s = lightness; - } else { - hue = *h + 120; - while (hue > 360) - hue -= 360; - while (hue < 0) - hue += 360; - - if (hue < 60) - r = m1 + (m2 - m1) * hue / 60; - else if (hue < 180) - r = m2; - else if (hue < 240) - r = m1 + (m2 - m1) * (240 - hue) / 60; - else - r = m1; - - hue = *h; - while (hue > 360) - hue -= 360; - while (hue < 0) - hue += 360; - - if (hue < 60) - g = m1 + (m2 - m1) * hue / 60; - else if (hue < 180) - g = m2; - else if (hue < 240) - g = m1 + (m2 - m1) * (240 - hue) / 60; - else - g = m1; - - hue = *h - 120; - while (hue > 360) - hue -= 360; - while (hue < 0) - hue += 360; - - if (hue < 60) - b = m1 + (m2 - m1) * hue / 60; - else if (hue < 180) - b = m2; - else if (hue < 240) - b = m1 + (m2 - m1) * (240 - hue) / 60; - else - b = m1; - - *h = r; - *l = g; - *s = b; - } -} - -/* This is copied from gtk+ sources */ -void -e_utils_shade_color (const GdkRGBA *a, - GdkRGBA *b, - gdouble mult) -{ - gdouble red; - gdouble green; - gdouble blue; - - g_return_if_fail (a != NULL); - g_return_if_fail (b != NULL); - - red = a->red; - green = a->green; - blue = a->blue; - - rgb_to_hls (&red, &green, &blue); - - green *= mult; - if (green > 1.0) - green = 1.0; - else if (green < 0.0) - green = 0.0; - - blue *= mult; - if (blue > 1.0) - blue = 1.0; - else if (blue < 0.0) - blue = 0.0; - - hls_to_rgb (&red, &green, &blue); - - b->red = red; - b->green = green; - b->blue = blue; - b->alpha = a->alpha; -} - -static gint -epow10 (gint number) -{ - gint value = 1; - - while (number-- > 0) - value *= 10; - - return value; -} - -gchar * -e_format_number (gint number) -{ - GList *iterator, *list = NULL; - struct lconv *locality; - gint char_length = 0; - gint group_count = 0; - gchar *grouping; - gint last_count = 3; - gint divider; - gchar *value; - gchar *value_iterator; - - locality = localeconv (); - grouping = locality->grouping; - while (number) { - gchar *group; - switch (*grouping) { - default: - last_count = *grouping; - grouping++; - /* coverity[fallthrough] */ - case 0: - divider = epow10 (last_count); - if (number >= divider) { - group = g_strdup_printf ( - "%0*d", last_count, number % divider); - } else { - group = g_strdup_printf ( - "%d", number % divider); - } - number /= divider; - break; - case CHAR_MAX: - group = g_strdup_printf ("%d", number); - number = 0; - break; - } - char_length += strlen (group); - list = g_list_prepend (list, group); - group_count++; - } - - if (list) { - value = g_new ( - gchar, 1 + char_length + (group_count - 1) * - strlen (locality->thousands_sep)); - - iterator = list; - value_iterator = value; - - strcpy (value_iterator, iterator->data); - value_iterator += strlen (iterator->data); - for (iterator = iterator->next; iterator; iterator = iterator->next) { - strcpy (value_iterator, locality->thousands_sep); - value_iterator += strlen (locality->thousands_sep); - - strcpy (value_iterator, iterator->data); - value_iterator += strlen (iterator->data); - } - g_list_foreach (list, (GFunc) g_free, NULL); - g_list_free (list); - return value; - } else { - return g_strdup ("0"); - } -} - -/* Perform a binary search for key in base which has nmemb elements - * of size bytes each. The comparisons are done by (*compare)(). */ -void -e_bsearch (gconstpointer key, - gconstpointer base, - gsize nmemb, - gsize size, - ESortCompareFunc compare, - gpointer closure, - gsize *start, - gsize *end) -{ - gsize l, u, idx; - gconstpointer p; - gint comparison; - if (!(start || end)) - return; - - l = 0; - u = nmemb; - while (l < u) { - idx = (l + u) / 2; - p = (((const gchar *) base) + (idx * size)); - comparison = (*compare) (key, p, closure); - if (comparison < 0) - u = idx; - else if (comparison > 0) - l = idx + 1; - else { - gsize lsave, usave; - lsave = l; - usave = u; - if (start) { - while (l < u) { - idx = (l + u) / 2; - p = (((const gchar *) base) + (idx * size)); - comparison = (*compare) (key, p, closure); - if (comparison <= 0) - u = idx; - else - l = idx + 1; - } - *start = l; - - l = lsave; - u = usave; - } - if (end) { - while (l < u) { - idx = (l + u) / 2; - p = (((const gchar *) base) + (idx * size)); - comparison = (*compare) (key, p, closure); - if (comparison < 0) - u = idx; - else - l = idx + 1; - } - *end = l; - } - return; - } - } - - if (start) - *start = l; - if (end) - *end = l; -} - -/* Function to do a last minute fixup of the AM/PM stuff if the locale - * and gettext haven't done it right. Most English speaking countries - * except the USA use the 24 hour clock (UK, Australia etc). However - * since they are English nobody bothers to write a language - * translation (gettext) file. So the locale turns off the AM/PM, but - * gettext does not turn on the 24 hour clock. Leaving a mess. - * - * This routine checks if AM/PM are defined in the locale, if not it - * forces the use of the 24 hour clock. - * - * The function itself is a front end on strftime and takes exactly - * the same arguments. - * - * TODO: Actually remove the '%p' from the fixed up string so that - * there isn't a stray space. - */ - -gsize -e_strftime_fix_am_pm (gchar *str, - gsize max, - const gchar *fmt, - const struct tm *tm) -{ - gchar buf[10]; - gchar *sp; - gchar *ffmt; - gsize ret; - - if (strstr (fmt, "%p") == NULL && strstr (fmt, "%P") == NULL) { - /* No AM/PM involved - can use the fmt string directly */ - ret = e_strftime (str, max, fmt, tm); - } else { - /* Get the AM/PM symbol from the locale */ - e_strftime (buf, 10, "%p", tm); - - if (buf[0]) { - /* AM/PM have been defined in the locale - * so we can use the fmt string directly. */ - ret = e_strftime (str, max, fmt, tm); - } else { - /* No AM/PM defined by locale - * must change to 24 hour clock. */ - ffmt = g_strdup (fmt); - for (sp = ffmt; (sp = strstr (sp, "%l")); sp++) { - /* Maybe this should be 'k', but I have never - * seen a 24 clock actually use that format. */ - sp[1]='H'; - } - for (sp = ffmt; (sp = strstr (sp, "%I")); sp++) { - sp[1]='H'; - } - ret = e_strftime (str, max, ffmt, tm); - g_free (ffmt); - } - } - - return (ret); -} - -gsize -e_utf8_strftime_fix_am_pm (gchar *str, - gsize max, - const gchar *fmt, - const struct tm *tm) -{ - gsize sz, ret; - gchar *locale_fmt, *buf; - - locale_fmt = g_locale_from_utf8 (fmt, -1, NULL, &sz, NULL); - if (!locale_fmt) - return 0; - - ret = e_strftime_fix_am_pm (str, max, locale_fmt, tm); - if (!ret) { - g_free (locale_fmt); - return 0; - } - - buf = g_locale_to_utf8 (str, ret, NULL, &sz, NULL); - if (!buf) { - g_free (locale_fmt); - return 0; - } - - if (sz >= max) { - gchar *tmp = buf + max - 1; - tmp = g_utf8_find_prev_char (buf, tmp); - if (tmp) - sz = tmp - buf; - else - sz = 0; - } - memcpy (str, buf, sz); - str[sz] = '\0'; - g_free (locale_fmt); - g_free (buf); - return sz; -} - -/** - * e_utf8_strftime_match_lc_messages: - * @string: The string to store the result in. - * @max: The size of the @string. - * @fmt: The formatting to use on @tm. - * @tm: The time value to format. - * - * The UTF-8 equivalent of e_strftime (), which also - * makes sure that the locale used for time and date - * formatting matches the locale used by the - * application so that, for example, the quoted - * message header produced by the mail composer in a - * reply uses only one locale (i.e. LC_MESSAGES, where - * available, overrides LC_TIME for consistency). - * - * Returns: The number of characters placed in @string. - * - * Since: 3.22 - **/ -gsize -e_utf8_strftime_match_lc_messages (gchar *string, - gsize max, - const gchar *fmt, - const struct tm *tm) -{ - gsize ret; -#if defined(LC_MESSAGES) && defined(LC_TIME) - gchar *ctime, *cmessages, *saved_locale; - - /* Use LC_MESSAGES instead of LC_TIME for time - * formatting (for consistency). - */ - ctime = setlocale (LC_TIME, NULL); - saved_locale = g_strdup (ctime); - g_return_val_if_fail (saved_locale != NULL, 0); - cmessages = setlocale (LC_MESSAGES, NULL); - setlocale (LC_TIME, cmessages); -#endif - - ret = e_utf8_strftime(string, max, fmt, tm); - -#if defined(LC_MESSAGES) && defined(LC_TIME) - /* Restore LC_TIME, if it has been changed to match - * LC_MESSAGES. - */ - setlocale (LC_TIME, saved_locale); - g_free (saved_locale); -#endif - - return ret; -} - -/** - * e_get_month_name: - * @month: month index - * @abbreviated: if %TRUE, abbreviate the month name - * - * Returns the localized name for @month. If @abbreviated is %TRUE, - * returns the locale's abbreviated month name. - * - * Returns: localized month name - **/ -const gchar * -e_get_month_name (GDateMonth month, - gboolean abbreviated) -{ - /* Make the indices correspond to the enum values. */ - static const gchar *abbr_names[G_DATE_DECEMBER + 1]; - static const gchar *full_names[G_DATE_DECEMBER + 1]; - static gboolean first_time = TRUE; - - g_return_val_if_fail (month >= G_DATE_JANUARY, NULL); - g_return_val_if_fail (month <= G_DATE_DECEMBER, NULL); - - if (G_UNLIKELY (first_time)) { - gchar buffer[256]; - GDateMonth ii; - GDate date; - - memset (abbr_names, 0, sizeof (abbr_names)); - memset (full_names, 0, sizeof (full_names)); - - /* First Julian day was in January. */ - g_date_set_julian (&date, 1); - - for (ii = G_DATE_JANUARY; ii <= G_DATE_DECEMBER; ii++) { - g_date_strftime (buffer, sizeof (buffer), "%b", &date); - abbr_names[ii] = g_intern_string (buffer); - g_date_strftime (buffer, sizeof (buffer), "%B", &date); - full_names[ii] = g_intern_string (buffer); - g_date_add_months (&date, 1); - } - - first_time = FALSE; - } - - return abbreviated ? abbr_names[month] : full_names[month]; -} - -/** - * e_get_weekday_name: - * @weekday: weekday index - * @abbreviated: if %TRUE, abbreviate the weekday name - * - * Returns the localized name for @weekday. If @abbreviated is %TRUE, - * returns the locale's abbreviated weekday name. - * - * Returns: localized weekday name - **/ -const gchar * -e_get_weekday_name (GDateWeekday weekday, - gboolean abbreviated) -{ - /* Make the indices correspond to the enum values. */ - static const gchar *abbr_names[G_DATE_SUNDAY + 1]; - static const gchar *full_names[G_DATE_SUNDAY + 1]; - static gboolean first_time = TRUE; - - g_return_val_if_fail (weekday >= G_DATE_MONDAY, NULL); - g_return_val_if_fail (weekday <= G_DATE_SUNDAY, NULL); - - if (G_UNLIKELY (first_time)) { - gchar buffer[256]; - GDateWeekday ii; - GDate date; - - memset (abbr_names, 0, sizeof (abbr_names)); - memset (full_names, 0, sizeof (full_names)); - - /* First Julian day was a Monday. */ - g_date_set_julian (&date, 1); - - for (ii = G_DATE_MONDAY; ii <= G_DATE_SUNDAY; ii++) { - g_date_strftime (buffer, sizeof (buffer), "%a", &date); - abbr_names[ii] = g_intern_string (buffer); - g_date_strftime (buffer, sizeof (buffer), "%A", &date); - full_names[ii] = g_intern_string (buffer); - g_date_add_days (&date, 1); - } - - first_time = FALSE; - } - - return abbreviated ? abbr_names[weekday] : full_names[weekday]; -} - -/** - * e_weekday_get_next: - * @weekday: a #GDateWeekday - * - * Returns the #GDateWeekday after @weekday. - * - * Returns: the day after @weekday - **/ -GDateWeekday -e_weekday_get_next (GDateWeekday weekday) -{ - GDateWeekday next; - - /* Verbose for readability. */ - switch (weekday) { - case G_DATE_MONDAY: - next = G_DATE_TUESDAY; - break; - case G_DATE_TUESDAY: - next = G_DATE_WEDNESDAY; - break; - case G_DATE_WEDNESDAY: - next = G_DATE_THURSDAY; - break; - case G_DATE_THURSDAY: - next = G_DATE_FRIDAY; - break; - case G_DATE_FRIDAY: - next = G_DATE_SATURDAY; - break; - case G_DATE_SATURDAY: - next = G_DATE_SUNDAY; - break; - case G_DATE_SUNDAY: - next = G_DATE_MONDAY; - break; - default: - next = G_DATE_BAD_WEEKDAY; - break; - } - - return next; -} - -/** - * e_weekday_get_prev: - * @weekday: a #GDateWeekday - * - * Returns the #GDateWeekday before @weekday. - * - * Returns: the day before @weekday - **/ -GDateWeekday -e_weekday_get_prev (GDateWeekday weekday) -{ - GDateWeekday prev; - - /* Verbose for readability. */ - switch (weekday) { - case G_DATE_MONDAY: - prev = G_DATE_SUNDAY; - break; - case G_DATE_TUESDAY: - prev = G_DATE_MONDAY; - break; - case G_DATE_WEDNESDAY: - prev = G_DATE_TUESDAY; - break; - case G_DATE_THURSDAY: - prev = G_DATE_WEDNESDAY; - break; - case G_DATE_FRIDAY: - prev = G_DATE_THURSDAY; - break; - case G_DATE_SATURDAY: - prev = G_DATE_FRIDAY; - break; - case G_DATE_SUNDAY: - prev = G_DATE_SATURDAY; - break; - default: - prev = G_DATE_BAD_WEEKDAY; - break; - } - - return prev; -} - -/** - * e_weekday_add_days: - * @weekday: a #GDateWeekday - * @n_days: number of days to add - * - * Increments @weekday by @n_days. - * - * Returns: a #GDateWeekday - **/ -GDateWeekday -e_weekday_add_days (GDateWeekday weekday, - guint n_days) -{ - g_return_val_if_fail ( - g_date_valid_weekday (weekday), - G_DATE_BAD_WEEKDAY); - - n_days %= 7; /* Weekdays repeat every 7 days. */ - - while (n_days-- > 0) - weekday = e_weekday_get_next (weekday); - - return weekday; -} - -/** - * e_weekday_subtract_days: - * @weekday: a #GDateWeekday - * @n_days: number of days to subtract - * - * Decrements @weekday by @n_days. - * - * Returns: a #GDateWeekday - **/ -GDateWeekday -e_weekday_subtract_days (GDateWeekday weekday, - guint n_days) -{ - g_return_val_if_fail ( - g_date_valid_weekday (weekday), - G_DATE_BAD_WEEKDAY); - - n_days %= 7; /* Weekdays repeat every 7 days. */ - - while (n_days-- > 0) - weekday = e_weekday_get_prev (weekday); - - return weekday; -} - -/** - * e_weekday_get_days_between: - * @weekday1: a #GDateWeekday - * @weekday2: a #GDateWeekday - * - * Counts the number of days starting at @weekday1 and ending at @weekday2. - * - * Returns: the number of days - **/ -guint -e_weekday_get_days_between (GDateWeekday weekday1, - GDateWeekday weekday2) -{ - guint n_days = 0; - - g_return_val_if_fail (g_date_valid_weekday (weekday1), 0); - g_return_val_if_fail (g_date_valid_weekday (weekday2), 0); - - while (weekday1 != weekday2) { - n_days++; - weekday1 = e_weekday_get_next (weekday1); - } - - return n_days; -} - -/** - * e_weekday_to_tm_wday: - * @weekday: a #GDateWeekday - * - * Converts a #GDateWeekday to the numbering used in - * struct tm. - * - * Returns: number of days since Sunday (0 - 6) - **/ -gint -e_weekday_to_tm_wday (GDateWeekday weekday) -{ - gint tm_wday; - - switch (weekday) { - case G_DATE_MONDAY: - tm_wday = 1; - break; - case G_DATE_TUESDAY: - tm_wday = 2; - break; - case G_DATE_WEDNESDAY: - tm_wday = 3; - break; - case G_DATE_THURSDAY: - tm_wday = 4; - break; - case G_DATE_FRIDAY: - tm_wday = 5; - break; - case G_DATE_SATURDAY: - tm_wday = 6; - break; - case G_DATE_SUNDAY: - tm_wday = 0; - break; - default: - g_return_val_if_reached (-1); - } - - return tm_wday; -} - -/** - * e_weekday_from_tm_wday: - * @tm_wday: number of days since Sunday (0 - 6) - * - * Converts a weekday in the numbering used in - * struct tm to a #GDateWeekday. - * - * Returns: a #GDateWeekday - **/ -GDateWeekday -e_weekday_from_tm_wday (gint tm_wday) -{ - GDateWeekday weekday; - - switch (tm_wday) { - case 0: - weekday = G_DATE_SUNDAY; - break; - case 1: - weekday = G_DATE_MONDAY; - break; - case 2: - weekday = G_DATE_TUESDAY; - break; - case 3: - weekday = G_DATE_WEDNESDAY; - break; - case 4: - weekday = G_DATE_THURSDAY; - break; - case 5: - weekday = G_DATE_FRIDAY; - break; - case 6: - weekday = G_DATE_SATURDAY; - break; - default: - g_return_val_if_reached (G_DATE_BAD_WEEKDAY); - } - - return weekday; -} - -/* Evolution Locks for crash recovery */ -static const gchar * -get_lock_filename (void) -{ - static gchar *filename = NULL; - - if (G_UNLIKELY (filename == NULL)) - filename = g_build_filename ( - e_get_user_config_dir (), ".running", NULL); - - return filename; -} - -gboolean -e_file_lock_create (void) -{ - const gchar *filename = get_lock_filename (); - gboolean status = FALSE; - FILE *file; - - file = g_fopen (filename, "w"); - if (file != NULL) { - /* The lock file also serves as a PID file. */ - g_fprintf ( - file, "%" G_GINT64_FORMAT "\n", - (gint64) getpid ()); - fclose (file); - status = TRUE; - } else { - const gchar *errmsg = g_strerror (errno); - g_warning ("Lock file creation failed: %s", errmsg); - } - - return status; -} - -void -e_file_lock_destroy (void) -{ - const gchar *filename = get_lock_filename (); - - if (g_unlink (filename) == -1) { - const gchar *errmsg = g_strerror (errno); - g_warning ("Lock file deletion failed: %s", errmsg); - } -} - -gboolean -e_file_lock_exists (void) -{ - const gchar *filename = get_lock_filename (); - - return g_file_test (filename, G_FILE_TEST_EXISTS); -} - -/* Returns a PID stored in the lock file; 0 if no such file exists. */ -GPid -e_file_lock_get_pid (void) -{ - const gchar *filename = get_lock_filename (); - gchar *contents = NULL; - GPid pid = (GPid) 0; - gint64 n_int64; - - if (!g_file_get_contents (filename, &contents, NULL, NULL)) { - return pid; - } - - /* Try to extract an integer value from the string. */ - n_int64 = g_ascii_strtoll (contents, NULL, 10); - if (n_int64 > 0 && n_int64 < G_MAXINT64) { - /* XXX Probably not portable. */ - pid = (GPid) n_int64; - } - - g_free (contents); - - return pid; -} - -/** - * e_util_guess_mime_type: - * @filename: a local file name, or URI - * @localfile: %TRUE to check the file content, FALSE to check only the name - * - * Tries to determine the MIME type for @filename. Free the returned - * string with g_free(). - * - * Returns: the MIME type of @filename, or %NULL if the the MIME type could - * not be determined - **/ -gchar * -e_util_guess_mime_type (const gchar *filename, - gboolean localfile) -{ - gchar *mime_type = NULL; - - g_return_val_if_fail (filename != NULL, NULL); - - if (localfile) { - GFile *file; - GFileInfo *fi; - - if (strstr (filename, "://")) - file = g_file_new_for_uri (filename); - else - file = g_file_new_for_path (filename); - - fi = g_file_query_info ( - file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, - G_FILE_QUERY_INFO_NONE, NULL, NULL); - if (fi) { - mime_type = g_content_type_get_mime_type ( - g_file_info_get_content_type (fi)); - g_object_unref (fi); - } - - g_object_unref (file); - } - - if (!mime_type) { - /* file doesn't exists locally, thus guess based on the filename */ - gboolean uncertain = FALSE; - gchar *content_type; - - content_type = g_content_type_guess (filename, NULL, 0, &uncertain); - if (content_type) { - mime_type = g_content_type_get_mime_type (content_type); - g_free (content_type); - } - } - - return mime_type; -} - -GSList * -e_util_get_category_filter_options (void) -{ - GSList *res = NULL; - GList *clist, *l; - - clist = e_categories_dup_list (); - for (l = clist; l; l = l->next) { - const gchar *cname = l->data; - struct _filter_option *fo; - - if (!e_categories_is_searchable (cname)) - continue; - - fo = g_new0 (struct _filter_option, 1); - - fo->title = g_strdup (cname); - fo->value = g_strdup (cname); - res = g_slist_prepend (res, fo); - } - - g_list_free_full (clist, g_free); - - return g_slist_reverse (res); -} - -/** - * e_util_dup_searchable_categories: - * - * Returns a list of the searchable categories, with each item being a UTF-8 - * category name. The list should be freed with g_list_free() when done with it, - * and the items should be freed with g_free(). Everything can be freed at once - * using g_list_free_full(). - * - * Returns: (transfer full) (element-type utf8): a list of searchable category - * names; free with g_list_free_full() - */ -GList * -e_util_dup_searchable_categories (void) -{ - GList *res = NULL, *all_categories, *l; - - all_categories = e_categories_dup_list (); - for (l = all_categories; l; l = l->next) { - gchar *cname = l->data; - - /* Steal the string from e_categories_dup_list(). */ - if (e_categories_is_searchable (cname)) - res = g_list_prepend (res, (gpointer) cname); - else - g_free (cname); - } - - /* NOTE: Do *not* free the items. They have been freed or stolen - * above. */ - g_list_free (all_categories); - - return g_list_reverse (res); -} -/** - * e_util_get_open_source_job_info: - * @extension_name: an extension name of the source - * @source_display_name: an ESource's display name - * @description: (out) (transfer-full): a description to use - * @alert_ident: (out) (transfer-full): an alert ident to use on failure - * @alert_arg_0: (out) (transfer-full): an alert argument 0 to use on failure - * - * Populates @desription, @alert_ident and @alert_arg_0 to be used - * to open an #ESource with extension @extension_name. The values - * can be used for functions like e_alert_sink_submit_thread_job(). - * - * If #TRUE is returned, then the caller is responsible to free - * all @desription, @alert_ident and @alert_arg_0 with g_free(), - * when no longer needed. - * - * Returns: #TRUE, if the values for @desription, @alert_ident and @alert_arg_0 - * were set for the given @extension_name; when #FALSE is returned, then - * none of these out variables are changed. - * - * Since: 3.16 - **/ -gboolean -e_util_get_open_source_job_info (const gchar *extension_name, - const gchar *source_display_name, - gchar **description, - gchar **alert_ident, - gchar **alert_arg_0) -{ - g_return_val_if_fail (extension_name != NULL, FALSE); - g_return_val_if_fail (source_display_name != NULL, FALSE); - g_return_val_if_fail (description != NULL, FALSE); - g_return_val_if_fail (alert_ident != NULL, FALSE); - g_return_val_if_fail (alert_arg_0 != NULL, FALSE); - - if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0) { - *alert_ident = g_strdup ("calendar:failed-open-calendar"); - *description = g_strdup_printf (_("Opening calendar “%s”"), source_display_name); - } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0) { - *alert_ident = g_strdup ("calendar:failed-open-memos"); - *description = g_strdup_printf (_("Opening memo list “%s”"), source_display_name); - } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_TASK_LIST) == 0) { - *alert_ident = g_strdup ("calendar:failed-open-tasks"); - *description = g_strdup_printf (_("Opening task list “%s”"), source_display_name); - } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_ADDRESS_BOOK) == 0) { - *alert_ident = g_strdup ("addressbook:load-error"); - *description = g_strdup_printf (_("Opening address book “%s”"), source_display_name); - } else { - return FALSE; - } - - *alert_arg_0 = g_strdup (source_display_name); - - return TRUE; -} - -/** - * e_util_propagate_open_source_job_error: - * @job_data: an #EAlertSinkThreadJobData instance - * @extension_name: what extension name had beeing opened - * @local_error: (allow none): a #GError as obtained in a thread job; can be NULL for success - * @error: (allow none): an output #GError, to which propagate the @local_error - * - * Propagates (and cosumes) the @local_error into the @error, eventually - * changes alert_ident for the @job_data for well-known error codes, - * where is available better error description. - * - * Since: 3.16 - **/ -void -e_util_propagate_open_source_job_error (EAlertSinkThreadJobData *job_data, - const gchar *extension_name, - GError *local_error, - GError **error) -{ - const gchar *alert_ident = NULL; - - g_return_if_fail (job_data != NULL); - g_return_if_fail (extension_name != NULL); - - if (!local_error) - return; - - if (!error) { - g_error_free (local_error); - return; - } - - if (g_error_matches (local_error, E_CLIENT_ERROR, E_CLIENT_ERROR_REPOSITORY_OFFLINE)) { - if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0) { - alert_ident = "calendar:prompt-no-contents-offline-calendar"; - } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0) { - alert_ident = "calendar:prompt-no-contents-offline-memos"; - } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_TASK_LIST) == 0) { - alert_ident = "calendar:prompt-no-contents-offline-tasks"; - } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_ADDRESS_BOOK) == 0) { - } - } - - if (alert_ident) - e_alert_sink_thread_job_set_alert_ident (job_data, alert_ident); - - g_propagate_error (error, local_error); -} - -EClient * -e_util_open_client_sync (EAlertSinkThreadJobData *job_data, - EClientCache *client_cache, - const gchar *extension_name, - ESource *source, - guint32 wait_for_connected_seconds, - GCancellable *cancellable, - GError **error) -{ - gchar *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL; - EClient *client = NULL; - ESourceRegistry *registry; - gchar *display_name; - GError *local_error = NULL; - - registry = e_client_cache_ref_registry (client_cache); - display_name = e_util_get_source_full_name (registry, source); - g_clear_object (®istry); - - g_warn_if_fail (e_util_get_open_source_job_info (extension_name, - display_name, &description, &alert_ident, &alert_arg_0)); - - g_free (display_name); - - camel_operation_push_message (cancellable, "%s", description); - - client = e_client_cache_get_client_sync (client_cache, source, extension_name, wait_for_connected_seconds, cancellable, &local_error); - - camel_operation_pop_message (cancellable); - - if (!client) { - e_alert_sink_thread_job_set_alert_ident (job_data, alert_ident); - e_alert_sink_thread_job_set_alert_arg_0 (job_data, alert_arg_0); - - e_util_propagate_open_source_job_error (job_data, extension_name, local_error, error); - } - - g_free (description); - g_free (alert_ident); - g_free (alert_arg_0); - - return client; -} - -/** - * e_binding_transform_color_to_string: - * @binding: a #GBinding - * @source_value: a #GValue of type #GDK_TYPE_COLOR - * @target_value: a #GValue of type #G_TYPE_STRING - * @not_used: not used - * - * Transforms a #GdkColor value to a color string specification. - * - * Returns: %TRUE always - **/ -gboolean -e_binding_transform_color_to_string (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer not_used) -{ - const GdkColor *color; - gchar *string; - - g_return_val_if_fail (G_IS_BINDING (binding), FALSE); - - color = g_value_get_boxed (source_value); - if (!color) { - g_value_set_string (target_value, ""); - } else { - /* encode color manually, because css styles expect colors in #rrggbb, - * not in #rrrrggggbbbb, which is a result of gdk_color_to_string() - */ - string = g_strdup_printf ( - "#%02x%02x%02x", - (gint) color->red * 256 / 65536, - (gint) color->green * 256 / 65536, - (gint) color->blue * 256 / 65536); - g_value_set_string (target_value, string); - g_free (string); - } - - return TRUE; -} - -/** - * e_binding_transform_string_to_color: - * @binding: a #GBinding - * @source_value: a #GValue of type #G_TYPE_STRING - * @target_value: a #GValue of type #GDK_TYPE_COLOR - * @not_used: not used - * - * Transforms a color string specification to a #GdkColor. - * - * Returns: %TRUE if color string specification was valid - **/ -gboolean -e_binding_transform_string_to_color (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer not_used) -{ - GdkColor color; - const gchar *string; - gboolean success = FALSE; - - g_return_val_if_fail (G_IS_BINDING (binding), FALSE); - - string = g_value_get_string (source_value); - if (gdk_color_parse (string, &color)) { - g_value_set_boxed (target_value, &color); - success = TRUE; - } - - return success; -} - -/** - * e_binding_transform_source_to_uid: - * @binding: a #GBinding - * @source_value: a #GValue of type #E_TYPE_SOURCE - * @target_value: a #GValue of type #G_TYPE_STRING - * @registry: an #ESourceRegistry - * - * Transforms an #ESource object to its UID string. - * - * Returns: %TRUE if @source_value was an #ESource object - **/ -gboolean -e_binding_transform_source_to_uid (GBinding *binding, - const GValue *source_value, - GValue *target_value, - ESourceRegistry *registry) -{ - ESource *source; - const gchar *string; - gboolean success = FALSE; - - g_return_val_if_fail (G_IS_BINDING (binding), FALSE); - g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE); - - source = g_value_get_object (source_value); - if (E_IS_SOURCE (source)) { - string = e_source_get_uid (source); - g_value_set_string (target_value, string); - success = TRUE; - } - - return success; -} - -/** - * e_binding_transform_uid_to_source: - * @binding: a #GBinding - * @source_value: a #GValue of type #G_TYPE_STRING - * @target_value: a #GValue of type #E_TYPE_SOURCe - * @registry: an #ESourceRegistry - * - * Transforms an #ESource UID string to the corresponding #ESource object - * in @registry. - * - * Returns: %TRUE if @registry had an #ESource object with a matching - * UID string - **/ -gboolean -e_binding_transform_uid_to_source (GBinding *binding, - const GValue *source_value, - GValue *target_value, - ESourceRegistry *registry) -{ - ESource *source; - const gchar *string; - gboolean success = FALSE; - - g_return_val_if_fail (G_IS_BINDING (binding), FALSE); - g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE); - - string = g_value_get_string (source_value); - if (string == NULL || *string == '\0') - return FALSE; - - source = e_source_registry_ref_source (registry, string); - if (source != NULL) { - g_value_take_object (target_value, source); - success = TRUE; - } - - return success; -} - -/** - * e_binding_transform_text_non_null: - * @binding: a #GBinding - * @source_value: a #GValue of type #G_TYPE_STRING - * @target_value: a #GValue of type #G_TYPE_STRING - * @user_data: custom user data, unused - * - * Transforms a text value to a text value which is never NULL; - * an empty string is used instead of NULL. - * - * Returns: %TRUE on success - **/ -gboolean -e_binding_transform_text_non_null (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - const gchar *str; - - g_return_val_if_fail (G_IS_BINDING (binding), FALSE); - g_return_val_if_fail (source_value != NULL, FALSE); - g_return_val_if_fail (target_value != NULL, FALSE); - - str = g_value_get_string (source_value); - if (!str) - str = ""; - - g_value_set_string (target_value, str); - - return TRUE; -} - -/** - * e_binding_bind_object_text_property: - * @source: the source #GObject - * @source_property: the text property on the source to bind - * @target: the target #GObject - * @target_property: the text property on the target to bind - * @flags: flags to pass to e_binding_bind_property_full() - * - * Installs a new text property object binding, using e_binding_bind_property_full(), - * with transform functions to make sure that a NULL pointer is not - * passed in either way. Instead of NULL an empty string is used. - * - * Returns: the #GBinding instance representing the binding between the two #GObject instances; - * there applies the same rules to it as for the result of e_binding_bind_property_full(). - **/ -GBinding * -e_binding_bind_object_text_property (gpointer source, - const gchar *source_property, - gpointer target, - const gchar *target_property, - GBindingFlags flags) -{ - GObjectClass *klass; - GParamSpec *property; - - g_return_val_if_fail (G_IS_OBJECT (source), NULL); - g_return_val_if_fail (source_property != NULL, NULL); - g_return_val_if_fail (G_IS_OBJECT (target), NULL); - g_return_val_if_fail (target_property != NULL, NULL); - - klass = G_OBJECT_GET_CLASS (source); - property = g_object_class_find_property (klass, source_property); - g_return_val_if_fail (property != NULL, NULL); - g_return_val_if_fail (property->value_type == G_TYPE_STRING, NULL); - - klass = G_OBJECT_GET_CLASS (target); - property = g_object_class_find_property (klass, target_property); - g_return_val_if_fail (property != NULL, NULL); - g_return_val_if_fail (property->value_type == G_TYPE_STRING, NULL); - - return e_binding_bind_property_full (source, source_property, - target, target_property, - flags, - e_binding_transform_text_non_null, - e_binding_transform_text_non_null, - NULL, NULL); -} - -typedef struct _EConnectNotifyData { - GConnectFlags flags; - GValue *old_value; - - GCallback c_handler; - gpointer user_data; -} EConnectNotifyData; - -static EConnectNotifyData * -e_connect_notify_data_new (GCallback c_handler, - gpointer user_data, - guint32 connect_flags) -{ - EConnectNotifyData *connect_data; - - connect_data = g_new0 (EConnectNotifyData, 1); - connect_data->flags = connect_flags; - connect_data->c_handler = c_handler; - connect_data->user_data = user_data; - - return connect_data; -} - -static void -e_connect_notify_data_free (EConnectNotifyData *data) -{ - if (!data) - return; - - if (data->old_value) { - g_value_unset (data->old_value); - g_free (data->old_value); - } - g_free (data); -} - -static gboolean -e_value_equal (GValue *value1, - GValue *value2) -{ - if (value1 == value2) - return TRUE; - - if (!value1 || !value2) - return FALSE; - - #define testType(_uc,_lc) G_STMT_START { \ - if (G_VALUE_HOLDS_ ## _uc (value1)) \ - return g_value_get_ ## _lc (value1) == g_value_get_ ## _lc (value2); \ - } G_STMT_END - - testType (BOOLEAN, boolean); - testType (BOXED, boxed); - testType (CHAR, schar); - testType (DOUBLE, double); - testType (ENUM, enum); - testType (FLAGS, flags); - testType (FLOAT, float); - testType (GTYPE, gtype); - testType (INT, int); - testType (INT64, int64); - testType (LONG, long); - testType (OBJECT, object); - testType (POINTER, pointer); - testType (UCHAR, uchar); - testType (UINT, uint); - testType (UINT64, uint64); - testType (ULONG, ulong); - - #undef testType - - if (G_VALUE_HOLDS_PARAM (value1)) { - GParamSpec *param1, *param2; - - param1 = g_value_get_param (value1); - param2 = g_value_get_param (value2); - - return param1 && param2 && - g_strcmp0 (param1->name, param2->name) == 0 && - param1->flags == param2->flags && - param1->value_type == param2->value_type && - param1->owner_type == param2->owner_type; - } else if (G_VALUE_HOLDS_STRING (value1)) { - const gchar *string1, *string2; - - string1 = g_value_get_string (value1); - string2 = g_value_get_string (value2); - - return g_strcmp0 (string1, string2) == 0; - } else if (G_VALUE_HOLDS_VARIANT (value1)) { - GVariant *variant1, *variant2; - - variant1 = g_value_get_variant (value1); - variant2 = g_value_get_variant (value2); - - return variant1 == variant2 || - (variant1 && variant2 && g_variant_equal (variant1, variant2)); - } - - return FALSE; -} - -static void -e_signal_connect_notify_cb (gpointer instance, - GParamSpec *param, - gpointer user_data) -{ - EConnectNotifyData *connect_data = user_data; - GValue *value; - - g_return_if_fail (connect_data != NULL); - - value = g_new0 (GValue, 1); - g_value_init (value, param->value_type); - g_object_get_property (instance, param->name, value); - - if (!e_value_equal (connect_data->old_value, value)) { - typedef void (* NotifyCBType) (gpointer instance, GParamSpec *param, gpointer user_data); - NotifyCBType c_handler = (NotifyCBType) connect_data->c_handler; - - if (connect_data->old_value) { - g_value_unset (connect_data->old_value); - g_free (connect_data->old_value); - } - connect_data->old_value = value; - - if (connect_data->flags == G_CONNECT_SWAPPED) { - c_handler (connect_data->user_data, param, instance); - } else { - c_handler (instance, param, connect_data->user_data); - } - } else { - g_value_unset (value); - g_free (value); - } -} - -/** - * e_signal_connect_notify: - * - * This installs a special handler in front of @c_handler, which will - * call the @c_handler only if the property value changed since the last - * time it was checked. Due to this, these handlers cannot be disconnected - * by by any of the g_signal_handlers_* functions, but only with the returned - * handler ID. A convenient e_signal_disconnect_notify_handler() was added - * to make it easier. - **/ -gulong -e_signal_connect_notify (gpointer instance, - const gchar *notify_name, - GCallback c_handler, - gpointer user_data) -{ - EConnectNotifyData *connect_data; - - g_return_val_if_fail (g_str_has_prefix (notify_name, "notify::"), 0); - - connect_data = e_connect_notify_data_new (c_handler, user_data, 0); - - return g_signal_connect_data (instance, - notify_name, - G_CALLBACK (e_signal_connect_notify_cb), - connect_data, - (GClosureNotify) e_connect_notify_data_free, - 0); -} - -/** - * e_signal_connect_notify_after: - * - * This installs a special handler in front of @c_handler, which will - * call the @c_handler only if the property value changed since the last - * time it was checked. Due to this, these handlers cannot be disconnected - * by by any of the g_signal_handlers_* functions, but only with the returned - * handler ID. A convenient e_signal_disconnect_notify_handler() was added - * to make it easier. - **/ -gulong -e_signal_connect_notify_after (gpointer instance, - const gchar *notify_name, - GCallback c_handler, - gpointer user_data) -{ - EConnectNotifyData *connect_data; - - g_return_val_if_fail (g_str_has_prefix (notify_name, "notify::"), 0); - - connect_data = e_connect_notify_data_new (c_handler, user_data, G_CONNECT_AFTER); - - return g_signal_connect_data (instance, - notify_name, - G_CALLBACK (e_signal_connect_notify_cb), - connect_data, - (GClosureNotify) e_connect_notify_data_free, - G_CONNECT_AFTER); -} - -/** - * e_signal_connect_notify_swapped: - * - * This installs a special handler in front of @c_handler, which will - * call the @c_handler only if the property value changed since the last - * time it was checked. Due to this, these handlers cannot be disconnected - * by by any of the g_signal_handlers_* functions, but only with the returned - * handler ID. A convenient e_signal_disconnect_notify_handler() was added - * to make it easier. - **/ -gulong -e_signal_connect_notify_swapped (gpointer instance, - const gchar *notify_name, - GCallback c_handler, - gpointer user_data) -{ - EConnectNotifyData *connect_data; - - g_return_val_if_fail (g_str_has_prefix (notify_name, "notify::"), 0); - - connect_data = e_connect_notify_data_new (c_handler, user_data, G_CONNECT_SWAPPED); - - return g_signal_connect_data (instance, - notify_name, - G_CALLBACK (e_signal_connect_notify_cb), - connect_data, - (GClosureNotify) e_connect_notify_data_free, - 0); -} - -/** - * e_signal_connect_notify_object: - * - * This installs a special handler in front of @c_handler, which will - * call the @c_handler only if the property value changed since the last - * time it was checked. Due to this, these handlers cannot be disconnected - * by by any of the g_signal_handlers_* functions, but only with the returned - * handler ID. A convenient e_signal_disconnect_notify_handler() was added - * to make it easier. - **/ -gulong -e_signal_connect_notify_object (gpointer instance, - const gchar *notify_name, - GCallback c_handler, - gpointer gobject, - GConnectFlags connect_flags) -{ - EConnectNotifyData *connect_data; - GClosure *closure; - - g_return_val_if_fail (g_str_has_prefix (notify_name, "notify::"), 0); - - if (!gobject) { - if ((connect_flags & G_CONNECT_SWAPPED) != 0) - return e_signal_connect_notify_swapped (instance, notify_name, c_handler, gobject); - else if ((connect_flags & G_CONNECT_AFTER) != 0) - e_signal_connect_notify_after (instance, notify_name, c_handler, gobject); - else - g_warn_if_fail (connect_flags == 0); - - return e_signal_connect_notify (instance, notify_name, c_handler, gobject); - } - - g_return_val_if_fail (G_IS_OBJECT (gobject), 0); - - connect_data = e_connect_notify_data_new (c_handler, gobject, connect_flags & G_CONNECT_SWAPPED); - closure = g_cclosure_new ( - G_CALLBACK (e_signal_connect_notify_cb), - connect_data, - (GClosureNotify) e_connect_notify_data_free); - - g_object_watch_closure (G_OBJECT (gobject), closure); - - return g_signal_connect_closure (instance, - notify_name, - closure, - connect_flags & G_CONNECT_AFTER); -} - -/** - * e_signal_disconnect_notify_handler: - * - * Convenient handler disconnect function to be used with - * returned handler IDs from: - * e_signal_connect_notify() - * e_signal_connect_notify_after() - * e_signal_connect_notify_swapped() - * e_signal_connect_notify_object() - * but not necessarily only with these functions. - **/ -void -e_signal_disconnect_notify_handler (gpointer instance, - gulong *handler_id) -{ - g_return_if_fail (instance != NULL); - g_return_if_fail (handler_id != NULL); - - if (!*handler_id) - return; - - g_signal_handler_disconnect (instance, *handler_id); - *handler_id = 0; -} - -static GMutex settings_hash_lock; -static GHashTable *settings_hash = NULL; - -/** - * e_util_ref_settings: - * @schema_id: the id of the schema to reference settings for - * - * Either returns an existing referenced #GSettings object for the given @schema_id, - * or creates a new one and remembers it for later use, to avoid having too many - * #GSettings objects created for the same @schema_id. - * - * Returns: A #GSettings for the given @schema_id. The returned #GSettings object - * is referenced, thus free it with g_object_unref() when done with it. - * - * Since: 3.16 - **/ -GSettings * -e_util_ref_settings (const gchar *schema_id) -{ - GSettings *settings; - - g_return_val_if_fail (schema_id != NULL, NULL); - g_return_val_if_fail (*schema_id, NULL); - - g_mutex_lock (&settings_hash_lock); - - if (!settings_hash) { - settings_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - } - - settings = g_hash_table_lookup (settings_hash, schema_id); - if (!settings) { - settings = g_settings_new (schema_id); - g_hash_table_insert (settings_hash, g_strdup (schema_id), settings); - } - - if (settings) - g_object_ref (settings); - - g_mutex_unlock (&settings_hash_lock); - - return settings; -} - -/** - * e_util_cleanup_settings: - * - * Frees all the memory taken by e_util_ref_settings(). - * - * Since: 3.16 - **/ -void -e_util_cleanup_settings (void) -{ - g_mutex_lock (&settings_hash_lock); - - if (settings_hash) { - g_hash_table_destroy (settings_hash); - settings_hash = NULL; - } - - g_mutex_unlock (&settings_hash_lock); -} - -static gdouble -get_screen_dpi (GdkScreen *screen) -{ - gdouble dpi; - gdouble dp, di; - - dpi = gdk_screen_get_resolution (screen); - if (dpi != -1) - return dpi; - - dp = hypot (gdk_screen_get_width (screen), gdk_screen_get_height (screen)); - di = hypot (gdk_screen_get_width_mm (screen), gdk_screen_get_height_mm (screen)) / 25.4; - - return dp / di; -} - -guint -e_util_normalize_font_size (GtkWidget *widget, - gdouble font_size) -{ - /* WebKit2 uses font sizes in pixels. */ - GdkScreen *screen; - gdouble dpi; - - if (widget) { - screen = gtk_widget_has_screen (widget) ? - gtk_widget_get_screen (widget) : gdk_screen_get_default (); - } else { - screen = gdk_screen_get_default (); - } - - dpi = screen ? get_screen_dpi (screen) : 96; - - return font_size / 72.0 * dpi; -} - -/** - * e_util_prompt_user: - * @parent: parent window - * @settings_schema: name of the settings schema where @promptkey belongs. - * @promptkey: settings key to check if we should prompt the user or not. - * @tag: e_alert tag. - * - * Convenience function to query the user with a Yes/No dialog and a - * "Do not show this dialog again" checkbox. If the user checks that - * checkbox, then @promptkey is set to %FALSE, otherwise it is set to - * %TRUE. - * - * Returns %TRUE if the user clicks Yes or %FALSE otherwise. - **/ -gboolean -e_util_prompt_user (GtkWindow *parent, - const gchar *settings_schema, - const gchar *promptkey, - const gchar *tag, - ...) -{ - GtkWidget *dialog; - GtkWidget *check = NULL; - GtkWidget *container; - va_list ap; - gint button; - GSettings *settings = NULL; - EAlert *alert = NULL; - - if (promptkey) { - settings = e_util_ref_settings (settings_schema); - - if (!g_settings_get_boolean (settings, promptkey)) { - g_object_unref (settings); - return TRUE; - } - } - - va_start (ap, tag); - alert = e_alert_new_valist (tag, ap); - va_end (ap); - - dialog = e_alert_dialog_new (parent, alert); - g_object_unref (alert); - - container = e_alert_dialog_get_content_area (E_ALERT_DIALOG (dialog)); - - if (promptkey) { - check = gtk_check_button_new_with_mnemonic ( - _("_Do not show this message again")); - gtk_box_pack_start ( - GTK_BOX (container), check, FALSE, FALSE, 0); - gtk_widget_show (check); - } - - button = gtk_dialog_run (GTK_DIALOG (dialog)); - if (promptkey) - g_settings_set_boolean ( - settings, promptkey, - !gtk_toggle_button_get_active ( - GTK_TOGGLE_BUTTON (check))); - - gtk_widget_destroy (dialog); - - g_clear_object (&settings); - - return button == GTK_RESPONSE_YES; -} - -typedef struct _EUtilSimpleAsyncResultThreadData { - GSimpleAsyncResult *simple; - GSimpleAsyncThreadFunc func; - GCancellable *cancellable; -} EUtilSimpleAsyncResultThreadData; - -static void -e_util_simple_async_result_thread (gpointer data, - gpointer user_data) -{ - EUtilSimpleAsyncResultThreadData *thread_data = data; - GError *error = NULL; - - g_return_if_fail (thread_data != NULL); - g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (thread_data->simple)); - g_return_if_fail (thread_data->func != NULL); - - if (g_cancellable_set_error_if_cancelled (thread_data->cancellable, &error)) { - g_simple_async_result_take_error (thread_data->simple, error); - } else { - thread_data->func (thread_data->simple, - g_async_result_get_source_object (G_ASYNC_RESULT (thread_data->simple)), - thread_data->cancellable); - } - - g_simple_async_result_complete_in_idle (thread_data->simple); - - g_clear_object (&thread_data->simple); - g_clear_object (&thread_data->cancellable); - g_free (thread_data); -} - -/** - * e_util_run_simple_async_result_in_thread: - * @simple: a #GSimpleAsyncResult - * @func: a #GSimpleAsyncThreadFunc to execute in the thread - * @cancellable: an optional #GCancellable, or %NULL - * - * Similar to g_simple_async_result_run_in_thread(), except - * it doesn't use GTask internally, thus doesn't block the GTask - * thread pool with possibly long job. - * - * It doesn't behave exactly the same as the g_simple_async_result_run_in_thread(), - * the @cancellable checking is not done before the finish. - * - * Since: 3.18 - **/ -void -e_util_run_simple_async_result_in_thread (GSimpleAsyncResult *simple, - GSimpleAsyncThreadFunc func, - GCancellable *cancellable) -{ - static GThreadPool *thread_pool = NULL; - static GMutex thread_pool_mutex; - EUtilSimpleAsyncResultThreadData *thread_data; - - g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (simple)); - g_return_if_fail (func != NULL); - - g_mutex_lock (&thread_pool_mutex); - - if (!thread_pool) - thread_pool = g_thread_pool_new (e_util_simple_async_result_thread, NULL, 20, FALSE, NULL); - - thread_data = g_new0 (EUtilSimpleAsyncResultThreadData, 1); - thread_data->simple = g_object_ref (simple); - thread_data->func = func; - thread_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - - g_thread_pool_push (thread_pool, thread_data, NULL); - - g_mutex_unlock (&thread_pool_mutex); -} - -/** - * e_util_is_running_gnome: - * - * Returns: Whether the current running desktop environment is GNOME. - * - * Since: 3.18 - **/ -gboolean -e_util_is_running_gnome (void) -{ -#ifdef G_OS_WIN32 - return FALSE; -#else - static gint runs_gnome = -1; - - if (runs_gnome == -1) { - runs_gnome = g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "GNOME") == 0 ? 1 : 0; - if (runs_gnome) { - GDesktopAppInfo *app_info; - - app_info = g_desktop_app_info_new ("gnome-notifications-panel.desktop"); - if (!app_info) { - runs_gnome = 0; - } - - g_clear_object (&app_info); - } - } - - return runs_gnome != 0; -#endif -} - -/** - * e_util_set_entry_issue_hint: - * @entry: a #GtkEntry - * @hint: (allow none): a hint to set, or %NULL to unset - * - * Sets a @hint on the secondary @entry icon about an entered value issue, - * or unsets it, when the @hint is %NULL. - * - * Since: 3.20 - **/ -void -e_util_set_entry_issue_hint (GtkWidget *entry, - const gchar *hint) -{ - GtkEntry *eentry; - - g_return_if_fail (GTK_IS_ENTRY (entry)); - - eentry = GTK_ENTRY (entry); - - if (hint) { - gtk_entry_set_icon_from_icon_name (eentry, GTK_ENTRY_ICON_SECONDARY, "dialog-warning"); - gtk_entry_set_icon_tooltip_text (eentry, GTK_ENTRY_ICON_SECONDARY, hint); - } else { - gtk_entry_set_icon_from_icon_name (eentry, GTK_ENTRY_ICON_SECONDARY, NULL); - gtk_entry_set_icon_tooltip_text (eentry, GTK_ENTRY_ICON_SECONDARY, NULL); - } -} - -static GThread *main_thread = NULL; - -void -e_util_init_main_thread (GThread *thread) -{ - g_return_if_fail (main_thread == NULL); - - main_thread = thread ? thread : g_thread_self (); -} - -gboolean -e_util_is_main_thread (GThread *thread) -{ - return thread ? thread == main_thread : g_thread_self () == main_thread; -} - -/** - * e_util_save_image_from_clipboard: - * @clipboard: a #GtkClipboard - * @hint: (allow none): a hint to set, or %NULL to unset - * - * Saves the image from @clipboard to a temporary file and returns its URI. - * - * Since: 3.22 - **/ -gchar * -e_util_save_image_from_clipboard (GtkClipboard *clipboard) -{ - GdkPixbuf *pixbuf = NULL; - gchar *tmpl; - gchar *filename = NULL; - gchar *uri = NULL; - GError *error = NULL; - - g_return_val_if_fail (GTK_IS_CLIPBOARD (clipboard), NULL); - - /* Extract the image data from the clipboard. */ - pixbuf = gtk_clipboard_wait_for_image (clipboard); - g_return_val_if_fail (pixbuf != NULL, FALSE); - - tmpl = g_strconcat (_("Image"), "-XXXXXX.png", NULL); - - /* Reserve a temporary file. */ - filename = e_mktemp (tmpl); - - g_free (tmpl); - - if (filename == NULL) { - g_set_error ( - &error, G_FILE_ERROR, - g_file_error_from_errno (errno), - "Could not create temporary file: %s", - g_strerror (errno)); - goto exit; - } - - /* Save the pixbuf as a temporary file in image/png format. */ - if (!gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL)) - goto exit; - - /* Convert the filename to a URI. */ - uri = g_filename_to_uri (filename, NULL, &error); - - exit: - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } - - g_object_unref (pixbuf); - g_free (filename); - - return uri; -} - -static void -e_util_stop_signal_emission_cb (gpointer instance, - const gchar *signal_name) -{ - g_signal_stop_emission_by_name (instance, signal_name); -} - -/** - * e_util_check_gtk_bindings_in_key_press_event_cb: - * @widget: a #GtkWidget, most often a #GtkWindow - * @event: a #GdkEventKey - * - * A callback function for GtkWidget::key-press-event signal, - * which checks whether currently focused widget inside @widget, - * if it's a #GtkWindow, or a toplevel window containing the @widget, - * will consume the @event due to gtk+ bindings and if so, then - * it'll stop processing the event further. When it's connected - * on a #GtkWindow, then it can prevent the event to be used - * for shortcuts of actions. - * - * Returns: %TRUE to stop other handlers from being invoked for - * the event, %FALSE to propagate the event further. - * - * Since: 3.22 - **/ -gboolean -e_util_check_gtk_bindings_in_key_press_event_cb (GtkWidget *widget, - GdkEvent *event) -{ - GdkEventKey *key_event = (GdkEventKey *) event; - GtkWindow *window = NULL; - GtkWidget *focused; - - g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - g_return_val_if_fail (event->type == GDK_KEY_PRESS, FALSE); - - if (GTK_IS_WINDOW (widget)) { - window = GTK_WINDOW (widget); - } else { - GtkWidget *toplevel; - - toplevel = gtk_widget_get_toplevel (widget); - if (GTK_IS_WINDOW (toplevel)) - window = GTK_WINDOW (toplevel); - } - - if (!window) - return FALSE; - - focused = gtk_window_get_focus (window); - if (!focused) - return FALSE; - - if (gtk_bindings_activate_event (G_OBJECT (focused), key_event)) - return TRUE; - - if (WEBKIT_IS_WEB_VIEW (focused) && - (key_event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) != 0) { - GtkWidget *text_view; - gboolean may_use; - - /* WebKit uses GtkTextView to process key bindings. Do the same. */ - text_view = gtk_text_view_new (); - - /* Stop emissing for clipboard signals, to not populate the text_view */ - g_signal_connect (text_view, "copy-clipboard", G_CALLBACK (e_util_stop_signal_emission_cb), (gpointer) "copy-clipboard"); - g_signal_connect (text_view, "cut-clipboard", G_CALLBACK (e_util_stop_signal_emission_cb), (gpointer) "cut-clipboard"); - g_signal_connect (text_view, "paste-clipboard", G_CALLBACK (e_util_stop_signal_emission_cb), (gpointer) "paste-clipboard"); - - may_use = gtk_bindings_activate_event (G_OBJECT (text_view), key_event); - gtk_widget_destroy (text_view); - - if (may_use) { - gboolean result = FALSE; - - g_signal_emit_by_name (focused, "key-press-event", event, &result); - - return result; - } - } - - return FALSE; -} - -/** - * e_util_claim_dbus_proxy_call_error: - * @dbus_proxy: a #GDBusProxy instance - * @method_name: a method name of the @dbus_proxy - * @in_error: (allow-none): a #GError with the failure, or %NULL - * - * Claims the @in_error on the console as a failure to call - * method @method_name of the @dbus_proxy. It's safe to call this - * with a %NULL @in_error, then the function does nothing. - * Some errors can be ignored, like the G_IO_ERROR_CANCELLED is. - * - * Since: 3.22 - **/ -void -e_util_claim_dbus_proxy_call_error (GDBusProxy *dbus_proxy, - const gchar *method_name, - const GError *in_error) -{ - g_return_if_fail (G_IS_DBUS_PROXY (dbus_proxy)); - g_return_if_fail (method_name != NULL); - - if (in_error && !g_error_matches (in_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("Failed to call a DBus Proxy method %s::%s: %s", - g_dbus_proxy_get_name (dbus_proxy), method_name, in_error->message); -} - -static void -e_util_finish_dbus_proxy_call_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - gchar *method_name = user_data; - GDBusProxy *dbus_proxy; - GVariant *ret; - GError *error = NULL; - - g_return_if_fail (G_IS_DBUS_PROXY (source_object)); - - dbus_proxy = G_DBUS_PROXY (source_object); - - ret = g_dbus_proxy_call_finish (dbus_proxy, result, &error); - - if (ret) - g_variant_unref (ret); - - if (error) - g_dbus_error_strip_remote_error (error); - - e_util_claim_dbus_proxy_call_error (dbus_proxy, method_name, error); - - g_clear_error (&error); - g_free (method_name); -} - -/** - * e_util_invoke_g_dbus_proxy_call_with_error_check: - * @dbus_proxy: a #GDBusProxy instance - * @method_name: a method name to invoke - * @parameters: (allow-none): parameters of the method, or %NULL - * @cancellable: (allow-none): a #GCancellable, or %NULL - * - * Calls g_dbus_proxy_call() on the @dbus_proxy for the @method_name with @parameters - * and adds its own callback for the result. Then, if an error is returned, passes this - * error into e_util_claim_dbus_proxy_call_error(). - * - * See: e_util_invoke_g_dbus_proxy_call_with_error_check_full() - * - * Since: 3.22 - **/ -void -e_util_invoke_g_dbus_proxy_call_with_error_check (GDBusProxy *dbus_proxy, - const gchar *method_name, - GVariant *parameters, - GCancellable *cancellable) -{ - g_return_if_fail (G_IS_DBUS_PROXY (dbus_proxy)); - g_return_if_fail (method_name != NULL); - - e_util_invoke_g_dbus_proxy_call_with_error_check_full ( - dbus_proxy, method_name, parameters, - G_DBUS_CALL_FLAGS_NONE, -1, cancellable); -} - -/** - * e_util_invoke_g_dbus_proxy_call_with_error_check_full: - * @dbus_proxy: a #GDBusProxy instance - * @method_name: a method name to invoke - * @parameters: (allow-none): parameters of the method, or %NULL - * @flags: a bit-or of #GDBusCallFlags, with the same meaning as in the g_dbus_proxy_call() - * @timeout_msec: timeout in milliseconds, with the same meaning as in the g_dbus_proxy_call(). - * @cancellable: (allow-none): a #GCancellable, or %NULL - * - * Calls g_dbus_proxy_call() on the @dbus_proxy for the @method_name with @parameters - * and adds its own callback for the result. Then, if an error is returned, passes this - * error into e_util_claim_dbus_proxy_call_error(). - * - * See: e_util_invoke_g_dbus_proxy_call_with_error_check() - * - * Since: 3.22 - **/ -void -e_util_invoke_g_dbus_proxy_call_with_error_check_full (GDBusProxy *dbus_proxy, - const gchar *method_name, - GVariant *parameters, - GDBusCallFlags flags, - gint timeout_msec, - GCancellable *cancellable) -{ - g_return_if_fail (G_IS_DBUS_PROXY (dbus_proxy)); - g_return_if_fail (method_name != NULL); - - g_dbus_proxy_call (dbus_proxy, method_name, parameters, - flags, timeout_msec, cancellable, - e_util_finish_dbus_proxy_call_cb, g_strdup (method_name)); -} - -/** - * e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check: - * @dbus_proxy: a #GDBusProxy instance - * @method_name: a method name to invoke - * @parameters: (allow-none): parameters of the method, or %NULL - * @cancellable: (allow-none): a #GCancellable, or %NULL - * - * Calls e_util_invoke_g_dbus_proxy_call_sync_wrapper_full() with some default - * values for flags and timeout_msec, while also providing its own GError and - * after the call is finished it calls e_util_claim_dbus_proxy_call_error() - * with the returned error, if any. - * - * Returns: The result of the method call, or %NULL on error. Free with g_variant_unref(). - * - * Since: 3.22 - **/ -GVariant * -e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (GDBusProxy *dbus_proxy, - const gchar *method_name, - GVariant *parameters, - GCancellable *cancellable) -{ - GVariant *result; - GError *error = NULL; - - g_return_val_if_fail (G_IS_DBUS_PROXY (dbus_proxy), NULL); - g_return_val_if_fail (method_name != NULL, NULL); - - result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (dbus_proxy, method_name, parameters, - G_DBUS_CALL_FLAGS_NONE, -1, cancellable, &error); - - if (error) - g_dbus_error_strip_remote_error (error); - - e_util_claim_dbus_proxy_call_error (dbus_proxy, method_name, error); - g_clear_error (&error); - - return result; -} - -static void -sync_wrapper_result_callback (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - GAsyncResult **out_async_result = user_data; - - g_return_if_fail (out_async_result != NULL); - g_return_if_fail (*out_async_result == NULL); - - *out_async_result = g_object_ref (result); -} - -/** - * e_util_invoke_g_dbus_proxy_call_sync_wrapper_full: - * @dbus_proxy: a #GDBusProxy instance - * @method_name: a method name to invoke - * @parameters: (allow-none): parameters of the method, or %NULL - * @flags: a bit-or of #GDBusCallFlags, with the same meaning as in the g_dbus_proxy_call() - * @timeout_msec: timeout in milliseconds, with the same meaning as in the g_dbus_proxy_call(). - * @cancellable: (allow-none): a #GCancellable, or %NULL - * @error: (allow-none): Return location for error, or %NULL - * - * Wraps GDBusProxy synchronous call into an asynchronous without blocking - * the main context. This can be useful when doing calls on a WebExtension, - * because it can avoid freeze when this is called in the UI process and - * the WebProcess also does its own IPC call. - * - * This function should be called only from the main thread. - * - * Returns: The result of the method call, or %NULL on error. Free with g_variant_unref(). - * - * Since: 3.22 - **/ -GVariant * -e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (GDBusProxy *dbus_proxy, - const gchar *method_name, - GVariant *parameters, - GDBusCallFlags flags, - gint timeout_msec, - GCancellable *cancellable, - GError **error) -{ - GAsyncResult *async_result = NULL; - GVariant *var_result; - GMainContext *main_context; - - g_return_val_if_fail (G_IS_DBUS_PROXY (dbus_proxy), NULL); - g_return_val_if_fail (method_name != NULL, NULL); - - g_warn_if_fail (e_util_is_main_thread (g_thread_self ())); - - g_dbus_proxy_call ( - dbus_proxy, method_name, parameters, flags, timeout_msec, cancellable, - sync_wrapper_result_callback, &async_result); - - main_context = g_main_context_get_thread_default (); - - while (!async_result) { - g_main_context_iteration (main_context, TRUE); - } - - var_result = g_dbus_proxy_call_finish (dbus_proxy, async_result, error); - - g_clear_object (&async_result); - - return var_result; -} - -/** - * e_util_save_file_chooser_folder: - * @file_chooser: a #GtkFileChooser - * - * Saves the current folder of the @file_chooser, thus it could be used - * by e_util_load_file_chooser_folder() to open it in the last chosen folder. - * - * Since: 3.24 - **/ -void -e_util_save_file_chooser_folder (GtkFileChooser *file_chooser) -{ - GSettings *settings; - gchar *uri; - - g_return_if_fail (GTK_IS_FILE_CHOOSER (file_chooser)); - - uri = gtk_file_chooser_get_current_folder_uri (file_chooser); - if (uri && g_str_has_prefix (uri, "file://")) { - settings = e_util_ref_settings ("org.gnome.evolution.shell"); - g_settings_set_string (settings, "file-chooser-folder", uri); - g_object_unref (settings); - } - - g_free (uri); -} - -/** - * e_util_load_file_chooser_folder: - * @file_chooser: a #GtkFileChooser - * - * Sets the current folder to the @file_chooser to the one previously saved - * by e_util_save_file_chooser_folder(). The function does nothing if none - * or invalid is saved. - * - * Since: 3.24 - **/ -void -e_util_load_file_chooser_folder (GtkFileChooser *file_chooser) -{ - GSettings *settings; - gchar *uri; - - g_return_if_fail (GTK_IS_FILE_CHOOSER (file_chooser)); - - settings = e_util_ref_settings ("org.gnome.evolution.shell"); - uri = g_settings_get_string (settings, "file-chooser-folder"); - g_object_unref (settings); - - if (uri && g_str_has_prefix (uri, "file://")) { - gchar *filename; - - filename = g_filename_from_uri (uri, NULL, NULL); - if (filename && g_file_test (filename, G_FILE_TEST_IS_DIR)) - gtk_file_chooser_set_current_folder_uri (file_chooser, uri); - - g_free (filename); - } - - g_free (uri); -} - -/** - * e_util_get_webkit_developer_mode_enabled: - * - * Returns: Whether WebKit developer mode is enabled. This is read only - * once, thus any changes in the GSettings property require restart - * of the Evolution. - * - * Since: 3.24 - **/ -gboolean -e_util_get_webkit_developer_mode_enabled (void) -{ - static gchar enabled = -1; - - if (enabled == -1) { - GSettings *settings; - - settings = e_util_ref_settings ("org.gnome.evolution.shell"); - enabled = g_settings_get_boolean (settings, "webkit-developer-mode") ? 1 : 0; - g_clear_object (&settings); - } - - return enabled != 0; -} - -/** - * e_util_next_uri_from_uri_list: - * @uri_list: array of URIs separated by new lines - * @len: (out): a length of the found URI - * @list_len: (out): a length of the array - * - * Returns: A newly allocated string with found URI. - * - * Since: 3.26 - **/ -gchar * -e_util_next_uri_from_uri_list (guchar **uri_list, - gint *len, - gint *list_len) -{ - guchar *uri, *begin; - - begin = *uri_list; - *len = 0; - while (**uri_list && **uri_list != '\n' && **uri_list != '\r' && *list_len) { - (*uri_list) ++; - (*len) ++; - (*list_len) --; - } - - uri = (guchar *) g_strndup ((gchar *) begin, *len); - - while ((!**uri_list || **uri_list == '\n' || **uri_list == '\r') && *list_len) { - (*uri_list) ++; - (*list_len) --; - } - - return (gchar *) uri; -} - -/** - * e_util_resize_window_for_screen: - * @window: a #GtkWindow - * @window_width: the @window width without @children, or -1 to compute - * @window_height: the @window height without @children, or -1 to compute - * @children: (element-type GtkWidget): (nullable): a #GSList with children to calculate with - * - * Calculates the size of the @window considering preferred sizes of @children, - * and shrinks the @window in case it won't be completely visible on the screen - * it is assigned to. - * - * Since: 3.26 - **/ -void -e_util_resize_window_for_screen (GtkWindow *window, - gint window_width, - gint window_height, - const GSList *children) -{ - gint width = -1, height = -1, content_width = -1, content_height = -1, current_width = -1, current_height = -1; - GtkRequisition requisition; - const GSList *link; - - g_return_if_fail (GTK_IS_WINDOW (window)); - - gtk_window_get_default_size (window, &width, &height); - if (width < 0 || height < 0) { - gtk_widget_get_preferred_size (GTK_WIDGET (window), &requisition, NULL); - - width = requisition.width; - height = requisition.height; - } - - for (link = children; link; link = g_slist_next (link)) { - GtkWidget *widget = link->data; - - if (GTK_IS_SCROLLED_WINDOW (widget)) - widget = gtk_bin_get_child (GTK_BIN (widget)); - - if (GTK_IS_VIEWPORT (widget)) - widget = gtk_bin_get_child (GTK_BIN (widget)); - - if (!GTK_IS_WIDGET (widget)) - continue; - - gtk_widget_get_preferred_size (widget, &requisition, NULL); - - if (requisition.width > content_width) - content_width = requisition.width; - if (requisition.height > content_height) - content_height = requisition.height; - - widget = gtk_widget_get_parent (widget); - if (GTK_IS_VIEWPORT (widget)) - widget = gtk_widget_get_parent (widget); - - if (GTK_IS_WIDGET (widget)) { - gtk_widget_get_preferred_size (widget, &requisition, NULL); - - if (current_width == -1 || current_width < requisition.width) - current_width = requisition.width; - if (current_height == -1 || current_height < requisition.height) - current_height = requisition.height; - } - } - - if (content_width > 0 && content_height > 0 && width > 0 && height > 0) { - GdkScreen *screen; - GdkRectangle monitor_area; - gint x = 0, y = 0, monitor; - - screen = gtk_window_get_screen (GTK_WINDOW (window)); - gtk_window_get_position (GTK_WINDOW (window), &x, &y); - - monitor = gdk_screen_get_monitor_at_point (screen, x, y); - if (monitor < 0 || monitor >= gdk_screen_get_n_monitors (screen)) - monitor = 0; - - gdk_screen_get_monitor_workarea (screen, monitor, &monitor_area); - - /* When the children are packed inside the window then influence the window - size too, thus subtract it, if possible. */ - if (window_width < 0) { - if (current_width > 0 && current_width < width) - width -= current_width; - } else { - width = window_width; - } - - if (window_height < 0) { - if (current_height > 0 && current_height < height) - height -= current_height; - } else { - height = window_height; - } - - if (content_width > monitor_area.width - width) - content_width = monitor_area.width - width; - - if (content_height > monitor_area.height - height) - content_height = monitor_area.height - height; - - if (content_width > 0 && content_height > 0) - gtk_window_set_default_size (GTK_WINDOW (window), width + content_width, height + content_height); - } -} - -/** - * e_util_query_ldap_root_dse_sync: - * @host: an LDAP server host name - * @port: an LDAP server port - * @out_root_dse: (out) (transfer full): NULL-terminated array of the server root DSE-s, or %NULL on error - * @cancellable: optional #GCancellable object, or %NULL - * @error: return location for a #GError, or %NULL - * - * Queries an LDAP server identified by @host and @port for supported - * search bases and returns them as an NULL-terminated array of strings - * at @out_root_dse. It sets @out_root_dse to NULL on error. - * Free the returned @out_root_dse with g_strfreev() when no longer needed. - * - * The function fails and sets @error to G_IO_ERROR_NOT_SUPPORTED when - * Evolution had been compiled without LDAP support. - * - * Returns: Whether succeeded. - * - * Since: 3.28 - **/ -gboolean -e_util_query_ldap_root_dse_sync (const gchar *host, - guint16 port, - gchar ***out_root_dse, - GCancellable *cancellable, - GError **error) -{ -#ifdef HAVE_LDAP - G_LOCK_DEFINE_STATIC (ldap); - LDAP *ldap = NULL; - LDAPMessage *result = NULL; - struct timeval timeout; - gchar **values = NULL, **root_dse; - gint ldap_error; - gint option; - gint version; - gint ii; - const gchar *attrs[] = { "namingContexts", NULL }; - - g_return_val_if_fail (host && *host, FALSE); - g_return_val_if_fail (port > 0, FALSE); - g_return_val_if_fail (out_root_dse != NULL, FALSE); - - *out_root_dse = NULL; - - timeout.tv_sec = 60; - timeout.tv_usec = 0; - - G_LOCK (ldap); - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto exit; - - ldap = ldap_init (host, port); - if (!ldap) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("This address book server might be unreachable or the server name may be misspelled or your network connection could be down.")); - goto exit; - } - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto exit; - - version = LDAP_VERSION3; - option = LDAP_OPT_PROTOCOL_VERSION; - ldap_error = ldap_set_option (ldap, option, &version); - if (ldap_error != LDAP_OPT_SUCCESS) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED, - _("Failed to set protocol version to LDAPv3 (%d): %s"), ldap_error, - ldap_err2string (ldap_error) ? ldap_err2string (ldap_error) : _("Unknown error")); - goto exit; - } - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto exit; - - /* FIXME Use the user's actual authentication settings. */ - ldap_error = ldap_simple_bind_s (ldap, NULL, NULL); - if (ldap_error != LDAP_SUCCESS) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, - _("Failed to authenticate with LDAP server (%d): %s"), ldap_error, - ldap_err2string (ldap_error) ? ldap_err2string (ldap_error) : _("Unknown error")); - goto exit; - } - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto exit; - - ldap_error = ldap_search_ext_s ( - ldap, LDAP_ROOT_DSE, LDAP_SCOPE_BASE, - "(objectclass=*)", (gchar **) attrs, 0, - NULL, NULL, &timeout, LDAP_NO_LIMIT, &result); - if (ldap_error != LDAP_SUCCESS) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - _("This LDAP server may use an older version of LDAP, which does not support this functionality or it may be misconfigured. Ask your administrator for supported search bases.\n\nDetailed error (%d): %s"), - ldap_error, ldap_err2string (ldap_error) ? ldap_err2string (ldap_error) : _("Unknown error")); - goto exit; - } - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto exit; - - values = ldap_get_values (ldap, result, "namingContexts"); - if (values == NULL || values[0] == NULL || *values[0] == '\0') { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - _("This LDAP server may use an older version of LDAP, which does not support this functionality or it may be misconfigured. Ask your administrator for supported search bases.")); - goto exit; - } - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto exit; - - root_dse = g_new0 (gchar *, g_strv_length (values) + 1); - - for (ii = 0; values[ii]; ii++) { - root_dse[ii] = g_strdup (values[ii]); - } - - root_dse[ii] = NULL; - - *out_root_dse = root_dse; - - exit: - if (values) - ldap_value_free (values); - - if (result) - ldap_msgfree (result); - - if (ldap) - ldap_unbind_s (ldap); - - G_UNLOCK (ldap); - - return *out_root_dse != NULL; - -#else /* HAVE_LDAP */ - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - _("Evolution had not been compiled with LDAP support")); - - return FALSE; -#endif -} diff --git a/src/e-util/gal-a11y-e-table-item.c b/src/e-util/gal-a11y-e-table-item.c index be302ed..cf06fb3 100644 --- a/src/e-util/gal-a11y-e-table-item.c +++ b/src/e-util/gal-a11y-e-table-item.c @@ -61,7 +61,6 @@ struct _GalA11yETableItemPrivate { ESelectionModel *selection; AtkStateSet *state_set; GtkWidget *widget; - GHashTable *a11y_column_headers; /* ETableCol * ~> GalA11yETableColumnHeader * */ }; static gboolean gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y, @@ -125,11 +124,6 @@ item_finalized (gpointer user_data, if (priv->selection) gal_a11y_e_table_item_unref_selection (a11y); - if (priv->columns) { - free_columns (priv->columns); - priv->columns = NULL; - } - g_object_unref (a11y); } @@ -279,60 +273,11 @@ eti_a11y_reset_focus_object (GalA11yETableItem *a11y, g_signal_emit_by_name (a11y, "active-descendant-changed", cell); } -static void eti_column_header_a11y_gone (gpointer user_data, GObject *a11y_col_header); - -static void -eti_table_column_gone (gpointer user_data, - GObject *col) -{ - GalA11yETableItem *a11y = user_data; - GalA11yETableItemPrivate *priv; - GalA11yETableColumnHeader *a11y_col_header; - - g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y)); - - priv = GET_PRIVATE (a11y); - - a11y_col_header = g_hash_table_lookup (priv->a11y_column_headers, col); - g_hash_table_remove (priv->a11y_column_headers, col); - - if (a11y_col_header) - g_object_weak_unref (G_OBJECT (a11y_col_header), eti_column_header_a11y_gone, a11y); -} - -static void -eti_column_header_a11y_gone (gpointer user_data, - GObject *a11y_col_header) -{ - GalA11yETableItem *a11y = user_data; - GalA11yETableItemPrivate *priv; - GHashTableIter iter; - gpointer key, value; - - g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y)); - - priv = GET_PRIVATE (a11y); - - g_hash_table_iter_init (&iter, priv->a11y_column_headers); - while (g_hash_table_iter_next (&iter, &key, &value)) { - ETableCol *col = key; - GalA11yETableColumnHeader *stored_a11y_col_header = value; - - if (((GObject *) stored_a11y_col_header) == a11y_col_header) { - g_object_weak_unref (G_OBJECT (col), eti_table_column_gone, a11y); - g_hash_table_remove (priv->a11y_column_headers, col); - break; - } - } -} - static void eti_dispose (GObject *object) { GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (object); GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); - GHashTableIter iter; - gpointer key, value; if (priv->columns) { free_columns (priv->columns); @@ -344,35 +289,10 @@ eti_dispose (GObject *object) priv->item = NULL; } - g_clear_object (&priv->state_set); - - g_hash_table_iter_init (&iter, priv->a11y_column_headers); - while (g_hash_table_iter_next (&iter, &key, &value)) { - ETableCol *col = key; - GalA11yETableColumnHeader *a11y_col_header = value; - - g_object_weak_unref (G_OBJECT (col), eti_table_column_gone, a11y); - g_object_weak_unref (G_OBJECT (a11y_col_header), eti_column_header_a11y_gone, a11y); - } - - g_hash_table_remove_all (priv->a11y_column_headers); - if (parent_class->dispose) parent_class->dispose (object); } -static void -eti_finalize (GObject *object) -{ - GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (object); - GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); - - g_hash_table_destroy (priv->a11y_column_headers); - - if (parent_class->finalize) - parent_class->finalize (object); -} - /* Static functions */ static gint eti_get_n_children (AtkObject *accessible) @@ -398,24 +318,12 @@ eti_ref_child (AtkObject *accessible, return NULL; if (index < item->cols) { - GalA11yETableItemPrivate *priv = GET_PRIVATE (accessible); ETableCol *ecol; AtkObject *child; ecol = e_table_header_get_column (item->header, index); - child = g_hash_table_lookup (priv->a11y_column_headers, ecol); - - if (!child) { - child = gal_a11y_e_table_column_header_new (ecol, item, accessible); - if (child) { - g_hash_table_insert (priv->a11y_column_headers, ecol, child); - - g_object_weak_ref (G_OBJECT (ecol), eti_table_column_gone, accessible); - g_object_weak_ref (G_OBJECT (child), eti_column_header_a11y_gone, accessible); - } - } - - return child ? g_object_ref (child) : NULL; + child = gal_a11y_e_table_column_header_new (ecol, item, accessible); + return child; } index -= item->cols; @@ -1058,7 +966,6 @@ eti_header_structure_changed (ETableHeader *eth, g_free (state); g_free (reorder); g_free (prev_state); - free_columns (cols); return; } @@ -1144,7 +1051,6 @@ eti_class_init (GalA11yETableItemClass *class) parent_class = g_type_class_ref (PARENT_TYPE); object_class->dispose = eti_dispose; - object_class->finalize = eti_finalize; atk_object_class->get_n_children = eti_get_n_children; atk_object_class->ref_child = eti_ref_child; @@ -1163,7 +1069,6 @@ eti_init (GalA11yETableItem *a11y) priv->selection_row_changed_id = 0; priv->cursor_changed_id = 0; priv->selection = NULL; - priv->a11y_column_headers = g_hash_table_new (g_direct_hash, g_direct_equal); } /* atk selection */ @@ -1284,17 +1189,14 @@ gal_a11y_e_table_item_new (ETableItem *item) accessible = ATK_OBJECT (a11y); + GET_PRIVATE (a11y)->item = item; /* Initialize cell data. */ GET_PRIVATE (a11y)->cols = item->cols; GET_PRIVATE (a11y)->rows = item->rows >= 0 ? item->rows : 0; GET_PRIVATE (a11y)->columns = e_table_header_get_columns (item->header); - if (GET_PRIVATE (a11y)->columns == NULL) { - g_clear_object (&a11y); + if (GET_PRIVATE (a11y)->columns == NULL) return NULL; - } - - GET_PRIVATE (a11y)->item = item; g_signal_connect ( item, "selection_model_removed", diff --git a/src/e-util/gal-a11y-e-table-item.c.gala11yetableitem-ref-child b/src/e-util/gal-a11y-e-table-item.c.gala11yetableitem-ref-child deleted file mode 100644 index cf06fb3..0000000 --- a/src/e-util/gal-a11y-e-table-item.c.gala11yetableitem-ref-child +++ /dev/null @@ -1,1508 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - * - * Authors: - * Christopher James Lahey - * Bolian Yin - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include "evolution-config.h" - -#include "gal-a11y-e-table-item.h" - -#include - -#include - -#include "e-canvas.h" -#include "e-selection-model.h" -#include "e-table-click-to-add.h" -#include "e-table-subset.h" -#include "e-table.h" -#include "e-tree.h" -#include "gal-a11y-e-cell-registry.h" -#include "gal-a11y-e-cell.h" -#include "gal-a11y-e-table-click-to-add.h" -#include "gal-a11y-e-table-column-header.h" -#include "gal-a11y-e-table-item-factory.h" -#include "gal-a11y-util.h" - -static GObjectClass *parent_class; -static AtkComponentIface *component_parent_iface; -static GType parent_type; -static gint priv_offset; -static GQuark quark_accessible_object = 0; -#define GET_PRIVATE(object) \ - ((GalA11yETableItemPrivate *) (((gchar *) object) + priv_offset)) -#define PARENT_TYPE (parent_type) - -struct _GalA11yETableItemPrivate { - ETableItem *item; - gint cols; - gint rows; - gulong selection_changed_id; - gulong selection_row_changed_id; - gulong cursor_changed_id; - ETableCol ** columns; - ESelectionModel *selection; - AtkStateSet *state_set; - GtkWidget *widget; -}; - -static gboolean gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y, - ESelectionModel *selection); -static gboolean gal_a11y_e_table_item_unref_selection (GalA11yETableItem *a11y); - -static AtkObject * eti_ref_at (AtkTable *table, gint row, gint column); - -static void -free_columns (ETableCol **columns) -{ - gint ii; - - if (!columns) - return; - - for (ii = 0; columns[ii]; ii++) { - g_object_unref (columns[ii]); - } - - g_free (columns); -} - -static void -table_item_cell_gone_cb (gpointer user_data, - GObject *gone_cell) -{ - GalA11yETableItem *a11y; - GObject *old_cell; - - a11y = GAL_A11Y_E_TABLE_ITEM (user_data); - - old_cell = g_object_get_data (G_OBJECT (a11y), "gail-focus-object"); - if (old_cell == gone_cell) - g_object_set_data (G_OBJECT (a11y), "gail-focus-object", NULL); -} - -static void -item_finalized (gpointer user_data, - GObject *gone_item) -{ - GalA11yETableItem *a11y; - GalA11yETableItemPrivate *priv; - GObject *old_cell; - - a11y = GAL_A11Y_E_TABLE_ITEM (user_data); - priv = GET_PRIVATE (a11y); - - priv->item = NULL; - - old_cell = g_object_get_data (G_OBJECT (a11y), "gail-focus-object"); - if (old_cell) { - g_object_weak_unref (G_OBJECT (old_cell), table_item_cell_gone_cb, a11y); - g_object_unref (old_cell); - } - g_object_set_data (G_OBJECT (a11y), "gail-focus-object", NULL); - - if (atk_state_set_add_state (priv->state_set, ATK_STATE_DEFUNCT)) - atk_object_notify_state_change (ATK_OBJECT (a11y), ATK_STATE_DEFUNCT, TRUE); - - if (priv->selection) - gal_a11y_e_table_item_unref_selection (a11y); - - g_object_unref (a11y); -} - -static void -gal_a11y_e_table_item_state_change_cb (AtkObject *atkobject, - const gchar *state_name, - gboolean was_set, - gpointer user_data) -{ - g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (atkobject)); - - if (atk_state_type_for_name (state_name) == ATK_STATE_DEFUNCT) { - GalA11yETableItemPrivate *priv; - - priv = GET_PRIVATE (atkobject); - - g_return_if_fail (priv != NULL); - - if (was_set) - atk_state_set_add_state (priv->state_set, ATK_STATE_DEFUNCT); - else - atk_state_set_remove_state (priv->state_set, ATK_STATE_DEFUNCT); - } -} - -static AtkStateSet * -eti_ref_state_set (AtkObject *accessible) -{ - GalA11yETableItemPrivate *priv = GET_PRIVATE (accessible); - - g_object_ref (priv->state_set); - - return priv->state_set; -} - -inline static gint -view_to_model_row (ETableItem *eti, - gint row) -{ - if (eti->uses_source_model) { - ETableSubset *etss = E_TABLE_SUBSET (eti->table_model); - if (row >= 0 && row < etss->n_map) { - eti->row_guess = row; - return etss->map_table[row]; - } else - return -1; - } else - return row; -} - -inline static gint -view_to_model_col (ETableItem *eti, - gint view_col) -{ - ETableCol *ecol = e_table_header_get_column (eti->header, view_col); - - return (ecol != NULL) ? ecol->spec->model_col : -1; -} - -inline static gint -model_to_view_row (ETableItem *eti, - gint row) -{ - gint i; - if (row == -1) - return -1; - if (eti->uses_source_model) { - ETableSubset *etss = E_TABLE_SUBSET (eti->table_model); - if (eti->row_guess >= 0 && eti->row_guess < etss->n_map) { - if (etss->map_table[eti->row_guess] == row) { - return eti->row_guess; - } - } - for (i = 0; i < etss->n_map; i++) { - if (etss->map_table[i] == row) - return i; - } - return -1; - } else - return row; -} - -inline static gint -model_to_view_col (ETableItem *eti, - gint model_col) -{ - gint i; - if (model_col == -1) - return -1; - for (i = 0; i < eti->cols; i++) { - ETableCol *ecol = e_table_header_get_column (eti->header, i); - if (ecol->spec->model_col == model_col) - return i; - } - return -1; -} - -inline static GObject * -eti_a11y_get_gobject (AtkObject *accessible) -{ - return atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)); -} - -static void -eti_a11y_reset_focus_object (GalA11yETableItem *a11y, - ETableItem *item, - gboolean notify) -{ - ESelectionModel * esm; - gint cursor_row, cursor_col, view_row, view_col; - AtkObject *cell, *old_cell; - - esm = item->selection; - g_return_if_fail (esm); - - cursor_row = e_selection_model_cursor_row (esm); - cursor_col = e_selection_model_cursor_col (esm); - - view_row = model_to_view_row (item, cursor_row); - view_col = model_to_view_col (item, cursor_col); - - if (view_row == -1) - view_row = 0; - if (view_col == -1) - view_col = 0; - - old_cell = (AtkObject *) g_object_get_data (G_OBJECT (a11y), "gail-focus-object"); - if (old_cell && GAL_A11Y_IS_E_CELL (old_cell)) - gal_a11y_e_cell_remove_state ( - GAL_A11Y_E_CELL (old_cell), ATK_STATE_FOCUSED, FALSE); - if (old_cell) { - g_object_weak_unref (G_OBJECT (old_cell), table_item_cell_gone_cb, a11y); - g_object_unref (old_cell); - } - - cell = eti_ref_at (ATK_TABLE (a11y), view_row, view_col); - - if (cell != NULL) { - g_object_set_data (G_OBJECT (a11y), "gail-focus-object", cell); - gal_a11y_e_cell_add_state ( - GAL_A11Y_E_CELL (cell), ATK_STATE_FOCUSED, FALSE); - g_object_weak_ref (G_OBJECT (cell), table_item_cell_gone_cb, a11y); - } else - g_object_set_data (G_OBJECT (a11y), "gail-focus-object", NULL); - - if (notify && cell) - g_signal_emit_by_name (a11y, "active-descendant-changed", cell); -} - -static void -eti_dispose (GObject *object) -{ - GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (object); - GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); - - if (priv->columns) { - free_columns (priv->columns); - priv->columns = NULL; - } - - if (priv->item) { - g_object_weak_unref (G_OBJECT (priv->item), item_finalized, a11y); - priv->item = NULL; - } - - if (parent_class->dispose) - parent_class->dispose (object); -} - -/* Static functions */ -static gint -eti_get_n_children (AtkObject *accessible) -{ - g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), 0); - if (!eti_a11y_get_gobject (accessible)) - return 0; - - return atk_table_get_n_columns (ATK_TABLE (accessible)) * - (atk_table_get_n_rows (ATK_TABLE (accessible)) + 1); -} - -static AtkObject * -eti_ref_child (AtkObject *accessible, - gint index) -{ - ETableItem *item; - gint col, row; - - g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), NULL); - item = E_TABLE_ITEM (eti_a11y_get_gobject (accessible)); - if (!item) - return NULL; - - if (index < item->cols) { - ETableCol *ecol; - AtkObject *child; - - ecol = e_table_header_get_column (item->header, index); - child = gal_a11y_e_table_column_header_new (ecol, item, accessible); - return child; - } - index -= item->cols; - - col = index % item->cols; - row = index / item->cols; - - return eti_ref_at (ATK_TABLE (accessible), row, col); -} - -static void -eti_get_extents (AtkComponent *component, - gint *x, - gint *y, - gint *width, - gint *height, - AtkCoordType coord_type) -{ - ETableItem *item; - AtkObject *parent; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component))); - if (!item) - return; - - parent = ATK_OBJECT (component)->accessible_parent; - if (parent && ATK_IS_COMPONENT (parent)) - atk_component_get_extents ( - ATK_COMPONENT (parent), - x, y, - width, height, - coord_type); - - if (parent && GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD (parent)) { - ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD ( - atk_gobject_accessible_get_object ( - ATK_GOBJECT_ACCESSIBLE (parent))); - if (etcta) { - *width = etcta->width; - *height = etcta->height; - } - } -} - -static AtkObject * -eti_ref_accessible_at_point (AtkComponent *component, - gint x, - gint y, - AtkCoordType coord_type) -{ - gint row = -1; - gint col = -1; - gint x_origin, y_origin; - ETableItem *item; - GtkWidget *tableOrTree; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component))); - if (!item) - return NULL; - - atk_component_get_extents ( - component, - &x_origin, - &y_origin, - NULL, - NULL, - coord_type); - x -= x_origin; - y -= y_origin; - - tableOrTree = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas)); - - if (E_IS_TREE (tableOrTree)) - e_tree_get_cell_at (E_TREE (tableOrTree), x, y, &row, &col); - else - e_table_get_cell_at (E_TABLE (tableOrTree), x, y, &row, &col); - - if (row != -1 && col != -1) { - return eti_ref_at (ATK_TABLE (component), row, col); - } else { - return NULL; - } -} - -/* atk table */ -static AtkObject * -eti_ref_at (AtkTable *table, - gint row, - gint column) -{ - ETableItem *item; - AtkObject * ret; - GalA11yETableItemPrivate *priv = GET_PRIVATE (table); - - if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) - return NULL; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return NULL; - - if (column >= 0 && - column < item->cols && - row >= 0 && - row < item->rows && - item->cell_views_realized) { - ECellView *cell_view = item->cell_views[column]; - ETableCol *ecol = e_table_header_get_column (item->header, column); - ret = gal_a11y_e_cell_registry_get_object ( - NULL, - item, - cell_view, - ATK_OBJECT (table), - ecol->spec->model_col, - column, - row); - if (ATK_IS_OBJECT (ret)) { - /* if current cell is focused, add FOCUSED state */ - if (e_selection_model_cursor_row (item->selection) == - GAL_A11Y_E_CELL (ret)->row && - e_selection_model_cursor_col (item->selection) == - GAL_A11Y_E_CELL (ret)->model_col) - gal_a11y_e_cell_add_state ( - GAL_A11Y_E_CELL (ret), - ATK_STATE_FOCUSED, FALSE); - } else - ret = NULL; - - return ret; - } - - return NULL; -} - -static gint -eti_get_index_at (AtkTable *table, - gint row, - gint column) -{ - ETableItem *item; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return -1; - - return column + (row + 1) * item->cols; -} - -static gint -eti_get_column_at_index (AtkTable *table, - gint index) -{ - ETableItem *item; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return -1; - - return index % item->cols; -} - -static gint -eti_get_row_at_index (AtkTable *table, - gint index) -{ - ETableItem *item; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return -1; - - return index / item->cols - 1; -} - -static gint -eti_get_n_columns (AtkTable *table) -{ - ETableItem *item; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return -1; - - return item->cols; -} - -static gint -eti_get_n_rows (AtkTable *table) -{ - ETableItem *item; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return -1; - - return item->rows; -} - -static gint -eti_get_column_extent_at (AtkTable *table, - gint row, - gint column) -{ - ETableItem *item; - gint width; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return -1; - - e_table_item_get_cell_geometry ( - item, - &row, - &column, - NULL, - NULL, - &width, - NULL); - - return width; -} - -static gint -eti_get_row_extent_at (AtkTable *table, - gint row, - gint column) -{ - ETableItem *item; - gint height; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return -1; - - e_table_item_get_cell_geometry ( - item, - &row, - &column, - NULL, - NULL, - NULL, - &height); - - return height; -} - -static AtkObject * -eti_get_caption (AtkTable *table) -{ - /* Unimplemented */ - return NULL; -} - -static const gchar * -eti_get_column_description (AtkTable *table, - gint column) -{ - ETableItem *item; - ETableCol *ecol; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return NULL; - - ecol = e_table_header_get_column (item->header, column); - - return ecol->text; -} - -static AtkObject * -eti_get_column_header (AtkTable *table, - gint column) -{ - ETableItem *item; - ETableCol *ecol; - AtkObject *atk_obj = NULL; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return NULL; - - ecol = e_table_header_get_column (item->header, column); - if (ecol) { - atk_obj = gal_a11y_e_table_column_header_new (ecol, item, ATK_OBJECT (table)); - } - - return atk_obj; -} - -static const gchar * -eti_get_row_description (AtkTable *table, - gint row) -{ - /* Unimplemented */ - return NULL; -} - -static AtkObject * -eti_get_row_header (AtkTable *table, - gint row) -{ - /* Unimplemented */ - return NULL; -} - -static AtkObject * -eti_get_summary (AtkTable *table) -{ - /* Unimplemented */ - return NULL; -} - -static gboolean -table_is_row_selected (AtkTable *table, - gint row) -{ - ETableItem *item; - GalA11yETableItemPrivate *priv = GET_PRIVATE (table); - - if (row < 0) - return FALSE; - - if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) - return FALSE; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return FALSE; - - return e_selection_model_is_row_selected ( - item->selection, view_to_model_row (item, row)); -} - -static gboolean -table_is_selected (AtkTable *table, - gint row, - gint column) -{ - return table_is_row_selected (table, row); -} - -static gint -table_get_selected_rows (AtkTable *table, - gint **rows_selected) -{ - ETableItem *item; - gint n_selected, row, index_selected; - GalA11yETableItemPrivate *priv = GET_PRIVATE (table); - - if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) - return 0; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return 0; - - n_selected = e_selection_model_selected_count (item->selection); - if (rows_selected) { - *rows_selected = (gint *) g_malloc (n_selected * sizeof (gint)); - - index_selected = 0; - for (row = 0; row < item->rows && index_selected < n_selected; ++row) { - if (atk_table_is_row_selected (table, row)) { - (*rows_selected)[index_selected] = row; - ++index_selected; - } - } - } - return n_selected; -} - -static gboolean -table_add_row_selection (AtkTable *table, - gint row) -{ - ETableItem *item; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return FALSE; - - if (table_is_row_selected (table, row)) - return TRUE; - e_selection_model_toggle_single_row ( - item->selection, - view_to_model_row (item, row)); - - return TRUE; -} - -static gboolean -table_remove_row_selection (AtkTable *table, - gint row) -{ - ETableItem *item; - GalA11yETableItemPrivate *priv = GET_PRIVATE (table); - - if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) - return FALSE; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); - if (!item) - return FALSE; - - if (!atk_table_is_row_selected (table, row)) - return TRUE; - - e_selection_model_toggle_single_row ( - item->selection, view_to_model_row (item, row)); - - return TRUE; -} - -static void -eti_atk_table_iface_init (AtkTableIface *iface) -{ - iface->ref_at = eti_ref_at; - iface->get_index_at = eti_get_index_at; - iface->get_column_at_index = eti_get_column_at_index; - iface->get_row_at_index = eti_get_row_at_index; - iface->get_n_columns = eti_get_n_columns; - iface->get_n_rows = eti_get_n_rows; - iface->get_column_extent_at = eti_get_column_extent_at; - iface->get_row_extent_at = eti_get_row_extent_at; - iface->get_caption = eti_get_caption; - iface->get_column_description = eti_get_column_description; - iface->get_column_header = eti_get_column_header; - iface->get_row_description = eti_get_row_description; - iface->get_row_header = eti_get_row_header; - iface->get_summary = eti_get_summary; - - iface->is_row_selected = table_is_row_selected; - iface->is_selected = table_is_selected; - iface->get_selected_rows = table_get_selected_rows; - iface->add_row_selection = table_add_row_selection; - iface->remove_row_selection = table_remove_row_selection; -} - -static void -eti_atk_component_iface_init (AtkComponentIface *iface) -{ - component_parent_iface = g_type_interface_peek_parent (iface); - - iface->ref_accessible_at_point = eti_ref_accessible_at_point; - iface->get_extents = eti_get_extents; -} - -static void -eti_rows_inserted (ETableModel *model, - gint row, - gint count, - AtkObject *table_item) -{ - gint n_cols,n_rows,i,j; - GalA11yETableItem * item_a11y; - gint old_nrows; - - g_return_if_fail (table_item); - item_a11y = GAL_A11Y_E_TABLE_ITEM (table_item); - - n_cols = atk_table_get_n_columns (ATK_TABLE (table_item)); - n_rows = atk_table_get_n_rows (ATK_TABLE (table_item)); - - old_nrows = GET_PRIVATE (item_a11y)->rows; - - g_return_if_fail (n_cols > 0 && n_rows > 0); - g_return_if_fail (old_nrows == n_rows - count); - - GET_PRIVATE (table_item)->rows = n_rows; - - g_signal_emit_by_name ( - table_item, "row-inserted", row, - count, NULL); - - for (i = row; i < (row + count); i++) { - for (j = 0; j < n_cols; j++) { - g_signal_emit_by_name ( - table_item, - "children_changed::add", - (((i + 1) * n_cols) + j), NULL, NULL); - } - } - - g_signal_emit_by_name (table_item, "visible-data-changed"); -} - -static void -eti_rows_deleted (ETableModel *model, - gint row, - gint count, - AtkObject *table_item) -{ - gint i,j, n_rows, n_cols, old_nrows; - ETableItem *item = E_TABLE_ITEM ( - atk_gobject_accessible_get_object ( - ATK_GOBJECT_ACCESSIBLE (table_item))); - - n_rows = atk_table_get_n_rows (ATK_TABLE (table_item)); - n_cols = atk_table_get_n_columns (ATK_TABLE (table_item)); - - old_nrows = GET_PRIVATE (table_item)->rows; - - g_return_if_fail (row + count <= old_nrows); - g_return_if_fail (old_nrows == n_rows + count); - GET_PRIVATE (table_item)->rows = n_rows; - - g_signal_emit_by_name ( - table_item, "row-deleted", row, - count, NULL); - - for (i = row; i < (row + count); i++) { - for (j = 0; j < n_cols; j++) { - g_signal_emit_by_name ( - table_item, - "children_changed::remove", - (((i + 1) * n_cols) + j), NULL, NULL); - } - } - g_signal_emit_by_name (table_item, "visible-data-changed"); - eti_a11y_reset_focus_object ((GalA11yETableItem *) table_item, item, TRUE); -} - -static void -eti_model_changed (ETableModel *model, - AtkObject *table_item) -{ - GalA11yETableItemPrivate *priv; - gint row_count; - - g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (table_item)); - - priv = GET_PRIVATE (table_item); - - row_count = e_table_model_row_count (model); - - if (priv->rows != row_count) { - priv->rows = row_count; - g_signal_emit_by_name (table_item, "visible-data-changed"); - } -} - -static void -eti_tree_model_node_changed_cb (ETreeModel *model, - ETreePath node, - ETableItem *eti) -{ - AtkObject *atk_obj; - GalA11yETableItem *a11y; - - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti)); - a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj); - - /* we can't figure out which rows are changed, so just send out a signal ... */ - if (GET_PRIVATE (a11y)->rows > 0) - g_signal_emit_by_name (a11y, "visible-data-changed"); -} - -enum { - ETI_HEADER_UNCHANGED = 0, - ETI_HEADER_REORDERED, - ETI_HEADER_NEW_ADDED, - ETI_HEADER_REMOVED -}; - -/* - * 1. Check what actually happened: column reorder, remove or add - * 2. Update cache - * 3. Emit signals - */ -static void -eti_header_structure_changed (ETableHeader *eth, - AtkObject *a11y) -{ - - gboolean reorder_found = FALSE, added_found = FALSE, removed_found = FALSE; - GalA11yETableItem * a11y_item; - ETableCol ** cols, **prev_cols; - GalA11yETableItemPrivate *priv; - gint *state = NULL, *prev_state = NULL, *reorder = NULL; - gint i,j,n_rows,n_cols, prev_n_cols; - - a11y_item = GAL_A11Y_E_TABLE_ITEM (a11y); - priv = GET_PRIVATE (a11y_item); - - /* Assume rows do not changed. */ - n_rows = priv->rows; - - prev_n_cols = priv->cols; - prev_cols = priv->columns; - - cols = e_table_header_get_columns (eth); - n_cols = eth->col_count; - - g_return_if_fail (cols && prev_cols && n_cols > 0); - - /* Init to ETI_HEADER_UNCHANGED. */ - state = g_malloc0 (sizeof (gint) * (MAX (prev_n_cols, n_cols) + 1)); - prev_state = g_malloc0 (sizeof (gint) * (MAX (prev_n_cols, n_cols) + 1)); - reorder = g_malloc0 (sizeof (gint) * (MAX (prev_n_cols, n_cols) + 1)); - - /* Compare with previously saved column headers. */ - for (i = 0; i < n_cols && cols[i]; i++) { - for (j = 0; j < prev_n_cols && prev_cols[j]; j++) { - if (prev_cols[j] == cols[i] && i != j) { - - reorder_found = TRUE; - state[i] = ETI_HEADER_REORDERED; - reorder[i] = j; - - break; - } else if (prev_cols[j] == cols[i]) { - /* OK, this column is not changed. */ - break; - } - } - - /* cols[i] is new added column. */ - if (j == prev_n_cols) { - added_found = TRUE; - state[i] = ETI_HEADER_NEW_ADDED; - } - } - - /* Now try to find if there are removed columns. */ - for (i = 0; i < prev_n_cols && prev_cols[i]; i++) { - for (j = 0; j < n_cols && cols[j]; j++) - if (prev_cols[j] == cols[i]) - break; - - /* Removed columns found. */ - if (j == n_cols) { - removed_found = TRUE; - prev_state[j] = ETI_HEADER_REMOVED; - } - } - - /* If nothing interesting just return. */ - if (!reorder_found && !added_found && !removed_found) { - g_free (state); - g_free (reorder); - g_free (prev_state); - return; - } - - /* Emit signals */ - if (reorder_found) - g_signal_emit_by_name (a11y_item, "column_reordered"); - - if (removed_found) { - for (i = 0; i < prev_n_cols; i++) { - if (prev_state[i] == ETI_HEADER_REMOVED) { - g_signal_emit_by_name ( - a11y_item, "column-deleted", i, 1); - for (j = 0; j < n_rows; j++) - g_signal_emit_by_name ( - a11y_item, - "children_changed::remove", - ((j + 1) * prev_n_cols + i), - NULL, NULL); - } - } - } - - if (added_found) { - for (i = 0; i < n_cols; i++) { - if (state[i] == ETI_HEADER_NEW_ADDED) { - g_signal_emit_by_name ( - a11y_item, "column-inserted", i, 1); - for (j = 0; j < n_rows; j++) - g_signal_emit_by_name ( - a11y_item, - "children_changed::add", - ((j + 1) * n_cols + i), - NULL, NULL); - } - } - } - - priv->cols = n_cols; - - g_free (state); - g_free (reorder); - g_free (prev_state); - - free_columns (priv->columns); - priv->columns = cols; -} - -static void -eti_real_initialize (AtkObject *obj, - gpointer data) -{ - ETableItem * eti; - ETableModel * model; - - ATK_OBJECT_CLASS (parent_class)->initialize (obj, data); - eti = E_TABLE_ITEM (data); - - model = eti->table_model; - - g_signal_connect_object ( - model, "model-rows-inserted", - G_CALLBACK (eti_rows_inserted), obj, 0); - g_signal_connect_object ( - model, "model-rows-deleted", - G_CALLBACK (eti_rows_deleted), obj, 0); - g_signal_connect_object ( - model, "model-changed", - G_CALLBACK (eti_model_changed), obj, 0); - g_signal_connect_object ( - eti->header, "structure_change", - G_CALLBACK (eti_header_structure_changed), obj, 0); -} - -static void -eti_class_init (GalA11yETableItemClass *class) -{ - AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (class); - GObjectClass *object_class = G_OBJECT_CLASS (class); - - quark_accessible_object = - g_quark_from_static_string ("gtk-accessible-object"); - - parent_class = g_type_class_ref (PARENT_TYPE); - - object_class->dispose = eti_dispose; - - atk_object_class->get_n_children = eti_get_n_children; - atk_object_class->ref_child = eti_ref_child; - atk_object_class->initialize = eti_real_initialize; - atk_object_class->ref_state_set = eti_ref_state_set; -} - -static void -eti_init (GalA11yETableItem *a11y) -{ - GalA11yETableItemPrivate *priv; - - priv = GET_PRIVATE (a11y); - - priv->selection_changed_id = 0; - priv->selection_row_changed_id = 0; - priv->cursor_changed_id = 0; - priv->selection = NULL; -} - -/* atk selection */ - -static void atk_selection_interface_init (AtkSelectionIface *iface); -static gboolean selection_add_selection (AtkSelection *selection, - gint i); -static gboolean selection_clear_selection (AtkSelection *selection); -static AtkObject * - selection_ref_selection (AtkSelection *selection, - gint i); -static gint selection_get_selection_count (AtkSelection *selection); -static gboolean selection_is_child_selected (AtkSelection *selection, - gint i); - -/* callbacks */ -static void eti_a11y_selection_model_removed_cb (ETableItem *eti, - ESelectionModel *selection, - gpointer data); -static void eti_a11y_selection_model_added_cb (ETableItem *eti, - ESelectionModel *selection, - gpointer data); -static void eti_a11y_selection_changed_cb (ESelectionModel *selection, - GalA11yETableItem *a11y); -static void eti_a11y_selection_row_changed_cb (ESelectionModel *selection, - gint row, - GalA11yETableItem *a11y); -static void eti_a11y_cursor_changed_cb (ESelectionModel *selection, - gint row, gint col, - GalA11yETableItem *a11y); - -/** - * gal_a11y_e_table_item_get_type: - * @void: - * - * Registers the &GalA11yETableItem class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the &GalA11yETableItem class. - **/ -GType -gal_a11y_e_table_item_get_type (void) -{ - static GType type = 0; - - if (!type) { - AtkObjectFactory *factory; - - GTypeInfo info = { - sizeof (GalA11yETableItemClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) eti_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (GalA11yETableItem), - 0, - (GInstanceInitFunc) eti_init, - NULL /* value_table_item */ - }; - - static const GInterfaceInfo atk_component_info = { - (GInterfaceInitFunc) eti_atk_component_iface_init, - (GInterfaceFinalizeFunc) NULL, - NULL - }; - static const GInterfaceInfo atk_table_info = { - (GInterfaceInitFunc) eti_atk_table_iface_init, - (GInterfaceFinalizeFunc) NULL, - NULL - }; - - static const GInterfaceInfo atk_selection_info = { - (GInterfaceInitFunc) atk_selection_interface_init, - (GInterfaceFinalizeFunc) NULL, - NULL - }; - - factory = atk_registry_get_factory ( - atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM); - parent_type = atk_object_factory_get_accessible_type (factory); - - type = gal_a11y_type_register_static_with_private ( - PARENT_TYPE, "GalA11yETableItem", &info, 0, - sizeof (GalA11yETableItemPrivate), &priv_offset); - - g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info); - g_type_add_interface_static (type, ATK_TYPE_TABLE, &atk_table_info); - g_type_add_interface_static (type, ATK_TYPE_SELECTION, &atk_selection_info); - } - - return type; -} - -AtkObject * -gal_a11y_e_table_item_new (ETableItem *item) -{ - GalA11yETableItem *a11y; - AtkObject *accessible; - ESelectionModel * esm; - AtkObject *parent; - const gchar *name; - - g_return_val_if_fail (item && item->cols >= 0, NULL); - a11y = g_object_new (gal_a11y_e_table_item_get_type (), NULL); - - atk_object_initialize (ATK_OBJECT (a11y), item); - - GET_PRIVATE (a11y)->state_set = atk_state_set_new (); - - atk_state_set_add_state (GET_PRIVATE (a11y)->state_set, ATK_STATE_MANAGES_DESCENDANTS); - atk_state_set_add_state (GET_PRIVATE (a11y)->state_set, ATK_STATE_ENABLED); - atk_state_set_add_state (GET_PRIVATE (a11y)->state_set, ATK_STATE_SENSITIVE); - atk_state_set_add_state (GET_PRIVATE (a11y)->state_set, ATK_STATE_SHOWING); - atk_state_set_add_state (GET_PRIVATE (a11y)->state_set, ATK_STATE_VISIBLE); - - g_signal_connect (a11y, "state-change", G_CALLBACK (gal_a11y_e_table_item_state_change_cb), NULL); - - accessible = ATK_OBJECT (a11y); - - GET_PRIVATE (a11y)->item = item; - /* Initialize cell data. */ - GET_PRIVATE (a11y)->cols = item->cols; - GET_PRIVATE (a11y)->rows = item->rows >= 0 ? item->rows : 0; - - GET_PRIVATE (a11y)->columns = e_table_header_get_columns (item->header); - if (GET_PRIVATE (a11y)->columns == NULL) - return NULL; - - g_signal_connect ( - item, "selection_model_removed", - G_CALLBACK (eti_a11y_selection_model_removed_cb), NULL); - g_signal_connect ( - item, "selection_model_added", - G_CALLBACK (eti_a11y_selection_model_added_cb), NULL); - if (item->selection) - gal_a11y_e_table_item_ref_selection ( - a11y, - item->selection); - - /* find the TableItem's parent: table or tree */ - GET_PRIVATE (a11y)->widget = gtk_widget_get_parent ( - GTK_WIDGET (item->parent.canvas)); - parent = gtk_widget_get_accessible (GET_PRIVATE (a11y)->widget); - name = atk_object_get_name (parent); - if (name) - atk_object_set_name (accessible, name); - atk_object_set_parent (accessible, parent); - - if (E_IS_TREE (GET_PRIVATE (a11y)->widget)) { - ETreeModel *model; - model = e_tree_get_model (E_TREE (GET_PRIVATE (a11y)->widget)); - g_signal_connect ( - model, "node_changed", - G_CALLBACK (eti_tree_model_node_changed_cb), item); - accessible->role = ATK_ROLE_TREE_TABLE; - } else if (E_IS_TABLE (GET_PRIVATE (a11y)->widget)) { - accessible->role = ATK_ROLE_TABLE; - } - - g_object_weak_ref (G_OBJECT (item), item_finalized, g_object_ref (a11y)); - - esm = item->selection; - - if (esm != NULL) { - eti_a11y_reset_focus_object (a11y, item, FALSE); - } - - return ATK_OBJECT (a11y); -} - -static gboolean -gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y, - ESelectionModel *selection) -{ - GalA11yETableItemPrivate *priv; - - g_return_val_if_fail (a11y && selection, FALSE); - - priv = GET_PRIVATE (a11y); - priv->selection_changed_id = g_signal_connect ( - selection, "selection-changed", - G_CALLBACK (eti_a11y_selection_changed_cb), a11y); - priv->selection_row_changed_id = g_signal_connect ( - selection, "selection-row-changed", - G_CALLBACK (eti_a11y_selection_row_changed_cb), a11y); - priv->cursor_changed_id = g_signal_connect ( - selection, "cursor-changed", - G_CALLBACK (eti_a11y_cursor_changed_cb), a11y); - - priv->selection = selection; - g_object_ref (selection); - - return TRUE; -} - -static gboolean -gal_a11y_e_table_item_unref_selection (GalA11yETableItem *a11y) -{ - GalA11yETableItemPrivate *priv; - - g_return_val_if_fail (a11y, FALSE); - - priv = GET_PRIVATE (a11y); - - g_return_val_if_fail (priv->selection_changed_id != 0, FALSE); - g_return_val_if_fail (priv->selection_row_changed_id != 0, FALSE); - g_return_val_if_fail (priv->cursor_changed_id != 0, FALSE); - - g_signal_handler_disconnect ( - priv->selection, - priv->selection_changed_id); - g_signal_handler_disconnect ( - priv->selection, - priv->selection_row_changed_id); - g_signal_handler_disconnect ( - priv->selection, - priv->cursor_changed_id); - priv->cursor_changed_id = 0; - priv->selection_row_changed_id = 0; - priv->selection_changed_id = 0; - - g_object_unref (priv->selection); - priv->selection = NULL; - - return TRUE; -} - -/* callbacks */ - -static void -eti_a11y_selection_model_removed_cb (ETableItem *eti, - ESelectionModel *selection, - gpointer data) -{ - AtkObject *atk_obj; - GalA11yETableItem *a11y; - - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - g_return_if_fail (E_IS_SELECTION_MODEL (selection)); - - atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti)); - a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj); - - if (selection == GET_PRIVATE (a11y)->selection) - gal_a11y_e_table_item_unref_selection (a11y); -} - -static void -eti_a11y_selection_model_added_cb (ETableItem *eti, - ESelectionModel *selection, - gpointer data) -{ - AtkObject *atk_obj; - GalA11yETableItem *a11y; - - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - g_return_if_fail (E_IS_SELECTION_MODEL (selection)); - - atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti)); - a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj); - - if (GET_PRIVATE (a11y)->selection) - gal_a11y_e_table_item_unref_selection (a11y); - gal_a11y_e_table_item_ref_selection (a11y, selection); -} - -static void -eti_a11y_selection_changed_cb (ESelectionModel *selection, - GalA11yETableItem *a11y) -{ - GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); - - if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) - return; - - g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y)); - - g_signal_emit_by_name (a11y, "selection_changed"); -} - -static void -eti_a11y_selection_row_changed_cb (ESelectionModel *selection, - gint row, - GalA11yETableItem *a11y) -{ - eti_a11y_selection_changed_cb (selection, a11y); -} - -static void -eti_a11y_cursor_changed_cb (ESelectionModel *selection, - gint row, - gint col, - GalA11yETableItem *a11y) -{ - ETableItem *item; - GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); - - g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y)); - - if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) - return; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (a11y))); - - g_return_if_fail (item); - - if (row == -1 && col == -1) - return; - eti_a11y_reset_focus_object (a11y, item, TRUE); -} - -/* atk selection */ - -static void atk_selection_interface_init (AtkSelectionIface *iface) -{ - g_return_if_fail (iface != NULL); - iface->add_selection = selection_add_selection; - iface->clear_selection = selection_clear_selection; - iface->ref_selection = selection_ref_selection; - iface->get_selection_count = selection_get_selection_count; - iface->is_child_selected = selection_is_child_selected; -} - -static gboolean -selection_add_selection (AtkSelection *selection, - gint index) -{ - AtkTable *table; - gint row, col, cursor_row, cursor_col, model_row, model_col; - ETableItem *item; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection))); - if (!item) - return FALSE; - - table = ATK_TABLE (selection); - - row = atk_table_get_row_at_index (table, index); - col = atk_table_get_column_at_index (table, index); - - model_row = view_to_model_row (item, row); - model_col = view_to_model_col (item, col); - - cursor_row = e_selection_model_cursor_row (item->selection); - cursor_col = e_selection_model_cursor_col (item->selection); - - /* check whether is selected already */ - if (model_row == cursor_row && model_col == cursor_col) - return TRUE; - - if (model_row != cursor_row) { - /* we need to make the item get focus */ - e_canvas_item_grab_focus (GNOME_CANVAS_ITEM (item), TRUE); - - /* FIXME, currently we only support single row selection */ - atk_selection_clear_selection (selection); - atk_table_add_row_selection (table, row); - } - - e_selection_model_change_cursor ( - item->selection, - model_row, - model_col); - e_selection_model_cursor_changed ( - item->selection, - model_row, - model_col); - e_selection_model_cursor_activated ( - item->selection, - model_row, - model_col); - return TRUE; -} - -static gboolean -selection_clear_selection (AtkSelection *selection) -{ - ETableItem *item; - - item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection))); - if (!item) - return FALSE; - - e_selection_model_clear (item->selection); - return TRUE; -} - -static AtkObject * -selection_ref_selection (AtkSelection *selection, - gint index) -{ - AtkTable *table; - gint row, col; - - table = ATK_TABLE (selection); - row = atk_table_get_row_at_index (table, index); - col = atk_table_get_column_at_index (table, index); - if (!atk_table_is_row_selected (table, row)) - return NULL; - - return eti_ref_at (table, row, col); -} - -static gint -selection_get_selection_count (AtkSelection *selection) -{ - AtkTable *table; - gint n_selected; - - table = ATK_TABLE (selection); - n_selected = atk_table_get_selected_rows (table, NULL); - if (n_selected > 0) - n_selected *= atk_table_get_n_columns (table); - return n_selected; -} - -static gboolean -selection_is_child_selected (AtkSelection *selection, - gint i) -{ - gint row; - - row = atk_table_get_row_at_index (ATK_TABLE (selection), i); - return atk_table_is_row_selected (ATK_TABLE (selection), row); -} - -void -gal_a11y_e_table_item_init (void) -{ - if (atk_get_root ()) - atk_registry_set_factory_type ( - atk_get_default_registry (), - E_TYPE_TABLE_ITEM, - gal_a11y_e_table_item_factory_get_type ()); -} - diff --git a/src/e-util/test-html-editor-units-bugs.c b/src/e-util/test-html-editor-units-bugs.c index a4fbfe0..e5f16be 100644 --- a/src/e-util/test-html-editor-units-bugs.c +++ b/src/e-util/test-html-editor-units-bugs.c @@ -1205,158 +1205,6 @@ test_bug_750636 (TestFixture *fixture) g_test_fail (); } -static void -test_issue_86 (TestFixture *fixture) -{ - const gchar *source_text = - "normal text\n" - "\n" - "> level 1\n" - "> level 1\n" - "> > level 2\n" - "> > level 2\n" - "> >\n" - "> > level 2\n" - ">\n" - "> level 1\n" - "> level 1\n" - ">\n" - "> > > level 3\n" - "> > > level 3\n" - ">\n" - "> > level 2\n" - "> > level 2\n" - ">\n" - "> level 1\n" - "\n" - "back normal text\n"; - gchar *converted, *to_insert; - - if (!test_utils_process_commands (fixture, - "mode:html\n")) { - g_test_fail (); - return; - } - - converted = camel_text_to_html (source_text, - CAMEL_MIME_FILTER_TOHTML_PRE | - CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | - CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES | - CAMEL_MIME_FILTER_TOHTML_QUOTE_CITATION, - 0xDDDDDD); - - g_return_if_fail (converted != NULL); - - to_insert = g_strconcat (converted, - "" - "", - NULL); - - test_utils_insert_content (fixture, to_insert, - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "
On Today, User wrote:
" - "
" - "
normal text
" - "

" - "
" - "
level 1
" - "
level 1
" - "
" - "
level 2
" - "
level 2
" - "

" - "
level 2
" - "
" - "

" - "
level 1
" - "
level 1
" - "

" - "
" - "
" - "
level 3
" - "
level 3
" - "
" - "
" - "

" - "
" - "
level 2
" - "
level 2
" - "
" - "

" - "
level 1
" - "
" - "

" - "
back normal text
" - "
" HTML_SUFFIX, - "On Today, User wrote:\n" - "> normal text\n" - "> \n" - "> > level 1\n" - "> > level 1\n" - "> > > level 2\n" - "> > > level 2\n" - "> > > \n" - "> > > level 2\n" - "> > \n" - "> > level 1\n" - "> > level 1\n" - "> > \n" - "> > > > level 3\n" - "> > > > level 3\n" - "> > \n" - "> > > level 2\n" - "> > > level 2\n" - "> > \n" - "> > level 1\n" - "> \n" - "> back normal text")) - g_test_fail (); - - g_free (to_insert); - g_free (converted); -} - -static void -test_issue_103 (TestFixture *fixture) -{ - #define LONG_URL "https://www.example.com/123456789012345678901234567890123456789012345678901234567890" - #define SHORTER_URL "https://www.example.com/1234567890123456789012345678901234567890" - #define SHORT_URL "https://www.example.com/" - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:before\\n" - LONG_URL "\\n" - "after\\n" - "prefix text " SHORTER_URL " suffix\\n" - "prefix " SHORT_URL " suffix\\n" - "end\n", - HTML_PREFIX "
before
" - "" - "
after
" - "
prefix text " SHORTER_URL " suffix
" - "
prefix " SHORT_URL " suffix
" - "
end
" - HTML_SUFFIX, - "before\n" - LONG_URL "\n" - "after\n" - "prefix text \n" - SHORTER_URL " suffix\n" - "prefix " SHORT_URL " suffix\n" - "end")) { - g_test_fail (); - return; - } - - #undef SHORT_URL - #undef SHORTER_URL - #undef LONG_URL -} - void test_add_html_editor_bug_tests (void) { @@ -1386,6 +1234,4 @@ test_add_html_editor_bug_tests (void) test_utils_add_test ("/bug/780088", test_bug_780088); test_utils_add_test ("/bug/788829", test_bug_788829); test_utils_add_test ("/bug/750636", test_bug_750636); - test_utils_add_test ("/issue/86", test_issue_86); - test_utils_add_test ("/issue/103", test_issue_103); } diff --git a/src/e-util/test-html-editor-units-bugs.c.extra-new-line-before-url b/src/e-util/test-html-editor-units-bugs.c.extra-new-line-before-url deleted file mode 100644 index 071be22..0000000 --- a/src/e-util/test-html-editor-units-bugs.c.extra-new-line-before-url +++ /dev/null @@ -1,1352 +0,0 @@ -/* - * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com) - * - * This library is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This library 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 Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include "evolution-config.h" - -#include - -#include "test-html-editor-units-utils.h" - -#include "test-html-editor-units-bugs.h" - -static void -test_bug_726548 (TestFixture *fixture) -{ - /* This test is known to fail, skip it. */ - printf ("SKIPPED "); -#if 0 - gboolean success; - gchar *text; - const gchar *expected_plain = - "aaa\n" - " 1. a\n" - " 2. b\n" - " 3. c\n"; - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:aaa\\n\n" - "action:style-list-number\n" - "type:a\\nb\\nc\\n\\n\n" - "seq:C\n" - "type:ac\n" - "seq:c\n", - HTML_PREFIX "
aaa
" - "
    " - "
  1. a
  2. b
  3. c
" - "

" HTML_SUFFIX, - expected_plain)) { - g_test_fail (); - return; - } - - text = test_utils_get_clipboard_text (FALSE); - success = test_utils_html_equal (fixture, text, expected_plain); - - if (!success) { - g_warning ("%s: clipboard Plain text \n---%s---\n does not match expected Plain\n---%s---", - G_STRFUNC, text, expected_plain); - g_free (text); - g_test_fail (); - } else { - g_free (text); - } -#endif -} - -static void -test_bug_750657 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:html\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "\n" - "
\n" - "
This is the first paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "

\n" - "
This is the third paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "
\n" - "
This is the first paragraph of a sub-quoted text which has some long text to test. It has the second sentence as well.
\n" - "
\n" - "
\n" - "
This is the fourth paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "
\n" - "

\n" - "", - E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:uuuSuusD\n", - HTML_PREFIX - "
\n" - "
This is the first paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "

\n" - "
This is the third paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "
\n" - "

\n" - "
\n" - "
This is the fourth paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "
\n" - "

" - HTML_SUFFIX, - NULL)) { - g_test_fail (); - return; - } -} - -static void -test_bug_760989 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:html\n" - "type:a\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "\n" - "One line before quotation
\n" - "
\n" - "
Single line quoted.
\n" - "
\n" - "", - E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:ChcD\n", - HTML_PREFIX "
One line before quotation
\n" - "
\n" - "
Single line quoted.
\n" - "
" HTML_SUFFIX, - "One line before quotation\n" - "> Single line quoted.")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:Cecb\n", - HTML_PREFIX "
One line before quotation
\n" - "
\n" - "
Single line quoted
\n" - "
" HTML_SUFFIX, - "One line before quotation\n" - "> Single line quoted")) { - g_test_fail (); - return; - } -} - -static void -test_bug_767903 (TestFixture *fixture) -{ - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:This is the first line:\\n\n" - "action:style-list-bullet\n" - "type:First item\\n\n" - "type:Second item\n", - HTML_PREFIX "
This is the first line:
" - "
    " - "
  • First item
  • Second item
" HTML_SUFFIX, - "This is the first line:\n" - " * First item\n" - " * Second item")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:uhb\n" - "undo:undo\n", - HTML_PREFIX "
This is the first line:
" - "
    " - "
  • First item
  • Second item
" HTML_SUFFIX, - "This is the first line:\n" - " * First item\n" - " * Second item")) { - g_test_fail (); - return; - } -} - -static void -test_bug_769708 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "" - "" - "" - "
aaa
" - "
-- 
" - "
user <user@no.where>
" - "
", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "
aaa
-- 
" - "
user <user@no.where>
" - "
" HTML_SUFFIX, - "aaa\n" - "-- \n" - "user ")) - g_test_fail (); -} - -static void -test_bug_769913 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:html\n")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "type:ab\n" - "seq:ltlD\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:ttllDD\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:ttlDlD\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:tttlllDDD\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:tttlDlDlD\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:tb\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:ttbb\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:ttlbrb\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:tttbbb\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:tttllbrbrb\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } -} - -static void -test_bug_769955 (TestFixture *fixture) -{ - test_utils_set_clipboard_text ("http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines", FALSE); - - /* Use paste action, pretty the same as Ctrl+V */ - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "action:paste\n" - "seq:ll\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		""
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" - HTML_SUFFIX, - "http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[1] \n" - "action:paste\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[1] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[1] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[2] \n" - "action:paste\n" - "seq:h\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[2] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[2] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[3] \n" - "action:paste\n" - "seq:Chc\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[3] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[3] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[4] \n" - "action:paste\n" - "seq:l\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[4] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[4] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - /* Use Shift+Insert instead of paste action */ - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "seq:Sis\n" - "seq:ll\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		""
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" - HTML_SUFFIX, - "http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[5] \n" - "seq:Sis\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[5] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[5] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[6] \n" - "seq:Sis\n" - "seq:h\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[6] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[6] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[7] \n" - "seq:Sis\n" - "seq:Chc\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[7] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[7] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[8] \n" - "seq:Sis\n" - "seq:l\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[8] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[8] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } -} - -static void -test_bug_770073 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "" - "
the 1st line text
" - "
" - "
the 3rd line text
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:Chcddbb\n", - HTML_PREFIX "
On Today, User wrote:
" - "
" - "
> the 1st line text
" - "
> the 3rd line text
" - "
" HTML_SUFFIX, - "On Today, User wrote:\n" - "> the 1st line text\n" - "> the 3rd line text")) { - g_test_fail (); - return; - } - - if (!test_utils_process_commands (fixture, - "mode:html\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "" - "
the first line text
" - "
" - "
the third line text
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:Chcddbb\n", - HTML_PREFIX "
On Today, User wrote:
" - "
" - "
the first line text
" - "
the third line text
" - "
" HTML_SUFFIX, - "On Today, User wrote:\n" - "> the first line text\n" - "> the third line text")) - g_test_fail (); - -} - -static void -test_bug_770074 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "" - "
the 1st line text
" - "
" - "
the 3rd line text
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:Chcddbb\n" - "seq:n\n" - "undo:undo\n", - HTML_PREFIX "
On Today, User wrote:
" - "
" - "
> the 1st line text
" - "
> the 3rd line text
" - "
" HTML_SUFFIX, - "On Today, User wrote:\n" - "> the 1st line text\n" - "> the 3rd line text")) - g_test_fail (); -} - -static void -test_bug_771044 (TestFixture *fixture) -{ - if (!test_utils_run_simple_test (fixture, - "type:123 456\\n789 abc\\n\n" - "seq:uuhSdsD\n", - HTML_PREFIX - "
789 abc
" - "

" - HTML_SUFFIX, - "789 abc\n")) - g_test_fail (); -} - -static void -test_bug_771131 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
On <date1>, <name1> wrote:\n"
-		"
\n" - "Hello\n" - "\n" - "Goodbye
" - "
the 3rd line text
" - "
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "
On Sat, 2016-09-10 at 20:00 +0000, example@example.com wrote:
" - "
" - "
> On <date1>, <name1> wrote:
" - "
" - "
> > Hello
" - "
> >
" - "
> > Goodbye
" - "
" - "
>
" - "
> the 3rd line text
" - "
" - HTML_SUFFIX, - "On Sat, 2016-09-10 at 20:00 +0000, example@example.com wrote:\n" - "> On , wrote:\n" - "> > Hello\n" - "> > \n" - "> > Goodbye\n" - "> \n" - "> the 3rd line text")) - g_test_fail (); -} - -static void -test_bug_771493 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "

" - "----- Original Message -----\n" - "
\n" - "This week summary:" - "
" - "
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "
On Thu, 2016-09-15 at 08:08 -0400, user wrote:
" - "
" - "
>
" - "
> ----- Original Message -----
" - "
" - "
> > This week summary:
" - "
" - "
" - HTML_SUFFIX, - "On Thu, 2016-09-15 at 08:08 -0400, user wrote:\n" - "> \n" - "> ----- Original Message -----\n" - "> > This week summary:")) - g_test_fail (); -} - -static void -test_bug_772171 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
a\n"
-		"b\n"
-		"
" - "" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:ddeb", - HTML_PREFIX "
On Thu, 2016-09-15 at 08:08 -0400, user wrote:
" - "
" - "
>
" - "
> b
" - "
" - HTML_SUFFIX, - "On Thu, 2016-09-15 at 08:08 -0400, user wrote:\n" - "> \n" - "> b")) - g_test_fail (); -} - -static void -test_bug_772513 (TestFixture *fixture) -{ - EContentEditor *cnt_editor; - gboolean set_signature_from_message, check_if_signature_is_changed, ignore_next_signature_change; - - test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail", "composer-reply-start-bottom", TRUE); - - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - cnt_editor = test_utils_get_content_editor (fixture); - - e_content_editor_insert_signature ( - cnt_editor, - "", - FALSE, - "none", - &set_signature_from_message, - &check_if_signature_is_changed, - &ignore_next_signature_change); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "

" HTML_SUFFIX, - "\n")) - g_test_fail (); -} - -static void -test_bug_772918 (TestFixture *fixture) -{ - if (!test_utils_run_simple_test (fixture, - "mode:html\n" - "type:a b c d\n" - "seq:lll\n" - "type:1 2 3 \n" - "undo:undo:6\n" - "undo:redo:6\n", - HTML_PREFIX "
a b 1 2 3 c d
" HTML_SUFFIX, - "a b 1 2 3 c d")) - g_test_fail (); -} - -static void -test_bug_773164 (TestFixture *fixture) -{ - test_utils_set_clipboard_text ("This is paragraph 1\n\nThis is paragraph 2\n\nThis is a longer paragraph 3", FALSE); - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "undo:save\n" - "action:paste\n" - "undo:undo\n" - "undo:test\n" - "undo:redo\n" - "seq:huuuue\n" /* Go to the end of the first line */ - "seq:Sdds\n" - "action:cut\n" - "seq:dde\n" /* Go to the end of the last line */ - "action:paste\n" - "undo:undo:5\n" - "undo:test\n" - "undo:redo:5\n", - HTML_PREFIX "
This is paragraph 1
" - "

" - "
This is a longer paragraph 3
" - "

" - "
This is paragraph 2
" - HTML_SUFFIX, - "This is paragraph 1\n" - "\n" - "This is a longer paragraph 3\n" - "\n" - "This is paragraph 2")) - g_test_fail (); -} - -static void -test_bug_775042 (TestFixture *fixture) -{ - test_utils_insert_content (fixture, - "
a\n"
-		"b\n"
-		"c"
-		""
-		"",
-		E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
-
-	if (!test_utils_run_simple_test (fixture,
-		"seq:rl\n"
-		"mode:plain\n",
-		HTML_PREFIX "
On Fri, 2016-11-25 at 08:18 +0000, user wrote:
" - "
" - "
> a
" - "> b
" - "> c
" - "
" - HTML_SUFFIX, - "On Fri, 2016-11-25 at 08:18 +0000, user wrote:\n" - "> a\n" - "> b\n" - "> c")) - g_test_fail (); -} - -static void -test_bug_775691 (TestFixture *fixture) -{ - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:abc def ghi\\n\n" - "seq:urrrrSrrrs\n" - "action:copy\n" - "seq:d\n" - "action:paste\n", - HTML_PREFIX "
abc def ghi
" - "
def
" - HTML_SUFFIX, - "abc def ghi\n" - "def")) - g_test_fail (); -} - -static void -test_bug_779707 (TestFixture *fixture) -{ - test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail", "composer-reply-start-bottom", TRUE); - test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail", "composer-wrap-quoted-text-in-replies", FALSE); - - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
line 1\n"
-		"line 2\n"
-		"line 3\n"
-		"
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:uuuSesDbnnu\n" - "type:a very long text, which splits into multiple lines when this paragraph is not marked as preformatted, but as normal, as it should be\n" - "", - HTML_PREFIX "
Credits:
" - "
" - "
> line 1
" - "
" - "

" - "
a very long text, which splits into multiple lines when this paragraph is not marked as preformatted, but as normal, as it should be
" - "

" - "
" - "
> line 3
" - "
" - "

" - HTML_SUFFIX, - "Credits:\n" - "> line 1\n" - "\n" - "a very long text, which splits into multiple lines when this paragraph\n" - "is not marked as preformatted, but as normal, as it should be\n" - "\n" - "> line 3\n")) - g_test_fail (); -} - -static void -test_bug_780275_html (TestFixture *fixture) -{ - test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE); - - if (!test_utils_run_simple_test (fixture, - "mode:html\n" - "type:line 0\n" - "seq:nn\n" - "action:paste-quote\n" - "undo:save\n" /* 1 */ - "seq:huuuD\n" - "undo:undo\n" - "undo:test:1\n" - "undo:redo\n" - "type:X\n" - "seq:ddenn\n" - "type:line 4\n" - "undo:drop\n" - "undo:save\n" /* 1 */ - "seq:hSuusD\n" - "undo:undo\n" - "undo:test:1\n" - "undo:redo\n" - "", - HTML_PREFIX "
line 0
" - "
" - "
Xline 1
" - "
line 2
" - "
" - "
line 4
" - HTML_SUFFIX, - "line 0\n" - "> Xline 1\n" - "> line 2\n" - "line 4")) - g_test_fail (); -} - -static void -test_bug_780275_plain (TestFixture *fixture) -{ - test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE); - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:line 0\n" - "seq:nn\n" - "action:paste-quote\n" - "undo:save\n" /* 1 */ - "seq:huuuD\n" - "undo:undo\n" - "undo:test:1\n" - "undo:redo\n" - "type:X\n" - "seq:ddenn\n" - "type:line 4\n" - "undo:drop\n" - "undo:save\n" /* 1 */ - "seq:hSuusD\n" - "undo:undo\n" - "undo:test:1\n" - "undo:redo\n", - HTML_PREFIX "
line 0
" - "
" - "
> Xline 1
" - "
> line 2
" - "
" - "
line 4
" - HTML_SUFFIX, - "line 0\n" - "> Xline 1\n" - "> line 2\n" - "line 4")) - g_test_fail (); -} - -static void -test_bug_781722 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
Signed-off-by: User <user@no.where>\n"
-		"
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:dd\n" - "action:style-preformat\n", - HTML_PREFIX "
Credits:
" - "
" - "
> Signed-off-by: User <user@no.where>
" - "
" - HTML_SUFFIX, - "Credits:\n" - "> Signed-off-by: User ")) - g_test_fail (); -} - -static void -test_bug_781116 (TestFixture *fixture) -{ - test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail", "composer-wrap-quoted-text-in-replies", FALSE); - - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
a very long text, which splits into multiple lines when this paragraph is not marked as preformatted, but as normal, as it should be
\n" - "
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:dd\n" - "action:wrap-lines\n", - HTML_PREFIX "
Credits:
" - "
" - "
> a very long text, which splits into multiple lines when this
" - "> paragraph is not marked as preformatted, but as normal, as it should
" - "> be
" - "
" - HTML_SUFFIX, - "Credits:\n" - "> a very long text, which splits into multiple lines when this\n" - "> paragraph is not marked as preformatted, but as normal, as it should\n" - "> be")) - g_test_fail (); -} - -static void -test_bug_780088 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_set_clipboard_text ("Seeing @blah instead of @foo XX'ed on" UNICODE_NBSP "https://example.sub" UNICODE_NBSP "domain.org/page I'd recommend to XX YY , click fjwvne on the left, click skjd sjewncj on the right, and set wqje wjfdn Xs to something like wqjfnm www.example.com/~user wjfdncj or such.", FALSE); - - if (!test_utils_run_simple_test (fixture, - "action:paste\n" - "seq:n", - HTML_PREFIX "
" - "Seeing @blah instead of @foo XX'ed on https://example.sub" - " domain.org/page I'd recommend to XX YY " - "<https://example.subdomain.org/p/user/> , " - "click fjwvne on the left, click skjd sjewncj on the right, and set wqje wjfdn Xs to something like " - "wqjfnm www.example.com/~user wjfdncj or such.
" - "

" - HTML_SUFFIX, - "Seeing @blah instead of @foo XX'ed on" UNICODE_NBSP "https://example.sub" UNICODE_NBSP "domain.org/pa\n" - "ge I'd recommend to XX YY ,\n" - "click fjwvne on the left, click skjd sjewncj on the right, and set wqje\n" - "wjfdn Xs to something like wqjfnm www.example.com/~user wjfdncj or\n" - "such.\n")) - g_test_fail (); -} - -static void -test_bug_788829 (TestFixture *fixture) -{ - test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail", "composer-wrap-quoted-text-in-replies", TRUE); - test_utils_fixture_change_setting_int32 (fixture, "org.gnome.evolution.mail", "composer-word-wrap-length", 71); - - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
Xxxxx xx xxxxxxxxx xx xxxxxxx xx xxxxx xxxx xxxx xx xxx xxx xxxx xxx xxxçx xôxé " - "\"xxxxx xxxx xxxxxxx xxx\" xx xxxx xxxxé xxx xxx xxxéx xxx x'x xéxxxxé x'xxxxxxxxx xx " - "xxx \"Xxxx XXX Xxxxxx Xxx\". Xx xxxx xxxxxxxx xxx xxxxxxxxxxxxxxxx.xx (xxxxxxx xxxxxxxxxx xx .xxx). Xxxx " - "êxxx xxx xxxxxxxxxxx xxxéxxxxxxxx, xxxx xxxxx xx XXX xx xéxxx à xx xxx \"xxx xxxxxx xxxx " - "xx xxxxxxx\" xx xxxx xx xxxxx xxxxxxxx xxxxxxxx xx $ xx xxxx x'xxxxxx.

" - "
Xxxx xx xéxxxxxxx, xxxxxxxx xxxxxxx (!), xxxxxxx à xxx, xxxx ooo$ XXX xxxxé: " - "https://xxxxxxxxxxxxxxxx.xx/xxxxxxx/xxxxx-xxxx-xxxxxxxx-x" - "xxxx-xxxx-xxx-xxxxxxxx-xxx/ xx xx xxxx xéxéxxxxxxx x'xxxxxx xxxx xx xxxxxx xx xxxxxx" - "xxxxxx xx xxx (xxxxx Xxxxxx) xxxx xxxx x'xxxxxxx xx xxxxxx: " - "https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxxxxxxxxx-Xxxxx-Xxxx-XXX-Xxxxxx-Xxx.xxx" - "

Xxxx xxx xxx xxxxxxx xxxxxxxéxx x'xxxêxxxx à xxxxx, xxx xx x" - "xxxé xx oooxooo xxxxx xxxxx xxxx... xxxx x'xxx xxxxxxxxxxxx xxxxx xxx xxxxxxxx xx \"xx xxx" - "xx xxx xxx xxxxxxx xxxxxxx xxxxxxxxxxxxxx xxxx xxxxx xxxxxx xx xx xxxx xx x'xxxxxx\". Xx " - "xxxx-êxxx xxx xx xxxxxxxx xx xxxx \"x'xxxêxx à xxxxx xx oooxooo xxxx xxx xéxxxxxxxx, xxxx" - "\"...

Xxxxx xxxxxx'xx xxx x xxxx xxxxxxx xxxxx xx xxèx xxxxxxxxx " - "xxxxxxxxxxxxxxxx à xx xxx x'xx xx xêxx (éxxxxxxxxx xxxx-xx-xxxxxxxx): https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxx-xxxx-xxx-xxxxxxxxxx-xx" - "xxx.xxx

...x'x xxxxx xx xxxxxx x'xxxxxx xéxxxxxxx, " - "xx xxx xxxx xxxxxx x'xxxxxxxxxxx xxxxxx, xxxx https://xxxx" - "xxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/ xxxxx xxx https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/ ...
" - "" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "
On Today, User wrote:
" - "
> Xxxxx xx xxxxxxxxx xx xxxxxxx xx xxxxx xxxx " - "xxxx xx xxx xxx xxxx xxx
> xxxçx xôxé \"xxxxx xxxx xxxxxxx xxx\" xx xxxx " - "xxxxé xxx xxx xxxéx xxx
> x'x xéxxxxé x'xxxxxxxxx xx xxx \"Xxxx XXX Xxxxxx " - "Xxx\". Xx xxxx
> xxxxxxxx xxx xxxxxxxxxxxxxxxx.xx (xxxxxxx xxxxxxxxxx xx .xx" - "x). Xxxx
> êxxx xxx xxxxxxxxxxx xxxéxxxxxxxx, xxxx xxxxx xx XXX xx xéxxx à " - "xx
> xxx \"xxx xxxxxx xxxx xx xxxxxxx\" xx xxxx xx xxxxx xxxxxxxx xxxxxxxx" - "
> xx $ xx xxxx x'xxxxxx.
>
" - "
> Xxxx xx xéxxxxxxx, xxxxxxxx xxxxxxx (!), " - "xxxxxxx à xxx, xxxx ooo$ XXX
> xxxxé: https://xxxxxxxxxxxxxxxx.xx/xxx" - "xxxx/xxxxx-xxxx-xxxxxxxx-xxxxx-
> xxxx-xxx-xxxxxxxx-xxx/ xx xx xxxx " - "xéxéxxxxxxx x'xxxxxx xxxx xx xxxxxx
> xx xxxxxxxxxxxx xx xxx (xxxxx " - "Xxxxxx) xxxx xxxx x'xxxxxxx xx xxxxxx:
> https://xxxxxxxxxxxxxxxx.xx" - "x/xx-xxxxxxx/xxxxxxx/Xxxxxxxxxxxx-Xxxxx-Xx
> xx-XXX-Xxxxxx-Xxx.xxx
" - "
>
> Xx" - "xx xxx xxx xxxxxxx xxxxxxxéxx x'xxxêxxxx à xxxxx, xxx xx xxxxé xx
> oooxo" - "oo xxxxx xxxxx xxxx... xxxx x'xxx xxxxxxxxxxxx xxxxx xxx
> xxxxxxxx xx \"" - "xx xxxxx xxx xxx xxxxxxx xxxxxxx xxxxxxxxxxxxxx xxxx
> xxxxx xxxxxx xx xx " - "xxxx xx x'xxxxxx\". Xx xxxx-êxxx xxx xx xxxxxxxx xx
> xxxx \"x'xxxêxx à " - "xxxxx xx oooxooo xxxx xxx xéxxxxxxxx, xxxx\"...
" - ">
> Xxxxx xxxxxx'xx xxx x xxxx xxxxxxx " - "xxxxx xx xxèx xxxxxxxxx
>
> xxxxxxxxxxxxxxxx à xx xxx x'xx xx xêxx " - "(éxxxxxxxxx xxxx-xx-xxxxxxxx): https://xxxxxxxxxxxxxxxx.xxx/xx-xxx" - "xxxx/xxxxxxx/Xxxxx-xxxx-xxx-
> xxxxxxxxxx-xxxxx.xxx
>
> ...x'x " - "xxxxx xx xxxxxx x'xxxxxx xéxxxxxxx, xx xxx xxxx xxxxxx
> x'xxxxxxxxxxx " - "xxxxxx, xxxx https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxx
> xxx-xxxx-xxx-o/ " - "xxxxx xxx https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxx
> xx-xxxx-xxx-o/ ...
" HTML_SUFFIX, - "On Today, User wrote:\n" - "> Xxxxx xx xxxxxxxxx xx xxxxxxx xx xxxxx xxxx xxxx xx xxx xxx xxxx xxx\n" - "> xxxçx xôxé \"xxxxx xxxx xxxxxxx xxx\" xx xxxx xxxxé xxx xxx xxxéx xxx\n" - "> x'x xéxxxxé x'xxxxxxxxx xx xxx \"Xxxx XXX Xxxxxx Xxx\". Xx xxxx\n" - "> xxxxxxxx xxx xxxxxxxxxxxxxxxx.xx (xxxxxxx xxxxxxxxxx xx .xxx). Xxxx\n" - "> êxxx xxx xxxxxxxxxxx xxxéxxxxxxxx, xxxx xxxxx xx XXX xx xéxxx à xx\n" - "> xxx \"xxx xxxxxx xxxx xx xxxxxxx\" xx xxxx xx xxxxx xxxxxxxx xxxxxxxx\n" - "> xx $ xx xxxx x'xxxxxx.\n" - "> \n" - "> Xxxx xx xéxxxxxxx, xxxxxxxx xxxxxxx (!), xxxxxxx à xxx, xxxx ooo$ XXX\n" - "> xxxxé: https://xxxxxxxxxxxxxxxx.xx/xxxxxxx/xxxxx-xxxx-xxxxxxxx-xxxxx-\n" - "> xxxx-xxx-xxxxxxxx-xxx/ xx xx xxxx xéxéxxxxxxx x'xxxxxx xxxx xx xxxxxx\n" - "> xx xxxxxxxxxxxx xx xxx (xxxxx Xxxxxx) xxxx xxxx x'xxxxxxx xx xxxxxx: \n" - "> https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxxxxxxxxx-Xxxxx-Xx\n" - "> xx-XXX-Xxxxxx-Xxx.xxx\n" - "> \n" - "> Xxxx xxx xxx xxxxxxx xxxxxxxéxx x'xxxêxxxx à xxxxx, xxx xx xxxxé xx\n" - "> oooxooo xxxxx xxxxx xxxx... xxxx x'xxx xxxxxxxxxxxx xxxxx xxx\n" - "> xxxxxxxx xx \"xx xxxxx xxx xxx xxxxxxx xxxxxxx xxxxxxxxxxxxxx xxxx\n" - "> xxxxx xxxxxx xx xx xxxx xx x'xxxxxx\". Xx xxxx-êxxx xxx xx xxxxxxxx xx\n" - "> xxxx \"x'xxxêxx à xxxxx xx oooxooo xxxx xxx xéxxxxxxxx, xxxx\"...\n" - "> \n" - "> Xxxxx xxxxxx'xx xxx x xxxx xxxxxxx xxxxx xx xxèx xxxxxxxxx\n" - "> \n" - "> xxxxxxxxxxxxxxxx à xx xxx x'xx xx xêxx (éxxxxxxxxx xxxx-xx-xxxxxxxx): https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxx-xxxx-xxx-\n" - "> xxxxxxxxxx-xxxxx.xxx ; \n" - "> \n" - "> ...x'x xxxxx xx xxxxxx x'xxxxxx xéxxxxxxx, xx xxx xxxx xxxxxx\n" - "> x'xxxxxxxxxxx xxxxxx, xxxx https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxx\n" - "> xxx-xxxx-xxx-o/ xxxxx xxx https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxx\n" - "> xx-xxxx-xxx-o/ ...")) - g_test_fail (); -} - -static void -test_bug_750636 (TestFixture *fixture) -{ - test_utils_fixture_change_setting_int32 (fixture, "org.gnome.evolution.mail", "composer-word-wrap-length", 71); - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:" - "12345678901234567890123456789012345678901234567890123456789012345678901" - "12345678901234567890123456789012345678901234567890123456789012345678901A\\n\\n" - "1234567890123456789012345678901234567890123456789012345678901234567890 B\\n\\n" - "12345678901234567890123456789012345678901234567890123456789012345678901 C\\n\\n" - "1234567890123456789012345678901234567890123456789012345678901234567890 D\\n\\n" - "12345678901234567890123456789012345678901234567890123456789012345678901" UNICODE_NBSP UNICODE_NBSP UNICODE_NBSP "E\\n\\n" - "1234567890123456789012345678901234567890123456789012345678901234567890" UNICODE_NBSP UNICODE_NBSP UNICODE_NBSP "F\\n\\n" - " 1\\n" - " 2\\n" - " 3\\n" - "\n", - HTML_PREFIX "
" - "12345678901234567890123456789012345678901234567890123456789012345678901" - "12345678901234567890123456789012345678901234567890123456789012345678901A
" - "

" - "1234567890123456789012345678901234567890123456789012345678901234567890 B
" - "

" - "12345678901234567890123456789012345678901234567890123456789012345678901 C
" - "

" - "1234567890123456789012345678901234567890123456789012345678901234567890 D
" - "

" - "12345678901234567890123456789012345678901234567890123456789012345678901   E
" - "

" - "1234567890123456789012345678901234567890123456789012345678901234567890   F
" - "

" - "
1
" - "
2
" - "
3
" - "

" - HTML_SUFFIX, - "12345678901234567890123456789012345678901234567890123456789012345678901\n" - "12345678901234567890123456789012345678901234567890123456789012345678901\n" - "A\n\n" - "1234567890123456789012345678901234567890123456789012345678901234567890\n" - "B\n\n" - "12345678901234567890123456789012345678901234567890123456789012345678901\n" - "C\n\n" - "1234567890123456789012345678901234567890123456789012345678901234567890 \n" - "D\n\n" - "12345678901234567890123456789012345678901234567890123456789012345678901\n" - " E\n\n" - "1234567890123456789012345678901234567890123456789012345678901234567890 \n" - " F\n\n" - " 1\n" - " 2\n" - " 3\n")) - g_test_fail (); -} - -static void -test_issue_86 (TestFixture *fixture) -{ - const gchar *source_text = - "normal text\n" - "\n" - "> level 1\n" - "> level 1\n" - "> > level 2\n" - "> > level 2\n" - "> >\n" - "> > level 2\n" - ">\n" - "> level 1\n" - "> level 1\n" - ">\n" - "> > > level 3\n" - "> > > level 3\n" - ">\n" - "> > level 2\n" - "> > level 2\n" - ">\n" - "> level 1\n" - "\n" - "back normal text\n"; - gchar *converted, *to_insert; - - if (!test_utils_process_commands (fixture, - "mode:html\n")) { - g_test_fail (); - return; - } - - converted = camel_text_to_html (source_text, - CAMEL_MIME_FILTER_TOHTML_PRE | - CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | - CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES | - CAMEL_MIME_FILTER_TOHTML_QUOTE_CITATION, - 0xDDDDDD); - - g_return_if_fail (converted != NULL); - - to_insert = g_strconcat (converted, - "" - "", - NULL); - - test_utils_insert_content (fixture, to_insert, - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "
On Today, User wrote:
" - "
" - "
normal text
" - "

" - "
" - "
level 1
" - "
level 1
" - "
" - "
level 2
" - "
level 2
" - "

" - "
level 2
" - "
" - "

" - "
level 1
" - "
level 1
" - "

" - "
" - "
" - "
level 3
" - "
level 3
" - "
" - "
" - "

" - "
" - "
level 2
" - "
level 2
" - "
" - "

" - "
level 1
" - "
" - "

" - "
back normal text
" - "
" HTML_SUFFIX, - "On Today, User wrote:\n" - "> normal text\n" - "> \n" - "> > level 1\n" - "> > level 1\n" - "> > > level 2\n" - "> > > level 2\n" - "> > > \n" - "> > > level 2\n" - "> > \n" - "> > level 1\n" - "> > level 1\n" - "> > \n" - "> > > > level 3\n" - "> > > > level 3\n" - "> > \n" - "> > > level 2\n" - "> > > level 2\n" - "> > \n" - "> > level 1\n" - "> \n" - "> back normal text")) - g_test_fail (); - - g_free (to_insert); - g_free (converted); -} - -void -test_add_html_editor_bug_tests (void) -{ - test_utils_add_test ("/bug/726548", test_bug_726548); - test_utils_add_test ("/bug/750657", test_bug_750657); - test_utils_add_test ("/bug/760989", test_bug_760989); - test_utils_add_test ("/bug/767903", test_bug_767903); - test_utils_add_test ("/bug/769708", test_bug_769708); - test_utils_add_test ("/bug/769913", test_bug_769913); - test_utils_add_test ("/bug/769955", test_bug_769955); - test_utils_add_test ("/bug/770073", test_bug_770073); - test_utils_add_test ("/bug/770074", test_bug_770074); - test_utils_add_test ("/bug/771044", test_bug_771044); - test_utils_add_test ("/bug/771131", test_bug_771131); - test_utils_add_test ("/bug/771493", test_bug_771493); - test_utils_add_test ("/bug/772171", test_bug_772171); - test_utils_add_test ("/bug/772513", test_bug_772513); - test_utils_add_test ("/bug/772918", test_bug_772918); - test_utils_add_test ("/bug/773164", test_bug_773164); - test_utils_add_test ("/bug/775042", test_bug_775042); - test_utils_add_test ("/bug/775691", test_bug_775691); - test_utils_add_test ("/bug/779707", test_bug_779707); - test_utils_add_test ("/bug/780275/html", test_bug_780275_html); - test_utils_add_test ("/bug/780275/plain", test_bug_780275_plain); - test_utils_add_test ("/bug/781722", test_bug_781722); - test_utils_add_test ("/bug/781116", test_bug_781116); - test_utils_add_test ("/bug/780088", test_bug_780088); - test_utils_add_test ("/bug/788829", test_bug_788829); - test_utils_add_test ("/bug/750636", test_bug_750636); - test_utils_add_test ("/issue/86", test_issue_86); -} diff --git a/src/e-util/test-html-editor-units-bugs.c.mangled-deeper-html-quotes b/src/e-util/test-html-editor-units-bugs.c.mangled-deeper-html-quotes deleted file mode 100644 index e5f16be..0000000 --- a/src/e-util/test-html-editor-units-bugs.c.mangled-deeper-html-quotes +++ /dev/null @@ -1,1237 +0,0 @@ -/* - * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com) - * - * This library is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This library 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 Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include "evolution-config.h" - -#include - -#include "test-html-editor-units-utils.h" - -#include "test-html-editor-units-bugs.h" - -static void -test_bug_726548 (TestFixture *fixture) -{ - /* This test is known to fail, skip it. */ - printf ("SKIPPED "); -#if 0 - gboolean success; - gchar *text; - const gchar *expected_plain = - "aaa\n" - " 1. a\n" - " 2. b\n" - " 3. c\n"; - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:aaa\\n\n" - "action:style-list-number\n" - "type:a\\nb\\nc\\n\\n\n" - "seq:C\n" - "type:ac\n" - "seq:c\n", - HTML_PREFIX "
aaa
" - "
    " - "
  1. a
  2. b
  3. c
" - "

" HTML_SUFFIX, - expected_plain)) { - g_test_fail (); - return; - } - - text = test_utils_get_clipboard_text (FALSE); - success = test_utils_html_equal (fixture, text, expected_plain); - - if (!success) { - g_warning ("%s: clipboard Plain text \n---%s---\n does not match expected Plain\n---%s---", - G_STRFUNC, text, expected_plain); - g_free (text); - g_test_fail (); - } else { - g_free (text); - } -#endif -} - -static void -test_bug_750657 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:html\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "\n" - "
\n" - "
This is the first paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "

\n" - "
This is the third paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "
\n" - "
This is the first paragraph of a sub-quoted text which has some long text to test. It has the second sentence as well.
\n" - "
\n" - "
\n" - "
This is the fourth paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "
\n" - "

\n" - "", - E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:uuuSuusD\n", - HTML_PREFIX - "
\n" - "
This is the first paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "

\n" - "
This is the third paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "
\n" - "

\n" - "
\n" - "
This is the fourth paragraph of a quoted text which has some long text to test. It has the second sentence as well.
\n" - "
\n" - "

" - HTML_SUFFIX, - NULL)) { - g_test_fail (); - return; - } -} - -static void -test_bug_760989 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:html\n" - "type:a\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "\n" - "One line before quotation
\n" - "
\n" - "
Single line quoted.
\n" - "
\n" - "", - E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:ChcD\n", - HTML_PREFIX "
One line before quotation
\n" - "
\n" - "
Single line quoted.
\n" - "
" HTML_SUFFIX, - "One line before quotation\n" - "> Single line quoted.")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:Cecb\n", - HTML_PREFIX "
One line before quotation
\n" - "
\n" - "
Single line quoted
\n" - "
" HTML_SUFFIX, - "One line before quotation\n" - "> Single line quoted")) { - g_test_fail (); - return; - } -} - -static void -test_bug_767903 (TestFixture *fixture) -{ - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:This is the first line:\\n\n" - "action:style-list-bullet\n" - "type:First item\\n\n" - "type:Second item\n", - HTML_PREFIX "
This is the first line:
" - "
    " - "
  • First item
  • Second item
" HTML_SUFFIX, - "This is the first line:\n" - " * First item\n" - " * Second item")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:uhb\n" - "undo:undo\n", - HTML_PREFIX "
This is the first line:
" - "
    " - "
  • First item
  • Second item
" HTML_SUFFIX, - "This is the first line:\n" - " * First item\n" - " * Second item")) { - g_test_fail (); - return; - } -} - -static void -test_bug_769708 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "" - "" - "" - "
aaa
" - "
-- 
" - "
user <user@no.where>
" - "
", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "
aaa
-- 
" - "
user <user@no.where>
" - "
" HTML_SUFFIX, - "aaa\n" - "-- \n" - "user ")) - g_test_fail (); -} - -static void -test_bug_769913 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:html\n")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "type:ab\n" - "seq:ltlD\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:ttllDD\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:ttlDlD\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:tttlllDDD\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:tttlDlDlD\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:tb\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:ttbb\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:ttlbrb\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:tttbbb\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:tttllbrbrb\n", - HTML_PREFIX "
ab
" HTML_SUFFIX, - "ab")) { - g_test_fail (); - return; - } -} - -static void -test_bug_769955 (TestFixture *fixture) -{ - test_utils_set_clipboard_text ("http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines", FALSE); - - /* Use paste action, pretty the same as Ctrl+V */ - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "action:paste\n" - "seq:ll\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		""
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" - HTML_SUFFIX, - "http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[1] \n" - "action:paste\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[1] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[1] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[2] \n" - "action:paste\n" - "seq:h\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[2] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[2] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[3] \n" - "action:paste\n" - "seq:Chc\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[3] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[3] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[4] \n" - "action:paste\n" - "seq:l\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[4] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[4] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - /* Use Shift+Insert instead of paste action */ - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "seq:Sis\n" - "seq:ll\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		""
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" - HTML_SUFFIX, - "http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[5] \n" - "seq:Sis\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[5] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[5] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[6] \n" - "seq:Sis\n" - "seq:h\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[6] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[6] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[7] \n" - "seq:Sis\n" - "seq:Chc\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[7] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[7] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } - - if (!test_utils_run_simple_test (fixture, - "seq:C\n" - "type:a\n" - "action:style-normal\n" - "seq:Dc\n" - "type:[8] \n" - "seq:Sis\n" - "seq:l\n" - "action:style-preformat\n", - HTML_PREFIX "
"
-		"[8] "
-		"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines
" HTML_SUFFIX, - "[8] http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) { - g_test_fail (); - return; - } -} - -static void -test_bug_770073 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "" - "
the 1st line text
" - "
" - "
the 3rd line text
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:Chcddbb\n", - HTML_PREFIX "
On Today, User wrote:
" - "
" - "
> the 1st line text
" - "
> the 3rd line text
" - "
" HTML_SUFFIX, - "On Today, User wrote:\n" - "> the 1st line text\n" - "> the 3rd line text")) { - g_test_fail (); - return; - } - - if (!test_utils_process_commands (fixture, - "mode:html\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "" - "
the first line text
" - "
" - "
the third line text
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:Chcddbb\n", - HTML_PREFIX "
On Today, User wrote:
" - "
" - "
the first line text
" - "
the third line text
" - "
" HTML_SUFFIX, - "On Today, User wrote:\n" - "> the first line text\n" - "> the third line text")) - g_test_fail (); - -} - -static void -test_bug_770074 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "" - "
the 1st line text
" - "
" - "
the 3rd line text
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:Chcddbb\n" - "seq:n\n" - "undo:undo\n", - HTML_PREFIX "
On Today, User wrote:
" - "
" - "
> the 1st line text
" - "
> the 3rd line text
" - "
" HTML_SUFFIX, - "On Today, User wrote:\n" - "> the 1st line text\n" - "> the 3rd line text")) - g_test_fail (); -} - -static void -test_bug_771044 (TestFixture *fixture) -{ - if (!test_utils_run_simple_test (fixture, - "type:123 456\\n789 abc\\n\n" - "seq:uuhSdsD\n", - HTML_PREFIX - "
789 abc
" - "

" - HTML_SUFFIX, - "789 abc\n")) - g_test_fail (); -} - -static void -test_bug_771131 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
On <date1>, <name1> wrote:\n"
-		"
\n" - "Hello\n" - "\n" - "Goodbye
" - "
the 3rd line text
" - "
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "
On Sat, 2016-09-10 at 20:00 +0000, example@example.com wrote:
" - "
" - "
> On <date1>, <name1> wrote:
" - "
" - "
> > Hello
" - "
> >
" - "
> > Goodbye
" - "
" - "
>
" - "
> the 3rd line text
" - "
" - HTML_SUFFIX, - "On Sat, 2016-09-10 at 20:00 +0000, example@example.com wrote:\n" - "> On , wrote:\n" - "> > Hello\n" - "> > \n" - "> > Goodbye\n" - "> \n" - "> the 3rd line text")) - g_test_fail (); -} - -static void -test_bug_771493 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "

" - "----- Original Message -----\n" - "
\n" - "This week summary:" - "
" - "
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "
On Thu, 2016-09-15 at 08:08 -0400, user wrote:
" - "
" - "
>
" - "
> ----- Original Message -----
" - "
" - "
> > This week summary:
" - "
" - "
" - HTML_SUFFIX, - "On Thu, 2016-09-15 at 08:08 -0400, user wrote:\n" - "> \n" - "> ----- Original Message -----\n" - "> > This week summary:")) - g_test_fail (); -} - -static void -test_bug_772171 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
a\n"
-		"b\n"
-		"
" - "" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:ddeb", - HTML_PREFIX "
On Thu, 2016-09-15 at 08:08 -0400, user wrote:
" - "
" - "
>
" - "
> b
" - "
" - HTML_SUFFIX, - "On Thu, 2016-09-15 at 08:08 -0400, user wrote:\n" - "> \n" - "> b")) - g_test_fail (); -} - -static void -test_bug_772513 (TestFixture *fixture) -{ - EContentEditor *cnt_editor; - gboolean set_signature_from_message, check_if_signature_is_changed, ignore_next_signature_change; - - test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail", "composer-reply-start-bottom", TRUE); - - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - cnt_editor = test_utils_get_content_editor (fixture); - - e_content_editor_insert_signature ( - cnt_editor, - "", - FALSE, - "none", - &set_signature_from_message, - &check_if_signature_is_changed, - &ignore_next_signature_change); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "

" HTML_SUFFIX, - "\n")) - g_test_fail (); -} - -static void -test_bug_772918 (TestFixture *fixture) -{ - if (!test_utils_run_simple_test (fixture, - "mode:html\n" - "type:a b c d\n" - "seq:lll\n" - "type:1 2 3 \n" - "undo:undo:6\n" - "undo:redo:6\n", - HTML_PREFIX "
a b 1 2 3 c d
" HTML_SUFFIX, - "a b 1 2 3 c d")) - g_test_fail (); -} - -static void -test_bug_773164 (TestFixture *fixture) -{ - test_utils_set_clipboard_text ("This is paragraph 1\n\nThis is paragraph 2\n\nThis is a longer paragraph 3", FALSE); - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "undo:save\n" - "action:paste\n" - "undo:undo\n" - "undo:test\n" - "undo:redo\n" - "seq:huuuue\n" /* Go to the end of the first line */ - "seq:Sdds\n" - "action:cut\n" - "seq:dde\n" /* Go to the end of the last line */ - "action:paste\n" - "undo:undo:5\n" - "undo:test\n" - "undo:redo:5\n", - HTML_PREFIX "
This is paragraph 1
" - "

" - "
This is a longer paragraph 3
" - "

" - "
This is paragraph 2
" - HTML_SUFFIX, - "This is paragraph 1\n" - "\n" - "This is a longer paragraph 3\n" - "\n" - "This is paragraph 2")) - g_test_fail (); -} - -static void -test_bug_775042 (TestFixture *fixture) -{ - test_utils_insert_content (fixture, - "
a\n"
-		"b\n"
-		"c"
-		""
-		"",
-		E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
-
-	if (!test_utils_run_simple_test (fixture,
-		"seq:rl\n"
-		"mode:plain\n",
-		HTML_PREFIX "
On Fri, 2016-11-25 at 08:18 +0000, user wrote:
" - "
" - "
> a
" - "> b
" - "> c
" - "
" - HTML_SUFFIX, - "On Fri, 2016-11-25 at 08:18 +0000, user wrote:\n" - "> a\n" - "> b\n" - "> c")) - g_test_fail (); -} - -static void -test_bug_775691 (TestFixture *fixture) -{ - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:abc def ghi\\n\n" - "seq:urrrrSrrrs\n" - "action:copy\n" - "seq:d\n" - "action:paste\n", - HTML_PREFIX "
abc def ghi
" - "
def
" - HTML_SUFFIX, - "abc def ghi\n" - "def")) - g_test_fail (); -} - -static void -test_bug_779707 (TestFixture *fixture) -{ - test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail", "composer-reply-start-bottom", TRUE); - test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail", "composer-wrap-quoted-text-in-replies", FALSE); - - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
line 1\n"
-		"line 2\n"
-		"line 3\n"
-		"
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:uuuSesDbnnu\n" - "type:a very long text, which splits into multiple lines when this paragraph is not marked as preformatted, but as normal, as it should be\n" - "", - HTML_PREFIX "
Credits:
" - "
" - "
> line 1
" - "
" - "

" - "
a very long text, which splits into multiple lines when this paragraph is not marked as preformatted, but as normal, as it should be
" - "

" - "
" - "
> line 3
" - "
" - "

" - HTML_SUFFIX, - "Credits:\n" - "> line 1\n" - "\n" - "a very long text, which splits into multiple lines when this paragraph\n" - "is not marked as preformatted, but as normal, as it should be\n" - "\n" - "> line 3\n")) - g_test_fail (); -} - -static void -test_bug_780275_html (TestFixture *fixture) -{ - test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE); - - if (!test_utils_run_simple_test (fixture, - "mode:html\n" - "type:line 0\n" - "seq:nn\n" - "action:paste-quote\n" - "undo:save\n" /* 1 */ - "seq:huuuD\n" - "undo:undo\n" - "undo:test:1\n" - "undo:redo\n" - "type:X\n" - "seq:ddenn\n" - "type:line 4\n" - "undo:drop\n" - "undo:save\n" /* 1 */ - "seq:hSuusD\n" - "undo:undo\n" - "undo:test:1\n" - "undo:redo\n" - "", - HTML_PREFIX "
line 0
" - "
" - "
Xline 1
" - "
line 2
" - "
" - "
line 4
" - HTML_SUFFIX, - "line 0\n" - "> Xline 1\n" - "> line 2\n" - "line 4")) - g_test_fail (); -} - -static void -test_bug_780275_plain (TestFixture *fixture) -{ - test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE); - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:line 0\n" - "seq:nn\n" - "action:paste-quote\n" - "undo:save\n" /* 1 */ - "seq:huuuD\n" - "undo:undo\n" - "undo:test:1\n" - "undo:redo\n" - "type:X\n" - "seq:ddenn\n" - "type:line 4\n" - "undo:drop\n" - "undo:save\n" /* 1 */ - "seq:hSuusD\n" - "undo:undo\n" - "undo:test:1\n" - "undo:redo\n", - HTML_PREFIX "
line 0
" - "
" - "
> Xline 1
" - "
> line 2
" - "
" - "
line 4
" - HTML_SUFFIX, - "line 0\n" - "> Xline 1\n" - "> line 2\n" - "line 4")) - g_test_fail (); -} - -static void -test_bug_781722 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
Signed-off-by: User <user@no.where>\n"
-		"
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:dd\n" - "action:style-preformat\n", - HTML_PREFIX "
Credits:
" - "
" - "
> Signed-off-by: User <user@no.where>
" - "
" - HTML_SUFFIX, - "Credits:\n" - "> Signed-off-by: User ")) - g_test_fail (); -} - -static void -test_bug_781116 (TestFixture *fixture) -{ - test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail", "composer-wrap-quoted-text-in-replies", FALSE); - - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
a very long text, which splits into multiple lines when this paragraph is not marked as preformatted, but as normal, as it should be
\n" - "
" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "seq:dd\n" - "action:wrap-lines\n", - HTML_PREFIX "
Credits:
" - "
" - "
> a very long text, which splits into multiple lines when this
" - "> paragraph is not marked as preformatted, but as normal, as it should
" - "> be
" - "
" - HTML_SUFFIX, - "Credits:\n" - "> a very long text, which splits into multiple lines when this\n" - "> paragraph is not marked as preformatted, but as normal, as it should\n" - "> be")) - g_test_fail (); -} - -static void -test_bug_780088 (TestFixture *fixture) -{ - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_set_clipboard_text ("Seeing @blah instead of @foo XX'ed on" UNICODE_NBSP "https://example.sub" UNICODE_NBSP "domain.org/page I'd recommend to XX YY , click fjwvne on the left, click skjd sjewncj on the right, and set wqje wjfdn Xs to something like wqjfnm www.example.com/~user wjfdncj or such.", FALSE); - - if (!test_utils_run_simple_test (fixture, - "action:paste\n" - "seq:n", - HTML_PREFIX "
" - "Seeing @blah instead of @foo XX'ed on https://example.sub" - " domain.org/page I'd recommend to XX YY " - "<https://example.subdomain.org/p/user/> , " - "click fjwvne on the left, click skjd sjewncj on the right, and set wqje wjfdn Xs to something like " - "wqjfnm www.example.com/~user wjfdncj or such.
" - "

" - HTML_SUFFIX, - "Seeing @blah instead of @foo XX'ed on" UNICODE_NBSP "https://example.sub" UNICODE_NBSP "domain.org/pa\n" - "ge I'd recommend to XX YY ,\n" - "click fjwvne on the left, click skjd sjewncj on the right, and set wqje\n" - "wjfdn Xs to something like wqjfnm www.example.com/~user wjfdncj or\n" - "such.\n")) - g_test_fail (); -} - -static void -test_bug_788829 (TestFixture *fixture) -{ - test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail", "composer-wrap-quoted-text-in-replies", TRUE); - test_utils_fixture_change_setting_int32 (fixture, "org.gnome.evolution.mail", "composer-word-wrap-length", 71); - - if (!test_utils_process_commands (fixture, - "mode:plain\n")) { - g_test_fail (); - return; - } - - test_utils_insert_content (fixture, - "
Xxxxx xx xxxxxxxxx xx xxxxxxx xx xxxxx xxxx xxxx xx xxx xxx xxxx xxx xxxçx xôxé " - "\"xxxxx xxxx xxxxxxx xxx\" xx xxxx xxxxé xxx xxx xxxéx xxx x'x xéxxxxé x'xxxxxxxxx xx " - "xxx \"Xxxx XXX Xxxxxx Xxx\". Xx xxxx xxxxxxxx xxx xxxxxxxxxxxxxxxx.xx (xxxxxxx xxxxxxxxxx xx .xxx). Xxxx " - "êxxx xxx xxxxxxxxxxx xxxéxxxxxxxx, xxxx xxxxx xx XXX xx xéxxx à xx xxx \"xxx xxxxxx xxxx " - "xx xxxxxxx\" xx xxxx xx xxxxx xxxxxxxx xxxxxxxx xx $ xx xxxx x'xxxxxx.

" - "
Xxxx xx xéxxxxxxx, xxxxxxxx xxxxxxx (!), xxxxxxx à xxx, xxxx ooo$ XXX xxxxé: " - "https://xxxxxxxxxxxxxxxx.xx/xxxxxxx/xxxxx-xxxx-xxxxxxxx-x" - "xxxx-xxxx-xxx-xxxxxxxx-xxx/ xx xx xxxx xéxéxxxxxxx x'xxxxxx xxxx xx xxxxxx xx xxxxxx" - "xxxxxx xx xxx (xxxxx Xxxxxx) xxxx xxxx x'xxxxxxx xx xxxxxx: " - "https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxxxxxxxxx-Xxxxx-Xxxx-XXX-Xxxxxx-Xxx.xxx" - "

Xxxx xxx xxx xxxxxxx xxxxxxxéxx x'xxxêxxxx à xxxxx, xxx xx x" - "xxxé xx oooxooo xxxxx xxxxx xxxx... xxxx x'xxx xxxxxxxxxxxx xxxxx xxx xxxxxxxx xx \"xx xxx" - "xx xxx xxx xxxxxxx xxxxxxx xxxxxxxxxxxxxx xxxx xxxxx xxxxxx xx xx xxxx xx x'xxxxxx\". Xx " - "xxxx-êxxx xxx xx xxxxxxxx xx xxxx \"x'xxxêxx à xxxxx xx oooxooo xxxx xxx xéxxxxxxxx, xxxx" - "\"...

Xxxxx xxxxxx'xx xxx x xxxx xxxxxxx xxxxx xx xxèx xxxxxxxxx " - "xxxxxxxxxxxxxxxx à xx xxx x'xx xx xêxx (éxxxxxxxxx xxxx-xx-xxxxxxxx): https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxx-xxxx-xxx-xxxxxxxxxx-xx" - "xxx.xxx

...x'x xxxxx xx xxxxxx x'xxxxxx xéxxxxxxx, " - "xx xxx xxxx xxxxxx x'xxxxxxxxxxx xxxxxx, xxxx https://xxxx" - "xxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/ xxxxx xxx https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/ ...
" - "" - "", - E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML); - - if (!test_utils_run_simple_test (fixture, - "", - HTML_PREFIX "
On Today, User wrote:
" - "
> Xxxxx xx xxxxxxxxx xx xxxxxxx xx xxxxx xxxx " - "xxxx xx xxx xxx xxxx xxx
> xxxçx xôxé \"xxxxx xxxx xxxxxxx xxx\" xx xxxx " - "xxxxé xxx xxx xxxéx xxx
> x'x xéxxxxé x'xxxxxxxxx xx xxx \"Xxxx XXX Xxxxxx " - "Xxx\". Xx xxxx
> xxxxxxxx xxx xxxxxxxxxxxxxxxx.xx (xxxxxxx xxxxxxxxxx xx .xx" - "x). Xxxx
> êxxx xxx xxxxxxxxxxx xxxéxxxxxxxx, xxxx xxxxx xx XXX xx xéxxx à " - "xx
> xxx \"xxx xxxxxx xxxx xx xxxxxxx\" xx xxxx xx xxxxx xxxxxxxx xxxxxxxx" - "
> xx $ xx xxxx x'xxxxxx.
>
" - "
> Xxxx xx xéxxxxxxx, xxxxxxxx xxxxxxx (!), " - "xxxxxxx à xxx, xxxx ooo$ XXX
> xxxxé: https://xxxxxxxxxxxxxxxx.xx/xxx" - "xxxx/xxxxx-xxxx-xxxxxxxx-xxxxx-
> xxxx-xxx-xxxxxxxx-xxx/ xx xx xxxx " - "xéxéxxxxxxx x'xxxxxx xxxx xx xxxxxx
> xx xxxxxxxxxxxx xx xxx (xxxxx " - "Xxxxxx) xxxx xxxx x'xxxxxxx xx xxxxxx:
> https://xxxxxxxxxxxxxxxx.xx" - "x/xx-xxxxxxx/xxxxxxx/Xxxxxxxxxxxx-Xxxxx-Xx
> xx-XXX-Xxxxxx-Xxx.xxx
" - "
>
> Xx" - "xx xxx xxx xxxxxxx xxxxxxxéxx x'xxxêxxxx à xxxxx, xxx xx xxxxé xx
> oooxo" - "oo xxxxx xxxxx xxxx... xxxx x'xxx xxxxxxxxxxxx xxxxx xxx
> xxxxxxxx xx \"" - "xx xxxxx xxx xxx xxxxxxx xxxxxxx xxxxxxxxxxxxxx xxxx
> xxxxx xxxxxx xx xx " - "xxxx xx x'xxxxxx\". Xx xxxx-êxxx xxx xx xxxxxxxx xx
> xxxx \"x'xxxêxx à " - "xxxxx xx oooxooo xxxx xxx xéxxxxxxxx, xxxx\"...
" - ">
> Xxxxx xxxxxx'xx xxx x xxxx xxxxxxx " - "xxxxx xx xxèx xxxxxxxxx
>
> xxxxxxxxxxxxxxxx à xx xxx x'xx xx xêxx " - "(éxxxxxxxxx xxxx-xx-xxxxxxxx): https://xxxxxxxxxxxxxxxx.xxx/xx-xxx" - "xxxx/xxxxxxx/Xxxxx-xxxx-xxx-
> xxxxxxxxxx-xxxxx.xxx
>
> ...x'x " - "xxxxx xx xxxxxx x'xxxxxx xéxxxxxxx, xx xxx xxxx xxxxxx
> x'xxxxxxxxxxx " - "xxxxxx, xxxx https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxx
> xxx-xxxx-xxx-o/ " - "xxxxx xxx https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxx
> xx-xxxx-xxx-o/ ...
" HTML_SUFFIX, - "On Today, User wrote:\n" - "> Xxxxx xx xxxxxxxxx xx xxxxxxx xx xxxxx xxxx xxxx xx xxx xxx xxxx xxx\n" - "> xxxçx xôxé \"xxxxx xxxx xxxxxxx xxx\" xx xxxx xxxxé xxx xxx xxxéx xxx\n" - "> x'x xéxxxxé x'xxxxxxxxx xx xxx \"Xxxx XXX Xxxxxx Xxx\". Xx xxxx\n" - "> xxxxxxxx xxx xxxxxxxxxxxxxxxx.xx (xxxxxxx xxxxxxxxxx xx .xxx). Xxxx\n" - "> êxxx xxx xxxxxxxxxxx xxxéxxxxxxxx, xxxx xxxxx xx XXX xx xéxxx à xx\n" - "> xxx \"xxx xxxxxx xxxx xx xxxxxxx\" xx xxxx xx xxxxx xxxxxxxx xxxxxxxx\n" - "> xx $ xx xxxx x'xxxxxx.\n" - "> \n" - "> Xxxx xx xéxxxxxxx, xxxxxxxx xxxxxxx (!), xxxxxxx à xxx, xxxx ooo$ XXX\n" - "> xxxxé: https://xxxxxxxxxxxxxxxx.xx/xxxxxxx/xxxxx-xxxx-xxxxxxxx-xxxxx-\n" - "> xxxx-xxx-xxxxxxxx-xxx/ xx xx xxxx xéxéxxxxxxx x'xxxxxx xxxx xx xxxxxx\n" - "> xx xxxxxxxxxxxx xx xxx (xxxxx Xxxxxx) xxxx xxxx x'xxxxxxx xx xxxxxx: \n" - "> https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxxxxxxxxx-Xxxxx-Xx\n" - "> xx-XXX-Xxxxxx-Xxx.xxx\n" - "> \n" - "> Xxxx xxx xxx xxxxxxx xxxxxxxéxx x'xxxêxxxx à xxxxx, xxx xx xxxxé xx\n" - "> oooxooo xxxxx xxxxx xxxx... xxxx x'xxx xxxxxxxxxxxx xxxxx xxx\n" - "> xxxxxxxx xx \"xx xxxxx xxx xxx xxxxxxx xxxxxxx xxxxxxxxxxxxxx xxxx\n" - "> xxxxx xxxxxx xx xx xxxx xx x'xxxxxx\". Xx xxxx-êxxx xxx xx xxxxxxxx xx\n" - "> xxxx \"x'xxxêxx à xxxxx xx oooxooo xxxx xxx xéxxxxxxxx, xxxx\"...\n" - "> \n" - "> Xxxxx xxxxxx'xx xxx x xxxx xxxxxxx xxxxx xx xxèx xxxxxxxxx\n" - "> \n" - "> xxxxxxxxxxxxxxxx à xx xxx x'xx xx xêxx (éxxxxxxxxx xxxx-xx-xxxxxxxx): https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxx-xxxx-xxx-\n" - "> xxxxxxxxxx-xxxxx.xxx ; \n" - "> \n" - "> ...x'x xxxxx xx xxxxxx x'xxxxxx xéxxxxxxx, xx xxx xxxx xxxxxx\n" - "> x'xxxxxxxxxxx xxxxxx, xxxx https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxx\n" - "> xxx-xxxx-xxx-o/ xxxxx xxx https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxx\n" - "> xx-xxxx-xxx-o/ ...")) - g_test_fail (); -} - -static void -test_bug_750636 (TestFixture *fixture) -{ - test_utils_fixture_change_setting_int32 (fixture, "org.gnome.evolution.mail", "composer-word-wrap-length", 71); - - if (!test_utils_run_simple_test (fixture, - "mode:plain\n" - "type:" - "12345678901234567890123456789012345678901234567890123456789012345678901" - "12345678901234567890123456789012345678901234567890123456789012345678901A\\n\\n" - "1234567890123456789012345678901234567890123456789012345678901234567890 B\\n\\n" - "12345678901234567890123456789012345678901234567890123456789012345678901 C\\n\\n" - "1234567890123456789012345678901234567890123456789012345678901234567890 D\\n\\n" - "12345678901234567890123456789012345678901234567890123456789012345678901" UNICODE_NBSP UNICODE_NBSP UNICODE_NBSP "E\\n\\n" - "1234567890123456789012345678901234567890123456789012345678901234567890" UNICODE_NBSP UNICODE_NBSP UNICODE_NBSP "F\\n\\n" - " 1\\n" - " 2\\n" - " 3\\n" - "\n", - HTML_PREFIX "
" - "12345678901234567890123456789012345678901234567890123456789012345678901" - "12345678901234567890123456789012345678901234567890123456789012345678901A
" - "

" - "1234567890123456789012345678901234567890123456789012345678901234567890 B
" - "

" - "12345678901234567890123456789012345678901234567890123456789012345678901 C
" - "

" - "1234567890123456789012345678901234567890123456789012345678901234567890 D
" - "

" - "12345678901234567890123456789012345678901234567890123456789012345678901   E
" - "

" - "1234567890123456789012345678901234567890123456789012345678901234567890   F
" - "

" - "
1
" - "
2
" - "
3
" - "

" - HTML_SUFFIX, - "12345678901234567890123456789012345678901234567890123456789012345678901\n" - "12345678901234567890123456789012345678901234567890123456789012345678901\n" - "A\n\n" - "1234567890123456789012345678901234567890123456789012345678901234567890\n" - "B\n\n" - "12345678901234567890123456789012345678901234567890123456789012345678901\n" - "C\n\n" - "1234567890123456789012345678901234567890123456789012345678901234567890 \n" - "D\n\n" - "12345678901234567890123456789012345678901234567890123456789012345678901\n" - " E\n\n" - "1234567890123456789012345678901234567890123456789012345678901234567890 \n" - " F\n\n" - " 1\n" - " 2\n" - " 3\n")) - g_test_fail (); -} - -void -test_add_html_editor_bug_tests (void) -{ - test_utils_add_test ("/bug/726548", test_bug_726548); - test_utils_add_test ("/bug/750657", test_bug_750657); - test_utils_add_test ("/bug/760989", test_bug_760989); - test_utils_add_test ("/bug/767903", test_bug_767903); - test_utils_add_test ("/bug/769708", test_bug_769708); - test_utils_add_test ("/bug/769913", test_bug_769913); - test_utils_add_test ("/bug/769955", test_bug_769955); - test_utils_add_test ("/bug/770073", test_bug_770073); - test_utils_add_test ("/bug/770074", test_bug_770074); - test_utils_add_test ("/bug/771044", test_bug_771044); - test_utils_add_test ("/bug/771131", test_bug_771131); - test_utils_add_test ("/bug/771493", test_bug_771493); - test_utils_add_test ("/bug/772171", test_bug_772171); - test_utils_add_test ("/bug/772513", test_bug_772513); - test_utils_add_test ("/bug/772918", test_bug_772918); - test_utils_add_test ("/bug/773164", test_bug_773164); - test_utils_add_test ("/bug/775042", test_bug_775042); - test_utils_add_test ("/bug/775691", test_bug_775691); - test_utils_add_test ("/bug/779707", test_bug_779707); - test_utils_add_test ("/bug/780275/html", test_bug_780275_html); - test_utils_add_test ("/bug/780275/plain", test_bug_780275_plain); - test_utils_add_test ("/bug/781722", test_bug_781722); - test_utils_add_test ("/bug/781116", test_bug_781116); - test_utils_add_test ("/bug/780088", test_bug_780088); - test_utils_add_test ("/bug/788829", test_bug_788829); - test_utils_add_test ("/bug/750636", test_bug_750636); -} diff --git a/src/em-format/e-mail-formatter-utils.c b/src/em-format/e-mail-formatter-utils.c index 50dae71..abd5155 100644 --- a/src/em-format/e-mail-formatter-utils.c +++ b/src/em-format/e-mail-formatter-utils.c @@ -549,136 +549,71 @@ e_mail_formatter_format_security_header (EMailFormatter *formatter, EMailPart *part, guint32 flags) { - struct _validity_flags { - guint32 flags; - const gchar *description_complete; - const gchar *description_partial; - } validity_flags[] = { - { E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SIGNED, N_("GPG signed"), N_("partially GPG signed") }, - { E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_ENCRYPTED, N_("GPG encrypted"), N_("partially GPG encrypted") }, - { E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_SIGNED, N_("S/MIME signed"), N_("partially S/MIME signed") }, - { E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_ENCRYPTED, N_("S/MIME encrypted"), N_("partially S/MIME encrypted") } - }; - const gchar *part_id; - gchar *part_id_prefix; + const gchar* part_id; + gchar* part_id_prefix; + GString* tmp; GQueue queue = G_QUEUE_INIT; GList *head, *link; - guint32 check_valid_flags = 0; - gint part_id_prefix_len; - gboolean is_partial = FALSE; - guint ii; g_return_if_fail (E_IS_MAIL_PART_HEADERS (part)); /* Get prefix of this PURI */ part_id = e_mail_part_get_id (part); part_id_prefix = g_strndup (part_id, g_strrstr (part_id, ".") - part_id); - part_id_prefix_len = strlen (part_id_prefix); + + /* Add encryption/signature header */ + tmp = g_string_new (""); e_mail_part_list_queue_parts (context->part_list, NULL, &queue); head = g_queue_peek_head_link (&queue); - /* Ignore the main message, the headers and the end parts */ - #define should_skip_part(_id) \ - (g_strcmp0 (_id, part_id_prefix) == 0 || \ - (_id && g_str_has_suffix (_id, ".rfc822.end")) || \ - (_id && strlen (_id) == part_id_prefix_len + 8 /* strlen (".headers") */ && \ - g_strcmp0 (_id + part_id_prefix_len, ".headers") == 0)) - - /* Check parts for this ID. */ - for (link = head; link != NULL; link = g_list_next (link)) { + /* Find first secured part. */ + for (link = head; link != NULL; link = g_list_next(link)) { EMailPart *mail_part = link->data; - const gchar *id = e_mail_part_get_id (mail_part); - if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix)) + if (!e_mail_part_has_validity (mail_part)) continue; - if (should_skip_part (id)) + if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix)) continue; - if (!e_mail_part_has_validity (mail_part)) { - /* A part without validity, thus it's partially signed/encrypted */ - is_partial = TRUE; - } else { - guint32 validies = 0; - for (ii = 0; ii < G_N_ELEMENTS (validity_flags); ii++) { - if (e_mail_part_get_validity (mail_part, validity_flags[ii].flags)) - validies |= validity_flags[ii].flags; - } - check_valid_flags |= validies; + if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SIGNED)) { + g_string_append (tmp, _("GPG signed")); } - /* Do not traverse sub-messages */ - if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822") && - !g_str_equal (e_mail_part_get_id (mail_part), part_id_prefix)) - link = e_mail_formatter_find_rfc822_end_iter (link); - } - - if (check_valid_flags) { - GString *tmp; - - if (!is_partial) { - for (link = head; link != NULL && !is_partial; link = g_list_next (link)) { - EMailPart *mail_part = link->data; - const gchar *id = e_mail_part_get_id (mail_part); - - if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix)) - continue; - - if (should_skip_part (id)) - continue; - - if (!e_mail_part_has_validity (mail_part)) { - /* A part without validity, thus it's partially signed/encrypted */ - is_partial = TRUE; - break; - } - - is_partial = !e_mail_part_get_validity (mail_part, check_valid_flags); - - /* Do not traverse sub-messages */ - if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822") && - !g_str_equal (e_mail_part_get_id (mail_part), part_id_prefix)) - link = e_mail_formatter_find_rfc822_end_iter (link); - } + if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_ENCRYPTED)) { + if (tmp->len > 0) + g_string_append (tmp, ", "); + g_string_append (tmp, _("GPG encrypted")); } - /* Add encryption/signature header */ - tmp = g_string_new (""); - - for (link = head; link; link = g_list_next (link)) { - EMailPart *mail_part = link->data; - const gchar *id = e_mail_part_get_id (mail_part); - - if (!e_mail_part_has_validity (mail_part) || - !e_mail_part_id_has_prefix (mail_part, part_id_prefix)) - continue; - - if (should_skip_part (id)) - continue; - - for (ii = 0; ii < G_N_ELEMENTS (validity_flags); ii++) { - if (e_mail_part_get_validity (mail_part, validity_flags[ii].flags)) { - if (tmp->len > 0) - g_string_append (tmp, ", "); - g_string_append (tmp, is_partial ? _(validity_flags[ii].description_partial) : _(validity_flags[ii].description_complete)); - } - } - - break; + if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_SIGNED)) { + if (tmp->len > 0) + g_string_append (tmp, ", "); + g_string_append (tmp, _("S/MIME signed")); } - if (tmp->len > 0) - e_mail_formatter_format_header (formatter, buffer, _("Security"), tmp->str, flags, "UTF-8"); + if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_ENCRYPTED)) { + if (tmp->len > 0) + g_string_append (tmp, ", "); + g_string_append (tmp, _("S/MIME encrypted")); + } - g_string_free (tmp, TRUE); + break; } - #undef should_skip_part + if (tmp->len > 0) { + e_mail_formatter_format_header ( + formatter, buffer, + _("Security"), tmp->str, + flags, + "UTF-8"); + } while (!g_queue_is_empty (&queue)) g_object_unref (g_queue_pop_head (&queue)); + g_string_free (tmp, TRUE); g_free (part_id_prefix); } diff --git a/src/em-format/e-mail-formatter-utils.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-formatter-utils.c.cve-2018-15587-reposition-signature-bar deleted file mode 100644 index abd5155..0000000 --- a/src/em-format/e-mail-formatter-utils.c.cve-2018-15587-reposition-signature-bar +++ /dev/null @@ -1,619 +0,0 @@ -/* - * e-mail-formatter-utils.h - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -#include "evolution-config.h" - -#include "e-mail-formatter-utils.h" -#include "e-mail-part-headers.h" - -#include -#include - -#include -#include - -#include -#include - -static const gchar *addrspec_hdrs[] = { - "Sender", "From", "Reply-To", "To", "Cc", "Bcc", - "Resent-Sender", "Resent-From", "Resent-Reply-To", - "Resent-To", "Resent-Cc", "Resent-Bcc", NULL -}; - -void -e_mail_formatter_format_text_header (EMailFormatter *formatter, - GString *buffer, - const gchar *label, - const gchar *value, - guint32 flags) -{ - GtkTextDirection direction; - const gchar *fmt, *html; - const gchar *display; - gchar *mhtml = NULL; - - g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); - g_return_if_fail (buffer != NULL); - g_return_if_fail (label != NULL); - - if (value == NULL) - return; - - while (*value == ' ') - value++; - - if (!(flags & E_MAIL_FORMATTER_HEADER_FLAG_HTML)) { - CamelMimeFilterToHTMLFlags text_format_flags; - - text_format_flags = - e_mail_formatter_get_text_format_flags (formatter); - html = mhtml = camel_text_to_html ( - value, text_format_flags, 0); - } else { - html = value; - } - - direction = gtk_widget_get_default_direction (); - - if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS) { - if (flags & E_MAIL_FORMATTER_HEADER_FLAG_BOLD) { - fmt = "" - "%s: %s"; - } else { - fmt = "" - "%s: %s"; - } - } else if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NODEC) { - if (direction == GTK_TEXT_DIR_RTL) - fmt = "" - "%s" - "%s" - ""; - else - fmt = "" - "%s" - "%s" - ""; - } else { - if (direction == GTK_TEXT_DIR_RTL) - fmt = "" - "%s:" - "%s" - ""; - else - fmt = "" - "%s:" - "%s" - ""; - } - - if (flags & E_MAIL_FORMATTER_HEADER_FLAG_HIDDEN) - display = "none"; - else - display = "table-row"; - - g_string_append_printf (buffer, fmt, display, label, html); - - g_free (mhtml); -} - -gchar * -e_mail_formatter_format_address (EMailFormatter *formatter, - GString *out, - struct _camel_header_address *a, - const gchar *field, - gboolean no_links, - gboolean elipsize) -{ - CamelMimeFilterToHTMLFlags flags; - gchar *name, *mailto, *addr; - gint i = 0; - gchar *str = NULL; - gint limit = mail_config_get_address_count (); - - g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL); - g_return_val_if_fail (out != NULL, NULL); - g_return_val_if_fail (field != NULL, NULL); - - flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES; - - while (a != NULL) { - if (a->name) - name = camel_text_to_html (a->name, flags, 0); - else - name = NULL; - - switch (a->type) { - case CAMEL_HEADER_ADDRESS_NAME: - if (name != NULL && *name != '\0') { - gchar *real, *mailaddr; - - if (strchr (a->name, ',') || strchr (a->name, ';')) - g_string_append_printf (out, ""%s"", name); - else - g_string_append (out, name); - - g_string_append (out, " <"); - - /* rfc2368 for mailto syntax and url encoding extras */ - if ((real = camel_header_encode_phrase ((guchar *) a->name))) { - mailaddr = g_strdup_printf ("%s <%s>", real, a->v.addr); - g_free (real); - mailto = camel_url_encode (mailaddr, "?=&()"); - g_free (mailaddr); - } else { - mailto = camel_url_encode (a->v.addr, "?=&()"); - } - } else { - mailto = camel_url_encode (a->v.addr, "?=&()"); - } - addr = camel_text_to_html (a->v.addr, flags, 0); - if (no_links) - g_string_append_printf (out, "%s", addr); - else - g_string_append_printf (out, "%s", mailto, addr); - g_free (mailto); - g_free (addr); - - if (name != NULL && *name != '\0') - g_string_append (out, ">"); - break; - case CAMEL_HEADER_ADDRESS_GROUP: - g_string_append_printf (out, "%s: ", name); - e_mail_formatter_format_address ( - formatter, out, a->v.members, field, - no_links, elipsize); - g_string_append_printf (out, ";"); - break; - default: - g_warning ("Invalid address type"); - break; - } - - g_free (name); - - i++; - a = a->next; - if (a != NULL) - g_string_append (out, ", "); - - if (!elipsize) - continue; - - /* Let us add a '...' if we have more addresses */ - if (limit > 0 && i == limit && a != NULL) { - if (strcmp (field, _("To")) == 0 || - strcmp (field, _("Cc")) == 0 || - strcmp (field, _("Bcc")) == 0) { - - g_string_append ( - out, - ""); - str = g_strdup_printf ( - "", - EVOLUTION_IMAGESDIR); - } - } - } - - if (elipsize && str) { - if (strcmp (field, _("To")) == 0 || - strcmp (field, _("Cc")) == 0 || - strcmp (field, _("Bcc")) == 0) { - - g_string_append ( - out, - "" - "..."); - } - } - - return str; -} - -void -e_mail_formatter_canon_header_name (gchar *name) -{ - gchar *inptr = name; - - g_return_if_fail (name != NULL); - - /* canonicalise the header name... first letter is - * capitalised and any letter following a '-' also gets - * capitalised */ - - if (*inptr >= 'a' && *inptr <= 'z') - *inptr -= 0x20; - - inptr++; - - while (*inptr) { - if (inptr[-1] == '-' && *inptr >= 'a' && *inptr <= 'z') - *inptr -= 0x20; - else if (inptr[-1] != '-' && *inptr >= 'A' && *inptr <= 'Z') - *inptr += 0x20; - - inptr++; - } -} - -void -e_mail_formatter_format_header (EMailFormatter *formatter, - GString *buffer, - const gchar *header_name, - const gchar *header_value, - guint32 flags, - const gchar *charset) -{ - gchar *canon_name, *buf, *value = NULL; - const gchar *label, *txt; - gboolean addrspec = FALSE; - gchar *str_field = NULL; - gint i; - - g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); - g_return_if_fail (buffer != NULL); - g_return_if_fail (header_name != NULL); - g_return_if_fail (header_value != NULL); - - canon_name = g_alloca (strlen (header_name) + 1); - strcpy (canon_name, header_name); - e_mail_formatter_canon_header_name (canon_name); - - for (i = 0; addrspec_hdrs[i]; i++) { - if (g_ascii_strcasecmp (canon_name, addrspec_hdrs[i]) == 0) { - addrspec = TRUE; - break; - } - } - - label = _(canon_name); - - if (addrspec) { - struct _camel_header_address *addrs; - GString *html; - gchar *img; - gchar *fmt_charset; - - fmt_charset = e_mail_formatter_dup_charset (formatter); - if (fmt_charset == NULL) - fmt_charset = e_mail_formatter_dup_default_charset (formatter); - - buf = camel_header_unfold (header_value); - addrs = camel_header_address_decode (buf, fmt_charset); - if (addrs == NULL) { - g_free (fmt_charset); - g_free (buf); - return; - } - - g_free (fmt_charset); - g_free (buf); - - html = g_string_new (""); - img = e_mail_formatter_format_address ( - formatter, html, addrs, label, - (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS), - !(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE)); - - if (img != NULL) { - str_field = g_strdup_printf ("%s: %s", label, img); - label = str_field; - flags |= E_MAIL_FORMATTER_HEADER_FLAG_NODEC; - g_free (img); - } - - camel_header_address_list_clear (&addrs); - txt = value = html->str; - g_string_free (html, FALSE); - - flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML; - flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD; - - } else if (g_str_equal (canon_name, "Subject")) { - buf = camel_header_unfold (header_value); - txt = value = camel_header_decode_string (buf, charset); - g_free (buf); - - flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD; - - } else if (g_str_equal (canon_name, "X-Evolution-Mailer")) { - /* pseudo-header */ - label = _("Mailer"); - txt = value = camel_header_format_ctext (header_value, charset); - flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD; - - } else if (g_str_equal (canon_name, "Date") || - g_str_equal (canon_name, "Resent-Date")) { - CamelMimeFilterToHTMLFlags text_format_flags; - gint msg_offset, local_tz; - time_t msg_date; - struct tm local; - gchar *html; - gboolean hide_real_date; - - hide_real_date = !e_mail_formatter_get_show_real_date (formatter); - - txt = header_value; - while (*txt == ' ' || *txt == '\t') - txt++; - - text_format_flags = - e_mail_formatter_get_text_format_flags (formatter); - - html = camel_text_to_html (txt, text_format_flags, 0); - - msg_date = camel_header_decode_date (txt, &msg_offset); - e_localtime_with_offset (msg_date, &local, &local_tz); - - /* 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; - - /* value will be freed at the end */ - if (!hide_real_date && !msg_offset) { - /* No timezone difference; just - * show the real Date: header. */ - txt = value = html; - } else { - gchar *date_str; - - date_str = e_datetime_format_format ( - "mail", "header", - DTFormatKindDateTime, msg_date); - - if (hide_real_date) { - /* Show only the local-formatted date, losing - * all timezone information like Outlook does. - * Should we attempt to show it somehow? */ - txt = value = date_str; - } else { - txt = value = g_strdup_printf ( - "%s (%s)", html, date_str); - g_free (date_str); - } - g_free (html); - } - - flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML; - flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD; - - } else if (g_str_equal (canon_name, "Newsgroups")) { - GSList *ng, *scan; - GString *html; - - buf = camel_header_unfold (header_value); - - if (!(ng = camel_header_newsgroups_decode (buf))) { - g_free (buf); - return; - } - - g_free (buf); - - html = g_string_new (""); - scan = ng; - while (scan) { - const gchar *newsgroup = scan->data; - - if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS) - g_string_append_printf ( - html, "%s", newsgroup); - else - g_string_append_printf ( - html, "%s", - newsgroup, newsgroup); - scan = g_slist_next (scan); - if (scan) - g_string_append_printf (html, ", "); - } - - g_slist_free_full (ng, g_free); - - txt = html->str; - value = g_string_free (html, FALSE); - - flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML; - flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD; - - } else if (g_str_equal (canon_name, "Received") || - g_str_has_prefix (canon_name, "X-")) { - /* don't unfold Received nor extension headers */ - txt = value = camel_header_decode_string (header_value, charset); - - } else { - /* don't unfold Received nor extension headers */ - buf = camel_header_unfold (header_value); - txt = value = camel_header_decode_string (buf, charset); - g_free (buf); - } - - e_mail_formatter_format_text_header ( - formatter, buffer, label, txt, flags); - - g_free (value); - g_free (str_field); -} - -GList * -e_mail_formatter_find_rfc822_end_iter (GList *rfc822_start_iter) -{ - GList *link = rfc822_start_iter; - EMailPart *part; - const gchar *part_id; - gchar *end; - - g_return_val_if_fail (rfc822_start_iter != NULL, NULL); - - part = E_MAIL_PART (link->data); - - part_id = e_mail_part_get_id (part); - g_return_val_if_fail (part_id != NULL, NULL); - - end = g_strconcat (part_id, ".end", NULL); - - while (link != NULL) { - part = E_MAIL_PART (link->data); - - part_id = e_mail_part_get_id (part); - g_return_val_if_fail (part_id != NULL, NULL); - - if (g_strcmp0 (part_id, end) == 0) - break; - - link = g_list_next (link); - } - - g_free (end); - - return link; -} - -gchar * -e_mail_formatter_parse_html_mnemonics (const gchar *label, - gchar **out_access_key) -{ - const gchar *pos = NULL; - GString *html_label = NULL; - - g_return_val_if_fail (label != NULL, NULL); - - if (out_access_key != NULL) - *out_access_key = NULL; - - if (!g_utf8_validate (label, -1, NULL)) { - gchar *res = g_strdup (label); - - g_return_val_if_fail (g_utf8_validate (label, -1, NULL), res); - - return res; - } - - pos = strstr (label, "_"); - if (pos != NULL) { - gunichar uk; - - html_label = g_string_new (""); - g_string_append_len (html_label, label, pos - label); - - pos++; - uk = g_utf8_get_char (pos); - - pos = g_utf8_next_char (pos); - - g_string_append (html_label, ""); - g_string_append_unichar (html_label, uk); - g_string_append (html_label, ""); - g_string_append (html_label, pos); - - if (out_access_key != NULL && uk != 0) { - gchar ukstr[10]; - gint len; - - len = g_unichar_to_utf8 (g_unichar_toupper (uk), ukstr); - if (len > 0) - *out_access_key = g_strndup (ukstr, len); - } - - } else { - html_label = g_string_new (label); - } - - return g_string_free (html_label, FALSE); -} - -void -e_mail_formatter_format_security_header (EMailFormatter *formatter, - EMailFormatterContext *context, - GString *buffer, - EMailPart *part, - guint32 flags) -{ - const gchar* part_id; - gchar* part_id_prefix; - GString* tmp; - GQueue queue = G_QUEUE_INIT; - GList *head, *link; - - g_return_if_fail (E_IS_MAIL_PART_HEADERS (part)); - - /* Get prefix of this PURI */ - part_id = e_mail_part_get_id (part); - part_id_prefix = g_strndup (part_id, g_strrstr (part_id, ".") - part_id); - - /* Add encryption/signature header */ - tmp = g_string_new (""); - - e_mail_part_list_queue_parts (context->part_list, NULL, &queue); - - head = g_queue_peek_head_link (&queue); - - /* Find first secured part. */ - for (link = head; link != NULL; link = g_list_next(link)) { - EMailPart *mail_part = link->data; - - if (!e_mail_part_has_validity (mail_part)) - continue; - - if (!e_mail_part_id_has_prefix (mail_part, part_id_prefix)) - continue; - - if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SIGNED)) { - g_string_append (tmp, _("GPG signed")); - } - - if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_ENCRYPTED)) { - if (tmp->len > 0) - g_string_append (tmp, ", "); - g_string_append (tmp, _("GPG encrypted")); - } - - if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_SIGNED)) { - if (tmp->len > 0) - g_string_append (tmp, ", "); - g_string_append (tmp, _("S/MIME signed")); - } - - if (e_mail_part_get_validity (mail_part, E_MAIL_PART_VALIDITY_SMIME | E_MAIL_PART_VALIDITY_ENCRYPTED)) { - if (tmp->len > 0) - g_string_append (tmp, ", "); - g_string_append (tmp, _("S/MIME encrypted")); - } - - break; - } - - if (tmp->len > 0) { - e_mail_formatter_format_header ( - formatter, buffer, - _("Security"), tmp->str, - flags, - "UTF-8"); - } - - while (!g_queue_is_empty (&queue)) - g_object_unref (g_queue_pop_head (&queue)); - - g_string_free (tmp, TRUE); - g_free (part_id_prefix); -} diff --git a/src/em-format/e-mail-parser-application-smime.c b/src/em-format/e-mail-parser-application-smime.c index e569cd7..87f25b3 100644 --- a/src/em-format/e-mail-parser-application-smime.c +++ b/src/em-format/e-mail-parser-application-smime.c @@ -22,7 +22,6 @@ #include -#include "e-mail-formatter-utils.h" #include "e-mail-parser-extension.h" #include "e-mail-part-utils.h" @@ -105,10 +104,6 @@ empe_app_smime_parse (EMailParserExtension *extension, mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_SMIME); - - /* Do not traverse sub-messages */ - if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822")) - link = e_mail_formatter_find_rfc822_end_iter (link); } e_queue_transfer (&work_queue, out_mail_parts); diff --git a/src/em-format/e-mail-parser-application-smime.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser-application-smime.c.cve-2018-15587-reposition-signature-bar deleted file mode 100644 index 87f25b3..0000000 --- a/src/em-format/e-mail-parser-application-smime.c.cve-2018-15587-reposition-signature-bar +++ /dev/null @@ -1,158 +0,0 @@ -/* - * e-mail-parser-application-xpkcs7mime.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -#include "evolution-config.h" - -#include -#include - -#include - -#include "e-mail-parser-extension.h" -#include "e-mail-part-utils.h" - -typedef EMailParserExtension EMailParserApplicationSMIME; -typedef EMailParserExtensionClass EMailParserApplicationSMIMEClass; - -GType e_mail_parser_application_smime_get_type (void); - -G_DEFINE_TYPE ( - EMailParserApplicationSMIME, - e_mail_parser_application_smime, - E_TYPE_MAIL_PARSER_EXTENSION) - -static const gchar *parser_mime_types[] = { - "application/xpkcs7mime", - "application/x-pkcs7-mime", - "application/pkcs7-mime", - "application/pkcs7-signature", - "application/xpkcs7-signature", - "application/x-pkcs7-signature", - NULL -}; - -static gboolean -empe_app_smime_parse (EMailParserExtension *extension, - EMailParser *parser, - CamelMimePart *part, - GString *part_id, - GCancellable *cancellable, - GQueue *out_mail_parts) -{ - CamelCipherContext *context; - CamelMimePart *opart; - CamelCipherValidity *valid; - CamelContentType *ct; - GError *local_error = NULL; - - ct = camel_mime_part_get_content_type (part); - if (camel_content_type_is (ct, "application", "pkcs7-signature") || - camel_content_type_is (ct, "application", "xpkcs7-signature") || - camel_content_type_is (ct, "application", "x-pkcs7-signature")) { - return TRUE; - } - - context = camel_smime_context_new (e_mail_parser_get_session (parser)); - - opart = camel_mime_part_new (); - valid = camel_cipher_context_decrypt_sync ( - context, part, opart, - cancellable, &local_error); - - e_mail_part_preserve_charset_in_content_type (part, opart); - - if (local_error != NULL) { - e_mail_parser_error ( - parser, out_mail_parts, - _("Could not parse S/MIME message: %s"), - local_error->message); - g_error_free (local_error); - - } else { - GQueue work_queue = G_QUEUE_INIT; - GList *head, *link; - gint len = part_id->len; - - g_string_append (part_id, ".encrypted"); - - e_mail_parser_parse_part ( - parser, opart, part_id, cancellable, &work_queue); - - g_string_truncate (part_id, len); - - head = g_queue_peek_head_link (&work_queue); - - /* Update validity flags of all the involved subp-arts */ - for (link = head; link != NULL; link = g_list_next (link)) { - EMailPart *mail_part = link->data; - - e_mail_part_update_validity ( - mail_part, valid, - E_MAIL_PART_VALIDITY_ENCRYPTED | - E_MAIL_PART_VALIDITY_SMIME); - } - - e_queue_transfer (&work_queue, out_mail_parts); - - /* Add a widget with details about the encryption, but only - * when the encrypted isn't itself secured, in that case it - * has created the button itself. */ - if (!e_mail_part_is_secured (opart)) { - EMailPart *mail_part; - - g_string_append (part_id, ".encrypted.button"); - - e_mail_parser_parse_part_as ( - parser, part, part_id, - "application/vnd.evolution.secure-button", - cancellable, &work_queue); - - mail_part = g_queue_peek_head (&work_queue); - - if (mail_part != NULL) - e_mail_part_update_validity ( - mail_part, valid, - E_MAIL_PART_VALIDITY_ENCRYPTED | - E_MAIL_PART_VALIDITY_SMIME); - - e_queue_transfer (&work_queue, out_mail_parts); - - g_string_truncate (part_id, len); - } - - camel_cipher_validity_free (valid); - } - - g_object_unref (opart); - g_object_unref (context); - - return TRUE; -} - -static void -e_mail_parser_application_smime_class_init (EMailParserExtensionClass *class) -{ - class->mime_types = parser_mime_types; - class->priority = G_PRIORITY_LOW; - class->flags = E_MAIL_PARSER_EXTENSION_INLINE; - class->parse = empe_app_smime_parse; -} - -static void -e_mail_parser_application_smime_init (EMailParserExtension *extension) -{ -} diff --git a/src/em-format/e-mail-parser-inlinepgp-encrypted.c b/src/em-format/e-mail-parser-inlinepgp-encrypted.c index e342825..c66195c 100644 --- a/src/em-format/e-mail-parser-inlinepgp-encrypted.c +++ b/src/em-format/e-mail-parser-inlinepgp-encrypted.c @@ -22,7 +22,6 @@ #include -#include "e-mail-formatter-utils.h" #include "e-mail-parser-extension.h" #include "e-mail-part-utils.h" @@ -136,10 +135,6 @@ empe_inlinepgp_encrypted_parse (EMailParserExtension *extension, mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); - - /* Do not traverse sub-messages */ - if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822")) - link = e_mail_formatter_find_rfc822_end_iter (link); } e_queue_transfer (&work_queue, out_mail_parts); diff --git a/src/em-format/e-mail-parser-inlinepgp-encrypted.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser-inlinepgp-encrypted.c.cve-2018-15587-reposition-signature-bar deleted file mode 100644 index c66195c..0000000 --- a/src/em-format/e-mail-parser-inlinepgp-encrypted.c.cve-2018-15587-reposition-signature-bar +++ /dev/null @@ -1,186 +0,0 @@ -/* - * e-mail-parser-inlinepgp-encrypted.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -#include "evolution-config.h" - -#include -#include - -#include - -#include "e-mail-parser-extension.h" -#include "e-mail-part-utils.h" - -typedef EMailParserExtension EMailParserInlinePGPEncrypted; -typedef EMailParserExtensionClass EMailParserInlinePGPEncryptedClass; - -GType e_mail_parser_inline_pgp_encrypted_get_type (void); - -G_DEFINE_TYPE ( - EMailParserInlinePGPEncrypted, - e_mail_parser_inline_pgp_encrypted, - E_TYPE_MAIL_PARSER_EXTENSION) - -static const gchar *parser_mime_types[] = { - "application/x-inlinepgp-encrypted", - NULL -}; - -static gboolean -empe_inlinepgp_encrypted_parse (EMailParserExtension *extension, - EMailParser *parser, - CamelMimePart *part, - GString *part_id, - GCancellable *cancellable, - GQueue *out_mail_parts) -{ - CamelCipherContext *cipher; - CamelCipherValidity *valid; - CamelMimePart *opart; - CamelDataWrapper *dw; - gchar *mime_type; - gint len; - GQueue work_queue = G_QUEUE_INIT; - GList *head, *link; - GError *local_error = NULL; - - if (g_cancellable_is_cancelled (cancellable)) - return FALSE; - - cipher = camel_gpg_context_new (e_mail_parser_get_session (parser)); - - opart = camel_mime_part_new (); - - /* Decrypt the message */ - valid = camel_cipher_context_decrypt_sync ( - cipher, part, opart, cancellable, &local_error); - - if (local_error != NULL) { - e_mail_parser_error ( - parser, out_mail_parts, - _("Could not parse PGP message: %s"), - local_error->message); - g_error_free (local_error); - - e_mail_parser_parse_part_as ( - parser, - part, part_id, - "application/vnd.evolution.source", - cancellable, out_mail_parts); - - g_object_unref (cipher); - g_object_unref (opart); - - return TRUE; - } - - dw = camel_medium_get_content ((CamelMedium *) opart); - mime_type = camel_data_wrapper_get_mime_type (dw); - - /* this ensures to show the 'opart' as inlined, if possible */ - if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) { - const gchar *snoop; - - snoop = e_mail_part_snoop_type (opart); - - if (snoop != NULL) { - camel_data_wrapper_set_mime_type (dw, snoop); - - /* Set the MIME type on the 'opart' itself as well. - * If it's "text/plain", then we want the TextPlain - * parser extension to treat it as "text/plain" and - * NOT wrap it as an attachment. */ - camel_data_wrapper_set_mime_type ( - CAMEL_DATA_WRAPPER (opart), snoop); - } - } - - e_mail_part_preserve_charset_in_content_type (part, opart); - g_free (mime_type); - - /* Pass it off to the real formatter */ - len = part_id->len; - g_string_append (part_id, ".inlinepgp_encrypted"); - - mime_type = camel_data_wrapper_get_mime_type (dw); - - g_warn_if_fail (e_mail_parser_parse_part_as ( - parser, opart, part_id, mime_type, - cancellable, &work_queue)); - - g_free (mime_type); - - g_string_truncate (part_id, len); - - head = g_queue_peek_head_link (&work_queue); - - for (link = head; link != NULL; link = g_list_next (link)) { - EMailPart *mail_part = link->data; - - e_mail_part_update_validity ( - mail_part, valid, - E_MAIL_PART_VALIDITY_ENCRYPTED | - E_MAIL_PART_VALIDITY_PGP); - } - - e_queue_transfer (&work_queue, out_mail_parts); - - /* Add a widget with details about the encryption, but only when - * the encrypted isn't itself secured, in that case it has created - * the button itself */ - if (!e_mail_part_is_secured (opart)) { - EMailPart *mail_part; - - g_string_append (part_id, ".inlinepgp_encrypted.button"); - - e_mail_parser_parse_part_as ( - parser, part, part_id, - "application/vnd.evolution.secure-button", - cancellable, &work_queue); - - mail_part = g_queue_peek_head (&work_queue); - if (mail_part != NULL) - e_mail_part_update_validity ( - mail_part, valid, - E_MAIL_PART_VALIDITY_ENCRYPTED | - E_MAIL_PART_VALIDITY_PGP); - - e_queue_transfer (&work_queue, out_mail_parts); - - g_string_truncate (part_id, len); - } - - /* Clean Up */ - camel_cipher_validity_free (valid); - g_object_unref (opart); - g_object_unref (cipher); - - return TRUE; -} - -static void -e_mail_parser_inline_pgp_encrypted_class_init (EMailParserExtensionClass *class) -{ - class->mime_types = parser_mime_types; - class->priority = G_PRIORITY_LOW; - class->parse = empe_inlinepgp_encrypted_parse; -} - -static void -e_mail_parser_inline_pgp_encrypted_init (EMailParserExtension *extension) -{ -} diff --git a/src/em-format/e-mail-parser-inlinepgp-signed.c b/src/em-format/e-mail-parser-inlinepgp-signed.c index 3235a1c..2ac8c3a 100644 --- a/src/em-format/e-mail-parser-inlinepgp-signed.c +++ b/src/em-format/e-mail-parser-inlinepgp-signed.c @@ -22,7 +22,6 @@ #include -#include "e-mail-formatter-utils.h" #include "e-mail-parser-extension.h" #include "e-mail-part-utils.h" @@ -143,10 +142,6 @@ empe_inlinepgp_signed_parse (EMailParserExtension *extension, mail_part, valid, E_MAIL_PART_VALIDITY_SIGNED | E_MAIL_PART_VALIDITY_PGP); - - /* Do not traverse sub-messages */ - if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822")) - link = e_mail_formatter_find_rfc822_end_iter (link); } e_queue_transfer (&work_queue, out_mail_parts); diff --git a/src/em-format/e-mail-parser-inlinepgp-signed.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser-inlinepgp-signed.c.cve-2018-15587-reposition-signature-bar deleted file mode 100644 index 2ac8c3a..0000000 --- a/src/em-format/e-mail-parser-inlinepgp-signed.c.cve-2018-15587-reposition-signature-bar +++ /dev/null @@ -1,196 +0,0 @@ -/* - * e-mail-parser-inlinepgp-signed.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -#include "evolution-config.h" - -#include -#include - -#include - -#include "e-mail-parser-extension.h" -#include "e-mail-part-utils.h" - -typedef EMailParserExtension EMailParserInlinePGPSigned; -typedef EMailParserExtensionClass EMailParserInlinePGPSignedClass; - -GType e_mail_parser_inline_pgp_signed_get_type (void); - -G_DEFINE_TYPE ( - EMailParserInlinePGPSigned, - e_mail_parser_inline_pgp_signed, - E_TYPE_MAIL_PARSER_EXTENSION) - -static const gchar *parser_mime_types[] = { - "application/x-inlinepgp-signed", - NULL -}; - -static gboolean -empe_inlinepgp_signed_parse (EMailParserExtension *extension, - EMailParser *parser, - CamelMimePart *part, - GString *part_id, - GCancellable *cancellable, - GQueue *out_mail_parts) -{ - CamelStream *filtered_stream; - CamelMimeFilterPgp *pgp_filter; - CamelContentType *content_type; - CamelCipherContext *cipher; - CamelCipherValidity *valid; - CamelDataWrapper *dw; - CamelMimePart *opart; - CamelStream *ostream; - GQueue work_queue = G_QUEUE_INIT; - GList *head, *link; - gchar *type; - gint len; - GError *local_error = NULL; - GByteArray *ba; - - if (g_cancellable_is_cancelled (cancellable)) - return FALSE; - - cipher = camel_gpg_context_new (e_mail_parser_get_session (parser)); - - /* Verify the signature of the message */ - valid = camel_cipher_context_verify_sync ( - cipher, part, cancellable, &local_error); - - if (local_error != NULL) { - e_mail_parser_error ( - parser, out_mail_parts, - _("Error verifying signature: %s"), - local_error->message); - - g_error_free (local_error); - - e_mail_parser_parse_part_as ( - parser, part, part_id, - "application/vnd.evolution.source", - cancellable, out_mail_parts); - - g_object_unref (cipher); - - return TRUE; - } - - /* Setup output stream */ - ostream = camel_stream_mem_new (); - filtered_stream = camel_stream_filter_new (ostream); - - /* Add PGP header / footer filter */ - pgp_filter = (CamelMimeFilterPgp *) camel_mime_filter_pgp_new (); - camel_stream_filter_add ( - CAMEL_STREAM_FILTER (filtered_stream), - CAMEL_MIME_FILTER (pgp_filter)); - g_object_unref (pgp_filter); - - /* Pass through the filters that have been setup */ - dw = camel_medium_get_content ((CamelMedium *) part); - camel_data_wrapper_decode_to_stream_sync ( - dw, (CamelStream *) filtered_stream, cancellable, NULL); - camel_stream_flush ((CamelStream *) filtered_stream, cancellable, NULL); - g_object_unref (filtered_stream); - - /* Create a new text/plain MIME part containing the signed - * content preserving the original part's Content-Type params. */ - content_type = camel_mime_part_get_content_type (part); - type = camel_content_type_format (content_type); - content_type = camel_content_type_decode (type); - g_free (type); - - g_free (content_type->type); - content_type->type = g_strdup ("text"); - g_free (content_type->subtype); - content_type->subtype = g_strdup ("plain"); - type = camel_content_type_format (content_type); - camel_content_type_unref (content_type); - - ba = camel_stream_mem_get_byte_array ((CamelStreamMem *) ostream); - opart = camel_mime_part_new (); - camel_mime_part_set_content (opart, (gchar *) ba->data, ba->len, type); - g_free (type); - - len = part_id->len; - g_string_append (part_id, ".inlinepgp_signed"); - - g_warn_if_fail (e_mail_parser_parse_part ( - parser, opart, part_id, cancellable, &work_queue)); - - head = g_queue_peek_head_link (&work_queue); - - for (link = head; link != NULL; link = g_list_next (link)) { - EMailPart *mail_part = link->data; - - e_mail_part_update_validity ( - mail_part, valid, - E_MAIL_PART_VALIDITY_SIGNED | - E_MAIL_PART_VALIDITY_PGP); - } - - e_queue_transfer (&work_queue, out_mail_parts); - - g_string_truncate (part_id, len); - - /* Add a widget with details about the encryption, but only when - * the encrypted isn't itself secured, in that case it has created - * the button itself */ - if (!e_mail_part_is_secured (opart)) { - EMailPart *mail_part; - - g_string_append (part_id, ".inlinepgp_signed.button"); - - e_mail_parser_parse_part_as ( - parser, part, part_id, - "application/vnd.evolution.secure-button", - cancellable, &work_queue); - - mail_part = g_queue_peek_head (&work_queue); - if (mail_part != NULL) - e_mail_part_update_validity ( - mail_part, valid, - E_MAIL_PART_VALIDITY_SIGNED | - E_MAIL_PART_VALIDITY_PGP); - - e_queue_transfer (&work_queue, out_mail_parts); - - g_string_truncate (part_id, len); - } - - /* Clean Up */ - camel_cipher_validity_free (valid); - g_object_unref (opart); - g_object_unref (ostream); - g_object_unref (cipher); - - return TRUE; -} - -static void -e_mail_parser_inline_pgp_signed_class_init (EMailParserExtensionClass *class) -{ - class->mime_types = parser_mime_types; - class->priority = G_PRIORITY_LOW; - class->parse = empe_inlinepgp_signed_parse; -} - -static void -e_mail_parser_inline_pgp_signed_init (EMailParserExtension *extension) -{ -} diff --git a/src/em-format/e-mail-parser-multipart-encrypted.c b/src/em-format/e-mail-parser-multipart-encrypted.c index 818214c..2baa98f 100644 --- a/src/em-format/e-mail-parser-multipart-encrypted.c +++ b/src/em-format/e-mail-parser-multipart-encrypted.c @@ -21,7 +21,6 @@ #include -#include "e-mail-formatter-utils.h" #include "e-mail-parser-extension.h" #include "e-mail-part-utils.h" @@ -127,10 +126,6 @@ empe_mp_encrypted_parse (EMailParserExtension *extension, mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); - - /* Do not traverse sub-messages */ - if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822")) - link = e_mail_formatter_find_rfc822_end_iter (link); } e_queue_transfer (&work_queue, out_mail_parts); diff --git a/src/em-format/e-mail-parser-multipart-encrypted.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser-multipart-encrypted.c.cve-2018-15587-reposition-signature-bar deleted file mode 100644 index 2baa98f..0000000 --- a/src/em-format/e-mail-parser-multipart-encrypted.c.cve-2018-15587-reposition-signature-bar +++ /dev/null @@ -1,179 +0,0 @@ -/* - * e-mail-parser-multipart-encrypted.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -#include "evolution-config.h" - -#include - -#include - -#include "e-mail-parser-extension.h" -#include "e-mail-part-utils.h" - -typedef EMailParserExtension EMailParserMultipartEncrypted; -typedef EMailParserExtensionClass EMailParserMultipartEncryptedClass; - -GType e_mail_parser_multipart_encrypted_get_type (void); - -G_DEFINE_TYPE ( - EMailParserMultipartEncrypted, - e_mail_parser_multipart_encrypted, - E_TYPE_MAIL_PARSER_EXTENSION) - -static const gchar *parser_mime_types[] = { - "multipart/encrypted", - NULL -}; - -static gboolean -empe_mp_encrypted_parse (EMailParserExtension *extension, - EMailParser *parser, - CamelMimePart *part, - GString *part_id, - GCancellable *cancellable, - GQueue *out_mail_parts) -{ - CamelCipherContext *context; - const gchar *protocol; - CamelMimePart *opart; - CamelCipherValidity *valid; - CamelMultipartEncrypted *mpe; - GQueue work_queue = G_QUEUE_INIT; - GList *head, *link; - GError *local_error = NULL; - gint len; - - mpe = (CamelMultipartEncrypted *) camel_medium_get_content ((CamelMedium *) part); - if (!CAMEL_IS_MULTIPART_ENCRYPTED (mpe)) { - e_mail_parser_error ( - parser, out_mail_parts, - _("Could not parse MIME message. " - "Displaying as source.")); - e_mail_parser_parse_part_as ( - parser, part, part_id, - "application/vnd.evolution/source", - cancellable, out_mail_parts); - - return TRUE; - } - - /* Currently we only handle RFC2015-style PGP encryption. */ - protocol = camel_content_type_param (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (mpe)), "protocol"); - if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) { - e_mail_parser_error ( - parser, out_mail_parts, - _("Unsupported encryption type for multipart/encrypted")); - e_mail_parser_parse_part_as ( - parser, part, part_id, "multipart/mixed", - cancellable, out_mail_parts); - - return TRUE; - } - - context = camel_gpg_context_new (e_mail_parser_get_session (parser)); - - opart = camel_mime_part_new (); - valid = camel_cipher_context_decrypt_sync ( - context, part, opart, cancellable, &local_error); - - e_mail_part_preserve_charset_in_content_type (part, opart); - - if (local_error != NULL) { - e_mail_parser_error ( - parser, out_mail_parts, - _("Could not parse PGP/MIME message: %s"), - local_error->message); - e_mail_parser_parse_part_as ( - parser, part, part_id, "multipart/mixed", - cancellable, out_mail_parts); - - g_object_unref (opart); - g_object_unref (context); - g_error_free (local_error); - - return TRUE; - } - - len = part_id->len; - g_string_append (part_id, ".encrypted"); - - g_warn_if_fail (e_mail_parser_parse_part ( - parser, opart, part_id, cancellable, &work_queue)); - - g_string_truncate (part_id, len); - - head = g_queue_peek_head_link (&work_queue); - - /* Update validity of all encrypted sub-parts */ - for (link = head; link != NULL; link = g_list_next (link)) { - EMailPart *mail_part = link->data; - - e_mail_part_update_validity ( - mail_part, valid, - E_MAIL_PART_VALIDITY_ENCRYPTED | - E_MAIL_PART_VALIDITY_PGP); - } - - e_queue_transfer (&work_queue, out_mail_parts); - - /* Add a widget with details about the encryption, but only when - * the decrypted part isn't itself secured, in that case it has - * created the button itself. */ - if (!e_mail_part_is_secured (opart)) { - EMailPart *mail_part; - - g_string_append (part_id, ".encrypted.button"); - - e_mail_parser_parse_part_as ( - parser, part, part_id, - "application/vnd.evolution.secure-button", - cancellable, &work_queue); - - mail_part = g_queue_peek_head (&work_queue); - - if (mail_part != NULL) - e_mail_part_update_validity ( - mail_part, valid, - E_MAIL_PART_VALIDITY_ENCRYPTED | - E_MAIL_PART_VALIDITY_PGP); - - e_queue_transfer (&work_queue, out_mail_parts); - - g_string_truncate (part_id, len); - } - - camel_cipher_validity_free (valid); - - /* TODO: Make sure when we finalize this part, it is zero'd out */ - g_object_unref (opart); - g_object_unref (context); - - return TRUE; -} - -static void -e_mail_parser_multipart_encrypted_class_init (EMailParserExtensionClass *class) -{ - class->mime_types = parser_mime_types; - class->priority = G_PRIORITY_LOW; - class->parse = empe_mp_encrypted_parse; -} - -static void -e_mail_parser_multipart_encrypted_init (EMailParserExtension *extension) -{ -} diff --git a/src/em-format/e-mail-parser-multipart-signed.c b/src/em-format/e-mail-parser-multipart-signed.c index ca0133a..a76ca61 100644 --- a/src/em-format/e-mail-parser-multipart-signed.c +++ b/src/em-format/e-mail-parser-multipart-signed.c @@ -21,7 +21,6 @@ #include -#include "e-mail-formatter-utils.h" #include "e-mail-parser-extension.h" #include "e-mail-part-utils.h" @@ -171,10 +170,6 @@ empe_mp_signed_parse (EMailParserExtension *extension, e_mail_part_update_validity ( mail_part, valid, validity_type | E_MAIL_PART_VALIDITY_SIGNED); - - /* Do not traverse sub-messages */ - if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822")) - link = e_mail_formatter_find_rfc822_end_iter (link); } e_queue_transfer (&work_queue, out_mail_parts); diff --git a/src/em-format/e-mail-parser-multipart-signed.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser-multipart-signed.c.cve-2018-15587-reposition-signature-bar deleted file mode 100644 index a76ca61..0000000 --- a/src/em-format/e-mail-parser-multipart-signed.c.cve-2018-15587-reposition-signature-bar +++ /dev/null @@ -1,222 +0,0 @@ -/* - * e-mail-parser-multipart-signed.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -#include "evolution-config.h" - -#include - -#include - -#include "e-mail-parser-extension.h" -#include "e-mail-part-utils.h" - -typedef EMailParserExtension EMailParserMultipartSigned; -typedef EMailParserExtensionClass EMailParserMultipartSignedClass; - -GType e_mail_parser_multipart_signed_get_type (void); - -G_DEFINE_TYPE ( - EMailParserMultipartSigned, - e_mail_parser_multipart_signed, - E_TYPE_MAIL_PARSER_EXTENSION) - -static const gchar *parser_mime_types[] = { - "multipart/signed", - "application/pgp-signature", - NULL -}; - -static gboolean -empe_mp_signed_parse (EMailParserExtension *extension, - EMailParser *parser, - CamelMimePart *part, - GString *part_id, - GCancellable *cancellable, - GQueue *out_mail_parts) -{ - CamelMimePart *cpart = NULL; - CamelMultipart *multipart; - CamelCipherContext *cipher = NULL; - CamelContentType *content_type; - CamelSession *session; - guint32 validity_type; - CamelCipherValidity *valid; - const gchar *protocol = NULL; - GError *local_error = NULL; - gint i, nparts, len; - gboolean secured; - - /* If the part is application/pgp-signature sub-part then skip it. */ - if (!CAMEL_IS_MULTIPART (part)) { - content_type = camel_mime_part_get_content_type (part); - if (camel_content_type_is ( - content_type, "application", "pgp-signature")) { - return TRUE; - } - } - - multipart = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); - if (CAMEL_IS_MULTIPART_SIGNED (multipart)) { - cpart = camel_multipart_get_part ( - multipart, CAMEL_MULTIPART_SIGNED_CONTENT); - } - - if (cpart == NULL) { - e_mail_parser_error ( - parser, out_mail_parts, - _("Could not parse MIME message. " - "Displaying as source.")); - e_mail_parser_parse_part_as ( - parser, part, part_id, - "application/vnd.evolution.source", - cancellable, out_mail_parts); - - return TRUE; - } - - content_type = camel_data_wrapper_get_mime_type_field ( - CAMEL_DATA_WRAPPER (multipart)); - if (content_type != NULL) - protocol = camel_content_type_param (content_type, "protocol"); - - session = e_mail_parser_get_session (parser); - /* FIXME: Should be done via a plugin interface */ - /* FIXME: duplicated in em-format-html-display.c */ - if (protocol != NULL) { -#ifdef ENABLE_SMIME - if (g_ascii_strcasecmp ("application/x-pkcs7-signature", protocol) == 0 - || g_ascii_strcasecmp ("application/pkcs7-signature", protocol) == 0) { - cipher = camel_smime_context_new (session); - validity_type = E_MAIL_PART_VALIDITY_SMIME; - } else { -#endif - if (g_ascii_strcasecmp ("application/pgp-signature", protocol) == 0) { - cipher = camel_gpg_context_new (session); - validity_type = E_MAIL_PART_VALIDITY_PGP; - } -#ifdef ENABLE_SMIME - } -#endif - } - - if (cipher == NULL) { - e_mail_parser_error ( - parser, out_mail_parts, - _("Unsupported signature format")); - e_mail_parser_parse_part_as ( - parser, part, part_id, "multipart/mixed", - cancellable, out_mail_parts); - - return TRUE; - } - - valid = camel_cipher_context_verify_sync ( - cipher, part, cancellable, &local_error); - - if (local_error != NULL) { - e_mail_parser_error ( - parser, out_mail_parts, - _("Error verifying signature: %s"), - local_error->message); - e_mail_parser_parse_part_as ( - parser, part, part_id, "multipart/mixed", - cancellable, out_mail_parts); - - g_object_unref (cipher); - g_error_free (local_error); - - return TRUE; - } - - nparts = camel_multipart_get_number (multipart); - secured = FALSE; - len = part_id->len; - for (i = 0; i < nparts; i++) { - GQueue work_queue = G_QUEUE_INIT; - GList *head, *link; - CamelMimePart *subpart; - - subpart = camel_multipart_get_part (multipart, i); - - g_string_append_printf (part_id, ".signed.%d", i); - - g_warn_if_fail (e_mail_parser_parse_part ( - parser, subpart, part_id, cancellable, &work_queue)); - - g_string_truncate (part_id, len); - - if (!secured) - secured = e_mail_part_is_secured (subpart); - - head = g_queue_peek_head_link (&work_queue); - - for (link = head; link != NULL; link = g_list_next (link)) { - EMailPart *mail_part = link->data; - - e_mail_part_update_validity ( - mail_part, valid, - validity_type | E_MAIL_PART_VALIDITY_SIGNED); - } - - e_queue_transfer (&work_queue, out_mail_parts); - } - - /* Add a widget with details about the encryption, but only when - * the encrypted isn't itself secured, in that case it has created - * the button itself. */ - if (!secured) { - GQueue work_queue = G_QUEUE_INIT; - EMailPart *mail_part; - - g_string_append (part_id, ".signed.button"); - - e_mail_parser_parse_part_as ( - parser, part, part_id, - "application/vnd.evolution.secure-button", - cancellable, &work_queue); - - mail_part = g_queue_peek_head (&work_queue); - - if (mail_part != NULL) - e_mail_part_update_validity ( - mail_part, valid, - validity_type | E_MAIL_PART_VALIDITY_SIGNED); - - e_queue_transfer (&work_queue, out_mail_parts); - - g_string_truncate (part_id, len); - } - - camel_cipher_validity_free (valid); - - g_object_unref (cipher); - - return TRUE; -} - -static void -e_mail_parser_multipart_signed_class_init (EMailParserExtensionClass *class) -{ - class->mime_types = parser_mime_types; - class->priority = G_PRIORITY_LOW; - class->parse = empe_mp_signed_parse; -} - -static void -e_mail_parser_multipart_signed_init (EMailParserExtension *extension) -{ -} diff --git a/src/em-format/e-mail-parser.c b/src/em-format/e-mail-parser.c index b1f1511..96c603f 100644 --- a/src/em-format/e-mail-parser.c +++ b/src/em-format/e-mail-parser.c @@ -79,67 +79,6 @@ GType e_mail_parser_application_smime_get_type (void); static gpointer parent_class; static void -mail_parser_move_security_before_headers (GQueue *part_queue) -{ - GList *link, *last_headers = NULL; - GSList *headers_stack = NULL; - - link = g_queue_peek_head_link (part_queue); - while (link) { - EMailPart *part = link->data; - const gchar *id; - - if (!part) { - link = g_list_next (link); - continue; - } - - id = e_mail_part_get_id (part); - if (!id) { - link = g_list_next (link); - continue; - } - - if (g_str_has_suffix (id, ".rfc822")) { - headers_stack = g_slist_prepend (headers_stack, last_headers); - last_headers = NULL; - } else if (g_str_has_suffix (id, ".rfc822.end")) { - g_warn_if_fail (headers_stack != NULL); - - if (headers_stack) { - last_headers = headers_stack->data; - headers_stack = g_slist_remove (headers_stack, last_headers); - } else { - last_headers = NULL; - } - } - - if (g_strcmp0 (e_mail_part_get_mime_type (part), "application/vnd.evolution.headers") == 0) { - last_headers = link; - link = g_list_next (link); - } else if (g_strcmp0 (e_mail_part_get_mime_type (part), "application/vnd.evolution.secure-button") == 0) { - g_warn_if_fail (last_headers != NULL); - - if (last_headers) { - GList *next = g_list_next (link); - - g_warn_if_fail (g_queue_remove (part_queue, part)); - g_queue_insert_before (part_queue, last_headers, part); - - link = next; - } else { - link = g_list_next (link); - } - } else { - link = g_list_next (link); - } - } - - g_warn_if_fail (headers_stack == NULL); - g_slist_free (headers_stack); -} - -static void mail_parser_run (EMailParser *parser, EMailPartList *part_list, GCancellable *cancellable) @@ -193,8 +132,6 @@ mail_parser_run (EMailParser *parser, break; } - mail_parser_move_security_before_headers (&mail_part_queue); - while (!g_queue_is_empty (&mail_part_queue)) { mail_part = g_queue_pop_head (&mail_part_queue); e_mail_part_list_add_part (part_list, mail_part); diff --git a/src/em-format/e-mail-parser.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-parser.c.cve-2018-15587-reposition-signature-bar deleted file mode 100644 index 96c603f..0000000 --- a/src/em-format/e-mail-parser.c.cve-2018-15587-reposition-signature-bar +++ /dev/null @@ -1,832 +0,0 @@ -/* - * e-mail-parser.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -#include "evolution-config.h" - -#include "e-mail-parser.h" - -#include - -#include - -#include -#include - -#include "e-mail-parser-extension.h" -#include "e-mail-part-attachment.h" -#include "e-mail-part-utils.h" - -#define E_MAIL_PARSER_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_MAIL_PARSER, EMailParserPrivate)) - -#define d(x) - -struct _EMailParserPrivate { - GMutex mutex; - - gint last_error; - - CamelSession *session; -}; - -enum { - PROP_0, - PROP_SESSION -}; - -/* internal parser extensions */ -GType e_mail_parser_application_mbox_get_type (void); -GType e_mail_parser_audio_get_type (void); -GType e_mail_parser_headers_get_type (void); -GType e_mail_parser_message_get_type (void); -GType e_mail_parser_secure_button_get_type (void); -GType e_mail_parser_source_get_type (void); -GType e_mail_parser_image_get_type (void); -GType e_mail_parser_inline_pgp_encrypted_get_type (void); -GType e_mail_parser_inline_pgp_signed_get_type (void); -GType e_mail_parser_message_delivery_status_get_type (void); -GType e_mail_parser_message_external_get_type (void); -GType e_mail_parser_message_rfc822_get_type (void); -GType e_mail_parser_multipart_alternative_get_type (void); -GType e_mail_parser_multipart_apple_double_get_type (void); -GType e_mail_parser_multipart_digest_get_type (void); -GType e_mail_parser_multipart_encrypted_get_type (void); -GType e_mail_parser_multipart_mixed_get_type (void); -GType e_mail_parser_multipart_related_get_type (void); -GType e_mail_parser_multipart_signed_get_type (void); -GType e_mail_parser_text_enriched_get_type (void); -GType e_mail_parser_text_html_get_type (void); -GType e_mail_parser_text_plain_get_type (void); -#ifdef ENABLE_SMIME -GType e_mail_parser_application_smime_get_type (void); -#endif - -static gpointer parent_class; - -static void -mail_parser_run (EMailParser *parser, - EMailPartList *part_list, - GCancellable *cancellable) -{ - EMailExtensionRegistry *reg; - CamelMimeMessage *message; - EMailPart *mail_part; - GQueue *parsers; - GQueue mail_part_queue = G_QUEUE_INIT; - GList *iter; - GString *part_id; - - message = e_mail_part_list_get_message (part_list); - - reg = e_mail_parser_get_extension_registry (parser); - - parsers = e_mail_extension_registry_get_for_mime_type ( - reg, "application/vnd.evolution.message"); - - if (parsers == NULL) - parsers = e_mail_extension_registry_get_for_mime_type ( - reg, "message/*"); - - /* No parsers means the internal Evolution parser - * extensions were not loaded. Something is terribly wrong! */ - g_return_if_fail (parsers != NULL); - - part_id = g_string_new (".message"); - - mail_part = e_mail_part_new (CAMEL_MIME_PART (message), ".message"); - e_mail_part_list_add_part (part_list, mail_part); - g_object_unref (mail_part); - - for (iter = parsers->head; iter; iter = iter->next) { - EMailParserExtension *extension; - gboolean message_handled; - - if (g_cancellable_is_cancelled (cancellable)) - break; - - extension = iter->data; - if (!extension) - continue; - - message_handled = e_mail_parser_extension_parse ( - extension, parser, - CAMEL_MIME_PART (message), - part_id, cancellable, &mail_part_queue); - - if (message_handled) - break; - } - - while (!g_queue_is_empty (&mail_part_queue)) { - mail_part = g_queue_pop_head (&mail_part_queue); - e_mail_part_list_add_part (part_list, mail_part); - g_object_unref (mail_part); - } - - g_string_free (part_id, TRUE); -} - -static void -shell_gone_cb (gpointer user_data, - GObject *gone_extension_registry) -{ - EMailParserClass *class = user_data; - - g_return_if_fail (class != NULL); - - g_clear_object (&class->extension_registry); -} - -static void -mail_parser_set_session (EMailParser *parser, - CamelSession *session) -{ - g_return_if_fail (CAMEL_IS_SESSION (session)); - g_return_if_fail (parser->priv->session == NULL); - - parser->priv->session = g_object_ref (session); -} - -static void -e_mail_parser_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_SESSION: - mail_parser_set_session ( - E_MAIL_PARSER (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -e_mail_parser_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_SESSION: - g_value_set_object ( - value, - e_mail_parser_get_session ( - E_MAIL_PARSER (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -e_mail_parser_finalize (GObject *object) -{ - EMailParserPrivate *priv; - - priv = E_MAIL_PARSER_GET_PRIVATE (object); - - g_clear_object (&priv->session); - g_mutex_clear (&priv->mutex); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -e_mail_parser_base_init (EMailParserClass *class) -{ - EShell *shell; - - /* Register internal extensions. */ - g_type_ensure (e_mail_parser_application_mbox_get_type ()); - /* This is currently disabled, because the WebKit player requires javascript, - which is disabled in Evolution. */ - /* g_type_ensure (e_mail_parser_audio_get_type ()); */ - g_type_ensure (e_mail_parser_headers_get_type ()); - g_type_ensure (e_mail_parser_message_get_type ()); - g_type_ensure (e_mail_parser_secure_button_get_type ()); - g_type_ensure (e_mail_parser_source_get_type ()); - g_type_ensure (e_mail_parser_image_get_type ()); - g_type_ensure (e_mail_parser_inline_pgp_encrypted_get_type ()); - g_type_ensure (e_mail_parser_inline_pgp_signed_get_type ()); - g_type_ensure (e_mail_parser_message_delivery_status_get_type ()); - g_type_ensure (e_mail_parser_message_external_get_type ()); - g_type_ensure (e_mail_parser_message_rfc822_get_type ()); - g_type_ensure (e_mail_parser_multipart_alternative_get_type ()); - g_type_ensure (e_mail_parser_multipart_apple_double_get_type ()); - g_type_ensure (e_mail_parser_multipart_digest_get_type ()); - g_type_ensure (e_mail_parser_multipart_encrypted_get_type ()); - g_type_ensure (e_mail_parser_multipart_mixed_get_type ()); - g_type_ensure (e_mail_parser_multipart_related_get_type ()); - g_type_ensure (e_mail_parser_multipart_signed_get_type ()); - g_type_ensure (e_mail_parser_text_enriched_get_type ()); - g_type_ensure (e_mail_parser_text_html_get_type ()); - g_type_ensure (e_mail_parser_text_plain_get_type ()); -#ifdef ENABLE_SMIME - g_type_ensure (e_mail_parser_application_smime_get_type ()); -#endif - - class->extension_registry = g_object_new ( - E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, NULL); - - e_mail_parser_extension_registry_load (class->extension_registry); - - e_extensible_load_extensions (E_EXTENSIBLE (class->extension_registry)); - - shell = e_shell_get_default (); - g_object_weak_ref (G_OBJECT (shell), shell_gone_cb, class); -} - -static void -e_mail_parser_class_init (EMailParserClass *class) -{ - GObjectClass *object_class; - - parent_class = g_type_class_peek_parent (class); - g_type_class_add_private (class, sizeof (EMailParserPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->finalize = e_mail_parser_finalize; - object_class->set_property = e_mail_parser_set_property; - object_class->get_property = e_mail_parser_get_property; - - g_object_class_install_property ( - object_class, - PROP_SESSION, - g_param_spec_object ( - "session", - "Camel Session", - NULL, - CAMEL_TYPE_SESSION, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); -} - -static void -e_mail_parser_init (EMailParser *parser) -{ - parser->priv = E_MAIL_PARSER_GET_PRIVATE (parser); - - g_mutex_init (&parser->priv->mutex); -} - -GType -e_mail_parser_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - static const GTypeInfo type_info = { - sizeof (EMailParserClass), - (GBaseInitFunc) e_mail_parser_base_init, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) e_mail_parser_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EMailParser), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_mail_parser_init, - NULL /* value_table */ - }; - - type = g_type_register_static ( - G_TYPE_OBJECT, "EMailParser", - &type_info, 0); - } - - return type; -} - -EMailParser * -e_mail_parser_new (CamelSession *session) -{ - g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL); - - return g_object_new ( - E_TYPE_MAIL_PARSER, - "session", session, NULL); -} - -/** - * e_mail_parser_parse_sync: - * @parser: an #EMailParser - * @folder: (allow none) a #CamelFolder containing the @message or %NULL - * @message_uid: (allow none) UID of the @message within the @folder or %NULL - * @message: a #CamelMimeMessage - * @cancellable: (allow-none) a #GCancellable - * - * Parses the @message synchronously. Returns a list of #EMailParts which - * represents structure of the message and additional properties of each part. - * - * Note that this function can block for a while, so it's not a good idea to call - * it from main thread. - * - * Return Value: An #EMailPartsList - */ -EMailPartList * -e_mail_parser_parse_sync (EMailParser *parser, - CamelFolder *folder, - const gchar *message_uid, - CamelMimeMessage *message, - GCancellable *cancellable) -{ - EMailPartList *part_list; - - g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL); - g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); - - part_list = e_mail_part_list_new (message, message_uid, folder); - - mail_parser_run (parser, part_list, cancellable); - - if (camel_debug_start ("emformat:parser")) { - GQueue queue = G_QUEUE_INIT; - - printf ( - "%s finished with EMailPartList:\n", - G_OBJECT_TYPE_NAME (parser)); - - e_mail_part_list_queue_parts (part_list, NULL, &queue); - - while (!g_queue_is_empty (&queue)) { - EMailPart *part; - - part = g_queue_pop_head (&queue); - - printf ( - " id: %s | cid: %s | mime_type: %s | " - "is_hidden: %d | is_attachment: %d\n", - e_mail_part_get_id (part), - e_mail_part_get_cid (part), - e_mail_part_get_mime_type (part), - part->is_hidden ? 1 : 0, - e_mail_part_get_is_attachment (part) ? 1 : 0); - - g_object_unref (part); - } - - camel_debug_end (); - } - - return part_list; -} - -static void -mail_parser_parse_thread (GSimpleAsyncResult *simple, - GObject *source_object, - GCancellable *cancellable) -{ - EMailPartList *part_list; - - part_list = g_simple_async_result_get_op_res_gpointer (simple); - - mail_parser_run ( - E_MAIL_PARSER (source_object), - part_list, cancellable); -} - -/** - * e_mail_parser_parse: - * @parser: an #EMailParser - * @message: a #CamelMimeMessage - * @callback: a #GAsyncReadyCallback - * @cancellable: (allow-none) a #GCancellable - * @user_data: (allow-none) user data passed to the callback - * - * Asynchronous version of e_mail_parser_parse_sync(). - */ -void -e_mail_parser_parse (EMailParser *parser, - CamelFolder *folder, - const gchar *message_uid, - CamelMimeMessage *message, - GAsyncReadyCallback callback, - GCancellable *cancellable, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - EMailPartList *part_list; - - g_return_if_fail (E_IS_MAIL_PARSER (parser)); - g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - - part_list = e_mail_part_list_new (message, message_uid, folder); - - simple = g_simple_async_result_new ( - G_OBJECT (parser), callback, - user_data, e_mail_parser_parse); - - g_simple_async_result_set_check_cancellable (simple, cancellable); - - g_simple_async_result_set_op_res_gpointer ( - simple, part_list, (GDestroyNotify) g_object_unref); - - g_simple_async_result_run_in_thread ( - simple, mail_parser_parse_thread, - G_PRIORITY_DEFAULT, cancellable); - - g_object_unref (simple); -} - -EMailPartList * -e_mail_parser_parse_finish (EMailParser *parser, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - EMailPartList *part_list; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (parser), e_mail_parser_parse), NULL); - - simple = G_SIMPLE_ASYNC_RESULT (result); - part_list = g_simple_async_result_get_op_res_gpointer (simple); - - if (camel_debug_start ("emformat:parser")) { - GQueue queue = G_QUEUE_INIT; - - printf ( - "%s finished with EMailPartList:\n", - G_OBJECT_TYPE_NAME (parser)); - - e_mail_part_list_queue_parts (part_list, NULL, &queue); - - while (!g_queue_is_empty (&queue)) { - EMailPart *part; - - part = g_queue_pop_head (&queue); - - printf ( - " id: %s | cid: %s | mime_type: %s | " - "is_hidden: %d | is_attachment: %d\n", - e_mail_part_get_id (part), - e_mail_part_get_cid (part), - e_mail_part_get_mime_type (part), - part->is_hidden ? 1 : 0, - e_mail_part_get_is_attachment (part) ? 1 : 0); - - g_object_unref (part); - } - - camel_debug_end (); - } - - return g_object_ref (part_list); -} - -GQueue * -e_mail_parser_get_parsers_for_part (EMailParser *parser, - CamelMimePart *part) -{ - CamelContentType *ct; - gchar *mime_type; - GQueue *parsers; - - g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL); - g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL); - - ct = camel_mime_part_get_content_type (part); - if (!ct) { - mime_type = (gchar *) "application/vnd.evolution.error"; - } else { - gchar *tmp; - tmp = camel_content_type_simple (ct); - mime_type = g_ascii_strdown (tmp, -1); - g_free (tmp); - } - - parsers = e_mail_parser_get_parsers (parser, mime_type); - - if (ct) - g_free (mime_type); - - return parsers; -} - -GQueue * -e_mail_parser_get_parsers (EMailParser *parser, - const gchar *mime_type) -{ - EMailExtensionRegistry *reg; - EMailParserClass *parser_class; - gchar *as_mime_type; - GQueue *parsers; - - g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL); - - parser_class = E_MAIL_PARSER_GET_CLASS (parser); - g_return_val_if_fail (parser_class != NULL, NULL); - - if (mime_type) - as_mime_type = g_ascii_strdown (mime_type, -1); - else - as_mime_type = NULL; - - reg = E_MAIL_EXTENSION_REGISTRY (parser_class->extension_registry); - - parsers = e_mail_extension_registry_get_for_mime_type (reg, as_mime_type); - if (!parsers) - parsers = e_mail_extension_registry_get_fallback (reg, as_mime_type); - - g_free (as_mime_type); - - return parsers; -} - -gboolean -e_mail_parser_parse_part (EMailParser *parser, - CamelMimePart *part, - GString *part_id, - GCancellable *cancellable, - GQueue *out_mail_parts) -{ - CamelContentType *ct; - gchar *mime_type; - gint handled; - - ct = camel_mime_part_get_content_type (part); - if (!ct) { - mime_type = (gchar *) "application/vnd.evolution.error"; - } else { - gchar *tmp; - tmp = camel_content_type_simple (ct); - mime_type = g_ascii_strdown (tmp, -1); - g_free (tmp); - } - - handled = e_mail_parser_parse_part_as ( - parser, part, part_id, mime_type, - cancellable, out_mail_parts); - - if (ct) { - g_free (mime_type); - } - - return handled; -} - -gboolean -e_mail_parser_parse_part_as (EMailParser *parser, - CamelMimePart *part, - GString *part_id, - const gchar *mime_type, - GCancellable *cancellable, - GQueue *out_mail_parts) -{ - GQueue *parsers; - GList *iter; - gboolean mime_part_handled = FALSE; - - parsers = e_mail_parser_get_parsers (parser, mime_type); - - if (parsers == NULL) { - e_mail_parser_wrap_as_attachment ( - parser, part, part_id, out_mail_parts); - return TRUE; - } - - for (iter = parsers->head; iter; iter = iter->next) { - EMailParserExtension *extension; - - extension = iter->data; - if (!extension) - continue; - - mime_part_handled = e_mail_parser_extension_parse ( - extension, parser, part, part_id, - cancellable, out_mail_parts); - - if (mime_part_handled) - break; - } - - return mime_part_handled; -} - -void -e_mail_parser_error (EMailParser *parser, - GQueue *out_mail_parts, - const gchar *format, - ...) -{ - const gchar *mime_type = "application/vnd.evolution.error"; - EMailPart *mail_part; - CamelMimePart *part; - gchar *errmsg; - gchar *uri; - va_list ap; - - g_return_if_fail (E_IS_MAIL_PARSER (parser)); - g_return_if_fail (out_mail_parts != NULL); - g_return_if_fail (format != NULL); - - va_start (ap, format); - errmsg = g_strdup_vprintf (format, ap); - - part = camel_mime_part_new (); - camel_mime_part_set_content ( - part, errmsg, strlen (errmsg), mime_type); - g_free (errmsg); - va_end (ap); - - g_mutex_lock (&parser->priv->mutex); - parser->priv->last_error++; - uri = g_strdup_printf (".error.%d", parser->priv->last_error); - g_mutex_unlock (&parser->priv->mutex); - - mail_part = e_mail_part_new (part, uri); - e_mail_part_set_mime_type (mail_part, mime_type); - mail_part->is_error = TRUE; - - g_free (uri); - g_object_unref (part); - - g_queue_push_tail (out_mail_parts, mail_part); -} - -static void -attachment_loaded (EAttachment *attachment, - GAsyncResult *res, - gpointer user_data) -{ - EShell *shell; - GtkWindow *window; - - shell = e_shell_get_default (); - window = e_shell_get_active_window (shell); - - e_attachment_load_handle_error (attachment, res, window); - - g_object_unref (attachment); -} - -/* Idle callback */ -static gboolean -load_attachment_idle (EAttachment *attachment) -{ - e_attachment_load_async ( - attachment, - (GAsyncReadyCallback) attachment_loaded, NULL); - - return FALSE; -} - -void -e_mail_parser_wrap_as_attachment (EMailParser *parser, - CamelMimePart *part, - GString *part_id, - GQueue *parts_queue) -{ - EMailPartAttachment *empa; - EAttachment *attachment; - EMailPart *first_part; - const gchar *snoop_mime_type; - GQueue *extensions; - CamelContentType *ct; - gchar *mime_type; - CamelDataWrapper *dw; - GByteArray *ba; - gsize size; - gint part_id_len; - - ct = camel_mime_part_get_content_type (part); - extensions = NULL; - snoop_mime_type = NULL; - if (ct) { - EMailExtensionRegistry *reg; - mime_type = camel_content_type_simple (ct); - - reg = e_mail_parser_get_extension_registry (parser); - extensions = e_mail_extension_registry_get_for_mime_type ( - reg, mime_type); - - if (camel_content_type_is (ct, "text", "*") || - camel_content_type_is (ct, "message", "*")) - snoop_mime_type = mime_type; - else - g_free (mime_type); - } - - if (!snoop_mime_type) - snoop_mime_type = e_mail_part_snoop_type (part); - - if (!extensions) { - EMailExtensionRegistry *reg; - - reg = e_mail_parser_get_extension_registry (parser); - extensions = e_mail_extension_registry_get_for_mime_type ( - reg, snoop_mime_type); - - if (!extensions) { - extensions = e_mail_extension_registry_get_fallback ( - reg, snoop_mime_type); - } - } - - part_id_len = part_id->len; - g_string_append (part_id, ".attachment"); - - empa = e_mail_part_attachment_new (part, part_id->str); - empa->shown = extensions && (!g_queue_is_empty (extensions) && - e_mail_part_is_inline (part, extensions)); - empa->snoop_mime_type = snoop_mime_type; - - first_part = g_queue_peek_head (parts_queue); - if (first_part != NULL && !E_IS_MAIL_PART_ATTACHMENT (first_part)) { - const gchar *id = e_mail_part_get_id (first_part); - empa->part_id_with_attachment = g_strdup (id); - first_part->is_hidden = TRUE; - } - - attachment = e_mail_part_attachment_ref_attachment (empa); - - e_attachment_set_initially_shown (attachment, empa->shown); - e_attachment_set_can_show ( - attachment, - extensions && !g_queue_is_empty (extensions)); - - /* Try to guess size of the attachments */ - dw = camel_medium_get_content (CAMEL_MEDIUM (part)); - ba = camel_data_wrapper_get_byte_array (dw); - if (ba) { - size = ba->len; - - if (camel_mime_part_get_encoding (part) == CAMEL_TRANSFER_ENCODING_BASE64) - size = size / 1.37; - } else { - size = 0; - } - - /* e_attachment_load_async must be called from main thread */ - /* Prioritize ahead of GTK+ redraws. */ - g_idle_add_full ( - G_PRIORITY_HIGH_IDLE, - (GSourceFunc) load_attachment_idle, - g_object_ref (attachment), - NULL); - - if (size != 0) { - GFileInfo *file_info; - - file_info = e_attachment_ref_file_info (attachment); - - if (file_info == NULL) { - file_info = g_file_info_new (); - g_file_info_set_content_type ( - file_info, empa->snoop_mime_type); - } - - g_file_info_set_size (file_info, size); - e_attachment_set_file_info (attachment, file_info); - - g_object_unref (file_info); - } - - g_object_unref (attachment); - - g_string_truncate (part_id, part_id_len); - - /* Push to head, not tail. */ - g_queue_push_head (parts_queue, empa); -} - -CamelSession * -e_mail_parser_get_session (EMailParser *parser) -{ - g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL); - - return parser->priv->session; -} - -EMailExtensionRegistry * -e_mail_parser_get_extension_registry (EMailParser *parser) -{ - EMailParserClass *parser_class; - - g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL); - - parser_class = E_MAIL_PARSER_GET_CLASS (parser); - g_return_val_if_fail (parser_class != NULL, NULL); - - return E_MAIL_EXTENSION_REGISTRY (parser_class->extension_registry); -} diff --git a/src/em-format/e-mail-part.c b/src/em-format/e-mail-part.c index 03271ce..135005e 100644 --- a/src/em-format/e-mail-part.c +++ b/src/em-format/e-mail-part.c @@ -662,15 +662,6 @@ e_mail_part_update_validity (EMailPart *part, mask = E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SMIME; - /* Auto-add flags when the related part is present */ - if (!(validity_type & E_MAIL_PART_VALIDITY_SIGNED) && - validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) - validity_type |= E_MAIL_PART_VALIDITY_SIGNED; - - if (!(validity_type & E_MAIL_PART_VALIDITY_ENCRYPTED) && - validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) - validity_type |= E_MAIL_PART_VALIDITY_ENCRYPTED; - pair = mail_part_find_validity_pair (part, validity_type & mask); if (pair != NULL) { pair->validity_type |= validity_type; diff --git a/src/em-format/e-mail-part.c.cve-2018-15587-reposition-signature-bar b/src/em-format/e-mail-part.c.cve-2018-15587-reposition-signature-bar deleted file mode 100644 index 135005e..0000000 --- a/src/em-format/e-mail-part.c.cve-2018-15587-reposition-signature-bar +++ /dev/null @@ -1,798 +0,0 @@ -/* - * e-mail-part.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -/** - * EMailPart: - * - * The #EMailPart is a wrapper around #CamelMimePart which holds additional - * information about the mime part, like it's ID, encryption type etc. - * - * Each #EMailPart must have a unique ID. The ID is a dot-separated - * hierarchical description of the location of the part within the email - * message. - */ - -#include "evolution-config.h" - -#include "e-mail-part.h" - -#include - -#include "e-mail-part-attachment.h" -#include "e-mail-part-list.h" - -#define E_MAIL_PART_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_MAIL_PART, EMailPartPrivate)) - -struct _EMailPartPrivate { - GWeakRef part_list; - CamelMimePart *mime_part; - - gchar *id; - gchar *cid; - gchar *mime_type; - - gboolean is_attachment; - gboolean converted_to_utf8; -}; - -enum { - PROP_0, - PROP_CID, - PROP_CONVERTED_TO_UTF8, - PROP_ID, - PROP_IS_ATTACHMENT, - PROP_MIME_PART, - PROP_MIME_TYPE, - PROP_PART_LIST -}; - -G_DEFINE_TYPE_WITH_CODE ( - EMailPart, - e_mail_part, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE ( - E_TYPE_EXTENSIBLE, NULL)) - -static void -mail_part_validity_pair_free (gpointer ptr) -{ - EMailPartValidityPair *pair = ptr; - - if (!pair) - return; - - camel_cipher_validity_free (pair->validity); - g_free (pair); -} - -static void -mail_part_set_id (EMailPart *part, - const gchar *id) -{ - g_return_if_fail (part->priv->id == NULL); - - part->priv->id = g_strdup (id); -} - -static void -mail_part_set_mime_part (EMailPart *part, - CamelMimePart *mime_part) -{ - g_return_if_fail (part->priv->mime_part == NULL); - - /* The CamelMimePart is optional. */ - if (mime_part != NULL) - part->priv->mime_part = g_object_ref (mime_part); -} - -static void -mail_part_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_CID: - e_mail_part_set_cid ( - E_MAIL_PART (object), - g_value_get_string (value)); - return; - - case PROP_CONVERTED_TO_UTF8: - e_mail_part_set_converted_to_utf8 ( - E_MAIL_PART (object), - g_value_get_boolean (value)); - return; - - case PROP_ID: - mail_part_set_id ( - E_MAIL_PART (object), - g_value_get_string (value)); - return; - - case PROP_IS_ATTACHMENT: - e_mail_part_set_is_attachment ( - E_MAIL_PART (object), - g_value_get_boolean (value)); - return; - - case PROP_MIME_PART: - mail_part_set_mime_part ( - E_MAIL_PART (object), - g_value_get_object (value)); - return; - - case PROP_MIME_TYPE: - e_mail_part_set_mime_type ( - E_MAIL_PART (object), - g_value_get_string (value)); - return; - - case PROP_PART_LIST: - e_mail_part_set_part_list ( - E_MAIL_PART (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_part_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_CID: - g_value_set_string ( - value, - e_mail_part_get_cid ( - E_MAIL_PART (object))); - return; - - case PROP_CONVERTED_TO_UTF8: - g_value_set_boolean ( - value, - e_mail_part_get_converted_to_utf8 ( - E_MAIL_PART (object))); - return; - - case PROP_ID: - g_value_set_string ( - value, - e_mail_part_get_id ( - E_MAIL_PART (object))); - return; - - case PROP_IS_ATTACHMENT: - g_value_set_boolean ( - value, - e_mail_part_get_is_attachment ( - E_MAIL_PART (object))); - return; - - case PROP_MIME_PART: - g_value_take_object ( - value, - e_mail_part_ref_mime_part ( - E_MAIL_PART (object))); - return; - - case PROP_MIME_TYPE: - g_value_set_string ( - value, - e_mail_part_get_mime_type ( - E_MAIL_PART (object))); - return; - - case PROP_PART_LIST: - g_value_take_object ( - value, - e_mail_part_ref_part_list ( - E_MAIL_PART (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_part_dispose (GObject *object) -{ - EMailPartPrivate *priv; - - priv = E_MAIL_PART_GET_PRIVATE (object); - - g_weak_ref_set (&priv->part_list, NULL); - - g_clear_object (&priv->mime_part); - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_mail_part_parent_class)->dispose (object); -} - -static void -mail_part_finalize (GObject *object) -{ - EMailPart *part = E_MAIL_PART (object); - EMailPartValidityPair *pair; - - g_free (part->priv->id); - g_free (part->priv->cid); - g_free (part->priv->mime_type); - - while ((pair = g_queue_pop_head (&part->validities)) != NULL) - mail_part_validity_pair_free (pair); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (e_mail_part_parent_class)->finalize (object); -} - -static void -mail_part_constructed (GObject *object) -{ - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_mail_part_parent_class)->constructed (object); - - e_extensible_load_extensions (E_EXTENSIBLE (object)); -} - -static void -e_mail_part_class_init (EMailPartClass *class) -{ - GObjectClass *object_class; - - g_type_class_add_private (class, sizeof (EMailPartPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = mail_part_set_property; - object_class->get_property = mail_part_get_property; - object_class->dispose = mail_part_dispose; - object_class->finalize = mail_part_finalize; - object_class->constructed = mail_part_constructed; - - g_object_class_install_property ( - object_class, - PROP_CID, - g_param_spec_string ( - "cid", - "Content ID", - "The MIME Content-ID", - NULL, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_CONVERTED_TO_UTF8, - g_param_spec_boolean ( - "converted-to-utf8", - "Converted To UTF8", - "Whether the part content was already converted to UTF-8", - FALSE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_ID, - g_param_spec_string ( - "id", - "Part ID", - "The part ID", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_IS_ATTACHMENT, - g_param_spec_boolean ( - "is-attachment", - "Is Attachment", - "Format the part as an attachment", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_MIME_PART, - g_param_spec_object ( - "mime-part", - "MIME Part", - "The MIME part", - CAMEL_TYPE_MIME_PART, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_MIME_TYPE, - g_param_spec_string ( - "mime-type", - "MIME Type", - "The MIME type", - NULL, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_PART_LIST, - g_param_spec_object ( - "part-list", - "Part List", - "The part list that owns the part", - E_TYPE_MAIL_PART_LIST, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); -} - -static void -e_mail_part_init (EMailPart *part) -{ - part->priv = E_MAIL_PART_GET_PRIVATE (part); -} - -/** - * e_mail_part_new: - * @mime_part: (allow-none) a #CamelMimePart or %NULL - * @id: part ID - * - * Creates a new #EMailPart for the given @mime_part. - * - * Return value: a new #EMailPart - */ -EMailPart * -e_mail_part_new (CamelMimePart *mime_part, - const gchar *id) -{ - g_return_val_if_fail (id != NULL, NULL); - - return g_object_new ( - E_TYPE_MAIL_PART, - "id", id, "mime-part", mime_part, NULL); -} - -const gchar * -e_mail_part_get_id (EMailPart *part) -{ - g_return_val_if_fail (E_IS_MAIL_PART (part), NULL); - - return part->priv->id; -} - -const gchar * -e_mail_part_get_cid (EMailPart *part) -{ - g_return_val_if_fail (E_IS_MAIL_PART (part), NULL); - - return part->priv->cid; -} - -void -e_mail_part_set_cid (EMailPart *part, - const gchar *cid) -{ - g_return_if_fail (E_IS_MAIL_PART (part)); - - g_free (part->priv->cid); - part->priv->cid = g_strdup (cid); - - g_object_notify (G_OBJECT (part), "cid"); -} - -gboolean -e_mail_part_id_has_prefix (EMailPart *part, - const gchar *prefix) -{ - g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE); - g_return_val_if_fail (prefix != NULL, FALSE); - - return g_str_has_prefix (part->priv->id, prefix); -} - -gboolean -e_mail_part_id_has_suffix (EMailPart *part, - const gchar *suffix) -{ - g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE); - g_return_val_if_fail (suffix != NULL, FALSE); - - return g_str_has_suffix (part->priv->id, suffix); -} - -gboolean -e_mail_part_id_has_substr (EMailPart *part, - const gchar *substr) -{ - g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE); - g_return_val_if_fail (substr != NULL, FALSE); - - return (strstr (part->priv->id, substr) != NULL); -} - -CamelMimePart * -e_mail_part_ref_mime_part (EMailPart *part) -{ - CamelMimePart *mime_part = NULL; - - g_return_val_if_fail (E_IS_MAIL_PART (part), NULL); - - if (part->priv->mime_part != NULL) - mime_part = g_object_ref (part->priv->mime_part); - - return mime_part; -} - -const gchar * -e_mail_part_get_mime_type (EMailPart *part) -{ - g_return_val_if_fail (E_IS_MAIL_PART (part), NULL); - - return part->priv->mime_type; -} - -void -e_mail_part_set_mime_type (EMailPart *part, - const gchar *mime_type) -{ - g_return_if_fail (E_IS_MAIL_PART (part)); - - if (g_strcmp0 (mime_type, part->priv->mime_type) == 0) - return; - - g_free (part->priv->mime_type); - part->priv->mime_type = g_strdup (mime_type); - - g_object_notify (G_OBJECT (part), "mime-type"); -} - -gboolean -e_mail_part_get_converted_to_utf8 (EMailPart *part) -{ - g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE); - - return part->priv->converted_to_utf8; -} - -void -e_mail_part_set_converted_to_utf8 (EMailPart *part, - gboolean converted_to_utf8) -{ - g_return_if_fail (E_IS_MAIL_PART (part)); - - if (converted_to_utf8 == part->priv->converted_to_utf8) - return; - - part->priv->converted_to_utf8 = converted_to_utf8; - - g_object_notify (G_OBJECT (part), "converted-to-utf8"); -} - -gboolean -e_mail_part_should_show_inline (EMailPart *part) -{ - CamelMimePart *mime_part; - const CamelContentDisposition *disposition; - gboolean res = FALSE; - - g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE); - - /* Automatically expand attachments that have inline - * disposition or the EMailParts have specific - * force_inline flag set. */ - - if (part->force_collapse) - return FALSE; - - if (part->force_inline) - return TRUE; - - if (E_IS_MAIL_PART_ATTACHMENT (part)) { - EMailPartAttachment *empa = E_MAIL_PART_ATTACHMENT (part); - - if (g_strcmp0 (empa->snoop_mime_type, "message/rfc822") == 0) - return TRUE; - } - - mime_part = e_mail_part_ref_mime_part (part); - if (!mime_part) - return FALSE; - - disposition = camel_mime_part_get_content_disposition (mime_part); - if (disposition && disposition->disposition && - g_ascii_strncasecmp (disposition->disposition, "inline", 6) == 0) { - GSettings *settings; - - settings = e_util_ref_settings ("org.gnome.evolution.mail"); - res = g_settings_get_boolean (settings, "display-content-disposition-inline"); - g_clear_object (&settings); - } - - g_object_unref (mime_part); - - return res; -} - -EMailPartList * -e_mail_part_ref_part_list (EMailPart *part) -{ - g_return_val_if_fail (E_IS_MAIL_PART (part), NULL); - - return g_weak_ref_get (&part->priv->part_list); -} - -void -e_mail_part_set_part_list (EMailPart *part, - EMailPartList *part_list) -{ - g_return_if_fail (E_IS_MAIL_PART (part)); - - if (part_list != NULL) - g_return_if_fail (E_IS_MAIL_PART_LIST (part_list)); - - g_weak_ref_set (&part->priv->part_list, part_list); - - g_object_notify (G_OBJECT (part), "part-list"); -} - -gboolean -e_mail_part_get_is_attachment (EMailPart *part) -{ - g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE); - - return part->priv->is_attachment; -} - -void -e_mail_part_set_is_attachment (EMailPart *part, - gboolean is_attachment) -{ - g_return_if_fail (E_IS_MAIL_PART (part)); - - if (is_attachment == part->priv->is_attachment) - return; - - part->priv->is_attachment = is_attachment; - - g_object_notify (G_OBJECT (part), "is-attachment"); -} - -void -e_mail_part_bind_dom_element (EMailPart *part, - EWebView *web_view, - guint64 page_id, - const gchar *element_id) -{ - EMailPartClass *class; - - g_return_if_fail (E_IS_MAIL_PART (part)); - g_return_if_fail (E_IS_WEB_VIEW (web_view)); - g_return_if_fail (page_id != 0); - g_return_if_fail (element_id && *element_id); - - class = E_MAIL_PART_GET_CLASS (part); - g_return_if_fail (class != NULL); - - if (class->bind_dom_element != NULL) - class->bind_dom_element (part, web_view, page_id, element_id); -} - -void -e_mail_part_web_view_loaded (EMailPart *part, - EWebView *web_view) -{ - EMailPartClass *klass; - - g_return_if_fail (E_IS_MAIL_PART (part)); - g_return_if_fail (E_IS_WEB_VIEW (web_view)); - - klass = E_MAIL_PART_GET_CLASS (part); - g_return_if_fail (klass != NULL); - - if (klass->web_view_loaded) - klass->web_view_loaded (part, web_view); -} - -static EMailPartValidityPair * -mail_part_find_validity_pair (EMailPart *part, - EMailPartValidityFlags validity_type) -{ - GList *head, *link; - - head = g_queue_peek_head_link (&part->validities); - - for (link = head; link != NULL; link = g_list_next (link)) { - EMailPartValidityPair *pair = link->data; - - if (pair == NULL) - continue; - - if ((pair->validity_type & validity_type) == validity_type) - return pair; - } - - return NULL; -} - -/** - * e_mail_part_update_validity: - * @part: An #EMailPart - * @validity: a #CamelCipherValidity - * @validity_type: E_MAIL_PART_VALIDITY_* flags - * - * Updates validity of the @part. When the part already has some validity - * set, the new @validity and @validity_type are just appended, preserving - * the original validity. Validities of the same type (PGP or S/MIME) are - * merged together. - */ -void -e_mail_part_update_validity (EMailPart *part, - CamelCipherValidity *validity, - EMailPartValidityFlags validity_type) -{ - EMailPartValidityPair *pair; - EMailPartValidityFlags mask; - - g_return_if_fail (E_IS_MAIL_PART (part)); - g_return_if_fail (validity != NULL); - - mask = E_MAIL_PART_VALIDITY_PGP | E_MAIL_PART_VALIDITY_SMIME; - - pair = mail_part_find_validity_pair (part, validity_type & mask); - if (pair != NULL) { - pair->validity_type |= validity_type; - camel_cipher_validity_envelope (pair->validity, validity); - } else { - pair = g_new0 (EMailPartValidityPair, 1); - pair->validity_type = validity_type; - pair->validity = camel_cipher_validity_clone (validity); - - g_queue_push_tail (&part->validities, pair); - } -} - -/** - * e_mail_part_get_validity: - * @part: An #EMailPart - * @validity_type: E_MAIL_PART_VALIDITY_* flags - * - * Returns, validity of @part contains any validity with the same bits - * as @validity_type set. It should contain all bits of it. - * - * Returns: a #CamelCipherValidity of the given type, %NULL if not found - * - * Since: 3.8 - */ -CamelCipherValidity * -e_mail_part_get_validity (EMailPart *part, - EMailPartValidityFlags validity_type) -{ - EMailPartValidityPair *pair; - - g_return_val_if_fail (E_IS_MAIL_PART (part), NULL); - - pair = mail_part_find_validity_pair (part, validity_type); - - return (pair != NULL) ? pair->validity : NULL; -} - -gboolean -e_mail_part_has_validity (EMailPart *part) -{ - g_return_val_if_fail (E_IS_MAIL_PART (part), FALSE); - - return !g_queue_is_empty (&part->validities); -} - -EMailPartValidityFlags -e_mail_part_get_validity_flags (EMailPart *part) -{ - EMailPartValidityFlags flags = 0; - GList *head, *link; - - g_return_val_if_fail (E_IS_MAIL_PART (part), 0); - - head = g_queue_peek_head_link (&part->validities); - - for (link = head; link != NULL; link = g_list_next (link)) { - EMailPartValidityPair *pair = link->data; - - if (pair != NULL) - flags |= pair->validity_type; - } - - return flags; -} - -static gboolean -from_matches_signers_alt_emails (CamelInternetAddress *from_address, - CamelCipherCertInfo *cinfo) -{ - GSList *props_link; - gboolean matches = FALSE; - - for (props_link = cinfo->properties; props_link && !matches; props_link = g_slist_next (props_link)) { - const CamelCipherCertInfoProperty *prop = props_link->data; - - if (prop && g_strcmp0 (prop->name, CAMEL_CIPHER_CERT_INFO_PROPERTY_SIGNERS_ALT_EMAILS) == 0 && prop->value) { - CamelInternetAddress *address; - gint count, ii; - - address = camel_internet_address_new (); - count = camel_address_unformat (CAMEL_ADDRESS (address), prop->value); - for (ii = 0; ii < count && !matches; ii++) { - const gchar *email = NULL; - - if (camel_internet_address_get (address, ii, NULL, &email) && email && *email) { - matches = camel_internet_address_find_address (from_address, email, NULL) >= 0; - } - } - g_object_unref (address); - break; - } - } - - return matches; -} - -void -e_mail_part_verify_validity_sender (EMailPart *part, - CamelInternetAddress *from_address) -{ - GList *link; - - g_return_if_fail (E_IS_MAIL_PART (part)); - - if (!from_address) - return; - - for (link = g_queue_peek_head_link (&part->validities); link; link = g_list_next (link)) { - EMailPartValidityPair *pair = link->data; - - if (pair && pair->validity && !(pair->validity_type & E_MAIL_PART_VALIDITY_VERIFIED)) { - pair->validity_type |= E_MAIL_PART_VALIDITY_VERIFIED; - - if (pair->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) { - GList *link2; - gboolean from_matches_signer = FALSE; - - for (link2 = g_queue_peek_head_link (&pair->validity->sign.signers); link2 && !from_matches_signer; link2 = g_list_next (link2)) { - CamelCipherCertInfo *cinfo = link2->data; - - if (cinfo->email && *cinfo->email) { - from_matches_signer = from_matches_signer || - (from_address && camel_internet_address_find_address (from_address, cinfo->email, NULL) >= 0) || - (from_address && from_matches_signers_alt_emails (from_address, cinfo)); - } - } - - if (!from_matches_signer) - pair->validity_type |= E_MAIL_PART_VALIDITY_SENDER_SIGNER_MISMATCH; - } - } - } -} diff --git a/src/mail/e-mail-config-assistant.c b/src/mail/e-mail-config-assistant.c index c441646..8aba8af 100644 --- a/src/mail/e-mail-config-assistant.c +++ b/src/mail/e-mail-config-assistant.c @@ -1069,26 +1069,7 @@ mail_config_assistant_prepare (GtkAssistant *assistant, e_named_parameters_free (params); } - if (!first_visit && E_IS_MAIL_CONFIG_IDENTITY_PAGE (page)) { - ESource *source; - ESourceMailIdentity *extension; - const gchar *email_address; - const gchar *extension_name; - - source = priv->identity_source; - extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; - extension = e_source_get_extension (source, extension_name); - email_address = e_source_mail_identity_get_address (extension); - - /* Set the value to an empty string when going back to the identity page, - thus when moving away from it the source's display name is updated - with the new address, in case it changed. Do not modify the display - name when the user changed it. */ - if (g_strcmp0 (e_mail_config_summary_page_get_account_name (priv->summary_page), email_address) == 0) - e_source_set_display_name (source, ""); - } - - if (E_IS_MAIL_CONFIG_RECEIVING_PAGE (page)) { + if (E_IS_MAIL_CONFIG_RECEIVING_PAGE (page) && first_visit) { ESource *source; ESourceMailIdentity *extension; const gchar *email_address; @@ -1103,9 +1084,7 @@ mail_config_assistant_prepare (GtkAssistant *assistant, extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; extension = e_source_get_extension (source, extension_name); email_address = e_source_mail_identity_get_address (extension); - - if (first_visit || g_strcmp0 (e_source_get_display_name (source), "") == 0) - e_source_set_display_name (source, email_address); + e_source_set_display_name (source, email_address); } if (first_visit && ( diff --git a/src/mail/e-mail-config-assistant.c.mail-account-name-sync-in-wizard b/src/mail/e-mail-config-assistant.c.mail-account-name-sync-in-wizard deleted file mode 100644 index 8aba8af..0000000 --- a/src/mail/e-mail-config-assistant.c.mail-account-name-sync-in-wizard +++ /dev/null @@ -1,1523 +0,0 @@ -/* - * e-mail-config-assistant.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -#include "evolution-config.h" - -#include - -#include - -#include -#include -#include -#include -#include - -#include "e-mail-config-confirm-page.h" -#include "e-mail-config-identity-page.h" -#include "e-mail-config-lookup-page.h" -#include "e-mail-config-provider-page.h" -#include "e-mail-config-receiving-page.h" -#include "e-mail-config-sending-page.h" -#include "e-mail-config-summary-page.h" -#include "e-mail-config-welcome-page.h" - -#include "em-folder-tree.h" - -#include "e-mail-config-assistant.h" - -#define E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_MAIL_CONFIG_ASSISTANT, EMailConfigAssistantPrivate)) - -/* GtkAssistant's back button label. */ -#define BACK_BUTTON_LABEL N_("Go _Back") - -typedef struct _ConfigLookupContext ConfigLookupContext; - -struct _EMailConfigAssistantPrivate { - EMailSession *session; - ESource *identity_source; - GPtrArray *account_sources; - GPtrArray *transport_sources; - EMailConfigServicePage *receiving_page; - EMailConfigServicePage *sending_page; - EMailConfigSummaryPage *summary_page; - EMailConfigPage *identity_page; - EMailConfigPage *lookup_page; - GHashTable *visited_pages; - gboolean auto_configured; - - /* GtkAssistant owns this. */ - GtkButton *back_button; /* not referenced */ -}; - -struct _ConfigLookupContext { - GtkAssistant *assistant; - GCancellable *cancellable; - GtkWidget *skip_button; /* not referenced */ - EConfigLookup *config_lookup; - gchar *email_address; -}; - -enum { - PROP_0, - PROP_ACCOUNT_BACKEND, - PROP_ACCOUNT_SOURCE, - PROP_IDENTITY_SOURCE, - PROP_SESSION, - PROP_TRANSPORT_BACKEND, - PROP_TRANSPORT_SOURCE -}; - -enum { - NEW_SOURCE, - LAST_SIGNAL -}; - -static gulong signals[LAST_SIGNAL]; - -/* XXX We implement EAlertSink but don't implement a custom submit_alert() - * method. So any alert results in a pop-up message dialog, which is a - * fashion faux pas these days. But it's only used when submitting the - * the newly-configured account fails, so should rarely be seen. */ - -G_DEFINE_TYPE_WITH_CODE ( - EMailConfigAssistant, - e_mail_config_assistant, - GTK_TYPE_ASSISTANT, - G_IMPLEMENT_INTERFACE ( - E_TYPE_ALERT_SINK, NULL) - G_IMPLEMENT_INTERFACE ( - E_TYPE_EXTENSIBLE, NULL)) - -static void -config_lookup_skip_button_clicked_cb (GtkButton *button, - GCancellable *cancellable) -{ - g_cancellable_cancel (cancellable); -} - -static ConfigLookupContext * -config_lookup_context_new (GtkAssistant *assistant, - ESourceRegistry *registry, - const gchar *email_address) -{ - ConfigLookupContext *context; - const gchar *text; - - context = g_slice_new0 (ConfigLookupContext); - context->assistant = g_object_ref (assistant); - context->cancellable = g_cancellable_new (); - context->config_lookup = e_config_lookup_new (registry); - context->email_address = g_strdup (email_address); - - /* GtkAssistant sinks the floating button reference. */ - text = _("_Skip Lookup"); - context->skip_button = gtk_button_new_with_mnemonic (text); - gtk_assistant_add_action_widget ( - context->assistant, context->skip_button); - gtk_widget_show (context->skip_button); - - g_signal_connect_object ( - context->skip_button, "clicked", - G_CALLBACK (config_lookup_skip_button_clicked_cb), - context->cancellable, 0); - - return context; -} - -static void -config_lookup_context_free (ConfigLookupContext *context) -{ - gtk_assistant_remove_action_widget ( - context->assistant, context->skip_button); - - g_object_unref (context->assistant); - g_object_unref (context->cancellable); - g_object_unref (context->config_lookup); - g_free (context->email_address); - - g_slice_free (ConfigLookupContext, context); -} - -static gint -mail_config_assistant_provider_compare (gconstpointer data1, - gconstpointer data2) -{ - const CamelProvider *provider1 = data1; - const CamelProvider *provider2 = data2; - - /* The "none" provider comes first. */ - if (g_strcmp0 (provider1->protocol, "none") == 0) - return -1; - if (g_strcmp0 (provider2->protocol, "none") == 0) - return 1; - - /* Then sort remote providers before local providers. */ - if (provider1->flags & CAMEL_PROVIDER_IS_REMOTE) { - if (provider2->flags & CAMEL_PROVIDER_IS_REMOTE) - return 0; - else - return -1; - } else { - if (provider2->flags & CAMEL_PROVIDER_IS_REMOTE) - return 1; - else - return 0; - } -} - -static GList * -mail_config_assistant_list_providers (void) -{ - GList *list, *link; - GQueue trash = G_QUEUE_INIT; - - list = camel_provider_list (TRUE); - list = g_list_sort (list, mail_config_assistant_provider_compare); - - /* Keep only providers with a "mail" or "news" domain. */ - - for (link = list; link != NULL; link = g_list_next (link)) { - CamelProvider *provider = link->data; - gboolean mail_or_news_domain; - - mail_or_news_domain = - (g_strcmp0 (provider->domain, "mail") == 0) || - (g_strcmp0 (provider->domain, "news") == 0); - - if (mail_or_news_domain) - continue; - - g_queue_push_tail (&trash, link); - } - - while ((link = g_queue_pop_head (&trash)) != NULL) - list = g_list_remove_link (list, link); - - return list; -} - -static void -mail_config_assistant_notify_account_backend (EMailConfigServicePage *page, - GParamSpec *pspec, - EMailConfigAssistant *assistant) -{ - EMailConfigServiceBackend *backend; - EMailConfigServicePage *sending_page; - EMailConfigServicePageClass *page_class; - CamelProvider *provider; - - backend = e_mail_config_service_page_get_active_backend (page); - - /* The Receiving Page combo box may not have an active item. */ - if (backend == NULL) - goto notify; - - /* The Sending Page may not have been created yet. */ - if (assistant->priv->sending_page == NULL) - goto notify; - - provider = e_mail_config_service_backend_get_provider (backend); - - /* XXX This should never fail, but the Camel macro below does - * not check for NULL so better to malfunction than crash. */ - g_return_if_fail (provider != NULL); - - sending_page = assistant->priv->sending_page; - page_class = E_MAIL_CONFIG_SERVICE_PAGE_GET_CLASS (sending_page); - - /* The Sending Page is invisible when the CamelProvider for the - * receiving type defines both a storage and transport service. - * This is common in CamelProviders for groupware products like - * Microsoft Exchange and Novell GroupWise. */ - if (CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (provider) && - g_strcmp0 (provider->protocol, "none") != 0) { - backend = e_mail_config_service_page_lookup_backend ( - sending_page, provider->protocol); - gtk_widget_hide (GTK_WIDGET (sending_page)); - } else { - backend = e_mail_config_service_page_lookup_backend ( - sending_page, page_class->default_backend_name); - gtk_widget_show (GTK_WIDGET (sending_page)); - } - - e_mail_config_service_page_set_active_backend (sending_page, backend); - -notify: - g_object_freeze_notify (G_OBJECT (assistant)); - - g_object_notify (G_OBJECT (assistant), "account-backend"); - g_object_notify (G_OBJECT (assistant), "account-source"); - - g_object_thaw_notify (G_OBJECT (assistant)); -} - -static void -mail_config_assistant_notify_transport_backend (EMailConfigServicePage *page, - GParamSpec *pspec, - EMailConfigAssistant *assistant) -{ - g_object_freeze_notify (G_OBJECT (assistant)); - - g_object_notify (G_OBJECT (assistant), "transport-backend"); - g_object_notify (G_OBJECT (assistant), "transport-source"); - - g_object_thaw_notify (G_OBJECT (assistant)); -} - -static void -mail_config_assistant_page_changed (EMailConfigPage *page, - EMailConfigAssistant *assistant) -{ - gtk_assistant_set_page_complete ( - GTK_ASSISTANT (assistant), GTK_WIDGET (page), - e_mail_config_page_check_complete (page)); -} - -static void -mail_config_assistant_config_lookup_run_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - EMailConfigAssistantPrivate *priv; - ConfigLookupContext *context; - gint n_pages, ii, complete = 0; - gboolean any_configured = FALSE; - gboolean is_complete; - - context = (ConfigLookupContext *) user_data; - - priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (context->assistant); - - e_config_lookup_run_finish (E_CONFIG_LOOKUP (source_object), result); - - is_complete = FALSE; - - if (e_mail_config_service_page_auto_configure (priv->receiving_page, context->config_lookup, &is_complete)) { - any_configured = TRUE; - /* Add the page to the visited pages hash table to - * prevent calling e_mail_config_page_setup_defaults(). */ - g_hash_table_add (priv->visited_pages, priv->receiving_page); - - if (is_complete) - complete++; - } - - is_complete = FALSE; - - if (e_mail_config_service_page_auto_configure (priv->sending_page, context->config_lookup, &is_complete)) { - any_configured = TRUE; - /* Add the page to the visited pages hash table to - * prevent calling e_mail_config_page_setup_defaults(). */ - g_hash_table_add (priv->visited_pages, priv->sending_page); - - if (is_complete) - complete++; - } - - if (!any_configured || complete != 2) { - if (any_configured) { - /* Set the initial display name to the email address - * given so the user can just click past the Summary page. */ - e_source_set_display_name (priv->identity_source, context->email_address); - } - - gtk_assistant_next_page (context->assistant); - goto exit; - } - - /* Autoconfiguration worked! Feed the results to the - * service pages and then skip to the Summary page. */ - - /* For the summary page... */ - priv->auto_configured = TRUE; - - /* Also set the initial display name to the email address - * given so the user can just click past the Summary page. */ - e_source_set_display_name (priv->identity_source, context->email_address); - - /* Go to the next page (Receiving Email) before skipping to the - * Summary Page to get it into GtkAssistant visited page history. - * We want the back button to return to Receiving Email. */ - gtk_assistant_next_page (context->assistant); - - /* XXX Can't find a better way to learn the page number of - * the summary page. Oh my god this API is horrible. */ - n_pages = gtk_assistant_get_n_pages (context->assistant); - for (ii = 0; ii < n_pages; ii++) { - GtkWidget *page; - - page = gtk_assistant_get_nth_page (context->assistant, ii); - if (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page)) - break; - } - - g_warn_if_fail (ii < n_pages); - gtk_assistant_set_current_page (context->assistant, ii); - -exit: - /* Set the page invisible so we never revisit it. */ - gtk_widget_set_visible (GTK_WIDGET (priv->lookup_page), FALSE); - - config_lookup_context_free (context); -} - -static ESource * -mail_config_assistant_get_source_cb (EConfigLookup *config_lookup, - EConfigLookupSourceKind kind, - gpointer user_data) -{ - EMailConfigAssistant *assistant = user_data; - EMailConfigServiceBackend *backend; - ESource *source = NULL; - - g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), NULL); - g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL); - - switch (kind) { - case E_CONFIG_LOOKUP_SOURCE_UNKNOWN: - break; - case E_CONFIG_LOOKUP_SOURCE_COLLECTION: - backend = e_mail_config_assistant_get_account_backend (assistant); - source = e_mail_config_service_backend_get_collection (backend); - break; - case E_CONFIG_LOOKUP_SOURCE_MAIL_ACCOUNT: - source = e_mail_config_assistant_get_account_source (assistant); - break; - case E_CONFIG_LOOKUP_SOURCE_MAIL_IDENTITY: - source = e_mail_config_assistant_get_identity_source (assistant); - break; - case E_CONFIG_LOOKUP_SOURCE_MAIL_TRANSPORT: - source = e_mail_config_assistant_get_transport_source (assistant); - break; - } - - return source; -} - -static gboolean -mail_config_assistant_provider_page_visible (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer unused) -{ - EMailConfigServiceBackend *active_backend; - EMailConfigServiceBackend *page_backend; - EMailConfigProviderPage *page; - GObject *target_object; - gboolean visible; - - target_object = g_binding_get_target (binding); - page = E_MAIL_CONFIG_PROVIDER_PAGE (target_object); - page_backend = e_mail_config_provider_page_get_backend (page); - - active_backend = g_value_get_object (source_value); - visible = (page_backend == active_backend); - g_value_set_boolean (target_value, visible); - - return TRUE; -} - -static void -mail_config_assistant_select_account_node (const gchar *account_uid) -{ - EShell *shell; - EShellWindow *shell_window; - EShellView *shell_view; - EShellSidebar *shell_sidebar; - EMFolderTree *folder_tree = NULL; - GtkWindow *active_window; - const gchar *active_view; - - g_return_if_fail (account_uid != NULL); - - shell = e_shell_get_default (); - active_window = e_shell_get_active_window (shell); - - if (!E_IS_SHELL_WINDOW (active_window)) - return; - - shell_window = E_SHELL_WINDOW (active_window); - active_view = e_shell_window_get_active_view (shell_window); - - if (g_strcmp0 (active_view, "mail") != 0) - return; - - shell_view = e_shell_window_get_shell_view (shell_window, "mail"); - - shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); - g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL); - - em_folder_tree_select_store_when_added (folder_tree, account_uid); - - g_object_unref (folder_tree); - -} - -static void -mail_config_assistant_close_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - EMailConfigAssistant *assistant; - GdkWindow *gdk_window; - GError *error = NULL; - - assistant = E_MAIL_CONFIG_ASSISTANT (object); - - /* Set the cursor back to normal. */ - gdk_window = gtk_widget_get_window (GTK_WIDGET (assistant)); - gdk_window_set_cursor (gdk_window, NULL); - - /* Allow user interaction with window content. */ - gtk_widget_set_sensitive (GTK_WIDGET (assistant), TRUE); - - e_mail_config_assistant_commit_finish (assistant, result, &error); - - /* Ignore cancellations. */ - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_error_free (error); - - } else if (error != NULL) { - e_alert_submit ( - E_ALERT_SINK (assistant), - "system:simple-error", - error->message, NULL); - g_error_free (error); - - } else { - ESource *source; - - source = e_mail_config_assistant_get_account_source (assistant); - if (source != NULL) { - const gchar *uid; - - uid = e_source_get_uid (source); - mail_config_assistant_select_account_node (uid); - } - - gtk_widget_destroy (GTK_WIDGET (assistant)); - } -} - -static void -mail_config_assistant_find_back_button_cb (GtkWidget *widget, - gpointer user_data) -{ - EMailConfigAssistant *assistant; - - assistant = E_MAIL_CONFIG_ASSISTANT (user_data); - - if (GTK_IS_BUTTON (widget)) { - GtkButton *button; - const gchar *gtk_label; - const gchar *our_label; - - button = GTK_BUTTON (widget); - - /* XXX The gtkassistant.ui file assigns the back button - * an ID of "back", but I don't think we have access - * to it from here. I guess just compare by label, - * and hope our translation matches GTK's. Yuck. */ - - gtk_label = gtk_button_get_label (button); - our_label = gettext (BACK_BUTTON_LABEL); - - if (g_strcmp0 (gtk_label, our_label) == 0) - assistant->priv->back_button = button; - - } else if (GTK_IS_CONTAINER (widget)) { - gtk_container_forall ( - GTK_CONTAINER (widget), - mail_config_assistant_find_back_button_cb, - assistant); - } -} - -static void -mail_config_assistant_set_session (EMailConfigAssistant *assistant, - EMailSession *session) -{ - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (assistant->priv->session == NULL); - - assistant->priv->session = g_object_ref (session); -} - -static void -mail_config_assistant_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_SESSION: - mail_config_assistant_set_session ( - E_MAIL_CONFIG_ASSISTANT (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_config_assistant_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_ACCOUNT_BACKEND: - g_value_set_object ( - value, - e_mail_config_assistant_get_account_backend ( - E_MAIL_CONFIG_ASSISTANT (object))); - return; - - case PROP_ACCOUNT_SOURCE: - g_value_set_object ( - value, - e_mail_config_assistant_get_account_source ( - E_MAIL_CONFIG_ASSISTANT (object))); - return; - - case PROP_IDENTITY_SOURCE: - g_value_set_object ( - value, - e_mail_config_assistant_get_identity_source ( - E_MAIL_CONFIG_ASSISTANT (object))); - return; - - case PROP_SESSION: - g_value_set_object ( - value, - e_mail_config_assistant_get_session ( - E_MAIL_CONFIG_ASSISTANT (object))); - return; - - case PROP_TRANSPORT_BACKEND: - g_value_set_object ( - value, - e_mail_config_assistant_get_transport_backend ( - E_MAIL_CONFIG_ASSISTANT (object))); - return; - - case PROP_TRANSPORT_SOURCE: - g_value_set_object ( - value, - e_mail_config_assistant_get_transport_source ( - E_MAIL_CONFIG_ASSISTANT (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_config_assistant_dispose (GObject *object) -{ - EMailConfigAssistantPrivate *priv; - - priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (object); - - if (priv->session != NULL) { - g_object_unref (priv->session); - priv->session = NULL; - } - - if (priv->identity_source != NULL) { - g_object_unref (priv->identity_source); - priv->identity_source = NULL; - } - - if (priv->receiving_page != NULL) { - g_object_unref (priv->receiving_page); - priv->receiving_page = NULL; - } - - if (priv->sending_page != NULL) { - g_object_unref (priv->sending_page); - priv->sending_page = NULL; - } - - if (priv->summary_page != NULL) { - g_object_unref (priv->summary_page); - priv->summary_page = NULL; - } - - if (priv->lookup_page != NULL) { - g_object_unref (priv->lookup_page); - priv->lookup_page = NULL; - } - - if (priv->identity_page != NULL) { - g_object_unref (priv->identity_page); - priv->identity_page = NULL; - } - - g_ptr_array_set_size (priv->account_sources, 0); - g_ptr_array_set_size (priv->transport_sources, 0); - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_mail_config_assistant_parent_class)-> - dispose (object); -} - -static void -mail_config_assistant_finalize (GObject *object) -{ - EMailConfigAssistantPrivate *priv; - - priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (object); - - g_ptr_array_free (priv->account_sources, TRUE); - g_ptr_array_free (priv->transport_sources, TRUE); - - g_hash_table_destroy (priv->visited_pages); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (e_mail_config_assistant_parent_class)-> - finalize (object); -} - -static void -mail_config_assistant_constructed (GObject *object) -{ - EMailConfigAssistant *assistant; - ESource *identity_source; - ESourceRegistry *registry; - ESourceExtension *extension; - ESourceMailComposition *mail_composition_extension; - ESourceMailIdentity *mail_identity_extension; - ESourceMailSubmission *mail_submission_extension; - EMailSession *session; - EMailConfigPage *page; - GtkWidget *autodiscover_check; - GList *list, *link; - const gchar *extension_name; - const gchar *title; - GtkRequisition requisition; - GSList *children = NULL; - gint ii, npages; - - assistant = E_MAIL_CONFIG_ASSISTANT (object); - - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_mail_config_assistant_parent_class)->constructed (object); - - title = _("Evolution Account Assistant"); - gtk_window_set_title (GTK_WINDOW (assistant), title); - gtk_window_set_position (GTK_WINDOW (assistant), GTK_WIN_POS_CENTER); - gtk_window_set_default_size (GTK_WINDOW (assistant), 640, 480); - - session = e_mail_config_assistant_get_session (assistant); - registry = e_mail_session_get_registry (session); - - /* XXX Locate the GtkAssistant's internal "Go Back" button so - * we can temporarily rename it for autoconfigure results. - * Walking the container like this is an extremely naughty - * and brittle hack, but GtkAssistant does not provide API - * to access it directly. */ - gtk_container_forall ( - GTK_CONTAINER (assistant), - mail_config_assistant_find_back_button_cb, - assistant); - - /* Configure a new identity source. */ - - identity_source = e_source_new (NULL, NULL, NULL); - assistant->priv->identity_source = identity_source; - session = e_mail_config_assistant_get_session (assistant); - - extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION; - extension = e_source_get_extension (identity_source, extension_name); - mail_composition_extension = E_SOURCE_MAIL_COMPOSITION (extension); - - extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; - extension = e_source_get_extension (identity_source, extension_name); - mail_identity_extension = E_SOURCE_MAIL_IDENTITY (extension); - - extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION; - extension = e_source_get_extension (identity_source, extension_name); - mail_submission_extension = E_SOURCE_MAIL_SUBMISSION (extension); - - e_source_mail_identity_set_name (mail_identity_extension, g_get_real_name ()); - - e_source_mail_composition_set_drafts_folder ( - mail_composition_extension, - e_mail_session_get_local_folder_uri ( - session, E_MAIL_LOCAL_FOLDER_DRAFTS)); - - e_source_mail_composition_set_templates_folder ( - mail_composition_extension, - e_mail_session_get_local_folder_uri ( - session, E_MAIL_LOCAL_FOLDER_TEMPLATES)); - - e_source_mail_submission_set_sent_folder ( - mail_submission_extension, - e_mail_session_get_local_folder_uri ( - session, E_MAIL_LOCAL_FOLDER_SENT)); - - gtk_widget_get_preferred_size (GTK_WIDGET (assistant), &requisition, NULL); - requisition.width += 2 * 12; - requisition.height += 2 * 12; - - /*** Welcome Page ***/ - - page = e_mail_config_welcome_page_new (); - e_mail_config_assistant_add_page (assistant, page); - - /*** Identity Page ***/ - - page = e_mail_config_identity_page_new (registry, identity_source); - e_mail_config_identity_page_set_show_account_info ( - E_MAIL_CONFIG_IDENTITY_PAGE (page), FALSE); - e_mail_config_identity_page_set_show_signatures ( - E_MAIL_CONFIG_IDENTITY_PAGE (page), FALSE); - e_mail_config_identity_page_set_show_autodiscover_check ( - E_MAIL_CONFIG_IDENTITY_PAGE (page), TRUE); - autodiscover_check = e_mail_config_identity_page_get_autodiscover_check ( - E_MAIL_CONFIG_IDENTITY_PAGE (page)); - e_mail_config_assistant_add_page (assistant, page); - assistant->priv->identity_page = g_object_ref (page); - - /*** Lookup Page ***/ - - page = e_mail_config_lookup_page_new (); - e_mail_config_assistant_add_page (assistant, page); - assistant->priv->lookup_page = g_object_ref (page); - - e_binding_bind_property ( - autodiscover_check, "active", - page, "visible", - G_BINDING_SYNC_CREATE); - - /*** Receiving Page ***/ - - page = e_mail_config_receiving_page_new (registry); - e_mail_config_assistant_add_page (assistant, page); - assistant->priv->receiving_page = g_object_ref (page); - - e_binding_bind_object_text_property ( - mail_identity_extension, "address", - page, "email-address", - G_BINDING_SYNC_CREATE); - - e_signal_connect_notify ( - page, "notify::active-backend", - G_CALLBACK (mail_config_assistant_notify_account_backend), - assistant); - - /*** Receiving Options (multiple) ***/ - - /* Populate the Receiving Email page while at the same time - * adding a Receiving Options page for each account type. */ - - list = mail_config_assistant_list_providers (); - - for (link = list; link != NULL; link = g_list_next (link)) { - EMailConfigServiceBackend *backend; - CamelProvider *provider = link->data; - ESourceBackend *backend_extension; - ESource *scratch_source; - const gchar *backend_name; - - if (provider->object_types[CAMEL_PROVIDER_STORE] == 0) - continue; - - /* ESource uses "backend_name" and CamelProvider - * uses "protocol", but the terms are synonymous. */ - backend_name = provider->protocol; - - scratch_source = e_source_new (NULL, NULL, NULL); - backend_extension = e_source_get_extension ( - scratch_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT); - e_source_backend_set_backend_name ( - backend_extension, backend_name); - - /* Keep display names synchronized. */ - e_binding_bind_property ( - identity_source, "display-name", - scratch_source, "display-name", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - /* We always pass NULL for the collection argument. - * The backend generates its own scratch collection - * source if implements the new_collection() method. */ - backend = e_mail_config_service_page_add_scratch_source ( - assistant->priv->receiving_page, scratch_source, NULL); - - g_object_unref (scratch_source); - - page = e_mail_config_provider_page_new (backend); - - /* Note: We exclude this page if it has no options, - * but we don't know that until we create it. */ - if (e_mail_config_provider_page_is_empty ( - E_MAIL_CONFIG_PROVIDER_PAGE (page))) { - g_object_unref (g_object_ref_sink (page)); - continue; - } else { - e_mail_config_assistant_add_page (assistant, page); - } - - /* Each Receiving Options page is only visible when its - * service backend is active on the Receiving Email page. */ - e_binding_bind_property_full ( - assistant->priv->receiving_page, "active-backend", - page, "visible", - G_BINDING_SYNC_CREATE, - mail_config_assistant_provider_page_visible, - NULL, - NULL, (GDestroyNotify) NULL); - } - - g_list_free (list); - - /*** Sending Page ***/ - - page = e_mail_config_sending_page_new (registry); - e_mail_config_assistant_add_page (assistant, page); - assistant->priv->sending_page = g_object_ref (page); - - e_binding_bind_object_text_property ( - mail_identity_extension, "address", - page, "email-address", - G_BINDING_SYNC_CREATE); - - e_signal_connect_notify ( - page, "notify::active-backend", - G_CALLBACK (mail_config_assistant_notify_transport_backend), - assistant); - - list = mail_config_assistant_list_providers (); - - for (link = list; link != NULL; link = g_list_next (link)) { - CamelProvider *provider = link->data; - ESourceBackend *backend_extension; - ESource *scratch_source; - const gchar *backend_name; - - if (provider->object_types[CAMEL_PROVIDER_TRANSPORT] == 0) - continue; - - /* ESource uses "backend_name" and CamelProvider - * uses "protocol", but the terms are synonymous. */ - backend_name = provider->protocol; - - scratch_source = e_source_new (NULL, NULL, NULL); - backend_extension = e_source_get_extension ( - scratch_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT); - e_source_backend_set_backend_name ( - backend_extension, backend_name); - - /* Keep display names synchronized. */ - e_binding_bind_property ( - identity_source, "display-name", - scratch_source, "display-name", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - /* We always pass NULL for the collection argument. - * The backend generates its own scratch collection - * source if implements the new_collection() method. */ - e_mail_config_service_page_add_scratch_source ( - assistant->priv->sending_page, scratch_source, NULL); - - g_object_unref (scratch_source); - } - - g_list_free (list); - - /*** Summary Page ***/ - - page = e_mail_config_summary_page_new (); - e_mail_config_assistant_add_page (assistant, page); - assistant->priv->summary_page = g_object_ref (page); - - e_binding_bind_property ( - assistant, "account-backend", - page, "account-backend", - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - assistant, "identity-source", - page, "identity-source", - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - assistant, "transport-backend", - page, "transport-backend", - G_BINDING_SYNC_CREATE); - - /*** Confirm Page ***/ - - page = e_mail_config_confirm_page_new (); - e_mail_config_assistant_add_page (assistant, page); - - e_extensible_load_extensions (E_EXTENSIBLE (assistant)); - - npages = gtk_assistant_get_n_pages (GTK_ASSISTANT (assistant)); - for (ii = 0; ii < npages; ii++) { - children = g_slist_prepend (children, gtk_assistant_get_nth_page (GTK_ASSISTANT (assistant), ii)); - } - - e_util_resize_window_for_screen (GTK_WINDOW (assistant), requisition.width, requisition.height, children); - - g_slist_free (children); -} - -static void -mail_config_assistant_remove (GtkContainer *container, - GtkWidget *widget) -{ - if (E_IS_MAIL_CONFIG_PAGE (widget)) - g_signal_handlers_disconnect_by_func ( - widget, mail_config_assistant_page_changed, - E_MAIL_CONFIG_ASSISTANT (container)); - - /* Chain up to parent's remove() method. */ - GTK_CONTAINER_CLASS (e_mail_config_assistant_parent_class)-> - remove (container, widget); -} - -static void -mail_config_assistant_prepare (GtkAssistant *assistant, - GtkWidget *page) -{ - EMailConfigAssistantPrivate *priv; - gboolean first_visit = FALSE; - - priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (assistant); - - /* Only setup defaults the first time a page is visited. */ - if (!g_hash_table_contains (priv->visited_pages, page)) { - if (E_IS_MAIL_CONFIG_PAGE (page)) - e_mail_config_page_setup_defaults ( - E_MAIL_CONFIG_PAGE (page)); - g_hash_table_add (priv->visited_pages, page); - first_visit = TRUE; - } - - /* Are we viewing autoconfiguration results? If so, temporarily - * rename the back button to clarify that account details can be - * revised. Otherwise reset the button to its original label. */ - if (priv->back_button != NULL) { - gboolean auto_configure_results; - const gchar *label; - - auto_configure_results = - E_IS_MAIL_CONFIG_SUMMARY_PAGE (page) && - priv->auto_configured && first_visit; - - if (auto_configure_results) - label = _("_Revise Details"); - else - label = gettext (BACK_BUTTON_LABEL); - - gtk_button_set_label (priv->back_button, label); - } - - if (E_IS_MAIL_CONFIG_LOOKUP_PAGE (page)) { - ConfigLookupContext *context; - ESource *source; - ESourceRegistry *registry; - ESourceMailIdentity *extension; - ENamedParameters *params; - const gchar *email_address; - const gchar *extension_name; - - registry = e_mail_session_get_registry (priv->session); - - source = priv->identity_source; - extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; - extension = e_source_get_extension (source, extension_name); - email_address = e_source_mail_identity_get_address (extension); - - context = config_lookup_context_new (assistant, registry, email_address); - - g_signal_connect (context->config_lookup, "get-source", - G_CALLBACK (mail_config_assistant_get_source_cb), assistant); - - params = e_named_parameters_new (); - e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_EMAIL_ADDRESS, email_address); - - e_config_lookup_run (context->config_lookup, - params, - context->cancellable, - mail_config_assistant_config_lookup_run_cb, - context); - - e_named_parameters_free (params); - } - - if (E_IS_MAIL_CONFIG_RECEIVING_PAGE (page) && first_visit) { - ESource *source; - ESourceMailIdentity *extension; - const gchar *email_address; - const gchar *extension_name; - - /* Use the email address from the Identity Page as - * the initial display name, so in case we have to - * query a remote mail server, the password prompt - * will have a more meaningful description. */ - - source = priv->identity_source; - extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; - extension = e_source_get_extension (source, extension_name); - email_address = e_source_mail_identity_get_address (extension); - e_source_set_display_name (source, email_address); - } - - if (first_visit && ( - E_IS_MAIL_CONFIG_LOOKUP_PAGE (page) || - E_IS_MAIL_CONFIG_RECEIVING_PAGE (page))) - e_mail_config_identity_page_set_show_autodiscover_check ( - E_MAIL_CONFIG_IDENTITY_PAGE (priv->identity_page), FALSE); -} - -static void -mail_config_assistant_close (GtkAssistant *assistant) -{ - GdkCursor *gdk_cursor; - GdkWindow *gdk_window; - - /* Do not chain up. GtkAssistant does not implement this method. */ - - /* Make the cursor appear busy. */ - gdk_cursor = gdk_cursor_new (GDK_WATCH); - gdk_window = gtk_widget_get_window (GTK_WIDGET (assistant)); - gdk_window_set_cursor (gdk_window, gdk_cursor); - g_object_unref (gdk_cursor); - - /* Prevent user interaction with window content. */ - gtk_widget_set_sensitive (GTK_WIDGET (assistant), FALSE); - - /* XXX This operation is not cancellable. */ - e_mail_config_assistant_commit ( - E_MAIL_CONFIG_ASSISTANT (assistant), - NULL, mail_config_assistant_close_cb, NULL); -} - -static void -mail_config_assistant_cancel (GtkAssistant *assistant) -{ - /* Do not chain up. GtkAssistant does not implement this method. */ - - gtk_widget_destroy (GTK_WIDGET (assistant)); -} - -static void -e_mail_config_assistant_class_init (EMailConfigAssistantClass *class) -{ - GObjectClass *object_class; - GtkContainerClass *container_class; - GtkAssistantClass *assistant_class; - - g_type_class_add_private (class, sizeof (EMailConfigAssistantPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = mail_config_assistant_set_property; - object_class->get_property = mail_config_assistant_get_property; - object_class->dispose = mail_config_assistant_dispose; - object_class->finalize = mail_config_assistant_finalize; - object_class->constructed = mail_config_assistant_constructed; - - container_class = GTK_CONTAINER_CLASS (class); - container_class->remove = mail_config_assistant_remove; - - assistant_class = GTK_ASSISTANT_CLASS (class); - assistant_class->prepare = mail_config_assistant_prepare; - assistant_class->close = mail_config_assistant_close; - assistant_class->cancel = mail_config_assistant_cancel; - - g_object_class_install_property ( - object_class, - PROP_ACCOUNT_BACKEND, - g_param_spec_object ( - "account-backend", - "Account Backend", - "Active mail account service backend", - E_TYPE_MAIL_CONFIG_SERVICE_BACKEND, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_ACCOUNT_SOURCE, - g_param_spec_object ( - "account-source", - "Account Source", - "Mail account source being edited", - E_TYPE_SOURCE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_IDENTITY_SOURCE, - g_param_spec_object ( - "identity-source", - "Identity Source", - "Mail identity source being edited", - E_TYPE_SOURCE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_SESSION, - g_param_spec_object ( - "session", - "Session", - "Mail session", - E_TYPE_MAIL_SESSION, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_TRANSPORT_BACKEND, - g_param_spec_object ( - "transport-backend", - "Transport Backend", - "Active mail transport service backend", - E_TYPE_MAIL_CONFIG_SERVICE_BACKEND, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_TRANSPORT_SOURCE, - g_param_spec_object ( - "transport-source", - "Transport Source", - "Mail transport source being edited", - E_TYPE_SOURCE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - /** - * EMailConfigAssistant::new-source: - * @uid: an #ESource UID which had been created - * - * Emitted to notify about the assistant finishing an account #ESource. - * - * Since: 3.28 - **/ - signals[NEW_SOURCE] = g_signal_new ( - "new-source", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (EMailConfigAssistantClass, new_source), - NULL, NULL, - NULL, - G_TYPE_NONE, 1, G_TYPE_STRING); -} - -static void -e_mail_config_assistant_init (EMailConfigAssistant *assistant) -{ - GObject *action_area; - GtkBuilder *builder; - - builder = gtk_builder_new (); - action_area = gtk_buildable_get_internal_child ( - GTK_BUILDABLE (assistant), builder, "action_area"); - if (action_area) - gtk_container_set_border_width (GTK_CONTAINER (action_area), 12); - g_object_unref (builder); - - assistant->priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (assistant); - - assistant->priv->account_sources = - g_ptr_array_new_with_free_func ( - (GDestroyNotify) g_object_unref); - - assistant->priv->transport_sources = - g_ptr_array_new_with_free_func ( - (GDestroyNotify) g_object_unref); - - assistant->priv->visited_pages = g_hash_table_new (NULL, NULL); -} - -GtkWidget * -e_mail_config_assistant_new (EMailSession *session) -{ - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - return g_object_new ( - E_TYPE_MAIL_CONFIG_ASSISTANT, - "session", session, NULL); -} - -EMailSession * -e_mail_config_assistant_get_session (EMailConfigAssistant *assistant) -{ - g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL); - - return assistant->priv->session; -} - -EMailConfigServiceBackend * -e_mail_config_assistant_get_account_backend (EMailConfigAssistant *assistant) -{ - EMailConfigServicePage *page; - - g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL); - - page = assistant->priv->receiving_page; - - return e_mail_config_service_page_get_active_backend (page); -} - -ESource * -e_mail_config_assistant_get_account_source (EMailConfigAssistant *assistant) -{ - EMailConfigServiceBackend *backend; - ESource *source = NULL; - - g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL); - - backend = e_mail_config_assistant_get_account_backend (assistant); - - if (backend != NULL) - source = e_mail_config_service_backend_get_source (backend); - - return source; -} - -ESource * -e_mail_config_assistant_get_identity_source (EMailConfigAssistant *assistant) -{ - g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL); - - return assistant->priv->identity_source; -} - -EMailConfigServiceBackend * -e_mail_config_assistant_get_transport_backend (EMailConfigAssistant *assistant) -{ - EMailConfigServicePage *page; - - g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL); - - page = assistant->priv->sending_page; - - return e_mail_config_service_page_get_active_backend (page); -} - -ESource * -e_mail_config_assistant_get_transport_source (EMailConfigAssistant *assistant) -{ - EMailConfigServiceBackend *backend; - ESource *source = NULL; - - g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL); - - backend = e_mail_config_assistant_get_transport_backend (assistant); - - if (backend != NULL) - source = e_mail_config_service_backend_get_source (backend); - - return source; -} - -void -e_mail_config_assistant_add_page (EMailConfigAssistant *assistant, - EMailConfigPage *page) -{ - EMailConfigPageInterface *page_interface; - GtkAssistantPageType page_type; - GtkWidget *page_widget; - gint n_pages, position; - const gchar *page_title; - gboolean complete; - - g_return_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant)); - g_return_if_fail (E_IS_MAIL_CONFIG_PAGE (page)); - - page_widget = GTK_WIDGET (page); - page_interface = E_MAIL_CONFIG_PAGE_GET_INTERFACE (page); - page_type = page_interface->page_type; - page_title = page_interface->title; - - /* Determine the position to insert the page. */ - n_pages = gtk_assistant_get_n_pages (GTK_ASSISTANT (assistant)); - for (position = 0; position < n_pages; position++) { - GtkWidget *nth_page; - - nth_page = gtk_assistant_get_nth_page ( - GTK_ASSISTANT (assistant), position); - if (e_mail_config_page_compare (page_widget, nth_page) < 0) - break; - } - - gtk_widget_show (page_widget); - - /* Some pages can be clicked through unchanged. */ - complete = e_mail_config_page_check_complete (page); - - gtk_assistant_insert_page ( - GTK_ASSISTANT (assistant), page_widget, position); - gtk_assistant_set_page_type ( - GTK_ASSISTANT (assistant), page_widget, page_type); - gtk_assistant_set_page_title ( - GTK_ASSISTANT (assistant), page_widget, page_title); - gtk_assistant_set_page_complete ( - GTK_ASSISTANT (assistant), page_widget, complete); - - /* XXX GtkAssistant has no equivalent to GtkNotebook's - * "page-added" and "page-removed" signals. Fortunately - * removing a page does trigger GtkContainer::remove, so - * we can override that method and disconnect our signal - * handler before chaining up. But I don't see any way - * for a subclass to intercept GtkAssistant pages being - * added, so we have to connect our signal handler here. - * Not really an issue, I'm just being pedantic. */ - - g_signal_connect ( - page, "changed", - G_CALLBACK (mail_config_assistant_page_changed), - assistant); -} - -/********************* e_mail_config_assistant_commit() **********************/ - -static void -mail_config_assistant_commit_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - GError *error = NULL; - - simple = G_SIMPLE_ASYNC_RESULT (user_data); - - e_source_registry_create_sources_finish ( - E_SOURCE_REGISTRY (object), result, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); - - g_simple_async_result_complete (simple); - - g_object_unref (simple); -} - -void -e_mail_config_assistant_commit (EMailConfigAssistant *assistant, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - EMailConfigServiceBackend *backend; - GSimpleAsyncResult *simple; - ESourceRegistry *registry; - EMailSession *session; - ESource *source; - GQueue *queue; - gint n_pages, ii; - - g_return_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant)); - - session = e_mail_config_assistant_get_session (assistant); - registry = e_mail_session_get_registry (session); - - queue = g_queue_new (); - - /* Queue the collection data source if one is defined. */ - backend = e_mail_config_assistant_get_account_backend (assistant); - source = e_mail_config_service_backend_get_collection (backend); - if (source != NULL) - g_queue_push_tail (queue, g_object_ref (source)); - - /* Queue the mail-related data sources for the account. */ - source = e_mail_config_assistant_get_account_source (assistant); - if (source != NULL) - g_queue_push_tail (queue, g_object_ref (source)); - source = e_mail_config_assistant_get_identity_source (assistant); - if (source != NULL) - g_queue_push_tail (queue, g_object_ref (source)); - source = e_mail_config_assistant_get_transport_source (assistant); - if (source != NULL) - g_queue_push_tail (queue, g_object_ref (source)); - - n_pages = gtk_assistant_get_n_pages (GTK_ASSISTANT (assistant)); - - /* Tell all EMailConfigPages to commit their UI state to their - * scratch ESources and push any additional data sources on to - * the given source queue, such as calendars or address books - * to be bundled with the mail account. */ - for (ii = 0; ii < n_pages; ii++) { - GtkWidget *widget; - - widget = gtk_assistant_get_nth_page ( - GTK_ASSISTANT (assistant), ii); - - if (E_IS_MAIL_CONFIG_PAGE (widget)) { - EMailConfigPage *page; - page = E_MAIL_CONFIG_PAGE (widget); - e_mail_config_page_commit_changes (page, queue); - } - } - - simple = g_simple_async_result_new ( - G_OBJECT (assistant), callback, user_data, - e_mail_config_assistant_commit); - - e_source_registry_create_sources ( - registry, g_queue_peek_head_link (queue), - cancellable, mail_config_assistant_commit_cb, simple); - - g_queue_free_full (queue, (GDestroyNotify) g_object_unref); -} - -gboolean -e_mail_config_assistant_commit_finish (EMailConfigAssistant *assistant, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - gboolean success; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (assistant), - e_mail_config_assistant_commit), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - success = !g_simple_async_result_propagate_error (simple, error); - - if (success) { - ESource *source; - - source = e_mail_config_assistant_get_account_source (assistant); - if (source) - g_signal_emit (assistant, signals[NEW_SOURCE], 0, e_source_get_uid (source)); - } - - return success; -} - diff --git a/src/mail/e-mail-config-summary-page.c b/src/mail/e-mail-config-summary-page.c index 20c669a..fb0306d 100644 --- a/src/mail/e-mail-config-summary-page.c +++ b/src/mail/e-mail-config-summary-page.c @@ -53,8 +53,6 @@ struct _EMailConfigSummaryPagePrivate { GtkLabel *send_user_label; GtkLabel *send_security_label; GtkEntry *account_name_entry; - - GBinding *account_name_binding; }; enum { @@ -551,6 +549,9 @@ mail_config_summary_page_refresh (EMailConfigSummaryPage *page) const gchar *extension_name; const gchar *value; + value = e_source_get_display_name (source); + gtk_entry_set_text (priv->account_name_entry, value); + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; extension = e_source_get_extension (source, extension_name); @@ -829,14 +830,6 @@ e_mail_config_summary_page_get_internal_box (EMailConfigSummaryPage *page) return page->priv->main_box; } -const gchar * -e_mail_config_summary_page_get_account_name (EMailConfigSummaryPage *page) -{ - g_return_val_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page), NULL); - - return gtk_entry_get_text (page->priv->account_name_entry); -} - void e_mail_config_summary_page_refresh (EMailConfigSummaryPage *page) { @@ -941,11 +934,6 @@ e_mail_config_summary_page_set_identity_source (EMailConfigSummaryPage *page, page->priv->identity_source = identity_source; page->priv->identity_source_changed_id = 0; - if (page->priv->account_name_binding) { - g_binding_unbind (page->priv->account_name_binding); - page->priv->account_name_binding = NULL; - } - if (identity_source != NULL) { gulong handler_id; @@ -955,11 +943,6 @@ e_mail_config_summary_page_set_identity_source (EMailConfigSummaryPage *page, page); page->priv->identity_source_changed_id = handler_id; - - page->priv->account_name_binding = - e_binding_bind_property (identity_source, "display-name", - page->priv->account_name_entry, "text", - G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } g_object_notify (G_OBJECT (page), "identity-source"); diff --git a/src/mail/e-mail-config-summary-page.c.mail-account-name-sync-in-wizard b/src/mail/e-mail-config-summary-page.c.mail-account-name-sync-in-wizard deleted file mode 100644 index fb0306d..0000000 --- a/src/mail/e-mail-config-summary-page.c.mail-account-name-sync-in-wizard +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * e-mail-config-summary-page.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -#include "evolution-config.h" - -#include - -#include -#include -#include - -#include "e-mail-config-summary-page.h" - -#define E_MAIL_CONFIG_SUMMARY_PAGE_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_MAIL_CONFIG_SUMMARY_PAGE, EMailConfigSummaryPagePrivate)) - -struct _EMailConfigSummaryPagePrivate { - ESource *account_source; - ESource *identity_source; - ESource *transport_source; - EMailConfigServiceBackend *account_backend; - EMailConfigServiceBackend *transport_backend; - - gulong account_source_changed_id; - gulong identity_source_changed_id; - gulong transport_source_changed_id; - - /* Widgets (not referenced) */ - GtkBox *main_box; - GtkLabel *name_label; - GtkLabel *address_label; - GtkLabel *recv_backend_label; - GtkLabel *recv_host_label; - GtkLabel *recv_user_label; - GtkLabel *recv_security_label; - GtkLabel *send_backend_label; - GtkLabel *send_host_label; - GtkLabel *send_user_label; - GtkLabel *send_security_label; - GtkEntry *account_name_entry; -}; - -enum { - PROP_0, - PROP_ACCOUNT_BACKEND, - PROP_ACCOUNT_SOURCE, - PROP_IDENTITY_SOURCE, - PROP_TRANSPORT_BACKEND, - PROP_TRANSPORT_SOURCE -}; - -enum { - REFRESH, - LAST_SIGNAL -}; - -static gulong signals[LAST_SIGNAL]; - -/* Forward Declarations */ -static void e_mail_config_summary_page_interface_init - (EMailConfigPageInterface *iface); - -G_DEFINE_TYPE_WITH_CODE ( - EMailConfigSummaryPage, - e_mail_config_summary_page, - GTK_TYPE_SCROLLED_WINDOW, - G_IMPLEMENT_INTERFACE ( - E_TYPE_EXTENSIBLE, NULL) - G_IMPLEMENT_INTERFACE ( - E_TYPE_MAIL_CONFIG_PAGE, - e_mail_config_summary_page_interface_init)) - -/* Helper for mail_config_summary_page_refresh() */ -static void -mail_config_summary_page_refresh_auth_labels (ESource *source, - GtkLabel *host_label, - GtkLabel *user_label) -{ - ESourceAuthentication *extension; - const gchar *extension_name; - const gchar *value; - - extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; - if (!e_source_has_extension (source, extension_name)) - return; - - extension = e_source_get_extension (source, extension_name); - - value = e_source_authentication_get_host (extension); - gtk_label_set_text (host_label, value); - - value = e_source_authentication_get_user (extension); - gtk_label_set_text (user_label, value); -} - -/* Helper for mail_config_summary_page_refresh() */ -static void -mail_config_summary_page_refresh_security_label (ESource *source, - GtkLabel *security_label) -{ - GEnumClass *enum_class; - GEnumValue *enum_value; - ESourceSecurity *extension; - const gchar *extension_name; - const gchar *value; - - extension_name = E_SOURCE_EXTENSION_SECURITY; - if (!e_source_has_extension (source, extension_name)) - return; - - extension = e_source_get_extension (source, extension_name); - - /* XXX This is a pain in the butt, but we want to avoid hard-coding - * string values from the CamelNetworkSecurityMethod enum class - * in case they change in the future. */ - enum_class = g_type_class_ref (CAMEL_TYPE_NETWORK_SECURITY_METHOD); - value = e_source_security_get_method (extension); - if (value != NULL) - enum_value = g_enum_get_value_by_nick (enum_class, value); - else - enum_value = NULL; - if (enum_value == NULL) { - gtk_label_set_text (security_label, value); - } else switch ((CamelNetworkSecurityMethod) enum_value->value) { - case CAMEL_NETWORK_SECURITY_METHOD_NONE: - gtk_label_set_text (security_label, _("None")); - break; - case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT: - gtk_label_set_text (security_label, _("TLS")); - break; - case CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT: - gtk_label_set_text (security_label, _("STARTTLS")); - break; - } - g_type_class_unref (enum_class); -} - -static void -mail_config_summary_page_source_changed (ESource *source, - EMailConfigSummaryPage *page) -{ - e_mail_config_summary_page_refresh (page); -} - -static void -mail_config_summary_page_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_ACCOUNT_BACKEND: - e_mail_config_summary_page_set_account_backend ( - E_MAIL_CONFIG_SUMMARY_PAGE (object), - g_value_get_object (value)); - return; - - case PROP_IDENTITY_SOURCE: - e_mail_config_summary_page_set_identity_source ( - E_MAIL_CONFIG_SUMMARY_PAGE (object), - g_value_get_object (value)); - return; - - case PROP_TRANSPORT_BACKEND: - e_mail_config_summary_page_set_transport_backend ( - E_MAIL_CONFIG_SUMMARY_PAGE (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_config_summary_page_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_ACCOUNT_BACKEND: - g_value_set_object ( - value, - e_mail_config_summary_page_get_account_backend ( - E_MAIL_CONFIG_SUMMARY_PAGE (object))); - return; - - case PROP_ACCOUNT_SOURCE: - g_value_set_object ( - value, - e_mail_config_summary_page_get_account_source ( - E_MAIL_CONFIG_SUMMARY_PAGE (object))); - return; - - case PROP_IDENTITY_SOURCE: - g_value_set_object ( - value, - e_mail_config_summary_page_get_identity_source ( - E_MAIL_CONFIG_SUMMARY_PAGE (object))); - return; - - case PROP_TRANSPORT_BACKEND: - g_value_set_object ( - value, - e_mail_config_summary_page_get_transport_backend ( - E_MAIL_CONFIG_SUMMARY_PAGE (object))); - return; - - case PROP_TRANSPORT_SOURCE: - g_value_set_object ( - value, - e_mail_config_summary_page_get_transport_source ( - E_MAIL_CONFIG_SUMMARY_PAGE (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_config_summary_page_dispose (GObject *object) -{ - EMailConfigSummaryPagePrivate *priv; - - priv = E_MAIL_CONFIG_SUMMARY_PAGE_GET_PRIVATE (object); - - if (priv->account_source != NULL) { - g_signal_handler_disconnect ( - priv->account_source, - priv->account_source_changed_id); - g_object_unref (priv->account_source); - priv->account_source = NULL; - priv->account_source_changed_id = 0; - } - - if (priv->identity_source != NULL) { - g_signal_handler_disconnect ( - priv->identity_source, - priv->identity_source_changed_id); - g_object_unref (priv->identity_source); - priv->identity_source = NULL; - } - - if (priv->transport_source != NULL) { - g_signal_handler_disconnect ( - priv->transport_source, - priv->transport_source_changed_id); - g_object_unref (priv->transport_source); - priv->transport_source = NULL; - priv->transport_source_changed_id = 0; - } - - if (priv->account_backend != NULL) { - g_object_unref (priv->account_backend); - priv->account_backend = NULL; - } - - if (priv->transport_backend != NULL) { - g_object_unref (priv->transport_backend); - priv->transport_backend = NULL; - } - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_mail_config_summary_page_parent_class)-> - dispose (object); -} - -static void -mail_config_summary_page_constructed (GObject *object) -{ - EMailConfigSummaryPage *page; - GtkLabel *label; - GtkWidget *widget; - GtkWidget *container; - GtkWidget *main_box; - GtkSizeGroup *size_group; - const gchar *text; - gchar *markup; - - page = E_MAIL_CONFIG_SUMMARY_PAGE (object); - - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_mail_config_summary_page_parent_class)->constructed (object); - - /* This page is dense with information, - * so put extra space between sections. */ - main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 24); - - size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - - text = _("This is a summary of the settings which will be used " - "to access your mail."); - widget = gtk_label_new (text); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (main_box), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - /*** Account Information ***/ - - widget = gtk_grid_new (); - gtk_grid_set_row_spacing (GTK_GRID (widget), 6); - gtk_grid_set_column_spacing (GTK_GRID (widget), 6); - gtk_box_pack_start (GTK_BOX (main_box), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - container = widget; - - text = _("Account Information"); - markup = g_markup_printf_escaped ("%s", text); - widget = gtk_label_new (markup); - gtk_label_set_use_markup (GTK_LABEL (widget), TRUE); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 2, 1); - gtk_widget_show (widget); - g_free (markup); - - text = _("_Name:"); - widget = gtk_label_new_with_mnemonic (text); - gtk_widget_set_margin_left (widget, 12); - gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 1, 1); - gtk_widget_show (widget); - - label = GTK_LABEL (widget); - - widget = gtk_entry_new (); - gtk_widget_set_hexpand (widget, TRUE); - gtk_label_set_mnemonic_widget (label, widget); - gtk_grid_attach (GTK_GRID (container), widget, 1, 1, 1, 1); - page->priv->account_name_entry = GTK_ENTRY (widget); - gtk_widget_show (widget); - - /* This entry affects the "check-complete" result. */ - g_signal_connect_swapped ( - widget, "changed", - G_CALLBACK (e_mail_config_page_changed), page); - - text = _("The above name will be used to identify this account.\n" - "Use for example, “Work” or “Personal”."); - widget = gtk_label_new (text); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 1, 2, 1, 1); - gtk_widget_show (widget); - - /*** Details ***/ - - widget = gtk_grid_new (); - gtk_grid_set_row_spacing (GTK_GRID (widget), 6); - gtk_grid_set_column_spacing (GTK_GRID (widget), 12); - gtk_box_pack_start (GTK_BOX (main_box), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - container = widget; - - text = _("Personal Details"); - markup = g_markup_printf_escaped ("%s", text); - widget = gtk_label_new (markup); - gtk_label_set_use_markup (GTK_LABEL (widget), TRUE); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 3, 1); - gtk_widget_show (widget); - g_free (markup); - - text = _("Full Name:"); - widget = gtk_label_new (text); - gtk_widget_set_margin_left (widget, 12); - gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 1, 1); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); - gtk_grid_attach (GTK_GRID (container), widget, 1, 1, 2, 1); - page->priv->name_label = GTK_LABEL (widget); - gtk_widget_show (widget); - - text = _("Email Address:"); - widget = gtk_label_new (text); - gtk_widget_set_margin_left (widget, 12); - gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 0, 2, 1, 1); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); - gtk_grid_attach (GTK_GRID (container), widget, 1, 2, 2, 1); - page->priv->address_label = GTK_LABEL (widget); - gtk_widget_show (widget); - - text = _("Receiving"); - markup = g_markup_printf_escaped ("%s", text); - widget = gtk_label_new (markup); - gtk_widget_set_hexpand (widget, TRUE); - gtk_widget_set_margin_top (widget, 6); - gtk_size_group_add_widget (size_group, widget); - gtk_label_set_use_markup (GTK_LABEL (widget), TRUE); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 1, 3, 1, 1); - gtk_widget_show (widget); - g_free (markup); - - text = _("Sending"); - markup = g_markup_printf_escaped ("%s", text); - widget = gtk_label_new (markup); - gtk_widget_set_hexpand (widget, TRUE); - gtk_widget_set_margin_top (widget, 6); - gtk_size_group_add_widget (size_group, widget); - gtk_label_set_use_markup (GTK_LABEL (widget), TRUE); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 2, 3, 1, 1); - gtk_widget_show (widget); - g_free (markup); - - text = _("Server Type:"); - widget = gtk_label_new (text); - gtk_widget_set_margin_left (widget, 12); - gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 0, 4, 1, 1); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); - gtk_grid_attach (GTK_GRID (container), widget, 1, 4, 1, 1); - page->priv->recv_backend_label = GTK_LABEL (widget); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); - gtk_grid_attach (GTK_GRID (container), widget, 2, 4, 1, 1); - page->priv->send_backend_label = GTK_LABEL (widget); - gtk_widget_show (widget); - - text = _("Server:"); - widget = gtk_label_new (text); - gtk_widget_set_margin_left (widget, 12); - gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 0, 5, 1, 1); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); - gtk_grid_attach (GTK_GRID (container), widget, 1, 5, 1, 1); - page->priv->recv_host_label = GTK_LABEL (widget); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); - gtk_grid_attach (GTK_GRID (container), widget, 2, 5, 1, 1); - page->priv->send_host_label = GTK_LABEL (widget); - gtk_widget_show (widget); - - text = _("Username:"); - widget = gtk_label_new (text); - gtk_widget_set_margin_left (widget, 12); - gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 0, 6, 1, 1); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); - gtk_grid_attach (GTK_GRID (container), widget, 1, 6, 1, 1); - page->priv->recv_user_label = GTK_LABEL (widget); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); - gtk_grid_attach (GTK_GRID (container), widget, 2, 6, 1, 1); - page->priv->send_user_label = GTK_LABEL (widget); - gtk_widget_show (widget); - - text = _("Security:"); - widget = gtk_label_new (text); - gtk_widget_set_margin_left (widget, 12); - gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); - gtk_grid_attach (GTK_GRID (container), widget, 0, 7, 1, 1); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); - gtk_grid_attach (GTK_GRID (container), widget, 1, 7, 1, 1); - page->priv->recv_security_label = GTK_LABEL (widget); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END); - gtk_grid_attach (GTK_GRID (container), widget, 2, 7, 1, 1); - page->priv->send_security_label = GTK_LABEL (widget); - gtk_widget_show (widget); - - g_object_unref (size_group); - - page->priv->main_box = GTK_BOX (main_box); - - e_mail_config_page_set_content (E_MAIL_CONFIG_PAGE (page), main_box); - - e_extensible_load_extensions (E_EXTENSIBLE (page)); -} - -static void -mail_config_summary_page_refresh (EMailConfigSummaryPage *page) -{ - EMailConfigSummaryPagePrivate *priv; - ESource *source; - gboolean account_is_transport = FALSE; - - priv = E_MAIL_CONFIG_SUMMARY_PAGE_GET_PRIVATE (page); - - /* Clear all labels. */ - gtk_label_set_text (priv->name_label, ""); - gtk_label_set_text (priv->address_label, ""); - gtk_label_set_text (priv->recv_backend_label, ""); - gtk_label_set_text (priv->recv_host_label, ""); - gtk_label_set_text (priv->recv_user_label, ""); - gtk_label_set_text (priv->recv_security_label, ""); - gtk_label_set_text (priv->send_backend_label, ""); - gtk_label_set_text (priv->send_host_label, ""); - gtk_label_set_text (priv->send_user_label, ""); - gtk_label_set_text (priv->send_security_label, ""); - - source = e_mail_config_summary_page_get_identity_source (page); - - if (source != NULL) { - ESourceMailIdentity *extension; - const gchar *extension_name; - const gchar *value; - - value = e_source_get_display_name (source); - gtk_entry_set_text (priv->account_name_entry, value); - - extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; - extension = e_source_get_extension (source, extension_name); - - value = e_source_mail_identity_get_name (extension); - gtk_label_set_text (priv->name_label, value); - - value = e_source_mail_identity_get_address (extension); - gtk_label_set_text (priv->address_label, value); - } - - source = e_mail_config_summary_page_get_account_source (page); - - if (source != NULL) { - ESourceBackend *extension; - const gchar *extension_name; - const gchar *value; - - extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; - extension = e_source_get_extension (source, extension_name); - - value = e_source_backend_get_backend_name (extension); - gtk_label_set_text (priv->recv_backend_label, value); - - mail_config_summary_page_refresh_auth_labels ( - source, - priv->recv_host_label, - priv->recv_user_label); - - mail_config_summary_page_refresh_security_label ( - source, - priv->recv_security_label); - - extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT; - if (e_source_has_extension (source, extension_name)) - account_is_transport = TRUE; - } - - if (account_is_transport) - source = e_mail_config_summary_page_get_account_source (page); - else - source = e_mail_config_summary_page_get_transport_source (page); - - if (source != NULL) { - ESourceBackend *extension; - const gchar *extension_name; - const gchar *value; - - extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT; - extension = e_source_get_extension (source, extension_name); - - value = e_source_backend_get_backend_name (extension); - gtk_label_set_text (priv->send_backend_label, value); - - mail_config_summary_page_refresh_auth_labels ( - source, - priv->send_host_label, - priv->send_user_label); - - mail_config_summary_page_refresh_security_label ( - source, - priv->send_security_label); - } - - e_mail_config_page_changed (E_MAIL_CONFIG_PAGE (page)); -} - -static gboolean -mail_config_summary_page_check_complete (EMailConfigPage *page) -{ - EMailConfigSummaryPagePrivate *priv; - gchar *stripped_text; - const gchar *text; - gboolean complete; - - priv = E_MAIL_CONFIG_SUMMARY_PAGE_GET_PRIVATE (page); - - /* Strip the account name of leading and trailing - * whitespace as e_source_set_display_name() does. */ - text = gtk_entry_get_text (priv->account_name_entry); - stripped_text = g_strstrip (g_strdup ((text != NULL) ? text : "")); - complete = (*stripped_text != '\0'); - g_free (stripped_text); - - e_util_set_entry_issue_hint (GTK_WIDGET (priv->account_name_entry), complete ? NULL : _("Account Name cannot be empty")); - - if (complete) { - gboolean recv_is_none, send_is_none; - - recv_is_none = gtk_widget_get_visible (GTK_WIDGET (priv->recv_backend_label)) && - g_strcmp0 (gtk_label_get_text (priv->recv_backend_label), "none") == 0; - - send_is_none = gtk_widget_get_visible (GTK_WIDGET (priv->send_backend_label)) && - g_strcmp0 (gtk_label_get_text (priv->send_backend_label), "none") == 0; - - complete = !recv_is_none || !send_is_none; - - e_util_set_entry_issue_hint (GTK_WIDGET (priv->account_name_entry), complete ? NULL : _("Cannot have both receiving and sending parts set to None")); - } - - return complete; -} - -static void -mail_config_summary_page_commit_changes (EMailConfigPage *page, - GQueue *source_queue) -{ - EMailConfigSummaryPagePrivate *priv; - EMailConfigServiceBackend *backend; - ESource *account_source; - ESource *identity_source; - ESource *transport_source; - ESource *collection_source; - ESourceExtension *extension; - const gchar *extension_name; - const gchar *parent_uid; - const gchar *text; - - priv = E_MAIL_CONFIG_SUMMARY_PAGE_GET_PRIVATE (page); - - backend = e_mail_config_summary_page_get_account_backend ( - E_MAIL_CONFIG_SUMMARY_PAGE (page)); - account_source = - e_mail_config_service_backend_get_source (backend); - collection_source = - e_mail_config_service_backend_get_collection (backend); - - /* The transport backend is NULL when the Sending Page is hidden. */ - backend = e_mail_config_summary_page_get_transport_backend ( - E_MAIL_CONFIG_SUMMARY_PAGE (page)); - transport_source = (backend != NULL) ? - e_mail_config_service_backend_get_source (backend) : NULL; - - identity_source = e_mail_config_summary_page_get_identity_source ( - E_MAIL_CONFIG_SUMMARY_PAGE (page)); - - /* This should propagate to the other sources through bindings. */ - text = gtk_entry_get_text (priv->account_name_entry); - e_source_set_display_name (identity_source, text); - - /* Setup parent/child relationships and cross-references. */ - - if (collection_source != NULL) { - parent_uid = e_source_get_uid (collection_source); - e_source_set_parent (account_source, parent_uid); - e_source_set_parent (identity_source, parent_uid); - if (transport_source != NULL) - e_source_set_parent (transport_source, parent_uid); - } else { - parent_uid = e_source_get_uid (account_source); - e_source_set_parent (identity_source, parent_uid); - if (transport_source != NULL) - e_source_set_parent (transport_source, parent_uid); - } - - extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; - extension = e_source_get_extension (account_source, extension_name); - e_source_mail_account_set_identity_uid ( - E_SOURCE_MAIL_ACCOUNT (extension), - e_source_get_uid (identity_source)); - - extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION; - extension = e_source_get_extension (identity_source, extension_name); - if (transport_source != NULL) - e_source_mail_submission_set_transport_uid ( - E_SOURCE_MAIL_SUBMISSION (extension), - e_source_get_uid (transport_source)); -} - -static void -e_mail_config_summary_page_class_init (EMailConfigSummaryPageClass *class) -{ - GObjectClass *object_class; - - g_type_class_add_private ( - class, sizeof (EMailConfigSummaryPagePrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = mail_config_summary_page_set_property; - object_class->get_property = mail_config_summary_page_get_property; - object_class->dispose = mail_config_summary_page_dispose; - object_class->constructed = mail_config_summary_page_constructed; - - class->refresh = mail_config_summary_page_refresh; - - g_object_class_install_property ( - object_class, - PROP_ACCOUNT_BACKEND, - g_param_spec_object ( - "account-backend", - "Account Backend", - "Active mail account service backend", - E_TYPE_MAIL_CONFIG_SERVICE_BACKEND, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_ACCOUNT_SOURCE, - g_param_spec_object ( - "account-source", - "Account Source", - "Mail account source being edited", - E_TYPE_SOURCE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_IDENTITY_SOURCE, - g_param_spec_object ( - "identity-source", - "Identity Source", - "Mail identity source being edited", - E_TYPE_SOURCE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_TRANSPORT_BACKEND, - g_param_spec_object ( - "transport-backend", - "Transport Backend", - "Active mail transport service backend", - E_TYPE_MAIL_CONFIG_SERVICE_BACKEND, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_TRANSPORT_SOURCE, - g_param_spec_object ( - "transport-source", - "Transport Source", - "Mail transport source being edited", - E_TYPE_SOURCE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - signals[REFRESH] = g_signal_new ( - "refresh", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EMailConfigSummaryPageClass, refresh), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -e_mail_config_summary_page_interface_init (EMailConfigPageInterface *iface) -{ - iface->title = _("Account Summary"); - iface->sort_order = E_MAIL_CONFIG_SUMMARY_PAGE_SORT_ORDER; - iface->check_complete = mail_config_summary_page_check_complete; - iface->commit_changes = mail_config_summary_page_commit_changes; -} - -static void -e_mail_config_summary_page_init (EMailConfigSummaryPage *page) -{ - page->priv = E_MAIL_CONFIG_SUMMARY_PAGE_GET_PRIVATE (page); -} - -EMailConfigPage * -e_mail_config_summary_page_new (void) -{ - return g_object_new (E_TYPE_MAIL_CONFIG_SUMMARY_PAGE, NULL); -} - -GtkBox * -e_mail_config_summary_page_get_internal_box (EMailConfigSummaryPage *page) -{ - g_return_val_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page), NULL); - - return page->priv->main_box; -} - -void -e_mail_config_summary_page_refresh (EMailConfigSummaryPage *page) -{ - g_return_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page)); - - g_signal_emit (page, signals[REFRESH], 0); -} - -EMailConfigServiceBackend * -e_mail_config_summary_page_get_account_backend (EMailConfigSummaryPage *page) -{ - g_return_val_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page), NULL); - - return page->priv->account_backend; -} - -void -e_mail_config_summary_page_set_account_backend (EMailConfigSummaryPage *page, - EMailConfigServiceBackend *backend) -{ - g_return_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page)); - - if (backend != NULL) { - g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend)); - g_object_ref (backend); - } - - if (page->priv->account_backend != NULL) - g_object_unref (page->priv->account_backend); - - page->priv->account_backend = backend; - - if (page->priv->account_source != NULL) { - g_signal_handler_disconnect ( - page->priv->account_source, - page->priv->account_source_changed_id); - g_object_unref (page->priv->account_source); - page->priv->account_source = NULL; - page->priv->account_source_changed_id = 0; - } - - if (backend != NULL) { - ESource *source; - gulong handler_id; - - source = e_mail_config_service_backend_get_source (backend); - - handler_id = g_signal_connect ( - source, "changed", - G_CALLBACK (mail_config_summary_page_source_changed), - page); - - page->priv->account_source = g_object_ref (source); - page->priv->account_source_changed_id = handler_id; - } - - g_object_freeze_notify (G_OBJECT (page)); - g_object_notify (G_OBJECT (page), "account-backend"); - g_object_notify (G_OBJECT (page), "account-source"); - g_object_thaw_notify (G_OBJECT (page)); - - e_mail_config_summary_page_refresh (page); -} - -ESource * -e_mail_config_summary_page_get_account_source (EMailConfigSummaryPage *page) -{ - g_return_val_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page), NULL); - - return page->priv->account_source; -} - -ESource * -e_mail_config_summary_page_get_identity_source (EMailConfigSummaryPage *page) -{ - g_return_val_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page), NULL); - - return page->priv->identity_source; -} - -void -e_mail_config_summary_page_set_identity_source (EMailConfigSummaryPage *page, - ESource *identity_source) -{ - g_return_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page)); - - if (page->priv->identity_source == identity_source) - return; - - if (identity_source != NULL) { - g_return_if_fail (E_IS_SOURCE (identity_source)); - g_object_ref (identity_source); - } - - if (page->priv->identity_source != NULL) { - g_signal_handler_disconnect ( - page->priv->identity_source, - page->priv->identity_source_changed_id); - g_object_unref (page->priv->identity_source); - } - - page->priv->identity_source = identity_source; - page->priv->identity_source_changed_id = 0; - - if (identity_source != NULL) { - gulong handler_id; - - handler_id = g_signal_connect ( - identity_source, "changed", - G_CALLBACK (mail_config_summary_page_source_changed), - page); - - page->priv->identity_source_changed_id = handler_id; - } - - g_object_notify (G_OBJECT (page), "identity-source"); - - e_mail_config_summary_page_refresh (page); -} - -EMailConfigServiceBackend * -e_mail_config_summary_page_get_transport_backend (EMailConfigSummaryPage *page) -{ - g_return_val_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page), NULL); - - return page->priv->transport_backend; -} - -void -e_mail_config_summary_page_set_transport_backend (EMailConfigSummaryPage *page, - EMailConfigServiceBackend *backend) -{ - g_return_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page)); - - if (backend != NULL) { - g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend)); - g_object_ref (backend); - } - - if (page->priv->transport_backend != NULL) - g_object_unref (page->priv->transport_backend); - - page->priv->transport_backend = backend; - - if (page->priv->transport_source != NULL) { - g_signal_handler_disconnect ( - page->priv->transport_source, - page->priv->transport_source_changed_id); - g_object_unref (page->priv->transport_source); - page->priv->transport_source = NULL; - page->priv->transport_source_changed_id = 0; - } - - if (backend != NULL) { - ESource *source; - gulong handler_id; - - source = e_mail_config_service_backend_get_source (backend); - - handler_id = g_signal_connect ( - source, "changed", - G_CALLBACK (mail_config_summary_page_source_changed), - page); - - page->priv->transport_source = g_object_ref (source); - page->priv->transport_source_changed_id = handler_id; - } - - g_object_freeze_notify (G_OBJECT (page)); - g_object_notify (G_OBJECT (page), "transport-backend"); - g_object_notify (G_OBJECT (page), "transport-source"); - g_object_thaw_notify (G_OBJECT (page)); - - e_mail_config_summary_page_refresh (page); -} - -ESource * -e_mail_config_summary_page_get_transport_source (EMailConfigSummaryPage *page) -{ - g_return_val_if_fail (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page), NULL); - - return page->priv->transport_source; -} - diff --git a/src/mail/e-mail-config-summary-page.h b/src/mail/e-mail-config-summary-page.h index 64d0af8..af793dc 100644 --- a/src/mail/e-mail-config-summary-page.h +++ b/src/mail/e-mail-config-summary-page.h @@ -68,8 +68,6 @@ EMailConfigPage * e_mail_config_summary_page_new (void); GtkBox * e_mail_config_summary_page_get_internal_box (EMailConfigSummaryPage *page); -const gchar * e_mail_config_summary_page_get_account_name - (EMailConfigSummaryPage *page); void e_mail_config_summary_page_refresh (EMailConfigSummaryPage *page); EMailConfigServiceBackend * diff --git a/src/mail/e-mail-config-summary-page.h.mail-account-name-sync-in-wizard b/src/mail/e-mail-config-summary-page.h.mail-account-name-sync-in-wizard deleted file mode 100644 index af793dc..0000000 --- a/src/mail/e-mail-config-summary-page.h.mail-account-name-sync-in-wizard +++ /dev/null @@ -1,96 +0,0 @@ -/* - * e-mail-config-summary-page.h - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * along with this program; if not, see . - * - */ - -#ifndef E_MAIL_CONFIG_SUMMARY_PAGE_H -#define E_MAIL_CONFIG_SUMMARY_PAGE_H - -#include - -#include -#include - -/* Standard GObject macros */ -#define E_TYPE_MAIL_CONFIG_SUMMARY_PAGE \ - (e_mail_config_summary_page_get_type ()) -#define E_MAIL_CONFIG_SUMMARY_PAGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_MAIL_CONFIG_SUMMARY_PAGE, EMailConfigSummaryPage)) -#define E_MAIL_CONFIG_SUMMARY_PAGE_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_MAIL_CONFIG_SUMMARY_PAGE, EMailConfigSummaryPageClass)) -#define E_IS_MAIL_CONFIG_SUMMARY_PAGE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_MAIL_CONFIG_SUMMARY_PAGE)) -#define E_IS_MAIL_CONFIG_SUMMARY_PAGE_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_MAIL_CONFIG_SUMMARY_PAGE)) -#define E_MAIL_CONFIG_SUMMARY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_MAIL_CONFIG_SUMMARY_PAGE, EMailConfigSummaryPageClass)) - -#define E_MAIL_CONFIG_SUMMARY_PAGE_SORT_ORDER (500) - -G_BEGIN_DECLS - -typedef struct _EMailConfigSummaryPage EMailConfigSummaryPage; -typedef struct _EMailConfigSummaryPageClass EMailConfigSummaryPageClass; -typedef struct _EMailConfigSummaryPagePrivate EMailConfigSummaryPagePrivate; - -struct _EMailConfigSummaryPage { - GtkScrolledWindow parent; - EMailConfigSummaryPagePrivate *priv; -}; - -struct _EMailConfigSummaryPageClass { - GtkScrolledWindowClass parent_class; - - /* Signals */ - void (*refresh) (EMailConfigSummaryPage *page); -}; - -GType e_mail_config_summary_page_get_type - (void) G_GNUC_CONST; -EMailConfigPage * - e_mail_config_summary_page_new (void); -GtkBox * e_mail_config_summary_page_get_internal_box - (EMailConfigSummaryPage *page); -void e_mail_config_summary_page_refresh - (EMailConfigSummaryPage *page); -EMailConfigServiceBackend * - e_mail_config_summary_page_get_account_backend - (EMailConfigSummaryPage *page); -void e_mail_config_summary_page_set_account_backend - (EMailConfigSummaryPage *page, - EMailConfigServiceBackend *backend); -ESource * e_mail_config_summary_page_get_account_source - (EMailConfigSummaryPage *page); -ESource * e_mail_config_summary_page_get_identity_source - (EMailConfigSummaryPage *page); -void e_mail_config_summary_page_set_identity_source - (EMailConfigSummaryPage *page, - ESource *identity_source); -EMailConfigServiceBackend * - e_mail_config_summary_page_get_transport_backend - (EMailConfigSummaryPage *page); -void e_mail_config_summary_page_set_transport_backend - (EMailConfigSummaryPage *page, - EMailConfigServiceBackend *backend); -ESource * e_mail_config_summary_page_get_transport_source - (EMailConfigSummaryPage *page); - -#endif /* E_MAIL_CONFIG_SUMMARY_PAGE_H */ - diff --git a/src/modules/calendar/e-cal-base-shell-sidebar.c b/src/modules/calendar/e-cal-base-shell-sidebar.c index 749d589..f574b18 100644 --- a/src/modules/calendar/e-cal-base-shell-sidebar.c +++ b/src/modules/calendar/e-cal-base-shell-sidebar.c @@ -296,7 +296,6 @@ typedef struct _OpenClientData { ECalBaseShellSidebar *sidebar; ESource *source; EClient *client; - gboolean was_cancelled; } OpenClientData; static void @@ -305,14 +304,9 @@ open_client_data_free (gpointer pdata) OpenClientData *data = pdata; if (data) { - /* To free the cancellable in the 'value' pair, which is useless now */ - g_hash_table_insert (data->sidebar->priv->selected_uids, - g_strdup (e_source_get_uid (data->source)), - NULL); - if (data->client) { g_signal_emit (data->sidebar, signals[CLIENT_OPENED], 0, data->client); - } else if (!data->was_cancelled) { + } else { ESourceSelector *selector = e_cal_base_shell_sidebar_get_selector (data->sidebar); e_source_selector_unselect_source (selector, data->source); } @@ -339,7 +333,6 @@ e_cal_base_shell_sidebar_open_client_thread (EAlertSinkThreadJobData *job_data, selector = E_CLIENT_SELECTOR (e_cal_base_shell_sidebar_get_selector (data->sidebar)); data->client = e_client_selector_get_client_sync ( selector, data->source, TRUE, (guint32) -1, cancellable, &local_error); - data->was_cancelled = g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED); e_util_propagate_open_source_job_error (job_data, data->extension_name, local_error, error); } @@ -357,10 +350,6 @@ e_cal_base_shell_sidebar_ensure_source_opened (ECalBaseShellSidebar *sidebar, g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar)); g_return_if_fail (E_IS_SOURCE (source)); - /* Skip it when it's already opening or opened */ - if (g_hash_table_contains (sidebar->priv->selected_uids, e_source_get_uid (source))) - return; - shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (sidebar)); switch (e_cal_base_shell_view_get_source_type (shell_view)) { diff --git a/src/modules/calendar/e-cal-base-shell-sidebar.c.deselect-task-memo-list b/src/modules/calendar/e-cal-base-shell-sidebar.c.deselect-task-memo-list deleted file mode 100644 index f574b18..0000000 --- a/src/modules/calendar/e-cal-base-shell-sidebar.c.deselect-task-memo-list +++ /dev/null @@ -1,957 +0,0 @@ -/* - * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * Authors: Milan Crha - */ - -#include "evolution-config.h" - -#include -#include - -#include "e-util/e-util.h" -#include "calendar/gui/comp-util.h" - -#include "e-cal-base-shell-view.h" -#include "e-cal-base-shell-sidebar.h" - -#define E_CAL_BASE_SHELL_SIDEBAR_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_CAL_BASE_SHELL_SIDEBAR, ECalBaseShellSidebarPrivate)) - -struct _ECalBaseShellSidebarPrivate { - ECalendar *date_navigator; /* not referenced, is inside itself */ - GtkWidget *paned; /* not referenced, is inside itself */ - ESourceSelector *selector; /* not referenced, is inside itself */ - - gulong date_navigator_scroll_event_handler_id; - - GHashTable *selected_uids; /* source UID -> cancellable */ -}; - -enum { - PROP_0, - PROP_DATE_NAVIGATOR, - PROP_SELECTOR -}; - -enum { - CLIENT_OPENED, - CLIENT_CLOSED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -G_DEFINE_DYNAMIC_TYPE (ECalBaseShellSidebar, e_cal_base_shell_sidebar, E_TYPE_SHELL_SIDEBAR) - -static gboolean -cal_base_shell_sidebar_map_uid_to_source (GValue *value, - GVariant *variant, - gpointer user_data) -{ - ESourceRegistry *registry; - ESource *source; - const gchar *uid; - - registry = E_SOURCE_REGISTRY (user_data); - uid = g_variant_get_string (variant, NULL); - if (uid != NULL && *uid != '\0') - source = e_source_registry_ref_source (registry, uid); - else - source = e_source_registry_ref_default_calendar (registry); - g_value_take_object (value, source); - - return (source != NULL); -} - -static GVariant * -cal_base_shell_sidebar_map_source_to_uid (const GValue *value, - const GVariantType *expected_type, - gpointer user_data) -{ - GVariant *variant = NULL; - ESource *source; - - source = g_value_get_object (value); - - if (source != NULL) { - const gchar *uid; - - uid = e_source_get_uid (source); - variant = g_variant_new_string (uid); - } - - return variant; -} - -static void -cal_base_shell_sidebar_restore_state_cb (EShellWindow *shell_window, - EShellView *shell_view, - EShellSidebar *shell_sidebar) -{ - ECalBaseShellSidebarPrivate *priv; - ESourceRegistry *registry; - ESourceSelector *selector; - GSettings *settings; - const gchar *primary_source_key = NULL; - - priv = E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar)->priv; - - g_signal_handlers_disconnect_by_func ( - shell_window, - cal_base_shell_sidebar_restore_state_cb, shell_sidebar); - - switch (e_cal_base_shell_view_get_source_type (shell_view)) { - case E_CAL_CLIENT_SOURCE_TYPE_EVENTS: - primary_source_key = "primary-calendar"; - break; - case E_CAL_CLIENT_SOURCE_TYPE_MEMOS: - primary_source_key = "primary-memos"; - break; - case E_CAL_CLIENT_SOURCE_TYPE_TASKS: - primary_source_key = "primary-tasks"; - break; - case E_CAL_CLIENT_SOURCE_TYPE_LAST: - g_warn_if_reached (); - return; - } - - selector = E_SOURCE_SELECTOR (priv->selector); - registry = e_source_selector_get_registry (selector); - - /* Bind GObject properties to settings keys. */ - - settings = e_util_ref_settings ("org.gnome.evolution.calendar"); - - g_settings_bind_with_mapping ( - settings, primary_source_key, - selector, "primary-selection", - G_SETTINGS_BIND_DEFAULT, - cal_base_shell_sidebar_map_uid_to_source, - cal_base_shell_sidebar_map_source_to_uid, - g_object_ref (registry), - (GDestroyNotify) g_object_unref); - - if (priv->date_navigator) { - if (e_shell_window_is_main_instance (shell_window)) { - g_settings_bind ( - settings, "date-navigator-pane-position", - priv->paned, "vposition", - G_SETTINGS_BIND_DEFAULT); - } else { - g_settings_bind ( - settings, "date-navigator-pane-position-sub", - priv->paned, "vposition", - G_SETTINGS_BIND_DEFAULT | - G_SETTINGS_BIND_GET_NO_CHANGES); - } - } - - g_object_unref (settings); -} - -static guint32 -cal_base_shell_sidebar_check_state (EShellSidebar *shell_sidebar) -{ - ECalBaseShellSidebar *cal_base_shell_sidebar; - ESourceSelector *selector; - ESourceRegistry *registry; - ESource *source; - gboolean is_writable = FALSE; - gboolean is_removable = FALSE; - gboolean is_remote_creatable = FALSE; - gboolean is_remote_deletable = FALSE; - gboolean in_collection = FALSE; - gboolean refresh_supported = FALSE; - gboolean has_primary_source = FALSE; - guint32 state = 0; - - cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar); - selector = e_cal_base_shell_sidebar_get_selector (cal_base_shell_sidebar); - source = e_source_selector_ref_primary_selection (selector); - registry = e_source_selector_get_registry (selector); - - if (source != NULL) { - EClient *client; - ESource *collection; - - has_primary_source = TRUE; - is_writable = e_source_get_writable (source); - is_removable = e_source_get_removable (source); - is_remote_creatable = e_source_get_remote_creatable (source); - is_remote_deletable = e_source_get_remote_deletable (source); - - collection = e_source_registry_find_extension ( - registry, source, E_SOURCE_EXTENSION_COLLECTION); - if (collection != NULL) { - in_collection = TRUE; - g_object_unref (collection); - } - - client = e_client_selector_ref_cached_client ( - E_CLIENT_SELECTOR (selector), source); - - if (client != NULL) { - refresh_supported = - e_client_check_refresh_supported (client); - g_object_unref (client); - } - - g_object_unref (source); - } - - if (e_source_selector_count_total (selector) == e_source_selector_count_selected (selector)) - state |= E_CAL_BASE_SHELL_SIDEBAR_ALL_SOURCES_SELECTED; - if (has_primary_source) - state |= E_CAL_BASE_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE; - if (is_writable) - state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE; - if (is_removable) - state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE; - if (is_remote_creatable) - state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE; - if (is_remote_deletable) - state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE; - if (in_collection) - state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION; - if (refresh_supported) - state |= E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH; - - return state; -} - -static gboolean -cal_base_shell_sidebar_date_navigator_scroll_event_cb (ECalBaseShellSidebar *cal_base_shell_sidebar, - GdkEventScroll *event, - ECalendar *date_navigator) -{ - ECalendarItem *calitem; - gint year = -1, month = -1; - GdkScrollDirection direction; - - calitem = e_calendar_get_item (date_navigator); - e_calendar_item_get_first_month (calitem, &year, &month); - if (year == -1 || month == -1) - return FALSE; - - direction = event->direction; - - if (direction == GDK_SCROLL_SMOOTH) { - static gdouble total_delta_y = 0.0; - - total_delta_y += event->delta_y; - - if (total_delta_y >= 1.0) { - total_delta_y = 0.0; - direction = GDK_SCROLL_DOWN; - } else if (total_delta_y <= -1.0) { - total_delta_y = 0.0; - direction = GDK_SCROLL_UP; - } else { - return FALSE; - } - } - - switch (direction) { - case GDK_SCROLL_UP: - month--; - if (month < 0) { - year--; - month += 12; - } - break; - - case GDK_SCROLL_DOWN: - month++; - if (month >= 12) { - year++; - month -= 12; - } - break; - - default: - g_return_val_if_reached (FALSE); - } - - e_calendar_item_set_first_month (calitem, year, month); - - return TRUE; -} - -typedef struct _OpenClientData { - const gchar *extension_name; - ECalBaseShellSidebar *sidebar; - ESource *source; - EClient *client; -} OpenClientData; - -static void -open_client_data_free (gpointer pdata) -{ - OpenClientData *data = pdata; - - if (data) { - if (data->client) { - g_signal_emit (data->sidebar, signals[CLIENT_OPENED], 0, data->client); - } else { - ESourceSelector *selector = e_cal_base_shell_sidebar_get_selector (data->sidebar); - e_source_selector_unselect_source (selector, data->source); - } - - g_clear_object (&data->sidebar); - g_clear_object (&data->source); - g_clear_object (&data->client); - g_free (data); - } -} - -static void -e_cal_base_shell_sidebar_open_client_thread (EAlertSinkThreadJobData *job_data, - gpointer user_data, - GCancellable *cancellable, - GError **error) -{ - EClientSelector *selector; - OpenClientData *data = user_data; - GError *local_error = NULL; - - g_return_if_fail (data != NULL); - - selector = E_CLIENT_SELECTOR (e_cal_base_shell_sidebar_get_selector (data->sidebar)); - data->client = e_client_selector_get_client_sync ( - selector, data->source, TRUE, (guint32) -1, cancellable, &local_error); - - e_util_propagate_open_source_job_error (job_data, data->extension_name, local_error, error); -} - -static void -e_cal_base_shell_sidebar_ensure_source_opened (ECalBaseShellSidebar *sidebar, - ESource *source) -{ - OpenClientData *data; - EShellView *shell_view; - EActivity *activity; - gchar *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL, *display_name; - const gchar *extension_name = NULL; - - g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar)); - g_return_if_fail (E_IS_SOURCE (source)); - - shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (sidebar)); - - switch (e_cal_base_shell_view_get_source_type (shell_view)) { - case E_CAL_CLIENT_SOURCE_TYPE_EVENTS: - extension_name = E_SOURCE_EXTENSION_CALENDAR; - break; - case E_CAL_CLIENT_SOURCE_TYPE_MEMOS: - extension_name = E_SOURCE_EXTENSION_MEMO_LIST; - break; - case E_CAL_CLIENT_SOURCE_TYPE_TASKS: - extension_name = E_SOURCE_EXTENSION_TASK_LIST; - break; - case E_CAL_CLIENT_SOURCE_TYPE_LAST: - g_warn_if_reached (); - return; - } - - display_name = e_util_get_source_full_name (e_shell_get_registry (e_shell_backend_get_shell (e_shell_view_get_shell_backend (shell_view))), source); - - if (!e_util_get_open_source_job_info (extension_name, display_name, - &description, &alert_ident, &alert_arg_0)) { - g_free (display_name); - g_warn_if_reached (); - return; - } - - g_free (display_name); - - data = g_new0 (OpenClientData, 1); - data->extension_name = extension_name; /* no need to copy, it's a static string */ - data->sidebar = g_object_ref (sidebar); - data->source = g_object_ref (source); - - activity = e_shell_view_submit_thread_job ( - shell_view, description, alert_ident, alert_arg_0, - e_cal_base_shell_sidebar_open_client_thread, data, - open_client_data_free); - - if (activity) { - GCancellable *cancellable; - - cancellable = e_activity_get_cancellable (activity); - - g_hash_table_insert (sidebar->priv->selected_uids, - g_strdup (e_source_get_uid (source)), - g_object_ref (cancellable)); - - g_object_unref (activity); - } - - g_free (description); - g_free (alert_ident); - g_free (alert_arg_0); -} - -static void -e_cal_base_shell_sidebar_primary_selection_changed_cb (ESourceSelector *selector, - EShellSidebar *sidebar) -{ - g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar)); - - e_shell_view_update_actions (e_shell_sidebar_get_shell_view (sidebar)); -} - -static void -e_cal_base_shell_sidebar_source_selected (ESourceSelector *selector, - ESource *source, - ECalBaseShellSidebar *sidebar) -{ - g_return_if_fail (E_IS_SOURCE_SELECTOR (selector)); - g_return_if_fail (E_IS_SOURCE (source)); - g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar)); - - if (!g_hash_table_contains (sidebar->priv->selected_uids, e_source_get_uid (source))) { - e_cal_base_shell_sidebar_ensure_source_opened (sidebar, source); - } -} - -static void -e_cal_base_shell_sidebar_source_unselected (ESourceSelector *selector, - ESource *source, - ECalBaseShellSidebar *sidebar) -{ - g_return_if_fail (E_IS_SOURCE_SELECTOR (selector)); - g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar)); - - if (g_hash_table_remove (sidebar->priv->selected_uids, e_source_get_uid (source))) - g_signal_emit (sidebar, signals[CLIENT_CLOSED], 0, source); -} - -typedef struct { - ESource *source; - ESource *destination; - gboolean do_copy; - icalcomponent *icalcomp; - EClientSelector *selector; -} TransferItemToData; - -static void -transfer_item_to_data_free (gpointer ptr) -{ - TransferItemToData *titd = ptr; - - if (titd) { - g_clear_object (&titd->source); - g_clear_object (&titd->destination); - g_clear_object (&titd->selector); - - if (titd->icalcomp) - icalcomponent_free (titd->icalcomp); - - g_free (titd); - } -} - -static void -cal_base_shell_sidebar_transfer_thread (EAlertSinkThreadJobData *job_data, - gpointer user_data, - GCancellable *cancellable, - GError **error) -{ - TransferItemToData *titd = user_data; - EClient *source_client, *destination_client; - - g_return_if_fail (titd != NULL); - g_return_if_fail (E_IS_SOURCE (titd->source)); - g_return_if_fail (E_IS_SOURCE (titd->destination)); - g_return_if_fail (E_IS_CLIENT_SELECTOR (titd->selector)); - g_return_if_fail (titd->icalcomp != NULL); - - source_client = e_client_selector_get_client_sync ( - titd->selector, titd->source, FALSE, 30, cancellable, error); - if (!source_client) - return; - - destination_client = e_client_selector_get_client_sync ( - titd->selector, titd->destination, FALSE, 30, cancellable, error); - if (!destination_client) { - g_object_unref (source_client); - return; - } - - cal_comp_transfer_item_to_sync (E_CAL_CLIENT (source_client), E_CAL_CLIENT (destination_client), - titd->icalcomp, titd->do_copy, cancellable, error); - - g_clear_object (&source_client); - g_clear_object (&destination_client); -} - -static gboolean -e_cal_base_shell_sidebar_selector_data_dropped (ESourceSelector *selector, - GtkSelectionData *selection_data, - ESource *destination, - GdkDragAction action, - guint info, - ECalBaseShellSidebar *sidebar) -{ - icalcomponent *icalcomp = NULL; - EActivity *activity; - EShellView *shell_view; - ESource *source = NULL; - ESourceRegistry *registry; - gchar **segments; - gchar *source_uid = NULL; - gchar *message = NULL; - gchar *display_name = NULL; - const gchar *alert_ident = NULL; - const guchar *data; - gboolean do_copy; - TransferItemToData *titd; - - g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE); - g_return_val_if_fail (E_IS_SOURCE (destination), FALSE); - g_return_val_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar), FALSE); - - data = gtk_selection_data_get_data (selection_data); - g_return_val_if_fail (data != NULL, FALSE); - - segments = g_strsplit ((const gchar *) data, "\n", 2); - if (g_strv_length (segments) != 2) - goto exit; - - source_uid = g_strdup (segments[0]); - icalcomp = icalparser_parse_string (segments[1]); - - if (!icalcomp) - goto exit; - - registry = e_source_selector_get_registry (selector); - source = e_source_registry_ref_source (registry, source_uid); - if (!source) - goto exit; - - display_name = e_util_get_source_full_name (registry, destination); - do_copy = action == GDK_ACTION_COPY ? TRUE : FALSE; - shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (sidebar)); - - switch (e_cal_base_shell_view_get_source_type (shell_view)) { - case E_CAL_CLIENT_SOURCE_TYPE_EVENTS: - message = do_copy ? - g_strdup_printf (_("Copying an event into the calendar “%s”"), display_name) : - g_strdup_printf (_("Moving an event into the calendar “%s”"), display_name); - alert_ident = do_copy ? "calendar:failed-copy-event" : "calendar:failed-move-event"; - break; - case E_CAL_CLIENT_SOURCE_TYPE_MEMOS: - message = do_copy ? - g_strdup_printf (_("Copying a memo into the memo list “%s”"), display_name) : - g_strdup_printf (_("Moving a memo into the memo list “%s”"), display_name); - alert_ident = do_copy ? "calendar:failed-copy-memo" : "calendar:failed-move-memo"; - break; - case E_CAL_CLIENT_SOURCE_TYPE_TASKS: - message = do_copy ? - g_strdup_printf (_("Copying a task into the task list “%s”"), display_name) : - g_strdup_printf (_("Moving a task into the task list “%s”"), display_name); - alert_ident = do_copy ? "calendar:failed-copy-task" : "calendar:failed-move-task"; - break; - case E_CAL_CLIENT_SOURCE_TYPE_LAST: - g_warn_if_reached (); - goto exit; - } - - titd = g_new0 (TransferItemToData, 1); - titd->source = g_object_ref (source); - titd->destination = g_object_ref (destination); - titd->do_copy = do_copy; - titd->icalcomp = icalcomp; - titd->selector = g_object_ref (selector); - - icalcomp = NULL; - - activity = e_shell_view_submit_thread_job (shell_view, message, - alert_ident, display_name, cal_base_shell_sidebar_transfer_thread, - titd, transfer_item_to_data_free); - - g_clear_object (&activity); - - exit: - if (icalcomp) - icalcomponent_free (icalcomp); - - g_clear_object (&source); - g_free (message); - g_free (source_uid); - g_free (display_name); - g_strfreev (segments); - - return TRUE; -} - -static void -cancel_and_unref (gpointer data) -{ - GCancellable *cancellable = data; - - if (cancellable) { - g_cancellable_cancel (cancellable); - g_object_unref (cancellable); - } -} - -static void -cal_base_shell_sidebar_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_DATE_NAVIGATOR: - g_value_set_object ( - value, - e_cal_base_shell_sidebar_get_date_navigator ( - E_CAL_BASE_SHELL_SIDEBAR (object))); - return; - - case PROP_SELECTOR: - g_value_set_object ( - value, - e_cal_base_shell_sidebar_get_selector ( - E_CAL_BASE_SHELL_SIDEBAR (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -e_cal_base_shell_sidebar_update_calendar_margin_cb (GObject *object, - GParamSpec *pspec, - gpointer *user_data) -{ - EShellWindow *shell_window; - GtkWidget *calendar; - gboolean switcher_visible; - - shell_window = E_SHELL_WINDOW (object); - calendar = GTK_WIDGET (user_data); - switcher_visible = e_shell_window_get_switcher_visible (shell_window); - - if (switcher_visible) - gtk_widget_set_margin_bottom (calendar, 0); - else - gtk_widget_set_margin_bottom (calendar, 6); -} - -static void -cal_base_shell_sidebar_constructed (GObject *object) -{ - EShellWindow *shell_window; - EShellView *shell_view; - EShellBackend *shell_backend; - EShell *shell; - EClientCache *client_cache; - const gchar *source_extension = NULL, *selector_name = NULL, *restore_state_signal = NULL; - ECalBaseShellSidebar *cal_base_shell_sidebar; - GtkWidget *container, *widget; - AtkObject *a11y; - gboolean add_navigator = FALSE; - - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_cal_base_shell_sidebar_parent_class)->constructed (object); - - cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (object); - shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (object)); - shell_backend = e_shell_view_get_shell_backend (shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - shell = e_shell_backend_get_shell (shell_backend); - - switch (e_cal_base_shell_view_get_source_type (shell_view)) { - case E_CAL_CLIENT_SOURCE_TYPE_EVENTS: - source_extension = E_SOURCE_EXTENSION_CALENDAR; - selector_name = _("Calendar Selector"); - restore_state_signal = "shell-view-created::calendar"; - add_navigator = TRUE; - break; - case E_CAL_CLIENT_SOURCE_TYPE_MEMOS: - source_extension = E_SOURCE_EXTENSION_MEMO_LIST; - selector_name = _("Memo List Selector"); - restore_state_signal = "shell-view-created::memos"; - break; - case E_CAL_CLIENT_SOURCE_TYPE_TASKS: - source_extension = E_SOURCE_EXTENSION_TASK_LIST; - selector_name = _("Task List Selector"); - restore_state_signal = "shell-view-created::tasks"; - break; - case E_CAL_CLIENT_SOURCE_TYPE_LAST: - g_warn_if_reached (); - return; - } - - client_cache = e_shell_get_client_cache (shell); - - container = GTK_WIDGET (object); - - widget = e_paned_new (GTK_ORIENTATION_VERTICAL); - gtk_container_add (GTK_CONTAINER (container), widget); - cal_base_shell_sidebar->priv->paned = widget; - - container = widget; - - widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); - gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, TRUE); - - container = widget; - - widget = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy ( - GTK_SCROLLED_WINDOW (widget), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); - - container = widget; - - widget = e_client_selector_new (client_cache, source_extension); - a11y = gtk_widget_get_accessible (widget); - atk_object_set_name (a11y, selector_name); - cal_base_shell_sidebar->priv->selector = E_SOURCE_SELECTOR (widget); - gtk_container_add (GTK_CONTAINER (container), widget); - - e_source_selector_load_groups_setup (cal_base_shell_sidebar->priv->selector, - e_shell_view_get_state_key_file (shell_view)); - - if (add_navigator) { - ECalendarItem *calitem; - - container = cal_base_shell_sidebar->priv->paned; - - widget = e_calendar_new (); - gtk_widget_set_margin_top (widget, 6); - gtk_widget_set_margin_start (widget, 6); - gtk_widget_set_margin_end (widget, 6); - calitem = e_calendar_get_item (E_CALENDAR (widget)); - e_calendar_item_set_days_start_week_sel (calitem, 9); - e_calendar_item_set_max_days_sel (calitem, 42); - gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE); - cal_base_shell_sidebar->priv->date_navigator = E_CALENDAR (widget); - gtk_widget_show (widget); - - gnome_canvas_item_set ( - GNOME_CANVAS_ITEM (e_calendar_get_item (cal_base_shell_sidebar->priv->date_navigator)), - "move-selection-when-moving", FALSE, - NULL); - - cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id = g_signal_connect_swapped ( - cal_base_shell_sidebar->priv->date_navigator, "scroll-event", - G_CALLBACK (cal_base_shell_sidebar_date_navigator_scroll_event_cb), cal_base_shell_sidebar); - } - - gtk_widget_show_all (GTK_WIDGET (object)); - - gtk_drag_dest_set ( - GTK_WIDGET (cal_base_shell_sidebar->priv->selector), GTK_DEST_DEFAULT_ALL, - NULL, 0, GDK_ACTION_COPY | GDK_ACTION_MOVE); - - e_drag_dest_add_calendar_targets (GTK_WIDGET (cal_base_shell_sidebar->priv->selector)); - - g_signal_connect (shell_window, - "notify::switcher-visible", G_CALLBACK (e_cal_base_shell_sidebar_update_calendar_margin_cb), - widget); - - g_signal_connect (cal_base_shell_sidebar->priv->selector, - "data-dropped", G_CALLBACK (e_cal_base_shell_sidebar_selector_data_dropped), - cal_base_shell_sidebar); - - g_signal_connect (cal_base_shell_sidebar->priv->selector, - "primary-selection-changed", G_CALLBACK (e_cal_base_shell_sidebar_primary_selection_changed_cb), - cal_base_shell_sidebar); - - g_signal_connect (cal_base_shell_sidebar->priv->selector, - "source-selected", G_CALLBACK (e_cal_base_shell_sidebar_source_selected), - cal_base_shell_sidebar); - - g_signal_connect (cal_base_shell_sidebar->priv->selector, - "source-unselected", G_CALLBACK (e_cal_base_shell_sidebar_source_unselected), - cal_base_shell_sidebar); - - /* Restore widget state from the last session once - * the shell view is fully initialized and visible. */ - g_signal_connect ( - shell_window, restore_state_signal, - G_CALLBACK (cal_base_shell_sidebar_restore_state_cb), - cal_base_shell_sidebar); -} - -static void -cal_base_shell_sidebar_dispose (GObject *object) -{ - ECalBaseShellSidebar *cal_base_shell_sidebar; - - cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (object); - - if (cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id > 0 && - cal_base_shell_sidebar->priv->date_navigator) { - g_signal_handler_disconnect (cal_base_shell_sidebar->priv->date_navigator, - cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id); - cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id = 0; - } - - cal_base_shell_sidebar->priv->date_navigator = NULL; - cal_base_shell_sidebar->priv->selector = NULL; - cal_base_shell_sidebar->priv->paned = NULL; - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_cal_base_shell_sidebar_parent_class)->dispose (object); -} - -static void -cal_base_shell_sidebar_finalize (GObject *object) -{ - ECalBaseShellSidebar *cal_base_shell_sidebar; - - cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (object); - - g_hash_table_destroy (cal_base_shell_sidebar->priv->selected_uids); - cal_base_shell_sidebar->priv->selected_uids = NULL; - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_cal_base_shell_sidebar_parent_class)->finalize (object); -} - -static void -e_cal_base_shell_sidebar_class_init (ECalBaseShellSidebarClass *class) -{ - GObjectClass *object_class; - EShellSidebarClass *shell_sidebar_class; - - g_type_class_add_private (class, sizeof (ECalBaseShellSidebarPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->get_property = cal_base_shell_sidebar_get_property; - object_class->constructed = cal_base_shell_sidebar_constructed; - object_class->dispose = cal_base_shell_sidebar_dispose; - object_class->finalize = cal_base_shell_sidebar_finalize; - - shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class); - shell_sidebar_class->check_state = cal_base_shell_sidebar_check_state; - - g_object_class_install_property ( - object_class, - PROP_SELECTOR, - g_param_spec_object ( - "selector", - "Source Selector Widget", - "This widget displays groups of calendars", - E_TYPE_SOURCE_SELECTOR, - G_PARAM_READABLE)); - - g_object_class_install_property ( - object_class, - PROP_DATE_NAVIGATOR, - g_param_spec_object ( - "date-navigator", - "Date Navigator Widget", - "This widget displays a miniature calendar", - E_TYPE_CALENDAR, - G_PARAM_READABLE)); - - signals[CLIENT_OPENED] = g_signal_new ( - "client-opened", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ECalBaseShellSidebarClass, client_opened), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - E_TYPE_CAL_CLIENT); - - signals[CLIENT_CLOSED] = g_signal_new ( - "client-closed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ECalBaseShellSidebarClass, client_closed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - E_TYPE_SOURCE); -} - -static void -e_cal_base_shell_sidebar_class_finalize (ECalBaseShellSidebarClass *class) -{ -} - -static void -e_cal_base_shell_sidebar_init (ECalBaseShellSidebar *cal_base_shell_sidebar) -{ - cal_base_shell_sidebar->priv = E_CAL_BASE_SHELL_SIDEBAR_GET_PRIVATE (cal_base_shell_sidebar); - cal_base_shell_sidebar->priv->selected_uids = - g_hash_table_new_full (g_str_hash, g_str_equal, g_free, cancel_and_unref); -} - -void -e_cal_base_shell_sidebar_type_register (GTypeModule *type_module) -{ - /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration - * function, so we have to wrap it with a public function in - * order to register types from a separate compilation unit. */ - e_cal_base_shell_sidebar_register_type (type_module); -} - -GtkWidget * -e_cal_base_shell_sidebar_new (EShellView *shell_view) -{ - g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); - - return g_object_new ( - E_TYPE_CAL_BASE_SHELL_SIDEBAR, - "shell-view", shell_view, NULL); -} - -ECalendar * -e_cal_base_shell_sidebar_get_date_navigator (ECalBaseShellSidebar *cal_base_shell_sidebar) -{ - g_return_val_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (cal_base_shell_sidebar), NULL); - - return cal_base_shell_sidebar->priv->date_navigator; -} - -ESourceSelector * -e_cal_base_shell_sidebar_get_selector (ECalBaseShellSidebar *cal_base_shell_sidebar) -{ - g_return_val_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (cal_base_shell_sidebar), NULL); - - return cal_base_shell_sidebar->priv->selector; -} - -void -e_cal_base_shell_sidebar_ensure_sources_open (ECalBaseShellSidebar *cal_base_shell_sidebar) -{ - GList *selected, *link; - ESourceSelector *selector; - - g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (cal_base_shell_sidebar)); - - selector = cal_base_shell_sidebar->priv->selector; - g_return_if_fail (E_IS_SOURCE_SELECTOR (selector)); - - selected = e_source_selector_get_selection (selector); - for (link = selected; link; link = g_list_next (link)) { - ESource *source = link->data; - - e_cal_base_shell_sidebar_ensure_source_opened (cal_base_shell_sidebar, source); - } - - g_list_free_full (selected, g_object_unref); -} diff --git a/src/modules/calendar/e-cal-shell-content.c b/src/modules/calendar/e-cal-shell-content.c index 69c4e72..87ed166 100644 --- a/src/modules/calendar/e-cal-shell-content.c +++ b/src/modules/calendar/e-cal-shell-content.c @@ -847,9 +847,9 @@ cal_shell_content_get_attendee_prop (icalcomponent *icalcomp, while (prop != NULL) { const gchar *attendee; - attendee = itip_strip_mailto (icalproperty_get_attendee (prop)); + attendee = icalproperty_get_attendee (prop); - if (attendee && g_ascii_strcasecmp (attendee, address) == 0) + if (g_str_equal (itip_strip_mailto (attendee), address)) return prop; prop = icalcomponent_get_next_property ( diff --git a/src/modules/calendar/e-cal-shell-content.c.crash-empty-attendee b/src/modules/calendar/e-cal-shell-content.c.crash-empty-attendee deleted file mode 100644 index 87ed166..0000000 --- a/src/modules/calendar/e-cal-shell-content.c.crash-empty-attendee +++ /dev/null @@ -1,2338 +0,0 @@ -/* - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser 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 Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - */ - -#include "evolution-config.h" - -#include -#include -#include - -#include "calendar/gui/calendar-config.h" -#include "calendar/gui/calendar-view.h" -#include "calendar/gui/comp-util.h" -#include "calendar/gui/e-cal-list-view.h" -#include "calendar/gui/e-cal-model-calendar.h" -#include "calendar/gui/e-cal-model-memos.h" -#include "calendar/gui/e-cal-model-tasks.h" -#include "calendar/gui/e-calendar-view.h" -#include "calendar/gui/e-day-view.h" -#include "calendar/gui/e-month-view.h" -#include "calendar/gui/e-week-view.h" -#include "calendar/gui/itip-utils.h" -#include "calendar/gui/tag-calendar.h" - -#include "e-cal-base-shell-sidebar.h" -#include "e-cal-shell-view-private.h" -#include "e-cal-shell-content.h" - -#define E_CAL_SHELL_CONTENT_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentPrivate)) - -struct _ECalShellContentPrivate { - GtkWidget *hpaned; - GtkWidget *vpaned; - - GtkWidget *calendar_notebook; - GtkWidget *task_table; - ECalModel *task_model; - ECalDataModel *task_data_model; - - GtkWidget *memo_table; - ECalModel *memo_model; - ECalDataModel *memo_data_model; - - ETagCalendar *tag_calendar; - gulong datepicker_selection_changed_id; - gulong datepicker_range_moved_id; - - ECalViewKind current_view; - ECalendarView *views[E_CAL_VIEW_KIND_LAST]; - GDate view_start, view_end; - guint32 view_start_range_day_offset; - GDate last_range_start; /* because "date-range-changed" can be emit with no real change */ - - time_t previous_selected_start_time; - time_t previous_selected_end_time; - - gulong current_view_id_changed_id; -}; - -enum { - PROP_0, - PROP_CALENDAR_NOTEBOOK, - PROP_MEMO_TABLE, - PROP_TASK_TABLE, - PROP_CURRENT_VIEW_ID, - PROP_CURRENT_VIEW -}; - -/* Used to indicate who has the focus within the calendar view. */ -typedef enum { - FOCUS_CALENDAR_NOTEBOOK, - FOCUS_MEMO_TABLE, - FOCUS_TASK_TABLE, - FOCUS_OTHER -} FocusLocation; - -G_DEFINE_DYNAMIC_TYPE (ECalShellContent, e_cal_shell_content, E_TYPE_CAL_BASE_SHELL_CONTENT) - -static time_t -convert_to_local_zone (time_t tm, - icaltimezone *from_zone) -{ - struct icaltimetype tt; - - tt = icaltime_from_timet_with_zone (tm, FALSE, from_zone); - return icaltime_as_timet (tt); -} - -static void -cal_shell_content_update_model_and_current_view_times (ECalShellContent *cal_shell_content, - ECalModel *model, - ECalendarItem *calitem, - time_t view_start_tt, - time_t view_end_tt, - const GDate *view_start, - const GDate *view_end) -{ - ECalendarView *current_view; - EDayView *day_view = NULL; - gint day_view_selection_start_day = -1, day_view_selection_end_day = -1; - gint day_view_selection_start_row = -1, day_view_selection_end_row = -1; - gdouble day_view_scrollbar_position = 0.0; - gint syy, smm, sdd, eyy, emm, edd; - time_t visible_range_start, visible_range_end; - gboolean filters_updated = FALSE; - icaltimezone *zone; - gchar *cal_filter; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - g_return_if_fail (E_IS_CAL_MODEL (model)); - g_return_if_fail (E_IS_CALENDAR_ITEM (calitem)); - - current_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content); - g_return_if_fail (current_view != NULL); - - zone = e_cal_model_get_timezone (model); - cal_filter = e_cal_data_model_dup_filter (e_cal_model_get_data_model (model)); - - if (E_IS_DAY_VIEW (current_view)) { - GtkAdjustment *adjustment; - - day_view = E_DAY_VIEW (current_view); - day_view_selection_start_day = day_view->selection_start_day; - day_view_selection_end_day = day_view->selection_end_day; - day_view_selection_start_row = day_view->selection_start_row; - day_view_selection_end_row = day_view->selection_end_row; - - adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (day_view->main_canvas)); - day_view_scrollbar_position = gtk_adjustment_get_value (adjustment); - } - - g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_range_moved_id); - g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_selection_changed_id); - - visible_range_start = view_start_tt; - visible_range_end = view_end_tt; - - e_calendar_view_precalc_visible_time_range (current_view, view_start_tt, view_end_tt, &visible_range_start, &visible_range_end); - if (view_start_tt != visible_range_start || view_end_tt != visible_range_end) { - time_t cmp_range_start = convert_to_local_zone (visible_range_start, zone); - time_t cmp_range_end = convert_to_local_zone (visible_range_end, zone); - - if (view_start_tt != cmp_range_start || - view_end_tt != cmp_range_end - 1) { - /* Calendar views update their inner time range during e_cal_model_set_time_range() call, - while they can change it if needed (like a clamp of a week view with a week start day - not being Monday */ - GDate new_view_start, new_view_end; - - /* Midnight means the next day, which is not desired here */ - cmp_range_end--; - visible_range_end--; - - /* These times are in the correct zone already */ - time_to_gdate_with_zone (&new_view_start, cmp_range_start, NULL); - time_to_gdate_with_zone (&new_view_end, cmp_range_end, NULL); - - e_calendar_item_set_selection (calitem, &new_view_start, &new_view_end); - e_cal_shell_content_update_filters (cal_shell_content, cal_filter, visible_range_start, visible_range_end); - e_calendar_view_set_selected_time_range (current_view, cmp_range_start, cmp_range_start); - filters_updated = TRUE; - view_start_tt = cmp_range_start; - view_end_tt = cmp_range_end; - } - } - - if (!filters_updated) { - e_calendar_item_set_selection (calitem, view_start, view_end); - e_cal_shell_content_update_filters (cal_shell_content, cal_filter, view_start_tt, view_end_tt); - e_calendar_view_set_selected_time_range (current_view, view_start_tt, view_start_tt); - } - - if (day_view && day_view_selection_start_day != -1 && day_view_selection_end_day != -1 && - day_view_selection_start_row != -1 && day_view_selection_end_row != -1) { - GtkAdjustment *adjustment; - - day_view->selection_start_day = day_view_selection_start_day; - day_view->selection_end_day = day_view_selection_end_day; - day_view->selection_start_row = day_view_selection_start_row; - day_view->selection_end_row = day_view_selection_end_row; - - /* This is better than e_day_view_ensure_rows_visible(), because it keeps both - selection and the exact scrollbar position in the main canvas, which may not - always correspond to each other. */ - adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (day_view->main_canvas)); - gtk_adjustment_set_value (adjustment, day_view_scrollbar_position); - } - - gtk_widget_queue_draw (GTK_WIDGET (current_view)); - - g_free (cal_filter); - - g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_range_moved_id); - g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_selection_changed_id); - - if (e_calendar_item_get_date_range (calitem, &syy, &smm, &sdd, &eyy, &emm, &edd)) { - GDate range_start; - - g_date_set_dmy (&range_start, sdd, smm + 1, syy); - - cal_shell_content->priv->view_start_range_day_offset = - g_date_get_julian (&cal_shell_content->priv->view_start) - g_date_get_julian (&range_start); - } -} - -static void -e_cal_shell_content_change_view (ECalShellContent *cal_shell_content, - ECalViewKind to_view, - const GDate *view_start, - const GDate *view_end, - gboolean force_change) -{ - EShellSidebar *shell_sidebar; - EShellView *shell_view; - ECalendar *calendar; - ECalModel *model; - icaltimezone *zone; - time_t view_start_tt, view_end_tt; - gboolean view_changed = FALSE; - gint selected_days; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - g_return_if_fail (to_view >= E_CAL_VIEW_KIND_DAY && to_view < E_CAL_VIEW_KIND_LAST); - g_return_if_fail (view_start != NULL); - g_return_if_fail (g_date_valid (view_start)); - g_return_if_fail (view_end != NULL); - g_return_if_fail (g_date_valid (view_end)); - - shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content)); - shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); - g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (shell_sidebar)); - - calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar)); - g_return_if_fail (E_IS_CALENDAR (calendar)); - - model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - zone = e_cal_model_get_timezone (model); - view_start_tt = cal_comp_gdate_to_timet (view_start, zone); - view_end_tt = cal_comp_gdate_to_timet (view_end, zone); - - if (to_view != cal_shell_content->priv->current_view) { - g_signal_handler_block (cal_shell_content, cal_shell_content->priv->current_view_id_changed_id); - e_cal_shell_content_set_current_view_id (cal_shell_content, to_view); - g_signal_handler_unblock (cal_shell_content, cal_shell_content->priv->current_view_id_changed_id); - view_changed = TRUE; - } - - selected_days = g_date_get_julian (view_end) - g_date_get_julian (view_start) + 1; - - if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY) { - EDayView *day_view; - - day_view = E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY]); - e_day_view_set_days_shown (day_view, selected_days); - } else if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_MONTH) { - EWeekView *month_view; - - month_view = E_WEEK_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_MONTH]); - e_week_view_set_weeks_shown (month_view, selected_days / 7); - } - - if (!force_change && - g_date_valid (&cal_shell_content->priv->view_start) && - g_date_valid (&cal_shell_content->priv->view_end) && - g_date_compare (&cal_shell_content->priv->view_start, view_start) == 0 && - g_date_compare (&cal_shell_content->priv->view_end, view_end) == 0) { - ECalendarItem *calitem = e_calendar_get_item (calendar); - - if (view_changed) - cal_shell_content_update_model_and_current_view_times ( - cal_shell_content, model, calitem, view_start_tt, view_end_tt, view_start, view_end); - - g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_range_moved_id); - g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_selection_changed_id); - - e_calendar_item_set_selection (calitem, view_start, view_end); - - g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_range_moved_id); - g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_selection_changed_id); - - return; - } - - cal_shell_content->priv->view_start = *view_start; - cal_shell_content->priv->view_end = *view_end; - - cal_shell_content_update_model_and_current_view_times ( - cal_shell_content, model, e_calendar_get_item (calendar), view_start_tt, view_end_tt, view_start, view_end); -} - -static void -cal_shell_content_clamp_for_whole_weeks (GDateWeekday week_start_day, - GDate *sel_start, - GDate *sel_end, - gboolean saturday_as_sunday) -{ - GDateWeekday wday; - guint32 julian_start, julian_end; - - g_return_if_fail (sel_start != NULL); - g_return_if_fail (sel_end != NULL); - - wday = g_date_get_weekday (sel_start); - - /* This is because the month/week view doesn't split weekends */ - if (saturday_as_sunday && wday == G_DATE_SATURDAY && week_start_day == G_DATE_SUNDAY) - wday = G_DATE_SUNDAY; - - if (week_start_day > wday) { - g_date_subtract_days (sel_start, wday); - wday = g_date_get_weekday (sel_start); - } - - if (week_start_day < wday) - g_date_subtract_days (sel_start, wday - week_start_day); - - julian_start = g_date_get_julian (sel_start); - julian_end = g_date_get_julian (sel_end); - - if (((julian_end - julian_start + 1) % 7) != 0) - g_date_add_days (sel_end, 7 - ((julian_end - julian_start + 1) % 7)); - - julian_end = g_date_get_julian (sel_end); - - /* Can show only up to 6 weeks */ - if ((julian_end - julian_start + 1) / 7 > 6) { - *sel_end = *sel_start; - g_date_add_days (sel_end, (7 * 6) - 1); - } - - if (g_date_compare (sel_start, sel_end) == 0) - g_date_add_days (sel_end, 6); -} - -static gboolean -cal_shell_content_weekday_within (GDateWeekday start_wday, - GDateWeekday end_wday, - GDateWeekday test_wday) -{ - gint ii; - - if (start_wday <= end_wday) - return start_wday <= test_wday && test_wday <= end_wday; - - for (ii = 0; ii < 7; ii++) { - if (start_wday == test_wday) - return TRUE; - - if (start_wday == end_wday) - break; - - start_wday = e_weekday_get_next (start_wday); - } - - return FALSE; -} - -static void -cal_shell_content_change_selection_in_current_view (ECalShellContent *cal_shell_content, - time_t sel_start_tt, - time_t sel_end_tt, - icaltimezone *zone) -{ - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - if (cal_shell_content->priv->current_view >= E_CAL_VIEW_KIND_DAY && - cal_shell_content->priv->current_view < E_CAL_VIEW_KIND_LAST) { - ECalendarView *view; - - view = cal_shell_content->priv->views[cal_shell_content->priv->current_view]; - - /* Preserve selected time (change only date) for these views */ - if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY || - cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WORKWEEK) { - time_t current_sel_start = (time_t) -1, current_sel_end = (time_t) -1; - - if (e_calendar_view_get_selected_time_range (view, ¤t_sel_start, ¤t_sel_end)) { - current_sel_start = icaltime_as_timet_with_zone (icaltime_from_timet_with_zone (current_sel_start, 0, zone), NULL); - current_sel_end = icaltime_as_timet_with_zone (icaltime_from_timet_with_zone (current_sel_end, 0, zone), NULL); - - sel_start_tt += current_sel_start % (24 * 60 * 60); - sel_end_tt += current_sel_end % (24 * 60 * 60); - } - } - - e_calendar_view_set_selected_time_range (view, sel_start_tt, sel_end_tt); - } -} - -static void -cal_shell_content_datepicker_selection_changed_cb (ECalendarItem *calitem, - ECalShellContent *cal_shell_content) -{ - GDate sel_start, sel_end; - guint32 selected_days, start_julian, end_julian; - icaltimezone *zone; - time_t sel_start_tt, sel_end_tt; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - g_return_if_fail (E_IS_CALENDAR_ITEM (calitem)); - - g_date_clear (&sel_start, 1); - g_date_clear (&sel_end, 1); - - e_calendar_item_get_selection (calitem, &sel_start, &sel_end); - - start_julian = g_date_get_julian (&sel_start); - end_julian = g_date_get_julian (&sel_end); - - g_return_if_fail (start_julian <= end_julian); - - if (g_date_compare (&cal_shell_content->priv->view_start, &sel_start) == 0 && - g_date_compare (&cal_shell_content->priv->view_end, &sel_end) == 0) { - /* No change in the selection range */ - return; - } - - zone = e_cal_model_get_timezone (e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content))); - sel_start_tt = cal_comp_gdate_to_timet (&sel_start, zone); - sel_end_tt = cal_comp_gdate_to_timet (&sel_end, zone); - - selected_days = end_julian - start_julian + 1; - if (selected_days == 1) { - GDateWeekday sel_start_wday, sel_end_wday, cur_start_wday, cur_end_wday; - - /* Clicked inside currently selected view range; do not do anything, - just make sure the days are selected again */ - if (g_date_compare (&cal_shell_content->priv->view_start, &sel_start) <= 0 && - g_date_compare (&sel_start, &cal_shell_content->priv->view_end) <= 0) { - sel_start = cal_shell_content->priv->view_start; - sel_end = cal_shell_content->priv->view_end; - - e_calendar_item_set_selection (calitem, &sel_start, &sel_end); - - cal_shell_content_change_selection_in_current_view (cal_shell_content, sel_start_tt, sel_end_tt, zone); - return; - } - - sel_start_wday = g_date_get_weekday (&sel_start); - sel_end_wday = g_date_get_weekday (&sel_end); - cur_start_wday = g_date_get_weekday (&cal_shell_content->priv->view_start); - cur_end_wday = g_date_get_weekday (&cal_shell_content->priv->view_end); - - if ((cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WORKWEEK || - (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY && - e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY])) != 1)) && - cal_shell_content_weekday_within (cur_start_wday, cur_end_wday, sel_start_wday)) { - if (cur_start_wday < sel_start_wday) { - g_date_subtract_days (&sel_start, sel_start_wday - cur_start_wday); - } else if (cur_start_wday > sel_start_wday) { - g_date_subtract_days (&sel_start, 7 - (cur_start_wday - sel_start_wday)); - } - sel_end = sel_start; - if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY) - g_date_add_days (&sel_end, e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY])) - 1); - else - g_date_add_days (&sel_end, e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK])) - 1); - - e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &sel_start, &sel_end, FALSE); - } else if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WEEK && - cal_shell_content_weekday_within (cur_start_wday, cur_end_wday, sel_start_wday) && - cal_shell_content_weekday_within (cur_start_wday, cur_end_wday, sel_end_wday)) { - if (cur_start_wday < sel_start_wday) - g_date_subtract_days (&sel_start, sel_start_wday - cur_start_wday); - sel_end = sel_start; - cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, &sel_end, TRUE); - - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_WEEK, &sel_start, &sel_end, FALSE); - } else if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_MONTH || - cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_LIST) { - /* whole month */ - g_date_set_day (&sel_start, 1); - sel_end = sel_start; - g_date_set_day (&sel_end, g_date_get_days_in_month (g_date_get_month (&sel_start), g_date_get_year (&sel_start)) - 1); - cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, &sel_end, cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_MONTH); - - e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &sel_start, &sel_end, FALSE); - } else if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WORKWEEK) { - cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, &sel_end, TRUE); - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_WEEK, &sel_start, &sel_end, FALSE); - } else { - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, &sel_end, FALSE); - } - - cal_shell_content_change_selection_in_current_view (cal_shell_content, sel_start_tt, sel_end_tt, zone); - } else if (selected_days < 7) { - GDateWeekday first_work_wday; - - first_work_wday = e_cal_model_get_work_day_first (e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content))); - - if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WORKWEEK && - first_work_wday == g_date_get_weekday (&sel_start) && - selected_days == e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK]))) - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_WORKWEEK, &sel_start, &sel_end, FALSE); - else - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, &sel_end, FALSE); - } else if (selected_days == 7) { - GDateWeekday sel_start_wday; - - sel_start_wday = g_date_get_weekday (&sel_start); - - if (sel_start_wday == calitem->week_start_day && - cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY && - e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY])) == 7) { - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, &sel_end, FALSE); - } else { - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_WEEK, &sel_start, &sel_end, FALSE); - } - } else { - if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_LIST) { - /* whole month */ - g_date_set_day (&sel_start, 1); - sel_end = sel_start; - g_date_set_day (&sel_end, g_date_get_days_in_month (g_date_get_month (&sel_start), g_date_get_year (&sel_start))); - cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, &sel_end, FALSE); - - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_LIST, &sel_start, &sel_end, FALSE); - } else { - cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, &sel_end, - cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_MONTH || cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WEEK); - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_MONTH, &sel_start, &sel_end, FALSE); - } - } -} - -static void -cal_shell_content_datepicker_range_moved_cb (ECalendarItem *calitem, - ECalShellContent *cal_shell_content) -{ - gint start_year, start_month, start_day, end_year, end_month, end_day; - GDate sel_start_date, sel_end_date, range_start_date; - - g_return_if_fail (E_IS_CALENDAR_ITEM (calitem)); - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - if (!e_calendar_item_get_date_range (calitem, &start_year, &start_month, &start_day, &end_year, &end_month, &end_day)) - return; - - g_date_set_dmy (&range_start_date, start_day, start_month + 1, start_year); - - if (g_date_valid (&cal_shell_content->priv->last_range_start) && - g_date_compare (&cal_shell_content->priv->last_range_start, &range_start_date) == 0) { - return; - } - - cal_shell_content->priv->last_range_start = range_start_date; - - g_date_clear (&sel_start_date, 1); - g_date_clear (&sel_end_date, 1); - - if (cal_shell_content->priv->view_start_range_day_offset == (guint32) -1) { - sel_start_date = cal_shell_content->priv->view_start; - sel_end_date = cal_shell_content->priv->view_end; - cal_shell_content->priv->view_start_range_day_offset = - g_date_get_julian (&cal_shell_content->priv->view_start) - g_date_get_julian (&range_start_date); - } else { - gint view_days; - - view_days = g_date_get_julian (&cal_shell_content->priv->view_end) - g_date_get_julian (&cal_shell_content->priv->view_start); - - sel_start_date = range_start_date; - g_date_add_days (&sel_start_date, cal_shell_content->priv->view_start_range_day_offset); - - sel_end_date = sel_start_date; - g_date_add_days (&sel_end_date, view_days); - } - - g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_range_moved_id); - - e_calendar_item_set_selection (calitem, &sel_start_date, &sel_end_date); - - g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_range_moved_id); -} - -static gboolean -cal_shell_content_datepicker_button_press_cb (ECalendar *calendar, - GdkEvent *event, - ECalShellContent *cal_shell_content) -{ - g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), FALSE); - - if (!event) - return FALSE; - - if (event->type == GDK_2BUTTON_PRESS) { - ECalendarItem *calitem = e_calendar_get_item (calendar); - GDate sel_start, sel_end; - - g_date_clear (&sel_start, 1); - g_date_clear (&sel_end, 1); - - e_calendar_item_get_selection (calitem, &sel_start, &sel_end); - - /* Switch to a day view on a double-click */ - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, &sel_start, FALSE); - } - - return FALSE; -} - -static void -cal_shell_content_current_view_id_changed_cb (ECalShellContent *cal_shell_content) -{ - GDate sel_start, sel_end; - GDateWeekday work_day_first, week_start_day; - ECalModel *model; - gint ii; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - work_day_first = e_cal_model_get_work_day_first (model); - week_start_day = e_cal_model_get_week_start_day (model); - - if (cal_shell_content->priv->previous_selected_start_time != -1 && - cal_shell_content->priv->previous_selected_end_time != -1) { - icaltimezone *zone; - - zone = e_cal_model_get_timezone (model); - time_to_gdate_with_zone (&sel_start, cal_shell_content->priv->previous_selected_start_time, zone); - time_to_gdate_with_zone (&sel_end, cal_shell_content->priv->previous_selected_end_time, zone); - } else { - sel_start = cal_shell_content->priv->view_start; - sel_end = cal_shell_content->priv->view_end; - } - - switch (cal_shell_content->priv->current_view) { - case E_CAL_VIEW_KIND_DAY: - /* Left the start & end being the current view start */ - sel_end = sel_start; - break; - case E_CAL_VIEW_KIND_WORKWEEK: - cal_shell_content_clamp_for_whole_weeks (week_start_day, &sel_start, &sel_end, FALSE); - ii = 0; - while (g_date_get_weekday (&sel_start) != work_day_first && ii < 7) { - g_date_add_days (&sel_start, 1); - ii++; - } - - sel_end = sel_start; - g_date_add_days (&sel_end, e_day_view_get_days_shown (E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK])) - 1); - break; - case E_CAL_VIEW_KIND_WEEK: - sel_end = sel_start; - cal_shell_content_clamp_for_whole_weeks (week_start_day, &sel_start, &sel_end, TRUE); - break; - case E_CAL_VIEW_KIND_MONTH: - case E_CAL_VIEW_KIND_LIST: - if (g_date_get_day (&sel_start) != 1 && - (g_date_get_julian (&sel_end) - g_date_get_julian (&sel_start) + 1) / 7 >= 3 && - g_date_get_month (&sel_start) != g_date_get_month (&sel_end)) { - g_date_set_day (&sel_start, 1); - g_date_add_months (&sel_start, 1); - } else { - g_date_set_day (&sel_start, 1); - } - sel_end = sel_start; - g_date_add_months (&sel_end, 1); - g_date_subtract_days (&sel_end, 1); - cal_shell_content_clamp_for_whole_weeks (week_start_day, &sel_start, &sel_end, cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_MONTH); - break; - default: - g_warn_if_reached (); - return; - } - - /* Ensure a change */ - e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &sel_start, &sel_end, TRUE); - - /* Try to preserve selection between the views */ - if (cal_shell_content->priv->previous_selected_start_time != -1 && - cal_shell_content->priv->previous_selected_end_time != -1) { - if (cal_shell_content->priv->current_view >= E_CAL_VIEW_KIND_DAY && - cal_shell_content->priv->current_view < E_CAL_VIEW_KIND_LAST) { - ECalendarView *cal_view = cal_shell_content->priv->views[cal_shell_content->priv->current_view]; - - e_calendar_view_set_selected_time_range (cal_view, - cal_shell_content->priv->previous_selected_start_time, - cal_shell_content->priv->previous_selected_end_time); - } - } - - cal_shell_content->priv->previous_selected_start_time = -1; - cal_shell_content->priv->previous_selected_end_time = -1; -} - -static void -cal_shell_content_display_view_cb (ECalShellContent *cal_shell_content, - GalView *gal_view) -{ - ECalViewKind view_kind; - GType gal_view_type; - - gal_view_type = G_OBJECT_TYPE (gal_view); - - if (gal_view_type == GAL_TYPE_VIEW_ETABLE) { - ECalendarView *calendar_view; - - view_kind = E_CAL_VIEW_KIND_LIST; - calendar_view = cal_shell_content->priv->views[view_kind]; - gal_view_etable_attach_table ( - GAL_VIEW_ETABLE (gal_view), - E_CAL_LIST_VIEW (calendar_view)->table); - - } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_DAY) { - view_kind = E_CAL_VIEW_KIND_DAY; - - } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_WORK_WEEK) { - view_kind = E_CAL_VIEW_KIND_WORKWEEK; - - } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_WEEK) { - view_kind = E_CAL_VIEW_KIND_WEEK; - - } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_MONTH) { - view_kind = E_CAL_VIEW_KIND_MONTH; - - } else { - g_return_if_reached (); - } - - e_cal_shell_content_set_current_view_id (cal_shell_content, view_kind); -} - -static void -cal_shell_content_notify_view_id_cb (ECalShellContent *cal_shell_content) -{ - EShellContent *shell_content; - EShellView *shell_view; - GSettings *settings; - GtkWidget *paned; - const gchar *key; - const gchar *view_id; - - settings = e_util_ref_settings ("org.gnome.evolution.calendar"); - paned = cal_shell_content->priv->hpaned; - - shell_content = E_SHELL_CONTENT (cal_shell_content); - shell_view = e_shell_content_get_shell_view (shell_content); - view_id = e_shell_view_get_view_id (shell_view); - - if (view_id != NULL && strcmp (view_id, "Month_View") == 0) - key = "month-hpane-position"; - else - key = "hpane-position"; - - g_settings_unbind (paned, "hposition"); - - g_settings_bind ( - settings, key, - paned, "hposition", - G_SETTINGS_BIND_DEFAULT); - - g_object_unref (settings); -} - -static void -cal_shell_content_is_editing_changed_cb (gpointer cal_view_tasks_memos_table, - GParamSpec *param, - EShellView *shell_view) -{ - g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); - - e_shell_view_update_actions (shell_view); -} - -static gchar * -cal_shell_content_get_pad_state_filename (EShellContent *shell_content, - ETable *table) -{ - EShellBackend *shell_backend; - EShellView *shell_view; - const gchar *config_dir, *nick = NULL; - - g_return_val_if_fail (shell_content != NULL, NULL); - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); - g_return_val_if_fail (table != NULL, NULL); - g_return_val_if_fail (E_IS_TABLE (table), NULL); - - if (E_IS_TASK_TABLE (table)) - nick = "TaskPad"; - else if (E_IS_MEMO_TABLE (table)) - nick = "MemoPad"; - - g_return_val_if_fail (nick != NULL, NULL); - - shell_view = e_shell_content_get_shell_view (shell_content); - shell_backend = e_shell_view_get_shell_backend (shell_view); - config_dir = e_shell_backend_get_config_dir (shell_backend); - - return g_build_filename (config_dir, nick, NULL); -} - -static void -cal_shell_content_save_table_state (EShellContent *shell_content, - ETable *table) -{ - gchar *filename; - - filename = cal_shell_content_get_pad_state_filename ( - shell_content, table); - g_return_if_fail (filename != NULL); - - e_table_save_state (table, filename); - g_free (filename); -} - -static void -cal_shell_content_load_table_state (EShellContent *shell_content, - ETable *table) -{ - gchar *filename; - - filename = cal_shell_content_get_pad_state_filename (shell_content, table); - g_return_if_fail (filename != NULL); - - e_table_load_state (table, filename); - g_free (filename); -} - -static icalproperty * -cal_shell_content_get_attendee_prop (icalcomponent *icalcomp, - const gchar *address) -{ - icalproperty *prop; - - if (address == NULL || *address == '\0') - return NULL; - - prop = icalcomponent_get_first_property ( - icalcomp, ICAL_ATTENDEE_PROPERTY); - - while (prop != NULL) { - const gchar *attendee; - - attendee = icalproperty_get_attendee (prop); - - if (g_str_equal (itip_strip_mailto (attendee), address)) - return prop; - - prop = icalcomponent_get_next_property ( - icalcomp, ICAL_ATTENDEE_PROPERTY); - } - - return NULL; -} - -static gboolean -cal_shell_content_icalcomp_is_delegated (icalcomponent *icalcomp, - const gchar *user_email) -{ - icalproperty *prop; - icalparameter *param; - const gchar *delto = NULL; - gboolean is_delegated = FALSE; - - prop = cal_shell_content_get_attendee_prop (icalcomp, user_email); - - if (prop != NULL) { - param = icalproperty_get_first_parameter ( - prop, ICAL_DELEGATEDTO_PARAMETER); - if (param != NULL) { - delto = icalparameter_get_delegatedto (param); - delto = itip_strip_mailto (delto); - } - } else - return FALSE; - - prop = cal_shell_content_get_attendee_prop (icalcomp, delto); - - if (prop != NULL) { - const gchar *delfrom = NULL; - icalparameter_partstat status = ICAL_PARTSTAT_NONE; - - param = icalproperty_get_first_parameter ( - prop, ICAL_DELEGATEDFROM_PARAMETER); - if (param != NULL) { - delfrom = icalparameter_get_delegatedfrom (param); - delfrom = itip_strip_mailto (delfrom); - } - param = icalproperty_get_first_parameter ( - prop, ICAL_PARTSTAT_PARAMETER); - if (param != NULL) - status = icalparameter_get_partstat (param); - is_delegated = - (status != ICAL_PARTSTAT_DECLINED) && - (g_strcmp0 (delfrom, user_email) == 0); - } - - return is_delegated; -} - -static guint32 -cal_shell_content_check_state (EShellContent *shell_content) -{ - EShell *shell; - EShellView *shell_view; - EShellBackend *shell_backend; - ESourceRegistry *registry; - ECalShellContent *cal_shell_content; - ECalendarView *calendar_view; - gboolean selection_is_editable = FALSE; - gboolean selection_is_instance = FALSE; - gboolean selection_is_meeting = FALSE; - gboolean selection_is_organizer = FALSE; - gboolean selection_is_recurring = FALSE; - gboolean selection_can_delegate = FALSE; - guint32 state = 0; - GList *selected; - GList *link; - guint n_selected; - - cal_shell_content = E_CAL_SHELL_CONTENT (shell_content); - - shell_view = e_shell_content_get_shell_view (shell_content); - shell_backend = e_shell_view_get_shell_backend (shell_view); - shell = e_shell_backend_get_shell (shell_backend); - registry = e_shell_get_registry (shell); - - calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content); - - selected = e_calendar_view_get_selected_events (calendar_view); - n_selected = g_list_length (selected); - - /* If we have a selection, assume it's - * editable until we learn otherwise. */ - if (n_selected > 0) - selection_is_editable = TRUE; - - for (link = selected; link != NULL; link = g_list_next (link)) { - ECalendarViewEvent *event = link->data; - ECalClient *client; - ECalComponent *comp; - gchar *user_email; - icalcomponent *icalcomp; - const gchar *capability; - gboolean cap_delegate_supported; - gboolean cap_delegate_to_many; - gboolean icalcomp_is_delegated; - gboolean read_only; - - if (!is_comp_data_valid (event)) - continue; - - client = event->comp_data->client; - icalcomp = event->comp_data->icalcomp; - - read_only = e_client_is_readonly (E_CLIENT (client)); - selection_is_editable &= !read_only; - - selection_is_instance |= - e_cal_util_component_is_instance (icalcomp); - - selection_is_meeting = - (n_selected == 1) && - e_cal_util_component_has_attendee (icalcomp); - - selection_is_recurring |= - e_cal_util_component_is_instance (icalcomp) || - e_cal_util_component_has_recurrences (icalcomp); - - /* XXX The rest of this is rather expensive and - * only applies if a single event is selected, - * so continue with the loop iteration if the - * rest of this is not applicable. */ - if (n_selected > 1) - continue; - - /* XXX This probably belongs in comp-util.c. */ - - comp = e_cal_component_new (); - e_cal_component_set_icalcomponent ( - comp, icalcomponent_new_clone (icalcomp)); - user_email = itip_get_comp_attendee ( - registry, comp, client); - - selection_is_organizer = - e_cal_util_component_has_organizer (icalcomp) && - itip_organizer_is_user (registry, comp, client); - - capability = CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED; - cap_delegate_supported = - e_client_check_capability ( - E_CLIENT (client), capability); - - capability = CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY; - cap_delegate_to_many = - e_client_check_capability ( - E_CLIENT (client), capability); - - icalcomp_is_delegated = - (user_email != NULL) && - cal_shell_content_icalcomp_is_delegated ( - icalcomp, user_email); - - selection_can_delegate = - cap_delegate_supported && - (cap_delegate_to_many || - (!selection_is_organizer && - !icalcomp_is_delegated)); - - g_free (user_email); - g_object_unref (comp); - } - - g_list_free (selected); - - if (n_selected == 1) - state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_SINGLE; - if (n_selected > 1) - state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_MULTIPLE; - if (selection_is_editable) - state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_EDITABLE; - if (selection_is_instance) - state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_INSTANCE; - if (selection_is_meeting) - state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_MEETING; - if (selection_is_organizer) - state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_ORGANIZER; - if (selection_is_recurring) - state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_RECURRING; - if (selection_can_delegate) - state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_CAN_DELEGATE; - - return state; -} - -static void -cal_shell_content_focus_search_results (EShellContent *shell_content) -{ - ECalendarView *calendar_view; - - calendar_view = e_cal_shell_content_get_current_calendar_view (E_CAL_SHELL_CONTENT (shell_content)); - - gtk_widget_grab_focus (GTK_WIDGET (calendar_view)); -} - -static time_t -cal_shell_content_get_default_time (ECalModel *model, - gpointer user_data) -{ - ECalShellContent *cal_shell_content = user_data; - icaltimezone *zone; - - g_return_val_if_fail (model != NULL, 0); - g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), 0); - - if (e_cal_shell_content_get_current_view_id (cal_shell_content) != E_CAL_VIEW_KIND_LIST) { - ECalendarView *cal_view; - time_t selected_start = (time_t) 0, selected_end = (time_t) 0; - - cal_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content); - - if (cal_view && e_calendar_view_get_selected_time_range (cal_view, &selected_start, &selected_end)) - return selected_start; - } - - zone = e_cal_model_get_timezone (model); - - return icaltime_as_timet_with_zone (icaltime_current_time_with_zone (zone), zone); -} - -static void -update_adjustment (ECalShellContent *cal_shell_content, - GtkAdjustment *adjustment, - EWeekView *week_view, - gboolean move_by_week) -{ - GDate start_date, end_date; - GDate first_day_shown; - ECalModel *model; - gint week_offset; - struct icaltimetype start_tt = icaltime_null_time (); - time_t lower; - guint32 old_first_day_julian, new_first_day_julian; - icaltimezone *timezone; - gdouble value; - - e_week_view_get_first_day_shown (week_view, &first_day_shown); - - /* If we don't have a valid date set yet, just return. */ - if (!g_date_valid (&first_day_shown)) - return; - - value = gtk_adjustment_get_value (adjustment); - - /* Determine the first date shown. */ - start_date = week_view->base_date; - week_offset = floor (value + 0.5); - g_date_add_days (&start_date, week_offset * 7); - - /* Convert the old & new first days shown to julian values. */ - old_first_day_julian = g_date_get_julian (&first_day_shown); - new_first_day_julian = g_date_get_julian (&start_date); - - /* If we are already showing the date, just return. */ - if (old_first_day_julian == new_first_day_julian) - return; - - /* Convert it to a time_t. */ - start_tt.year = g_date_get_year (&start_date); - start_tt.month = g_date_get_month (&start_date); - start_tt.day = g_date_get_day (&start_date); - - model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - timezone = e_cal_model_get_timezone (model); - lower = icaltime_as_timet_with_zone (start_tt, timezone); - - end_date = start_date; - if (move_by_week) { - g_date_add_days (&end_date, 7 - 1); - } else { - g_date_add_days (&end_date, 7 * e_week_view_get_weeks_shown (week_view) - 1); - } - - e_week_view_set_update_base_date (week_view, FALSE); - e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &start_date, &end_date, FALSE); - e_calendar_view_set_selected_time_range (E_CALENDAR_VIEW (week_view), lower, lower); - e_week_view_set_update_base_date (week_view, TRUE); -} - -static void -week_view_adjustment_changed_cb (GtkAdjustment *adjustment, - ECalShellContent *cal_shell_content) -{ - ECalendarView *view; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - view = cal_shell_content->priv->views[E_CAL_VIEW_KIND_WEEK]; - update_adjustment (cal_shell_content, adjustment, E_WEEK_VIEW (view), TRUE); -} - -static void -month_view_adjustment_changed_cb (GtkAdjustment *adjustment, - ECalShellContent *cal_shell_content) -{ - ECalendarView *view; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - view = cal_shell_content->priv->views[E_CAL_VIEW_KIND_MONTH]; - update_adjustment (cal_shell_content, adjustment, E_WEEK_VIEW (view), FALSE); -} - -static void -cal_shell_content_notify_work_day_cb (ECalModel *model, - GParamSpec *param, - ECalShellContent *cal_shell_content) -{ - GDateWeekday work_day_first, work_day_last; - - g_return_if_fail (E_IS_CAL_MODEL (model)); - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - if (cal_shell_content->priv->current_view != E_CAL_VIEW_KIND_WORKWEEK) - return; - - work_day_first = e_cal_model_get_work_day_first (model); - work_day_last = e_cal_model_get_work_day_last (model); - - if (work_day_first == g_date_get_weekday (&cal_shell_content->priv->view_start) && - work_day_last == g_date_get_weekday (&cal_shell_content->priv->view_end)) - return; - - cal_shell_content->priv->previous_selected_start_time = -1; - cal_shell_content->priv->previous_selected_end_time = -1; - - /* This makes sure that the selection in the datepicker corresponds - to the time range used in the Work Week view */ - cal_shell_content_current_view_id_changed_cb (cal_shell_content); -} - -static void -cal_shell_content_notify_week_start_day_cb (ECalModel *model, - GParamSpec *param, - ECalShellContent *cal_shell_content) -{ - g_return_if_fail (E_IS_CAL_MODEL (model)); - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - cal_shell_content->priv->previous_selected_start_time = -1; - cal_shell_content->priv->previous_selected_end_time = -1; - - /* This makes sure that the selection in the datepicker corresponds - to the time range used in the current view */ - cal_shell_content_current_view_id_changed_cb (cal_shell_content); -} - -static void -cal_shell_content_move_view_range_cb (ECalendarView *cal_view, - ECalendarViewMoveType move_type, - gint64 exact_date, - ECalShellContent *cal_shell_content) -{ - g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view)); - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - if (!cal_view->in_focus) - return; - - e_cal_shell_content_move_view_range (cal_shell_content, move_type, (time_t) exact_date); -} - -static void -cal_shell_content_foreign_client_opened_cb (ECalBaseShellSidebar *cal_base_shell_sidebar, - ECalClient *client, - ECalModel *model) -{ - g_return_if_fail (E_IS_CAL_CLIENT (client)); - g_return_if_fail (E_IS_CAL_MODEL (model)); - - e_cal_data_model_add_client (e_cal_model_get_data_model (model), client); -} - -static void -cal_shell_content_foreign_client_closed_cb (ECalBaseShellSidebar *cal_base_shell_sidebar, - ESource *source, - ECalModel *model) -{ - g_return_if_fail (E_IS_SOURCE (source)); - g_return_if_fail (E_IS_CAL_MODEL (model)); - - e_cal_data_model_remove_client (e_cal_model_get_data_model (model), e_source_get_uid (source)); -} - -static void -cal_shell_content_setup_foreign_sources (EShellWindow *shell_window, - const gchar *view_name, - const gchar *extension_name, - ECalModel *model) -{ - EShellSidebar *foreign_sidebar; - EShellContent *foreign_content; - EShellView *foreign_view; - ECalModel *foreign_model; - gboolean is_new_view; - - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - g_return_if_fail (E_IS_CAL_MODEL (model)); - - is_new_view = e_shell_window_peek_shell_view (shell_window, view_name) == NULL; - - foreign_view = e_shell_window_get_shell_view (shell_window, view_name); - g_return_if_fail (E_IS_SHELL_VIEW (foreign_view)); - - foreign_sidebar = e_shell_view_get_shell_sidebar (foreign_view); - g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (foreign_sidebar)); - - if (is_new_view) { - /* Preselect default source, when the view was not created yet */ - ESourceSelector *source_selector; - ESourceRegistry *registry; - ESource *source; - - source_selector = e_cal_base_shell_sidebar_get_selector (E_CAL_BASE_SHELL_SIDEBAR (foreign_sidebar)); - registry = e_source_selector_get_registry (source_selector); - source = e_source_registry_ref_default_for_extension_name (registry, extension_name); - - if (source) - e_source_selector_set_primary_selection (source_selector, source); - - g_clear_object (&source); - } - - g_signal_connect_object (foreign_sidebar, "client-opened", - G_CALLBACK (cal_shell_content_foreign_client_opened_cb), model, 0); - g_signal_connect_object (foreign_sidebar, "client-closed", - G_CALLBACK (cal_shell_content_foreign_client_closed_cb), model, 0); - - foreign_content = e_shell_view_get_shell_content (foreign_view); - foreign_model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (foreign_content)); - - e_binding_bind_property ( - foreign_model, "default-source-uid", - model, "default-source-uid", - G_BINDING_SYNC_CREATE); - - g_signal_connect_object (model, "row-appended", - G_CALLBACK (e_cal_base_shell_view_model_row_appended), foreign_view, G_CONNECT_SWAPPED); - - /* This makes sure that the local models for memos and tasks - in the calendar view get populated with the same sources - as those in the respective views. */ - - e_cal_base_shell_sidebar_ensure_sources_open (E_CAL_BASE_SHELL_SIDEBAR (foreign_sidebar)); -} - -static void -cal_shell_content_view_created (ECalBaseShellContent *cal_base_shell_content) -{ - ECalShellContent *cal_shell_content; - EShellView *shell_view; - EShellWindow *shell_window; - EShellSidebar *shell_sidebar; - GalViewInstance *view_instance; - ECalendar *calendar; - ECalModel *model; - ECalDataModel *data_model; - GDate date; - time_t today; - - cal_shell_content = E_CAL_SHELL_CONTENT (cal_base_shell_content); - cal_shell_content->priv->current_view = E_CAL_VIEW_KIND_DAY; - - today = time (NULL); - g_date_clear (&date, 1); - g_date_set_time_t (&date, today); - - shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content)); - shell_window = e_shell_view_get_shell_window (shell_view); - shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); - g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (shell_sidebar)); - - calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar)); - g_return_if_fail (E_IS_CALENDAR (calendar)); - - model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - e_calendar_item_set_selection (e_calendar_get_item (calendar), &date, &date); - e_cal_model_set_time_range (model, today, today); - - /* Show everything known by default in the task and memo pads */ - e_cal_model_set_time_range (cal_shell_content->priv->memo_model, 0, 0); - e_cal_model_set_time_range (cal_shell_content->priv->task_model, 0, 0); - - cal_shell_content->priv->datepicker_selection_changed_id = - g_signal_connect (e_calendar_get_item (calendar), "selection-changed", - G_CALLBACK (cal_shell_content_datepicker_selection_changed_cb), cal_shell_content); - cal_shell_content->priv->datepicker_range_moved_id = - g_signal_connect (e_calendar_get_item (calendar), "date-range-moved", - G_CALLBACK (cal_shell_content_datepicker_range_moved_cb), cal_shell_content); - - g_signal_connect_after (calendar, "button-press-event", - G_CALLBACK (cal_shell_content_datepicker_button_press_cb), cal_shell_content); - - data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - cal_shell_content->priv->tag_calendar = e_tag_calendar_new (calendar); - e_tag_calendar_subscribe (cal_shell_content->priv->tag_calendar, data_model); - - /* Intentionally not using e_signal_connect_notify() here, no need to filter - out "false" notifications, it's dealt with them in another way */ - cal_shell_content->priv->current_view_id_changed_id = g_signal_connect ( - cal_shell_content, "notify::current-view-id", - G_CALLBACK (cal_shell_content_current_view_id_changed_cb), NULL); - - /* List of selected Task/Memo sources is taken from respective views, - which are loaded if necessary. */ - cal_shell_content_setup_foreign_sources (shell_window, "memos", E_SOURCE_EXTENSION_MEMO_LIST, - cal_shell_content->priv->memo_model); - - cal_shell_content_setup_foreign_sources (shell_window, "tasks", E_SOURCE_EXTENSION_TASK_LIST, - cal_shell_content->priv->task_model); - - /* Finally load the view instance */ - view_instance = e_shell_view_get_view_instance (shell_view); - gal_view_instance_load (view_instance); - - /* Keep the toolbar view buttons in sync with the calendar. */ - e_binding_bind_property ( - cal_shell_content, "current-view-id", - ACTION (CALENDAR_VIEW_DAY), "current-value", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - e_signal_connect_notify ( - model, "notify::work-day-monday", - G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content); - - e_signal_connect_notify ( - model, "notify::work-day-tuesday", - G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content); - - e_signal_connect_notify ( - model, "notify::work-day-wednesday", - G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content); - - e_signal_connect_notify ( - model, "notify::work-day-thursday", - G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content); - - e_signal_connect_notify ( - model, "notify::work-day-friday", - G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content); - - e_signal_connect_notify ( - model, "notify::work-day-saturday", - G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content); - - e_signal_connect_notify ( - model, "notify::work-day-sunday", - G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content); - - e_signal_connect_notify ( - model, "notify::week-start-day", - G_CALLBACK (cal_shell_content_notify_week_start_day_cb), cal_shell_content); -} - -static void -e_cal_shell_content_create_calendar_views (ECalShellContent *cal_shell_content) -{ - EShellView *shell_view; - ECalModel *model; - ECalendarView *calendar_view; - GtkAdjustment *adjustment; - time_t today; - gint ii; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - g_return_if_fail (cal_shell_content->priv->calendar_notebook != NULL); - g_return_if_fail (cal_shell_content->priv->views[0] == NULL); - - model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - - /* Day View */ - calendar_view = e_day_view_new (model); - cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY] = calendar_view; - g_object_ref_sink (calendar_view); - - /* Work Week View */ - calendar_view = e_day_view_new (model); - e_day_view_set_work_week_view (E_DAY_VIEW (calendar_view), TRUE); - e_day_view_set_days_shown (E_DAY_VIEW (calendar_view), 5); - cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK] = calendar_view; - g_object_ref_sink (calendar_view); - - /* Week View */ - calendar_view = e_week_view_new (model); - cal_shell_content->priv->views[E_CAL_VIEW_KIND_WEEK] = calendar_view; - g_object_ref_sink (calendar_view); - - adjustment = gtk_range_get_adjustment ( - GTK_RANGE (E_WEEK_VIEW (calendar_view)->vscrollbar)); - g_signal_connect ( - adjustment, "value-changed", - G_CALLBACK (week_view_adjustment_changed_cb), cal_shell_content); - - /* Month View */ - calendar_view = e_month_view_new (model); - e_week_view_set_multi_week_view (E_WEEK_VIEW (calendar_view), TRUE); - e_week_view_set_weeks_shown (E_WEEK_VIEW (calendar_view), 6); - cal_shell_content->priv->views[E_CAL_VIEW_KIND_MONTH] = calendar_view; - g_object_ref_sink (calendar_view); - - adjustment = gtk_range_get_adjustment ( - GTK_RANGE (E_WEEK_VIEW (calendar_view)->vscrollbar)); - g_signal_connect ( - adjustment, "value-changed", - G_CALLBACK (month_view_adjustment_changed_cb), cal_shell_content); - - /* List View */ - calendar_view = e_cal_list_view_new (model); - cal_shell_content->priv->views[E_CAL_VIEW_KIND_LIST] = calendar_view; - g_object_ref_sink (calendar_view); - - shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content)); - today = time (NULL); - - for (ii = 0; ii < E_CAL_VIEW_KIND_LAST; ii++) { - calendar_view = cal_shell_content->priv->views[ii]; - - calendar_view->in_focus = ii == cal_shell_content->priv->current_view; - - e_calendar_view_set_selected_time_range (calendar_view, today, today); - - e_signal_connect_notify ( - calendar_view, "notify::is-editing", - G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view); - - g_signal_connect ( - calendar_view, "move-view-range", - G_CALLBACK (cal_shell_content_move_view_range_cb), cal_shell_content); - - gtk_notebook_append_page ( - GTK_NOTEBOOK (cal_shell_content->priv->calendar_notebook), - GTK_WIDGET (calendar_view), NULL); - gtk_widget_show (GTK_WIDGET (calendar_view)); - } -} - -static void -cal_shell_content_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_CURRENT_VIEW_ID: - e_cal_shell_content_set_current_view_id (E_CAL_SHELL_CONTENT (object), - g_value_get_int (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -cal_shell_content_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_CALENDAR_NOTEBOOK: - g_value_set_object ( - value, e_cal_shell_content_get_calendar_notebook ( - E_CAL_SHELL_CONTENT (object))); - return; - - case PROP_MEMO_TABLE: - g_value_set_object ( - value, e_cal_shell_content_get_memo_table ( - E_CAL_SHELL_CONTENT (object))); - return; - - case PROP_TASK_TABLE: - g_value_set_object ( - value, e_cal_shell_content_get_task_table ( - E_CAL_SHELL_CONTENT (object))); - return; - - case PROP_CURRENT_VIEW_ID: - g_value_set_int (value, - e_cal_shell_content_get_current_view_id (E_CAL_SHELL_CONTENT (object))); - return; - - case PROP_CURRENT_VIEW: - g_value_set_object (value, - e_cal_shell_content_get_current_calendar_view (E_CAL_SHELL_CONTENT (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -cal_shell_content_dispose (GObject *object) -{ - ECalShellContent *cal_shell_content = E_CAL_SHELL_CONTENT (object); - gint ii; - - if (cal_shell_content->priv->task_data_model) { - e_cal_data_model_set_disposing (cal_shell_content->priv->task_data_model, TRUE); - e_cal_data_model_unsubscribe (cal_shell_content->priv->task_data_model, - E_CAL_DATA_MODEL_SUBSCRIBER (cal_shell_content->priv->task_model)); - } - - if (cal_shell_content->priv->memo_data_model) { - e_cal_data_model_set_disposing (cal_shell_content->priv->memo_data_model, TRUE); - e_cal_data_model_unsubscribe (cal_shell_content->priv->memo_data_model, - E_CAL_DATA_MODEL_SUBSCRIBER (cal_shell_content->priv->memo_model)); - } - - if (cal_shell_content->priv->tag_calendar) { - ECalDataModel *data_model; - - data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - e_cal_data_model_set_disposing (data_model, TRUE); - e_tag_calendar_unsubscribe (cal_shell_content->priv->tag_calendar, data_model); - g_clear_object (&cal_shell_content->priv->tag_calendar); - } - - for (ii = 0; ii < E_CAL_VIEW_KIND_LAST; ii++) { - g_clear_object (&(cal_shell_content->priv->views[ii])); - } - - g_clear_object (&cal_shell_content->priv->hpaned); - g_clear_object (&cal_shell_content->priv->vpaned); - g_clear_object (&cal_shell_content->priv->calendar_notebook); - g_clear_object (&cal_shell_content->priv->task_table); - g_clear_object (&cal_shell_content->priv->task_model); - g_clear_object (&cal_shell_content->priv->task_data_model); - g_clear_object (&cal_shell_content->priv->memo_table); - g_clear_object (&cal_shell_content->priv->memo_model); - g_clear_object (&cal_shell_content->priv->memo_data_model); - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_cal_shell_content_parent_class)->dispose (object); -} - -static void -cal_shell_content_constructed (GObject *object) -{ - ECalShellContent *cal_shell_content; - EShellContent *shell_content; - EShellView *shell_view; - EShellWindow *shell_window; - EShell *shell; - GalViewInstance *view_instance; - GSettings *settings; - GtkWidget *container; - GtkWidget *widget; - gchar *markup; - - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_cal_shell_content_parent_class)->constructed (object); - - cal_shell_content = E_CAL_SHELL_CONTENT (object); - shell_content = E_SHELL_CONTENT (cal_shell_content); - shell_view = e_shell_content_get_shell_view (shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); - shell = e_shell_window_get_shell (shell_window); - - cal_shell_content->priv->memo_data_model = - e_cal_base_shell_content_create_new_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - cal_shell_content->priv->memo_model = - e_cal_model_memos_new (cal_shell_content->priv->memo_data_model, e_shell_get_registry (shell), shell); - - cal_shell_content->priv->task_data_model = - e_cal_base_shell_content_create_new_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - cal_shell_content->priv->task_model = - e_cal_model_tasks_new (cal_shell_content->priv->task_data_model, e_shell_get_registry (shell), shell); - - e_binding_bind_property ( - cal_shell_content->priv->memo_model, "timezone", - cal_shell_content->priv->memo_data_model, "timezone", - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - cal_shell_content->priv->task_model, "timezone", - cal_shell_content->priv->task_data_model, "timezone", - G_BINDING_SYNC_CREATE); - - /* Build content widgets. */ - - container = GTK_WIDGET (object); - - widget = e_paned_new (GTK_ORIENTATION_HORIZONTAL); - gtk_container_add (GTK_CONTAINER (container), widget); - cal_shell_content->priv->hpaned = g_object_ref (widget); - gtk_widget_show (widget); - - container = cal_shell_content->priv->hpaned; - - widget = gtk_notebook_new (); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE); - gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE); - gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE); - cal_shell_content->priv->calendar_notebook = g_object_ref (widget); - gtk_widget_show (widget); - - widget = e_paned_new (GTK_ORIENTATION_VERTICAL); - e_paned_set_fixed_resize (E_PANED (widget), FALSE); - gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, TRUE); - cal_shell_content->priv->vpaned = g_object_ref (widget); - gtk_widget_show (widget); - - container = cal_shell_content->priv->calendar_notebook; - - e_cal_shell_content_create_calendar_views (cal_shell_content); - - e_binding_bind_property ( - cal_shell_content, "current-view-id", - cal_shell_content->priv->calendar_notebook, "page", - G_BINDING_SYNC_CREATE); - - container = cal_shell_content->priv->vpaned; - - widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, TRUE); - gtk_widget_show (widget); - - container = widget; - - widget = gtk_label_new (NULL); - markup = g_strdup_printf ("%s", _("Tasks")); - gtk_label_set_markup (GTK_LABEL (widget), markup); - gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0); - gtk_widget_show (widget); - g_free (markup); - - widget = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy ( - GTK_SCROLLED_WINDOW (widget), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); - gtk_widget_show (widget); - - container = widget; - - widget = e_task_table_new (shell_view, cal_shell_content->priv->task_model); - gtk_container_add (GTK_CONTAINER (container), widget); - cal_shell_content->priv->task_table = g_object_ref (widget); - gtk_widget_show (widget); - - cal_shell_content_load_table_state (shell_content, E_TABLE (widget)); - - g_signal_connect_swapped ( - widget, "open-component", - G_CALLBACK (e_cal_shell_view_taskpad_open_task), - shell_view); - - e_signal_connect_notify ( - widget, "notify::is-editing", - G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view); - - container = cal_shell_content->priv->vpaned; - - widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, TRUE); - gtk_widget_show (widget); - - container = widget; - - widget = gtk_label_new (NULL); - markup = g_strdup_printf ("%s", _("Memos")); - gtk_label_set_markup (GTK_LABEL (widget), markup); - gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0); - gtk_widget_show (widget); - g_free (markup); - - widget = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy ( - GTK_SCROLLED_WINDOW (widget), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); - gtk_widget_show (widget); - - container = widget; - - widget = e_memo_table_new (shell_view, cal_shell_content->priv->memo_model); - gtk_container_add (GTK_CONTAINER (container), widget); - cal_shell_content->priv->memo_table = g_object_ref (widget); - gtk_widget_show (widget); - - cal_shell_content_load_table_state (shell_content, E_TABLE (widget)); - - e_cal_model_set_default_time_func (cal_shell_content->priv->memo_model, cal_shell_content_get_default_time, cal_shell_content); - - g_signal_connect_swapped ( - widget, "open-component", - G_CALLBACK (e_cal_shell_view_memopad_open_memo), - shell_view); - - e_signal_connect_notify ( - widget, "notify::is-editing", - G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view); - - /* Prepare the view instance. */ - - view_instance = e_shell_view_new_view_instance (shell_view, NULL); - g_signal_connect_swapped ( - view_instance, "display-view", - G_CALLBACK (cal_shell_content_display_view_cb), - object); - /* Actual load happens at cal_shell_content_view_created() */ - e_shell_view_set_view_instance (shell_view, view_instance); - g_object_unref (view_instance); - - e_signal_connect_notify_swapped ( - shell_view, "notify::view-id", - G_CALLBACK (cal_shell_content_notify_view_id_cb), - cal_shell_content); - - settings = e_util_ref_settings ("org.gnome.evolution.calendar"); - - g_settings_bind ( - settings, "tag-vpane-position", - cal_shell_content->priv->vpaned, "proportion", - G_SETTINGS_BIND_DEFAULT); - - g_object_unref (settings); - - /* Cannot access shell sidebar here, thus rely on cal_shell_content_view_created() - with exact widget settings which require it */ -} - -static void -e_cal_shell_content_class_init (ECalShellContentClass *class) -{ - GObjectClass *object_class; - EShellContentClass *shell_content_class; - ECalBaseShellContentClass *cal_base_shell_content_class; - - g_type_class_add_private (class, sizeof (ECalShellContentPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = cal_shell_content_set_property; - object_class->get_property = cal_shell_content_get_property; - object_class->dispose = cal_shell_content_dispose; - object_class->constructed = cal_shell_content_constructed; - - shell_content_class = E_SHELL_CONTENT_CLASS (class); - shell_content_class->check_state = cal_shell_content_check_state; - shell_content_class->focus_search_results = cal_shell_content_focus_search_results; - - cal_base_shell_content_class = E_CAL_BASE_SHELL_CONTENT_CLASS (class); - cal_base_shell_content_class->new_cal_model = e_cal_model_calendar_new; - cal_base_shell_content_class->view_created = cal_shell_content_view_created; - - g_object_class_install_property ( - object_class, - PROP_CALENDAR_NOTEBOOK, - g_param_spec_object ( - "calendar-notebook", - NULL, - NULL, - GTK_TYPE_NOTEBOOK, - G_PARAM_READABLE)); - - g_object_class_install_property ( - object_class, - PROP_MEMO_TABLE, - g_param_spec_object ( - "memo-table", - NULL, - NULL, - E_TYPE_MEMO_TABLE, - G_PARAM_READABLE)); - - g_object_class_install_property ( - object_class, - PROP_TASK_TABLE, - g_param_spec_object ( - "task-table", - NULL, - NULL, - E_TYPE_TASK_TABLE, - G_PARAM_READABLE)); - - g_object_class_install_property ( - object_class, - PROP_CURRENT_VIEW_ID, - g_param_spec_int ( - "current-view-id", - "Current Calendar View ID", - NULL, - E_CAL_VIEW_KIND_DAY, - E_CAL_VIEW_KIND_LAST - 1, - E_CAL_VIEW_KIND_DAY, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_CURRENT_VIEW, - g_param_spec_object ( - "current-view", - "Current Calendar View", - NULL, - E_TYPE_CALENDAR_VIEW, - G_PARAM_READABLE)); -} - -static void -e_cal_shell_content_class_finalize (ECalShellContentClass *class) -{ -} - -static void -e_cal_shell_content_init (ECalShellContent *cal_shell_content) -{ - time_t now; - - cal_shell_content->priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (cal_shell_content); - g_date_clear (&cal_shell_content->priv->view_start, 1); - g_date_clear (&cal_shell_content->priv->view_end, 1); - g_date_clear (&cal_shell_content->priv->last_range_start, 1); - - now = time (NULL); - g_date_set_time_t (&cal_shell_content->priv->view_start, now); - g_date_set_time_t (&cal_shell_content->priv->view_end, now); - - cal_shell_content->priv->view_start_range_day_offset = (guint32) -1; - cal_shell_content->priv->previous_selected_start_time = -1; - cal_shell_content->priv->previous_selected_end_time = -1; -} - -void -e_cal_shell_content_type_register (GTypeModule *type_module) -{ - /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration - * function, so we have to wrap it with a public function in - * order to register types from a separate compilation unit. */ - e_cal_shell_content_register_type (type_module); -} - -GtkWidget * -e_cal_shell_content_new (EShellView *shell_view) -{ - g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); - - return g_object_new ( - E_TYPE_CAL_SHELL_CONTENT, - "shell-view", shell_view, NULL); -} - -GtkNotebook * -e_cal_shell_content_get_calendar_notebook (ECalShellContent *cal_shell_content) -{ - g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL); - - return GTK_NOTEBOOK (cal_shell_content->priv->calendar_notebook); -} - -EMemoTable * -e_cal_shell_content_get_memo_table (ECalShellContent *cal_shell_content) -{ - g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL); - - return E_MEMO_TABLE (cal_shell_content->priv->memo_table); -} - -ETaskTable * -e_cal_shell_content_get_task_table (ECalShellContent *cal_shell_content) -{ - g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL); - - return E_TASK_TABLE (cal_shell_content->priv->task_table); -} - -EShellSearchbar * -e_cal_shell_content_get_searchbar (ECalShellContent *cal_shell_content) -{ - EShellView *shell_view; - EShellContent *shell_content; - GtkWidget *widget; - - g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL); - - shell_content = E_SHELL_CONTENT (cal_shell_content); - shell_view = e_shell_content_get_shell_view (shell_content); - widget = e_shell_view_get_searchbar (shell_view); - - return E_SHELL_SEARCHBAR (widget); -} - -static void -cal_shell_content_resubscribe (ECalendarView *cal_view, - ECalModel *model) -{ - ECalDataModel *data_model; - ECalDataModelSubscriber *subscriber; - time_t range_start, range_end; - gboolean is_tasks_or_memos; - - g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view)); - g_return_if_fail (E_IS_CAL_MODEL (model)); - - data_model = e_cal_model_get_data_model (model); - subscriber = E_CAL_DATA_MODEL_SUBSCRIBER (model); - is_tasks_or_memos = e_cal_model_get_component_kind (model) == ICAL_VJOURNAL_COMPONENT || - e_cal_model_get_component_kind (model) == ICAL_VTODO_COMPONENT; - - if ((!is_tasks_or_memos && e_calendar_view_get_visible_time_range (cal_view, &range_start, &range_end)) || - e_cal_data_model_get_subscriber_range (data_model, subscriber, &range_start, &range_end)) { - e_cal_data_model_unsubscribe (data_model, subscriber); - e_cal_model_remove_all_objects (model); - - if (is_tasks_or_memos) - e_cal_data_model_subscribe (data_model, subscriber, range_start, range_end); - } -} - -void -e_cal_shell_content_set_current_view_id (ECalShellContent *cal_shell_content, - ECalViewKind view_kind) -{ - time_t start_time = -1, end_time = -1; - gint ii; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - g_return_if_fail (view_kind >= E_CAL_VIEW_KIND_DAY && view_kind < E_CAL_VIEW_KIND_LAST); - - if (cal_shell_content->priv->current_view == view_kind) - return; - - if (cal_shell_content->priv->current_view >= E_CAL_VIEW_KIND_DAY && - cal_shell_content->priv->current_view < E_CAL_VIEW_KIND_LAST) { - ECalendarView *cal_view = cal_shell_content->priv->views[cal_shell_content->priv->current_view]; - - if (!e_calendar_view_get_selected_time_range (cal_view, &start_time, &end_time)) { - start_time = -1; - end_time = -1; - } - } - - cal_shell_content->priv->previous_selected_start_time = start_time; - cal_shell_content->priv->previous_selected_end_time = end_time; - - for (ii = 0; ii < E_CAL_VIEW_KIND_LAST; ii++) { - ECalendarView *cal_view = cal_shell_content->priv->views[ii]; - gboolean in_focus = ii == view_kind; - gboolean focus_changed; - - if (!cal_view) { - g_warn_if_reached (); - continue; - } - - focus_changed = (cal_view->in_focus ? 1 : 0) != (in_focus ? 1 : 0); - - cal_view->in_focus = in_focus; - - if (focus_changed && in_focus) { - /* Currently focused view changed. Any events within the common time - range are not shown in the newly focused view, thus make sure it'll - contain all what it should have. */ - ECalModel *model; - - model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - - /* This may not cause any queries to backends with events, - because the time range should be always within the one - shown in the date picker. */ - cal_shell_content_resubscribe (cal_view, model); - - if (cal_shell_content->priv->task_table) { - ETaskTable *task_table; - - task_table = E_TASK_TABLE (cal_shell_content->priv->task_table); - cal_shell_content_resubscribe (cal_view, e_task_table_get_model (task_table)); - } - - if (cal_shell_content->priv->memo_table) { - EMemoTable *memo_table; - - memo_table = E_MEMO_TABLE (cal_shell_content->priv->memo_table); - cal_shell_content_resubscribe (cal_view, e_memo_table_get_model (memo_table)); - } - } - } - - cal_shell_content->priv->current_view = view_kind; - - g_object_notify (G_OBJECT (cal_shell_content), "current-view-id"); - - gtk_widget_queue_draw (GTK_WIDGET (cal_shell_content->priv->views[cal_shell_content->priv->current_view])); -} - -ECalViewKind -e_cal_shell_content_get_current_view_id (ECalShellContent *cal_shell_content) -{ - g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), E_CAL_VIEW_KIND_LAST); - - return cal_shell_content->priv->current_view; -} - -ECalendarView * -e_cal_shell_content_get_calendar_view (ECalShellContent *cal_shell_content, - ECalViewKind view_kind) -{ - g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL); - g_return_val_if_fail (view_kind >= E_CAL_VIEW_KIND_DAY && view_kind < E_CAL_VIEW_KIND_LAST, NULL); - - return cal_shell_content->priv->views[view_kind]; -} - -ECalendarView * -e_cal_shell_content_get_current_calendar_view (ECalShellContent *cal_shell_content) -{ - g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL); - - return e_cal_shell_content_get_calendar_view (cal_shell_content, - e_cal_shell_content_get_current_view_id (cal_shell_content)); -} - -void -e_cal_shell_content_save_state (ECalShellContent *cal_shell_content) -{ - ECalShellContentPrivate *priv; - - g_return_if_fail (cal_shell_content != NULL); - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - priv = cal_shell_content->priv; - - if (priv->task_table != NULL) - cal_shell_content_save_table_state ( - E_SHELL_CONTENT (cal_shell_content), - E_TABLE (priv->task_table)); - - if (priv->memo_table != NULL) - cal_shell_content_save_table_state ( - E_SHELL_CONTENT (cal_shell_content), - E_TABLE (priv->memo_table)); -} - -void -e_cal_shell_content_get_current_range (ECalShellContent *cal_shell_content, - time_t *range_start, - time_t *range_end) -{ - icaltimezone *zone; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - g_return_if_fail (range_start != NULL); - g_return_if_fail (range_end != NULL); - - zone = e_cal_data_model_get_timezone (e_cal_base_shell_content_get_data_model ( - E_CAL_BASE_SHELL_CONTENT (cal_shell_content))); - - *range_start = cal_comp_gdate_to_timet (&(cal_shell_content->priv->view_start), zone); - *range_end = cal_comp_gdate_to_timet (&(cal_shell_content->priv->view_end), zone); -} - -void -e_cal_shell_content_get_current_range_dates (ECalShellContent *cal_shell_content, - GDate *range_start, - GDate *range_end) -{ - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - g_return_if_fail (range_start != NULL); - g_return_if_fail (range_end != NULL); - - *range_start = cal_shell_content->priv->view_start; - *range_end = cal_shell_content->priv->view_end; -} - -static void -cal_shell_content_move_view_range_relative (ECalShellContent *cal_shell_content, - gint direction) -{ - GDate start, end; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - g_return_if_fail (direction != 0); - - start = cal_shell_content->priv->view_start; - end = cal_shell_content->priv->view_end; - - switch (cal_shell_content->priv->current_view) { - case E_CAL_VIEW_KIND_DAY: - if (direction > 0) { - g_date_add_days (&start, direction); - g_date_add_days (&end, direction); - } else { - g_date_subtract_days (&start, direction * -1); - g_date_subtract_days (&end, direction * -1); - } - break; - case E_CAL_VIEW_KIND_WORKWEEK: - case E_CAL_VIEW_KIND_WEEK: - if (direction > 0) { - g_date_add_days (&start, direction * 7); - g_date_add_days (&end, direction * 7); - } else { - g_date_subtract_days (&start, direction * -7); - g_date_subtract_days (&end, direction * -7); - } - break; - case E_CAL_VIEW_KIND_MONTH: - case E_CAL_VIEW_KIND_LIST: - if (g_date_get_day (&start) != 1) { - g_date_add_months (&start, 1); - g_date_set_day (&start, 1); - } - if (direction > 0) - g_date_add_months (&start, direction); - else - g_date_subtract_months (&start, direction * -1); - end = start; - g_date_set_day (&end, g_date_get_days_in_month (g_date_get_month (&start), g_date_get_year (&start))); - g_date_add_days (&end, 6); - break; - case E_CAL_VIEW_KIND_LAST: - return; - } - - e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &start, &end, FALSE); -} - -void -e_cal_shell_content_move_view_range (ECalShellContent *cal_shell_content, - ECalendarViewMoveType move_type, - time_t exact_date) -{ - ECalendar *calendar; - ECalDataModel *data_model; - EShellSidebar *shell_sidebar; - EShellView *shell_view; - struct icaltimetype tt; - icaltimezone *zone; - GDate date; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content)); - shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); - g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (shell_sidebar)); - - calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar)); - g_return_if_fail (E_IS_CALENDAR (calendar)); - g_return_if_fail (e_calendar_get_item (calendar) != NULL); - - data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - zone = e_cal_data_model_get_timezone (data_model); - - switch (move_type) { - case E_CALENDAR_VIEW_MOVE_PREVIOUS: - cal_shell_content_move_view_range_relative (cal_shell_content, -1); - break; - case E_CALENDAR_VIEW_MOVE_NEXT: - cal_shell_content_move_view_range_relative (cal_shell_content, +1); - break; - case E_CALENDAR_VIEW_MOVE_TO_TODAY: - tt = icaltime_current_time_with_zone (zone); - g_date_set_dmy (&date, tt.day, tt.month, tt.year); - /* one-day selection takes care of the view range move with left view kind */ - e_calendar_item_set_selection (e_calendar_get_item (calendar), &date, &date); - break; - case E_CALENDAR_VIEW_MOVE_TO_EXACT_DAY: - time_to_gdate_with_zone (&date, exact_date, zone); - e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &date, &date, FALSE); - break; - } -} - -static void -cal_shell_content_update_model_filter (ECalDataModel *data_model, - ECalModel *model, - const gchar *filter, - time_t range_start, - time_t range_end) -{ - time_t tmp_start, tmp_end; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (E_IS_CAL_MODEL (model)); - - e_cal_data_model_freeze_views_update (data_model); - if (filter != NULL) - e_cal_data_model_set_filter (data_model, filter); - e_cal_model_set_time_range (model, range_start, range_end); - - if (!e_cal_data_model_get_subscriber_range (data_model, E_CAL_DATA_MODEL_SUBSCRIBER (model), &tmp_start, &tmp_end)) { - e_cal_data_model_subscribe (data_model, E_CAL_DATA_MODEL_SUBSCRIBER (model), range_start, range_end); - } - - e_cal_data_model_thaw_views_update (data_model); -} - -void -e_cal_shell_content_update_filters (ECalShellContent *cal_shell_content, - const gchar *cal_filter, - time_t start_range, - time_t end_range) -{ - ECalDataModel *data_model; - ECalModel *model; - - g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content)); - - if (!cal_filter) - return; - - data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content)); - - cal_shell_content_update_model_filter (data_model, model, cal_filter, start_range, end_range); - - if (cal_shell_content->priv->task_table) { - ETaskTable *task_table; - gchar *hide_completed_tasks_sexp; - - /* Set the query on the task pad. */ - - task_table = E_TASK_TABLE (cal_shell_content->priv->task_table); - model = e_task_table_get_model (task_table); - data_model = e_cal_model_get_data_model (model); - - hide_completed_tasks_sexp = calendar_config_get_hide_completed_tasks_sexp (FALSE); - - if (hide_completed_tasks_sexp != NULL) { - if (*cal_filter) { - gchar *filter; - - filter = g_strdup_printf ("(and %s %s)", hide_completed_tasks_sexp, cal_filter); - cal_shell_content_update_model_filter (data_model, model, filter, 0, 0); - g_free (filter); - } else { - cal_shell_content_update_model_filter (data_model, model, hide_completed_tasks_sexp, 0, 0); - } - } else { - cal_shell_content_update_model_filter (data_model, model, *cal_filter ? cal_filter : "#t", 0, 0); - } - - g_free (hide_completed_tasks_sexp); - } - - if (cal_shell_content->priv->memo_table) { - EMemoTable *memo_table; - - /* Set the query on the memo pad. */ - - memo_table = E_MEMO_TABLE (cal_shell_content->priv->memo_table); - model = e_memo_table_get_model (memo_table); - data_model = e_cal_model_get_data_model (model); - - if (start_range != 0 && end_range != 0) { - icaltimezone *zone; - const gchar *default_tzloc = NULL; - time_t end = end_range; - gchar *filter; - gchar *iso_start; - gchar *iso_end; - - zone = e_cal_data_model_get_timezone (data_model); - if (zone && zone != icaltimezone_get_utc_timezone ()) - default_tzloc = icaltimezone_get_location (zone); - if (!default_tzloc) - default_tzloc = ""; - - if (start_range != (time_t) 0 && end_range != (time_t) 0) { - end = time_day_end_with_zone (end_range, zone); - } - - iso_start = isodate_from_time_t (start_range); - iso_end = isodate_from_time_t (end); - - filter = g_strdup_printf ( - "(and (or (not (has-start?)) " - "(occur-in-time-range? (make-time \"%s\") " - "(make-time \"%s\") \"%s\")) %s)", - iso_start, iso_end, default_tzloc, cal_filter); - - cal_shell_content_update_model_filter (data_model, model, filter, 0, 0); - - g_free (filter); - g_free (iso_start); - g_free (iso_end); - } else { - cal_shell_content_update_model_filter (data_model, model, *cal_filter ? cal_filter : "#t", 0, 0); - } - } -} diff --git a/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c b/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c index 3568f6e..f82f1cc 100644 --- a/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c +++ b/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c @@ -6230,6 +6230,7 @@ e_editor_dom_convert_content (EEditorPage *editor_page, WEBKIT_DOM_NODE (content_wrapper), WEBKIT_DOM_NODE (e_editor_dom_prepare_paragraph (editor_page, FALSE)), NULL); + if (!cite_body) { if (!empty) { WebKitDOMNode *child; @@ -8753,133 +8754,6 @@ adapt_to_editor_dom_changes (WebKitDOMDocument *document) g_clear_object (&collection); } -static void -traverse_nodes_to_split_pre (WebKitDOMDocument *document, - WebKitDOMNode *node, - WebKitDOMNode *new_parent, /* can be NULL, then prepend to out_new_nodes */ - gboolean is_in_pre, - GSList **out_new_nodes) /* WebKitDOMNode * */ -{ - if (is_in_pre && WEBKIT_DOM_IS_TEXT (node)) { - gchar *text; - - text = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (node)); - if (text) { - WebKitDOMElement *pre; - gint ii; - gchar **strv; - - strv = g_strsplit (text, "\n", -1); - - for (ii = 0; strv && strv[ii]; ii++) { - if (*(strv[ii])) { - gint len = strlen (strv[ii]); - - if (strv[ii][len - 1] == '\r') { - strv[ii][len - 1] = '\0'; - } - } - - /*
 is shown as a block, thus adding a new line at the end behaves like two 
-s */ - if (!*(strv[ii]) && !strv[ii + 1]) - break; - - pre = webkit_dom_document_create_element (document, "pre", NULL); - - if (*(strv[ii])) { - webkit_dom_html_element_set_inner_text (WEBKIT_DOM_HTML_ELEMENT (pre), strv[ii], NULL); - } else { - WebKitDOMElement *br; - - br = webkit_dom_document_create_element (document, "br", NULL); - webkit_dom_node_append_child (WEBKIT_DOM_NODE (pre), WEBKIT_DOM_NODE (br), NULL); - } - - if (new_parent) - webkit_dom_node_append_child (new_parent, WEBKIT_DOM_NODE (pre), NULL); - else - *out_new_nodes = g_slist_prepend (*out_new_nodes, pre); - } - - g_strfreev (strv); - } - - g_free (text); - } else if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (node)) { - is_in_pre = TRUE; - } else { - WebKitDOMNode *nd; - GError *error = NULL; - - nd = webkit_dom_node_clone_node_with_error (node, FALSE, &error); - if (nd) { - if (new_parent) - webkit_dom_node_append_child (new_parent, nd, NULL); - else - *out_new_nodes = g_slist_prepend (*out_new_nodes, nd); - - new_parent = nd; - } else { - g_warning ("%s: Failed to clone node %s: %s\n", G_STRFUNC, G_OBJECT_TYPE_NAME (node), error ? error->message : "Unknown error"); - } - } - - for (node = webkit_dom_node_get_first_child (node); - node; - node = webkit_dom_node_get_next_sibling (node)) { - traverse_nodes_to_split_pre (document, node, new_parent, is_in_pre, out_new_nodes); - } -} - -static void -maybe_split_pre_paragraphs (WebKitDOMDocument *document) -{ - WebKitDOMHTMLElement *body; - WebKitDOMNodeList *list; - - body = webkit_dom_document_get_body (document); - if (!body) - return; - - list = webkit_dom_document_query_selector_all (document, "pre", NULL); - if (webkit_dom_node_list_get_length (list)) { - WebKitDOMNode *body_node, *node, *current; - GSList *new_nodes = NULL, *to_remove = NULL, *link; - - g_clear_object (&list); - - body_node = WEBKIT_DOM_NODE (body); - webkit_dom_node_normalize (body_node); - - for (current = webkit_dom_node_get_first_child (body_node); - current; - current = webkit_dom_node_get_next_sibling (current)) { - traverse_nodes_to_split_pre (document, current, NULL, FALSE, &new_nodes); - to_remove = g_slist_prepend (to_remove, current); - } - - for (link = to_remove; link; link = g_slist_next (link)) { - node = link->data; - - webkit_dom_node_remove_child (body_node, node, NULL); - } - - /* They are in reverse order, thus reverse it */ - new_nodes = g_slist_reverse (new_nodes); - - for (link = new_nodes; link; link = g_slist_next (link)) { - node = link->data; - - webkit_dom_node_append_child (body_node, node, NULL); - } - - g_slist_free (to_remove); - g_slist_free (new_nodes); - } - - g_clear_object (&list); -} - void e_editor_dom_process_content_after_load (EEditorPage *editor_page) { @@ -8929,8 +8803,60 @@ e_editor_dom_process_content_after_load (EEditorPage *editor_page) } goto out; - } else if (!webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (body), "data-evo-draft")) { - maybe_split_pre_paragraphs (document); + } else { + WebKitDOMNodeList *list; + gulong ii; + + list = webkit_dom_document_query_selector_all (document, "pre", NULL); + for (ii = webkit_dom_node_list_get_length (list); ii--;) { + WebKitDOMNode *node = webkit_dom_node_list_item (list, ii), *parent; + WebKitDOMElement *element; + gchar *inner_html; + + element = WEBKIT_DOM_ELEMENT (node); + parent = webkit_dom_node_get_parent_node (node); + inner_html = webkit_dom_element_get_inner_html (element); + + if (inner_html && *inner_html) { + gchar **strv; + + strv = g_strsplit (inner_html, "\n", -1); + if (strv && strv[0] && strv[1]) { + WebKitDOMElement *pre; + gint jj; + + for (jj = 0; strv[jj]; jj++) { + pre = webkit_dom_document_create_element (document, "pre", NULL); + if (*(strv[jj])) { + gint len = strlen (strv[jj]); + + if (strv[jj][len - 1] == '\r') { + strv[jj][len - 1] = '\0'; + } + } + + if (*(strv[jj])) { + webkit_dom_html_element_set_inner_html (WEBKIT_DOM_HTML_ELEMENT (pre), strv[jj], NULL); + } else { + WebKitDOMElement *br; + + br = webkit_dom_document_create_element (document, "br", NULL); + webkit_dom_node_append_child (WEBKIT_DOM_NODE (pre), WEBKIT_DOM_NODE (br), NULL); + } + + webkit_dom_node_insert_before (parent, WEBKIT_DOM_NODE (pre), node, NULL); + } + + remove_node (node); + } + + g_strfreev (strv); + } + + g_free (inner_html); + } + + g_clear_object (&list); } adapt_to_editor_dom_changes (document); @@ -14089,7 +14015,7 @@ wrap_lines (EEditorPage *editor_page, next_sibling = webkit_dom_node_get_next_sibling (node); /* If the anchor doesn't fit on the line, add it to a separate line. */ - if (line_length > 0 && (line_length + anchor_length) > length_to_wrap) { + if ((line_length + anchor_length) > length_to_wrap) { /* Put
before the anchor, thus it starts on a new line */ element = webkit_dom_document_create_element (document, "BR", NULL); element_add_class (element, "-x-evo-wrap-br"); diff --git a/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c.extra-new-line-before-url b/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c.extra-new-line-before-url deleted file mode 100644 index 87bc86e..0000000 --- a/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c.extra-new-line-before-url +++ /dev/null @@ -1,18123 +0,0 @@ -/* - * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com) - * - * This library is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This library 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 Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include "evolution-config.h" - -#include - -#include - -#include "web-extensions/e-dom-utils.h" - -#include "e-editor-page.h" -#include "e-editor-undo-redo-manager.h" - -#include "e-editor-dom-functions.h" - -#define HTML_KEY_CODE_BACKSPACE 8 -#define HTML_KEY_CODE_RETURN 13 -#define HTML_KEY_CODE_CONTROL 17 -#define HTML_KEY_CODE_SPACE 32 -#define HTML_KEY_CODE_DELETE 46 -#define HTML_KEY_CODE_TABULATOR 9 - -/* ******************** Tests ******************** */ - -static gchar * -workaround_spaces (const gchar *text) -{ - GString *tmp; - gchar *str = NULL; - - tmp = e_str_replace_string (text, " ", " "); - if (tmp) { - str = g_string_free (tmp, FALSE); - text = str; - } - - tmp = e_str_replace_string (text, " ", " "); - if (tmp) { - g_free (str); - str = g_string_free (tmp, FALSE); - } else if (!str) { - str = g_strdup (text); - } - - return str; -} - -gboolean -e_editor_dom_test_html_equal (WebKitDOMDocument *document, - const gchar *html1, - const gchar *html2) -{ - WebKitDOMElement *elem1, *elem2; - gchar *str1, *str2; - gboolean res = FALSE; - GError *error = NULL; - - g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (document), FALSE); - g_return_val_if_fail (html1 != NULL, FALSE); - g_return_val_if_fail (html2 != NULL, FALSE); - - elem1 = webkit_dom_document_create_element (document, "TestHtmlEqual", &error); - if (error || !elem1) { - g_warning ("%s: Failed to create elem1: %s", G_STRFUNC, error ? error->message : "Unknown error"); - g_clear_error (&error); - return FALSE; - } - - elem2 = webkit_dom_document_create_element (document, "TestHtmlEqual", &error); - if (error || !elem2) { - g_warning ("%s: Failed to create elem2: %s", G_STRFUNC, error ? error->message : "Unknown error"); - g_clear_error (&error); - return FALSE; - } - - /* FIXME WK2: Workaround when   is used instead of regular spaces. (Placed by WebKit?) */ - str1 = workaround_spaces (html1); - str2 = workaround_spaces (html2); - - webkit_dom_element_set_inner_html (elem1, str1, &error); - if (!error) { - webkit_dom_element_set_inner_html (elem2, str2, &error); - - if (!error) { - webkit_dom_node_normalize (WEBKIT_DOM_NODE (elem1)); - webkit_dom_node_normalize (WEBKIT_DOM_NODE (elem2)); - - res = webkit_dom_node_is_equal_node (WEBKIT_DOM_NODE (elem1), WEBKIT_DOM_NODE (elem2)); - } else { - g_warning ("%s: Failed to set inner html2: %s", G_STRFUNC, error->message); - } - } else { - g_warning ("%s: Failed to set inner html1: %s", G_STRFUNC, error->message); - } - - if (res && (g_strcmp0 (html1, str1) != 0 || g_strcmp0 (html2, str2) != 0)) - g_warning ("%s: Applied the ' ' workaround", G_STRFUNC); - - g_clear_error (&error); - g_free (str1); - g_free (str2); - - return res; -} - -/* ******************** Actions ******************** */ - -static WebKitDOMElement * -get_table_cell_element (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMElement *cell; - WebKitDOMNode *node_under_mouse_click; - - document = e_editor_page_get_document (editor_page); - cell = webkit_dom_document_get_element_by_id (document, "-x-evo-current-cell"); - - if (cell) - return cell; - - node_under_mouse_click = e_editor_page_get_node_under_mouse_click (editor_page); - - if (node_under_mouse_click && WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node_under_mouse_click)) { - cell = WEBKIT_DOM_ELEMENT (node_under_mouse_click); - } else { - WebKitDOMElement *selection_start; - - e_editor_dom_selection_save (editor_page); - - selection_start = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - - cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (selection_start), "TD"); - if (!cell) - cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (selection_start), "TH"); - - e_editor_dom_selection_restore (editor_page); - } - - return cell; -} - -static void -prepare_history_for_table (EEditorPage *editor_page, - WebKitDOMElement *table, - EEditorHistoryEvent *ev) -{ - ev->type = HISTORY_TABLE_DIALOG; - - e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, &ev->before.start.y, &ev->before.end.x, &ev->before.end.y); - - ev->data.dom.from = g_object_ref (webkit_dom_node_clone_node_with_error ( - WEBKIT_DOM_NODE (table), TRUE, NULL)); -} - - -static void -save_history_for_table (EEditorPage *editor_page, - WebKitDOMElement *table, - EEditorHistoryEvent *ev) -{ - EEditorUndoRedoManager *manager; - - if (table) - ev->data.dom.to = g_object_ref (webkit_dom_node_clone_node_with_error ( - WEBKIT_DOM_NODE (table), TRUE, NULL)); - else - ev->data.dom.to = NULL; - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->after.start.x, &ev->after.start.y, &ev->after.end.x, &ev->after.end.y); - - manager = e_editor_page_get_undo_redo_manager (editor_page); - e_editor_undo_redo_manager_insert_history_event (manager, ev); -} - -void -e_editor_dom_delete_cell_contents (EEditorPage *editor_page) -{ - WebKitDOMNode *node; - WebKitDOMElement *cell, *table_cell, *table; - EEditorHistoryEvent *ev = NULL; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - table_cell = get_table_cell_element (editor_page); - g_return_if_fail (table_cell != NULL); - - cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD"); - if (!cell) - cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH"); - g_return_if_fail (cell != NULL); - - table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE"); - g_return_if_fail (table != NULL); - - ev = g_new0 (EEditorHistoryEvent, 1); - prepare_history_for_table (editor_page, table, ev); - - while ((node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (cell)))) - remove_node (node); - - save_history_for_table (editor_page, table, ev); -} - -void -e_editor_dom_delete_column (EEditorPage *editor_page) -{ - WebKitDOMElement *cell, *table, *table_cell; - WebKitDOMHTMLCollection *rows = NULL; - EEditorHistoryEvent *ev = NULL; - gulong index, length, ii; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - table_cell = get_table_cell_element (editor_page); - g_return_if_fail (table_cell != NULL); - - /* Find TD in which the selection starts */ - cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD"); - if (!cell) - cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH"); - g_return_if_fail (cell != NULL); - - table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE"); - g_return_if_fail (table != NULL); - - ev = g_new0 (EEditorHistoryEvent, 1); - prepare_history_for_table (editor_page, table, ev); - - rows = webkit_dom_html_table_element_get_rows ( - WEBKIT_DOM_HTML_TABLE_ELEMENT (table)); - length = webkit_dom_html_collection_get_length (rows); - - index = webkit_dom_html_table_cell_element_get_cell_index ( - WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell)); - - for (ii = 0; ii < length; ii++) { - WebKitDOMNode *row; - - row = webkit_dom_html_collection_item (rows, ii); - - webkit_dom_html_table_row_element_delete_cell ( - WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index, NULL); - } - - g_clear_object (&rows); - - save_history_for_table (editor_page, table, ev); -} - -void -e_editor_dom_delete_row (EEditorPage *editor_page) -{ - WebKitDOMElement *row, *table, *table_cell; - EEditorHistoryEvent *ev = NULL; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - table_cell = get_table_cell_element (editor_page); - g_return_if_fail (table_cell != NULL); - - row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR"); - g_return_if_fail (row != NULL); - - table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE"); - g_return_if_fail (table != NULL); - - ev = g_new0 (EEditorHistoryEvent, 1); - prepare_history_for_table (editor_page, table, ev); - - remove_node (WEBKIT_DOM_NODE (row)); - - save_history_for_table (editor_page, table, ev); -} - -void -e_editor_dom_delete_table (EEditorPage *editor_page) -{ - WebKitDOMElement *table, *table_cell; - EEditorHistoryEvent *ev = NULL; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - table_cell = get_table_cell_element (editor_page); - g_return_if_fail (table_cell != NULL); - - table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE"); - g_return_if_fail (table != NULL); - - ev = g_new0 (EEditorHistoryEvent, 1); - prepare_history_for_table (editor_page, table, ev); - - remove_node (WEBKIT_DOM_NODE (table)); - - save_history_for_table (editor_page, NULL, ev); -} - -void -e_editor_dom_insert_column_after (EEditorPage *editor_page) -{ - WebKitDOMElement *cell, *row, *table_cell, *table; - EEditorHistoryEvent *ev = NULL; - gulong index; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - table_cell = get_table_cell_element (editor_page); - g_return_if_fail (table_cell != NULL); - - cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD"); - if (!cell) - cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH"); - g_return_if_fail (cell != NULL); - - row = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TR"); - g_return_if_fail (row != NULL); - - table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE"); - g_return_if_fail (table != NULL); - - ev = g_new0 (EEditorHistoryEvent, 1); - prepare_history_for_table (editor_page, table, ev); - - /* Get the first row in the table */ - row = WEBKIT_DOM_ELEMENT ( - webkit_dom_node_get_first_child ( - webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row)))); - - index = webkit_dom_html_table_cell_element_get_cell_index ( - WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell)); - - while (row) { - webkit_dom_html_table_row_element_insert_cell ( - WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index + 1, NULL); - - row = WEBKIT_DOM_ELEMENT ( - webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (row))); - } - - save_history_for_table (editor_page, table, ev); -} - -void -e_editor_dom_insert_column_before (EEditorPage *editor_page) -{ - WebKitDOMElement *cell, *row, *table_cell, *table; - EEditorHistoryEvent *ev = NULL; - gulong index; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - table_cell = get_table_cell_element (editor_page); - g_return_if_fail (table_cell != NULL); - - cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD"); - if (!cell) { - cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH"); - } - g_return_if_fail (cell != NULL); - - row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR"); - g_return_if_fail (row != NULL); - - table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE"); - g_return_if_fail (table != NULL); - - ev = g_new0 (EEditorHistoryEvent, 1); - prepare_history_for_table (editor_page, table, ev); - - /* Get the first row in the table */ - row = WEBKIT_DOM_ELEMENT ( - webkit_dom_node_get_first_child ( - webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row)))); - - index = webkit_dom_html_table_cell_element_get_cell_index ( - WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell)); - - while (row) { - webkit_dom_html_table_row_element_insert_cell ( - WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index, NULL); - - row = WEBKIT_DOM_ELEMENT ( - webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (row))); - } - - save_history_for_table (editor_page, table, ev); -} - -void -e_editor_dom_insert_row_above (EEditorPage *editor_page) -{ - WebKitDOMElement *row, *table, *table_cell; - WebKitDOMHTMLCollection *cells = NULL; - WebKitDOMHTMLElement *new_row; - EEditorHistoryEvent *ev = NULL; - gulong index, cell_count, ii; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - table_cell = get_table_cell_element (editor_page); - g_return_if_fail (table_cell != NULL); - - row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR"); - g_return_if_fail (row != NULL); - - table = dom_node_find_parent_element (WEBKIT_DOM_NODE (row), "TABLE"); - g_return_if_fail (table != NULL); - - ev = g_new0 (EEditorHistoryEvent, 1); - prepare_history_for_table (editor_page, table, ev); - - index = webkit_dom_html_table_row_element_get_row_index ( - WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row)); - - new_row = webkit_dom_html_table_element_insert_row ( - WEBKIT_DOM_HTML_TABLE_ELEMENT (table), index, NULL); - - cells = webkit_dom_html_table_row_element_get_cells ( - WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row)); - cell_count = webkit_dom_html_collection_get_length (cells); - for (ii = 0; ii < cell_count; ii++) { - webkit_dom_html_table_row_element_insert_cell ( - WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL); - } - - g_clear_object (&cells); - - save_history_for_table (editor_page, table, ev); -} - -void -e_editor_dom_insert_row_below (EEditorPage *editor_page) -{ - WebKitDOMElement *row, *table, *table_cell; - WebKitDOMHTMLCollection *cells = NULL; - WebKitDOMHTMLElement *new_row; - EEditorHistoryEvent *ev = NULL; - gulong index, cell_count, ii; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - table_cell = get_table_cell_element (editor_page); - g_return_if_fail (table_cell != NULL); - - row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR"); - g_return_if_fail (row != NULL); - - table = dom_node_find_parent_element (WEBKIT_DOM_NODE (row), "TABLE"); - g_return_if_fail (table != NULL); - - ev = g_new0 (EEditorHistoryEvent, 1); - prepare_history_for_table (editor_page, table, ev); - - index = webkit_dom_html_table_row_element_get_row_index ( - WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row)); - - new_row = webkit_dom_html_table_element_insert_row ( - WEBKIT_DOM_HTML_TABLE_ELEMENT (table), index + 1, NULL); - - cells = webkit_dom_html_table_row_element_get_cells ( - WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row)); - cell_count = webkit_dom_html_collection_get_length (cells); - for (ii = 0; ii < cell_count; ii++) { - webkit_dom_html_table_row_element_insert_cell ( - WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL); - } - - g_clear_object (&cells); - - save_history_for_table (editor_page, table, ev); -} - -void -e_editor_dom_save_history_for_cut (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMDocumentFragment *fragment; - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMRange *range = NULL; - EEditorHistoryEvent *ev; - EEditorUndoRedoManager *manager; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - g_clear_object (&dom_window); - - if (!webkit_dom_dom_selection_get_range_count (dom_selection) || - webkit_dom_dom_selection_get_is_collapsed (dom_selection)) { - g_clear_object (&dom_selection); - return; - } - - range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - - ev = g_new0 (EEditorHistoryEvent, 1); - ev->type = HISTORY_DELETE; - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->before.start.x, - &ev->before.start.y, - &ev->before.end.x, - &ev->before.end.y); - - ev->after.start.x = ev->before.start.x; - ev->after.start.y = ev->before.start.y; - ev->after.end.x = ev->before.start.x; - ev->after.end.y = ev->before.start.y; - - /* Save the fragment. */ - fragment = webkit_dom_range_clone_contents (range, NULL); - g_clear_object (&dom_selection); - g_clear_object (&range); - ev->data.fragment = g_object_ref (fragment); - - manager = e_editor_page_get_undo_redo_manager (editor_page); - e_editor_undo_redo_manager_insert_history_event (manager, ev); - e_editor_page_set_dont_save_history_in_body_input (editor_page, TRUE); -} - -/* ******************** View ******************** */ - -/* - * e_editor_dom_exec_command: - * @document: a #WebKitDOMDocument - * @command: an #EContentEditorCommand to execute - * @value: value of the command (or @NULL if the command does not require value) - * - * The function will fail when @value is @NULL or empty but the current @command - * requires a value to be passed. The @value is ignored when the @command does - * not expect any value. - * - * Returns: @TRUE when the command was succesfully executed, @FALSE otherwise. - */ -gboolean -e_editor_dom_exec_command (EEditorPage *editor_page, - EContentEditorCommand command, - const gchar *value) -{ - const gchar *cmd_str = 0; - gboolean has_value = FALSE; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE); - -#define CHECK_COMMAND(cmd,str,val) case cmd:\ - if (val) {\ - g_return_val_if_fail (value && *value, FALSE);\ - }\ - has_value = val; \ - cmd_str = str;\ - break; - - switch (command) { - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_BACKGROUND_COLOR, "BackColor", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_BOLD, "Bold", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_COPY, "Copy", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_CREATE_LINK, "CreateLink", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_CUT, "Cut", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_DEFAULT_PARAGRAPH_SEPARATOR, "DefaultParagraphSeparator", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_DELETE, "Delete", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FIND_STRING, "FindString", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FONT_NAME, "FontName", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FONT_SIZE, "FontSize", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FONT_SIZE_DELTA, "FontSizeDelta", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FORE_COLOR, "ForeColor", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FORMAT_BLOCK, "FormatBlock", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE, "ForwardDelete", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_HILITE_COLOR, "HiliteColor", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INDENT, "Indent", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_HORIZONTAL_RULE, "InsertHorizontalRule", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_HTML, "InsertHTML", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_IMAGE, "InsertImage", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_LINE_BREAK, "InsertLineBreak", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT, "InsertNewlineInQuotedContent", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_ORDERED_LIST, "InsertOrderedList", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_PARAGRAPH, "InsertParagraph", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, "InsertText", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_UNORDERED_LIST, "InsertUnorderedList", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_ITALIC, "Italic", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_CENTER, "JustifyCenter", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_FULL, "JustifyFull", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_LEFT, "JustifyLeft", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_NONE, "JustifyNone", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_RIGHT, "JustifyRight", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_OUTDENT, "Outdent", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PASTE, "Paste", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PASTE_AND_MATCH_STYLE, "PasteAndMatchStyle", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PASTE_AS_PLAIN_TEXT, "PasteAsPlainText", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PRINT, "Print", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_REDO, "Redo", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_REMOVE_FORMAT, "RemoveFormat", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_SELECT_ALL, "SelectAll", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH, "Strikethrough", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_STYLE_WITH_CSS, "StyleWithCSS", TRUE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_SUBSCRIPT, "Subscript", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_SUPERSCRIPT, "Superscript", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_TRANSPOSE, "Transpose", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNDERLINE, "Underline", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNDO, "Undo", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNLINK, "Unlink", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNSELECT, "Unselect", FALSE) - CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_USE_CSS, "UseCSS", TRUE) - } - - e_editor_page_set_dont_save_history_in_body_input (editor_page, TRUE); - - return webkit_dom_document_exec_command ( - e_editor_page_get_document (editor_page), cmd_str, FALSE, has_value ? value : "" ); -} - -static void -perform_spell_check (WebKitDOMDOMSelection *dom_selection, - WebKitDOMRange *start_range, - WebKitDOMRange *end_range) -{ - WebKitDOMRange *actual = start_range; - - /* FIXME WK2: this doesn't work, the cursor is moved, but the spellcheck is not updated */ - /* Go through all words to spellcheck them. To avoid this we have to wait for - * http://www.w3.org/html/wg/drafts/html/master/editing.html#dom-forcespellcheck */ - /* We are moving forward word by word until we hit the text on the end. */ - while (actual && webkit_dom_range_compare_boundary_points (actual, WEBKIT_DOM_RANGE_START_TO_START, end_range, NULL) < 0) { - if (actual != start_range) - g_object_unref (actual); - webkit_dom_dom_selection_modify ( - dom_selection, "move", "forward", "word"); - actual = webkit_dom_dom_selection_get_range_at ( - dom_selection, 0, NULL); - } - g_clear_object (&actual); -} - -void -e_editor_dom_force_spell_check_for_current_paragraph (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMElement *selection_start_marker, *selection_end_marker; - WebKitDOMElement *parent; - WebKitDOMHTMLElement *body; - WebKitDOMRange *end_range = NULL, *actual = NULL; - WebKitDOMText *text; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - - if (!e_editor_page_get_inline_spelling_enabled (editor_page)) - return; - - document = e_editor_page_get_document (editor_page); - body = webkit_dom_document_get_body (document); - - if (!body) - return; - - if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body))) - return; - - e_editor_dom_selection_save (editor_page); - - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - selection_end_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-end-marker"); - - if (!selection_start_marker || !selection_end_marker) - return; - - /* Block callbacks of selection-changed signal as we don't want to - * recount all the block format things in EEditorSelection and here as well - * when we are moving with caret */ - e_editor_page_block_selection_changed (editor_page); - - parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_end_marker)); - if (!parent) - parent = WEBKIT_DOM_ELEMENT (body); - - /* Append some text on the end of the element */ - text = webkit_dom_document_create_text_node (document, "-x-evo-end"); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (parent), - WEBKIT_DOM_NODE (text), - NULL); - - parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_start_marker)); - if (!parent) - parent = WEBKIT_DOM_ELEMENT (body); - - /* Create range that's pointing on the end of this text */ - end_range = webkit_dom_document_create_range (document); - webkit_dom_range_select_node_contents ( - end_range, WEBKIT_DOM_NODE (text), NULL); - webkit_dom_range_collapse (end_range, FALSE, NULL); - - /* Move on the beginning of the paragraph */ - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - - actual = webkit_dom_document_create_range (document); - webkit_dom_range_select_node_contents ( - actual, WEBKIT_DOM_NODE (parent), NULL); - webkit_dom_range_collapse (actual, TRUE, NULL); - webkit_dom_dom_selection_remove_all_ranges (dom_selection); - webkit_dom_dom_selection_add_range (dom_selection, actual); - g_clear_object (&actual); - - actual = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - perform_spell_check (dom_selection, actual, end_range); - - g_clear_object (&dom_selection); - g_clear_object (&dom_window); - g_clear_object (&end_range); - g_clear_object (&actual); - - /* Remove the text that we inserted on the end of the paragraph */ - remove_node (WEBKIT_DOM_NODE (text)); - - e_editor_dom_selection_restore (editor_page); - /* Unblock the callbacks */ - e_editor_page_unblock_selection_changed (editor_page); -} - -static void -refresh_spell_check (EEditorPage *editor_page, - gboolean enable_spell_check) -{ - WebKitDOMDocument *document; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMElement *selection_start_marker, *selection_end_marker; - WebKitDOMHTMLElement *body; - WebKitDOMRange *end_range = NULL, *actual = NULL; - WebKitDOMText *text; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - body = webkit_dom_document_get_body (document); - - if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body))) - return; - - /* Enable/Disable spellcheck in composer */ - webkit_dom_element_set_attribute ( - WEBKIT_DOM_ELEMENT (body), - "spellcheck", - enable_spell_check ? "true" : "false", - NULL); - - e_editor_dom_selection_save (editor_page); - - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - selection_end_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-end-marker"); - - /* Sometimes the web view is not focused, so we have to save the selection - * manually into the body */ - if (!selection_start_marker || !selection_end_marker) { - WebKitDOMNode *child; - - child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)); - if (!WEBKIT_DOM_IS_ELEMENT (child)) - return; - - dom_add_selection_markers_into_element_start ( - document, - WEBKIT_DOM_ELEMENT (child), - &selection_start_marker, - &selection_end_marker); - } - - /* Block callbacks of selection-changed signal as we don't want to - * recount all the block format things in EEditorSelection and here as well - * when we are moving with caret */ - e_editor_page_block_selection_changed (editor_page); - - /* Append some text on the end of the body */ - text = webkit_dom_document_create_text_node (document, "-x-evo-end"); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (text), NULL); - - /* Create range that's pointing on the end of this text */ - end_range = webkit_dom_document_create_range (document); - webkit_dom_range_select_node_contents ( - end_range, WEBKIT_DOM_NODE (text), NULL); - webkit_dom_range_collapse (end_range, FALSE, NULL); - - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - - /* Move on the beginning of the document */ - webkit_dom_dom_selection_modify ( - dom_selection, "move", "backward", "documentboundary"); - - actual = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - perform_spell_check (dom_selection, actual, end_range); - - g_clear_object (&dom_selection); - g_clear_object (&dom_window); - g_clear_object (&end_range); - g_clear_object (&actual); - - /* Remove the text that we inserted on the end of the body */ - remove_node (WEBKIT_DOM_NODE (text)); - - e_editor_dom_selection_restore (editor_page); - /* Unblock the callbacks */ - e_editor_page_unblock_selection_changed (editor_page); -} - -void -e_editor_dom_turn_spell_check_off (EEditorPage *editor_page) -{ - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - refresh_spell_check (editor_page, FALSE); -} - -void -e_editor_dom_force_spell_check_in_viewport (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMElement *last_element; - WebKitDOMHTMLElement *body; - WebKitDOMRange *end_range = NULL, *actual = NULL; - WebKitDOMText *text; - glong viewport_height; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - if (!e_editor_page_get_inline_spelling_enabled (editor_page)) - return; - - document = e_editor_page_get_document (editor_page); - body = webkit_dom_document_get_body (document); - - if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body))) - return; - - e_editor_dom_selection_save (editor_page); - - /* Block callbacks of selection-changed signal as we don't want to - * recount all the block format things in EEditorSelection and here as well - * when we are moving with caret */ - e_editor_page_block_selection_changed (editor_page); - - /* We have to add 10 px offset as otherwise just the HTML element will be returned */ - actual = webkit_dom_document_caret_range_from_point (document, 10, 10); - if (!actual) - goto out; - - /* Append some text on the end of the body */ - text = webkit_dom_document_create_text_node (document, "-x-evo-end"); - - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - - /* We have to add 10 px offset as otherwise just the HTML element will be returned */ - viewport_height = webkit_dom_dom_window_get_inner_height (dom_window); - last_element = webkit_dom_document_element_from_point (document, 10, viewport_height - 10); - if (last_element && !WEBKIT_DOM_IS_HTML_HTML_ELEMENT (last_element) && - !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (last_element)) { - WebKitDOMElement *parent; - - parent = get_parent_block_element (WEBKIT_DOM_NODE (last_element)); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (parent ? parent : last_element), WEBKIT_DOM_NODE (text), NULL); - } else - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (text), NULL); - - /* Create range that's pointing on the end of viewport */ - end_range = webkit_dom_document_create_range (document); - webkit_dom_range_select_node_contents ( - end_range, WEBKIT_DOM_NODE (text), NULL); - webkit_dom_range_collapse (end_range, FALSE, NULL); - - webkit_dom_dom_selection_remove_all_ranges (dom_selection); - webkit_dom_dom_selection_add_range (dom_selection, actual); - perform_spell_check (dom_selection, actual, end_range); - - g_clear_object (&dom_selection); - g_clear_object (&dom_window); - g_clear_object (&end_range); - g_clear_object (&actual); - - /* Remove the text that we inserted on the end of the body */ - remove_node (WEBKIT_DOM_NODE (text)); - - out: - e_editor_dom_selection_restore (editor_page); - /* Unblock the callbacks */ - e_editor_page_unblock_selection_changed (editor_page); -} - -void -e_editor_dom_force_spell_check (EEditorPage *editor_page) -{ - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - if (e_editor_page_get_inline_spelling_enabled (editor_page)) - refresh_spell_check (editor_page, TRUE); -} - -gboolean -e_editor_dom_node_is_citation_node (WebKitDOMNode *node) -{ - gboolean ret_val = FALSE; - gchar *value; - - if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node)) - return FALSE; - - /* citation ==
*/ - if ((value = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "type"))) - ret_val = g_strcmp0 (value, "cite") == 0; - - g_free (value); - - return ret_val; -} - -gint -e_editor_dom_get_citation_level (WebKitDOMNode *node) -{ - WebKitDOMNode *parent = node; - gint level = 0; - - while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) { - if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) && - webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "type")) - level++; - - parent = webkit_dom_node_get_parent_node (parent); - } - - return level; -} - -static gchar * -get_quotation_for_level (gint quote_level) -{ - const gchar *quote_element = "" QUOTE_SYMBOL " "; - gint ii; - GString *output = g_string_new (""); - - for (ii = 0; ii < quote_level; ii++) - g_string_append (output, quote_element); - - return g_string_free (output, FALSE); -} - -void -e_editor_dom_quote_plain_text_element_after_wrapping (EEditorPage *editor_page, - WebKitDOMElement *element, - gint quote_level) -{ - WebKitDOMDocument *document; - WebKitDOMNodeList *list = NULL; - WebKitDOMNode *quoted_node; - gint ii; - gchar *quotation; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - g_return_if_fail (element != NULL); - - document = e_editor_page_get_document (editor_page); - - quoted_node = WEBKIT_DOM_NODE ( - webkit_dom_document_create_element (document, "SPAN", NULL)); - webkit_dom_element_set_class_name ( - WEBKIT_DOM_ELEMENT (quoted_node), "-x-evo-quoted"); - quotation = get_quotation_for_level (quote_level); - webkit_dom_element_set_inner_html ( - WEBKIT_DOM_ELEMENT (quoted_node), quotation, NULL); - - list = webkit_dom_element_query_selector_all ( - element, "br.-x-evo-wrap-br, pre > br", NULL); - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (element), - quoted_node, - webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)), - NULL); - - for (ii = webkit_dom_node_list_get_length (list); ii--;) { - WebKitDOMNode *br = webkit_dom_node_list_item (list, ii); - WebKitDOMNode *prev_sibling = webkit_dom_node_get_previous_sibling (br); - - if ((!WEBKIT_DOM_IS_ELEMENT (prev_sibling) || - !element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-quoted")) && - webkit_dom_node_get_next_sibling (br)) { - - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (br), - webkit_dom_node_clone_node_with_error (quoted_node, TRUE, NULL), - webkit_dom_node_get_next_sibling (br), - NULL); - } - } - - g_clear_object (&list); - g_free (quotation); -} - -static gboolean -return_pressed_in_empty_line (EEditorPage *editor_page) -{ - WebKitDOMNode *node; - WebKitDOMRange *range = NULL; - - range = e_editor_dom_get_current_range (editor_page); - if (!range) - return FALSE; - - node = webkit_dom_range_get_start_container (range, NULL); - if (!WEBKIT_DOM_IS_TEXT (node)) { - WebKitDOMNode *first_child; - - first_child = webkit_dom_node_get_first_child (node); - if (first_child && WEBKIT_DOM_IS_ELEMENT (first_child) && - element_has_class (WEBKIT_DOM_ELEMENT (first_child), "-x-evo-quoted")) { - WebKitDOMNode *prev_sibling; - - prev_sibling = webkit_dom_node_get_previous_sibling (node); - if (!prev_sibling) { - gboolean collapsed; - - collapsed = webkit_dom_range_get_collapsed (range, NULL); - g_clear_object (&range); - return collapsed; - } - } - } - - g_clear_object (&range); - - return FALSE; -} - -WebKitDOMNode * -e_editor_dom_get_parent_block_node_from_child (WebKitDOMNode *node) -{ - WebKitDOMNode *parent = node; - - if (!WEBKIT_DOM_IS_ELEMENT (parent) || - e_editor_dom_is_selection_position_node (parent)) - parent = webkit_dom_node_get_parent_node (parent); - - if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quoted") || - element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quote-character") || - element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-signature") || - element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-resizable-wrapper") || - WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) || - element_has_tag (WEBKIT_DOM_ELEMENT (parent), "b") || - element_has_tag (WEBKIT_DOM_ELEMENT (parent), "i") || - element_has_tag (WEBKIT_DOM_ELEMENT (parent), "u")) - parent = webkit_dom_node_get_parent_node (parent); - - if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quoted") || - element_has_class (WEBKIT_DOM_ELEMENT (parent), "Apple-tab-span") || - element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-resizable-wrapper")) - parent = webkit_dom_node_get_parent_node (parent); - - return parent; -} - -gboolean -e_editor_dom_node_is_paragraph (WebKitDOMNode *node) -{ - if (!WEBKIT_DOM_IS_HTML_DIV_ELEMENT (node)) - return FALSE; - - return webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (node), "data-evo-paragraph"); -} - -WebKitDOMElement * -e_editor_dom_wrap_and_quote_element (EEditorPage *editor_page, - WebKitDOMElement *element) -{ - gint citation_level; - WebKitDOMElement *tmp_element = element; - - g_return_val_if_fail (WEBKIT_DOM_IS_ELEMENT (element), element); - - if (e_editor_page_get_html_mode (editor_page)) - return element; - - citation_level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (element)); - - e_editor_dom_remove_quoting_from_element (element); - e_editor_dom_remove_wrapping_from_element (element); - - if (e_editor_dom_node_is_paragraph (WEBKIT_DOM_NODE (element))) { - gint word_wrap_length, length; - - word_wrap_length = e_editor_page_get_word_wrap_length (editor_page); - length = word_wrap_length - 2 * citation_level; - tmp_element = e_editor_dom_wrap_paragraph_length ( - editor_page, element, length); - } - - if (citation_level > 0) { - webkit_dom_node_normalize (WEBKIT_DOM_NODE (tmp_element)); - e_editor_dom_quote_plain_text_element_after_wrapping ( - editor_page, tmp_element, citation_level); - } - - return tmp_element; -} - -WebKitDOMElement * -e_editor_dom_insert_new_line_into_citation (EEditorPage *editor_page, - const gchar *html_to_insert) -{ - WebKitDOMDocument *document; - WebKitDOMElement *element, *paragraph = NULL; - WebKitDOMNode *last_block; - gboolean html_mode = FALSE, ret_val, avoid_editor_call; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL); - - document = e_editor_page_get_document (editor_page); - html_mode = e_editor_page_get_html_mode (editor_page); - - avoid_editor_call = return_pressed_in_empty_line (editor_page); - - if (avoid_editor_call) { - WebKitDOMElement *selection_start_marker; - WebKitDOMNode *current_block, *parent, *parent_block, *block_clone; - - e_editor_dom_selection_save (editor_page); - - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - - current_block = e_editor_dom_get_parent_block_node_from_child ( - WEBKIT_DOM_NODE (selection_start_marker)); - - block_clone = webkit_dom_node_clone_node_with_error (current_block, TRUE, NULL); - /* Find selection start marker and restore it after the new line - * is inserted */ - selection_start_marker = webkit_dom_element_query_selector ( - WEBKIT_DOM_ELEMENT (block_clone), "#-x-evo-selection-start-marker", NULL); - - /* Find parent node that is immediate child of the BODY */ - /* Build the same structure of parent nodes of the current block */ - parent_block = current_block; - parent = webkit_dom_node_get_parent_node (parent_block); - while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) { - WebKitDOMNode *node; - - parent_block = parent; - node = webkit_dom_node_clone_node_with_error (parent_block, FALSE, NULL); - webkit_dom_node_append_child (node, block_clone, NULL); - block_clone = node; - parent = webkit_dom_node_get_parent_node (parent_block); - } - - paragraph = e_editor_dom_get_paragraph_element (editor_page, -1, 0); - - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (paragraph), - WEBKIT_DOM_NODE ( - webkit_dom_document_create_element (document, "BR", NULL)), - NULL); - - /* Insert the selection markers to right place */ - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (paragraph), - webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_start_marker)), - webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (paragraph)), - NULL); - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (paragraph), - WEBKIT_DOM_NODE (selection_start_marker), - webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (paragraph)), - NULL); - - /* Insert the cloned nodes before the BODY parent node */ - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent_block), - block_clone, - parent_block, - NULL); - - /* Insert the new empty paragraph before the BODY parent node */ - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent_block), - WEBKIT_DOM_NODE (paragraph), - parent_block, - NULL); - - /* Remove the old block (its copy was moved to the right place) */ - remove_node (current_block); - - e_editor_dom_selection_restore (editor_page); - - return NULL; - } else { - e_editor_dom_remove_input_event_listener_from_body (editor_page); - e_editor_page_block_selection_changed (editor_page); - - ret_val = e_editor_dom_exec_command ( - editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT, NULL); - - e_editor_page_unblock_selection_changed (editor_page); - e_editor_dom_register_input_event_listener_on_body (editor_page); - - if (!ret_val) - return NULL; - - element = webkit_dom_document_query_selector ( - document, "body>br", NULL); - - if (!element) - return NULL; - } - - last_block = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element)); - while (last_block && e_editor_dom_node_is_citation_node (last_block)) - last_block = webkit_dom_node_get_last_child (last_block); - - if (last_block) { - WebKitDOMNode *last_child; - - if ((last_child = webkit_dom_node_get_last_child (last_block))) { - if (WEBKIT_DOM_IS_ELEMENT (last_child) && - element_has_class (WEBKIT_DOM_ELEMENT (last_child), "-x-evo-quoted")) - webkit_dom_node_append_child ( - last_block, - WEBKIT_DOM_NODE ( - webkit_dom_document_create_element ( - document, "br", NULL)), - NULL); - } - } - - if (!html_mode) { - WebKitDOMNode *sibling; - - sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element)); - - if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (sibling)) { - WebKitDOMNode *node; - - node = webkit_dom_node_get_first_child (sibling); - while (node && e_editor_dom_node_is_citation_node (node)) - node = webkit_dom_node_get_first_child (node); - - /* Rewrap and requote nodes that were created by split. */ - if (WEBKIT_DOM_IS_ELEMENT (node)) - e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (node)); - - if (WEBKIT_DOM_IS_ELEMENT (last_block)) - e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (last_block)); - - e_editor_dom_force_spell_check_in_viewport (editor_page); - } - } - - if (html_to_insert && *html_to_insert) { - paragraph = e_editor_dom_prepare_paragraph (editor_page, FALSE); - webkit_dom_element_set_inner_html ( - paragraph, html_to_insert, NULL); - if (!webkit_dom_element_query_selector (paragraph, "#-x-evo-selection-start-marker", NULL)) - dom_add_selection_markers_into_element_end ( - document, paragraph, NULL, NULL); - } else - paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE); - - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)), - WEBKIT_DOM_NODE (paragraph), - WEBKIT_DOM_NODE (element), - NULL); - - remove_node (WEBKIT_DOM_NODE (element)); - - e_editor_dom_selection_restore (editor_page); - - return paragraph; -} - -/* For purpose of this function see e-mail-formatter-quote.c */ -static void -put_body_in_citation (WebKitDOMDocument *document) -{ - WebKitDOMElement *cite_body = webkit_dom_document_query_selector ( - document, "span.-x-evo-cite-body", NULL); - - if (cite_body) { - WebKitDOMHTMLElement *body = webkit_dom_document_get_body (document); - WebKitDOMNode *citation; - WebKitDOMNode *sibling; - - citation = WEBKIT_DOM_NODE ( - webkit_dom_document_create_element (document, "blockquote", NULL)); - webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (citation), "-x-evo-main-cite"); - webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (citation), "type", "cite", NULL); - - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (body), - citation, - webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)), - NULL); - - while ((sibling = webkit_dom_node_get_next_sibling (citation))) - webkit_dom_node_append_child (citation, sibling, NULL); - - remove_node (WEBKIT_DOM_NODE (cite_body)); - } -} - -/* For purpose of this function see e-mail-formatter-quote.c */ -static void -move_elements_to_body (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMHTMLElement *body; - WebKitDOMNodeList *list = NULL; - gint ii, jj; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - body = webkit_dom_document_get_body (document); - list = webkit_dom_document_query_selector_all ( - document, "div[data-headers]", NULL); - for (ii = webkit_dom_node_list_get_length (list); ii--;) { - WebKitDOMNode *node = webkit_dom_node_list_item (list, ii); - - webkit_dom_element_remove_attribute ( - WEBKIT_DOM_ELEMENT (node), "data-headers"); - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (body), - node, - webkit_dom_node_get_first_child ( - WEBKIT_DOM_NODE (body)), - NULL); - - } - g_clear_object (&list); - - list = webkit_dom_document_query_selector_all ( - document, "span.-x-evo-to-body[data-credits]", NULL); - e_editor_page_set_allow_top_signature (editor_page, webkit_dom_node_list_get_length (list) > 0); - for (jj = 0, ii = webkit_dom_node_list_get_length (list); ii--; jj++) { - char *credits; - WebKitDOMElement *element; - WebKitDOMNode *node = webkit_dom_node_list_item (list, jj); - - element = e_editor_dom_get_paragraph_element (editor_page, -1, 0); - credits = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "data-credits"); - if (credits) - webkit_dom_html_element_set_inner_text (WEBKIT_DOM_HTML_ELEMENT (element), credits, NULL); - g_free (credits); - - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (body), - WEBKIT_DOM_NODE (element), - webkit_dom_node_get_first_child ( - WEBKIT_DOM_NODE (body)), - NULL); - - remove_node (node); - } - g_clear_object (&list); -} - -static void -repair_blockquotes (WebKitDOMDocument *document) -{ - WebKitDOMHTMLCollection *collection; - gulong ii; - - collection = webkit_dom_document_get_elements_by_class_name_as_html_collection ( - document, "gmail_quote"); - for (ii = webkit_dom_html_collection_get_length (collection); ii--;) { - WebKitDOMNode *node = webkit_dom_html_collection_item (collection, ii); - - if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node)) - continue; - - webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "class"); - webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "style"); - webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (node), "type", "cite", NULL); - - if (!WEBKIT_DOM_IS_HTML_BR_ELEMENT (webkit_dom_node_get_last_child (node)) && - webkit_dom_node_get_next_sibling (node)) - webkit_dom_node_append_child ( - node, - WEBKIT_DOM_NODE ( - webkit_dom_document_create_element ( - document, "br", NULL)), - NULL); - } - g_clear_object (&collection); - - collection = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "blockquote"); - for (ii = webkit_dom_html_collection_get_length (collection); ii--;) { - WebKitDOMNode *node = webkit_dom_html_collection_item (collection, ii); - - if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node)) - continue; - - webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "class"); - webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "style"); - webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (node), "type", "cite", NULL); - } - g_clear_object (&collection); -} - -static void -style_blockquotes (WebKitDOMElement *element) -{ - WebKitDOMNodeList *list; - gulong ii; - - g_return_if_fail (WEBKIT_DOM_IS_ELEMENT (element)); - - list = webkit_dom_element_query_selector_all (element, "blockquote", NULL); - for (ii = webkit_dom_node_list_get_length (list); ii--;) { - WebKitDOMNode *node = webkit_dom_node_list_item (list, ii); - - if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node)) - continue; - - webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (node), "style", E_EVOLUTION_BLOCKQUOTE_STYLE, NULL); - } - g_clear_object (&list); -} - -static void -remove_thunderbird_signature (WebKitDOMDocument *document) -{ - WebKitDOMElement *signature; - - signature = webkit_dom_document_query_selector ( - document, "pre.moz-signature", NULL); - if (signature) - remove_node (WEBKIT_DOM_NODE (signature)); -} - -void -e_editor_dom_check_magic_links (EEditorPage *editor_page, - gboolean include_space_by_user) -{ - WebKitDOMDocument *document; - WebKitDOMNode *node; - WebKitDOMRange *range = NULL; - gchar *node_text; - gchar **urls; - gboolean include_space = FALSE; - gboolean is_email_address = FALSE; - gboolean return_key_pressed; - GRegex *regex = NULL; - GMatchInfo *match_info; - gint start_pos_url, end_pos_url; - gboolean has_selection; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - if (!e_editor_page_get_magic_links_enabled (editor_page)) - return; - - return_key_pressed = e_editor_page_get_return_key_pressed (editor_page); - document = e_editor_page_get_document (editor_page); - - if (include_space_by_user) - include_space = TRUE; - else - include_space = e_editor_page_get_space_key_pressed (editor_page); - - range = e_editor_dom_get_current_range (editor_page); - node = webkit_dom_range_get_end_container (range, NULL); - has_selection = !webkit_dom_range_get_collapsed (range, NULL); - g_clear_object (&range); - - if (return_key_pressed) { - WebKitDOMNode* block; - - block = e_editor_dom_get_parent_block_node_from_child (node); - /* Get previous block */ - if (!(block = webkit_dom_node_get_previous_sibling (block))) - return; - - /* If block is quoted content, get the last block there */ - while (block && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (block)) - block = webkit_dom_node_get_last_child (block); - - /* Get the last non-empty node */ - node = webkit_dom_node_get_last_child (block); - if (WEBKIT_DOM_IS_CHARACTER_DATA (node) && - webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node)) == 0) - node = webkit_dom_node_get_previous_sibling (node); - } else { - e_editor_dom_selection_save (editor_page); - if (has_selection) { - WebKitDOMElement *selection_end_marker; - - selection_end_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-end-marker"); - - node = webkit_dom_node_get_previous_sibling ( - WEBKIT_DOM_NODE (selection_end_marker)); - } - } - - if (!node || WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node)) - goto out; - - if (!WEBKIT_DOM_IS_TEXT (node)) { - if (webkit_dom_node_has_child_nodes (node)) - node = webkit_dom_node_get_first_child (node); - if (!WEBKIT_DOM_IS_TEXT (node)) - goto out; - } - - node_text = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (node)); - if (!(node_text && *node_text) || !g_utf8_validate (node_text, -1, NULL)) { - g_free (node_text); - goto out; - } - - if (strstr (node_text, "@") && !strstr (node_text, "://")) { - is_email_address = TRUE; - regex = g_regex_new (include_space ? E_MAIL_PATTERN_SPACE : E_MAIL_PATTERN, 0, 0, NULL); - } else - regex = g_regex_new (include_space ? URL_PATTERN_SPACE : URL_PATTERN, 0, 0, NULL); - - if (!regex) { - g_free (node_text); - goto out; - } - - g_regex_match_all (regex, node_text, G_REGEX_MATCH_NOTEMPTY, &match_info); - urls = g_match_info_fetch_all (match_info); - - if (urls) { - const gchar *end_of_match = NULL; - gchar *final_url = NULL, *url_end_raw, *url_text; - glong url_start, url_end, url_length; - WebKitDOMNode *url_text_node; - WebKitDOMElement *anchor; - - g_match_info_fetch_pos (match_info, 0, &start_pos_url, &end_pos_url); - - /* Get start and end position of URL in node's text because positions - * that we get from g_match_info_fetch_pos are not UTF-8 aware */ - url_end_raw = g_strndup (node_text, end_pos_url); - url_end = g_utf8_strlen (url_end_raw, -1); - url_length = g_utf8_strlen (urls[0], -1); - - end_of_match = url_end_raw + end_pos_url - (include_space ? 3 : 2); - /* URLs are extremely unlikely to end with any punctuation, so - * strip any trailing punctuation off from link and put it after - * the link. Do the same for any closing double-quotes as well. */ - while (end_of_match && end_of_match != url_end_raw && strchr (URL_INVALID_TRAILING_CHARS, *end_of_match)) { - url_length--; - url_end--; - end_of_match--; - } - - url_start = url_end - url_length; - - webkit_dom_text_split_text ( - WEBKIT_DOM_TEXT (node), - include_space ? url_end - 1 : url_end, - NULL); - - webkit_dom_text_split_text ( - WEBKIT_DOM_TEXT (node), url_start, NULL); - url_text_node = webkit_dom_node_get_next_sibling (node); - if (url_text_node) - url_text = webkit_dom_character_data_get_data (WEBKIT_DOM_CHARACTER_DATA (url_text_node)); - else - url_text = NULL; - - /* Sanity check */ - if (!url_text || !*url_text || strrchr (url_text, ' ')) - goto skip; - - if (g_str_has_prefix (url_text, "www.")) - final_url = g_strconcat ("http://" , url_text, NULL); - else if (is_email_address) - final_url = g_strconcat ("mailto:" , url_text, NULL); - else - final_url = g_strdup (url_text); - - /* Create and prepare new anchor element */ - anchor = webkit_dom_document_create_element (document, "A", NULL); - - webkit_dom_element_set_inner_html (anchor, url_text, NULL); - - webkit_dom_html_anchor_element_set_href ( - WEBKIT_DOM_HTML_ANCHOR_ELEMENT (anchor), - final_url); - - /* Insert new anchor element into document */ - webkit_dom_node_replace_child ( - webkit_dom_node_get_parent_node (node), - WEBKIT_DOM_NODE (anchor), - WEBKIT_DOM_NODE (url_text_node), - NULL); - - skip: - g_free (url_end_raw); - g_free (url_text); - if (final_url) - g_free (final_url); - } else { - gboolean appending_to_link = FALSE; - gchar *href, *text, *url, *text_to_append = NULL; - gint diff; - WebKitDOMElement *parent; - WebKitDOMNode *prev_sibling; - - parent = webkit_dom_node_get_parent_element (node); - prev_sibling = webkit_dom_node_get_previous_sibling (node); - - /* If previous sibling is ANCHOR and actual text node is not beginning with - * space => we're appending to link */ - if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (prev_sibling)) { - text_to_append = webkit_dom_node_get_text_content (node); - if (text_to_append && *text_to_append && - !strstr (text_to_append, " ") && - !(strchr (URL_INVALID_TRAILING_CHARS, *text_to_append) && - !(*text_to_append == '?' && strlen(text_to_append) > 1)) && - !g_str_has_prefix (text_to_append, UNICODE_NBSP)) { - - appending_to_link = TRUE; - parent = WEBKIT_DOM_ELEMENT (prev_sibling); - /* If the node(text) contains the some of unwanted characters - * split it into two nodes and select the right one. */ - if (g_str_has_suffix (text_to_append, UNICODE_NBSP) || - g_str_has_suffix (text_to_append, UNICODE_ZERO_WIDTH_SPACE)) { - webkit_dom_text_split_text ( - WEBKIT_DOM_TEXT (node), - g_utf8_strlen (text_to_append, -1) - 1, - NULL); - g_free (text_to_append); - text_to_append = webkit_dom_node_get_text_content (node); - } - } - } - - /* If parent is ANCHOR => we're editing the link */ - if ((!WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) && !appending_to_link) || !text_to_append) { - g_match_info_free (match_info); - g_regex_unref (regex); - g_free (node_text); - g_free (text_to_append); - goto out; - } - - /* edit only if href and description are the same */ - href = webkit_dom_html_anchor_element_get_href ( - WEBKIT_DOM_HTML_ANCHOR_ELEMENT (parent)); - - if (appending_to_link) { - gchar *inner_text; - - inner_text = - webkit_dom_html_element_get_inner_text ( - WEBKIT_DOM_HTML_ELEMENT (parent)), - - text = g_strconcat (inner_text, text_to_append, NULL); - g_free (inner_text); - } else - text = webkit_dom_html_element_get_inner_text ( - WEBKIT_DOM_HTML_ELEMENT (parent)); - - element_remove_class (parent, "-x-evo-visited-link"); - - if (strstr (href, "://") && !strstr (text, "://")) { - url = strstr (href, "://") + 3; - diff = strlen (text) - strlen (url); - - if (text [strlen (text) - 1] != '/') - diff++; - - if ((g_strcmp0 (url, text) != 0 && ABS (diff) == 1) || appending_to_link) { - gchar *new_href; - - new_href = g_strconcat (href, appending_to_link ? "" : text_to_append, NULL); - - webkit_dom_html_anchor_element_set_href ( - WEBKIT_DOM_HTML_ANCHOR_ELEMENT (parent), - new_href); - - if (appending_to_link) { - webkit_dom_element_insert_adjacent_html ( - WEBKIT_DOM_ELEMENT (parent), - "beforeend", - text_to_append, - NULL); - - remove_node (node); - } - - g_free (new_href); - } - } else { - diff = strlen (text) - strlen (href); - if (text [strlen (text) - 1] != '/') - diff++; - - if ((g_strcmp0 (href, text) != 0 && ABS (diff) == 1) || appending_to_link) { - gchar *inner_html; - gchar *new_href; - - inner_html = webkit_dom_element_get_inner_html (parent); - new_href = g_strconcat ( - inner_html, - appending_to_link ? text_to_append : "", - NULL); - - webkit_dom_html_anchor_element_set_href ( - WEBKIT_DOM_HTML_ANCHOR_ELEMENT (parent), - new_href); - - if (appending_to_link) { - webkit_dom_element_insert_adjacent_html ( - WEBKIT_DOM_ELEMENT (parent), - "beforeend", - text_to_append, - NULL); - - remove_node (node); - } - - g_free (new_href); - g_free (inner_html); - } - - } - g_free (text_to_append); - g_free (text); - g_free (href); - } - - g_match_info_free (match_info); - g_regex_unref (regex); - g_free (node_text); - - out: - if (!return_key_pressed) - e_editor_dom_selection_restore (editor_page); -} - -void -e_editor_dom_embed_style_sheet (EEditorPage *editor_page, - const gchar *style_sheet_content) -{ - WebKitDOMDocument *document; - WebKitDOMElement *sheet; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - - e_dom_utils_create_and_add_css_style_sheet (document, "-x-evo-composer-sheet"); - - sheet = webkit_dom_document_get_element_by_id (document, "-x-evo-composer-sheet"); - webkit_dom_element_set_attribute ( - sheet, - "type", - "text/css", - NULL); - - webkit_dom_element_set_inner_html (sheet, style_sheet_content, NULL); -} - -void -e_editor_dom_remove_embedded_style_sheet (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMElement *sheet; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - - sheet = webkit_dom_document_get_element_by_id ( - document, "-x-evo-composer-sheet"); - - if (sheet) - remove_node (WEBKIT_DOM_NODE (sheet)); -} - -static void -insert_delete_event (EEditorPage *editor_page, - WebKitDOMRange *range) -{ - EEditorHistoryEvent *ev; - WebKitDOMDocumentFragment *fragment; - EEditorUndoRedoManager *manager; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - manager = e_editor_page_get_undo_redo_manager (editor_page); - - if (e_editor_undo_redo_manager_is_operation_in_progress (manager)) - return; - - ev = g_new0 (EEditorHistoryEvent, 1); - ev->type = HISTORY_DELETE; - - fragment = webkit_dom_range_clone_contents (range, NULL); - ev->data.fragment = g_object_ref (fragment); - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->before.start.x, - &ev->before.start.y, - &ev->before.end.x, - &ev->before.end.y); - - ev->after.start.x = ev->before.start.x; - ev->after.start.y = ev->before.start.y; - ev->after.end.x = ev->before.start.x; - ev->after.end.y = ev->before.start.y; - - e_editor_undo_redo_manager_insert_history_event (manager, ev); - - ev = g_new0 (EEditorHistoryEvent, 1); - ev->type = HISTORY_AND; - - e_editor_undo_redo_manager_insert_history_event (manager, ev); -} - -/* Based on original use_pictograms() from GtkHTML */ -static const gchar *emoticons_chars = - /* 0 */ "DO)(|/PQ*!" - /* 10 */ "S\0:-\0:\0:-\0" - /* 20 */ ":\0:;=-\"\0:;" - /* 30 */ "B\"|\0:-'\0:X" - /* 40 */ "\0:\0:-\0:\0:-" - /* 50 */ "\0:\0:-\0:\0:-" - /* 60 */ "\0:\0:\0:-\0:\0" - /* 70 */ ":-\0:\0:-\0:\0"; -static gint emoticons_states[] = { - /* 0 */ 12, 17, 22, 34, 43, 48, 53, 58, 65, 70, - /* 10 */ 75, 0, -15, 15, 0, -15, 0, -17, 20, 0, - /* 20 */ -17, 0, -14, -20, -14, 28, 63, 0, -14, -20, - /* 30 */ -3, 63, -18, 0, -12, 38, 41, 0, -12, -2, - /* 40 */ 0, -4, 0, -10, 46, 0, -10, 0, -19, 51, - /* 50 */ 0, -19, 0, -11, 56, 0, -11, 0, -13, 61, - /* 60 */ 0, -13, 0, -6, 0, 68, -7, 0, -7, 0, - /* 70 */ -16, 73, 0, -16, 0, -21, 78, 0, -21, 0 }; -static const gchar *emoticons_icon_names[] = { - "face-angel", - "face-angry", - "face-cool", - "face-crying", - "face-devilish", - "face-embarrassed", - "face-kiss", - "face-laugh", /* not used */ - "face-monkey", /* not used */ - "face-plain", - "face-raspberry", - "face-sad", - "face-sick", - "face-smile", - "face-smile-big", - "face-smirk", - "face-surprise", - "face-tired", - "face-uncertain", - "face-wink", - "face-worried" -}; - -typedef struct _EmoticonLoadContext { - EEmoticon *emoticon; - EEditorPage *editor_page; - gchar *content_type; - gchar *name; -} EmoticonLoadContext; - -static EmoticonLoadContext * -emoticon_load_context_new (EEditorPage *editor_page, - EEmoticon *emoticon) -{ - EmoticonLoadContext *load_context; - - load_context = g_slice_new0 (EmoticonLoadContext); - load_context->emoticon = emoticon; - load_context->editor_page = editor_page; - - return load_context; -} - -static void -emoticon_load_context_free (EmoticonLoadContext *load_context) -{ - g_free (load_context->content_type); - g_free (load_context->name); - g_slice_free (EmoticonLoadContext, load_context); -} - -static void -emoticon_insert_span (EEmoticon *emoticon, - EmoticonLoadContext *load_context, - WebKitDOMElement *span) -{ - EEditorHistoryEvent *ev = NULL; - EEditorUndoRedoManager *manager; - EEditorPage *editor_page = load_context->editor_page; - gboolean misplaced_selection = FALSE, smiley_written; - gchar *node_text = NULL; - const gchar *emoticon_start; - WebKitDOMDocument *document; - WebKitDOMElement *selection_start_marker, *selection_end_marker; - WebKitDOMNode *node, *insert_before, *prev_sibling, *next_sibling; - WebKitDOMNode *selection_end_marker_parent, *inserted_node; - WebKitDOMRange *range = NULL; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - smiley_written = e_editor_page_get_is_smiley_written (editor_page); - manager = e_editor_page_get_undo_redo_manager (editor_page); - - if (e_editor_dom_selection_is_collapsed (editor_page)) { - e_editor_dom_selection_save (editor_page); - - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - selection_end_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-end-marker"); - - if (!smiley_written) { - if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) { - ev = g_new0 (EEditorHistoryEvent, 1); - if (e_editor_page_get_unicode_smileys_enabled (editor_page)) - ev->type = HISTORY_INPUT; - else { - ev->type = HISTORY_SMILEY; - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->before.start.x, - &ev->before.start.y, - &ev->before.end.x, - &ev->before.end.y); - } - } - } - } else { - WebKitDOMRange *tmp_range = NULL; - - tmp_range = e_editor_dom_get_current_range (editor_page); - insert_delete_event (editor_page, tmp_range); - g_clear_object (&tmp_range); - - e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL); - - if (!smiley_written) { - if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) { - ev = g_new0 (EEditorHistoryEvent, 1); - - if (e_editor_page_get_unicode_smileys_enabled (editor_page)) - ev->type = HISTORY_INPUT; - else { - ev->type = HISTORY_SMILEY; - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->before.start.x, - &ev->before.start.y, - &ev->before.end.x, - &ev->before.end.y); - } - } - } - - e_editor_dom_selection_save (editor_page); - - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - selection_end_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-end-marker"); - } - - /* If the selection was not saved, move it into the first child of body */ - if (!selection_start_marker || !selection_end_marker) { - WebKitDOMHTMLElement *body; - WebKitDOMNode *child; - - body = webkit_dom_document_get_body (document); - child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)); - - dom_add_selection_markers_into_element_start ( - document, - WEBKIT_DOM_ELEMENT (child), - &selection_start_marker, - &selection_end_marker); - - if (ev && !e_editor_page_get_unicode_smileys_enabled (editor_page)) - e_editor_dom_selection_get_coordinates (editor_page, - &ev->before.start.x, - &ev->before.start.y, - &ev->before.end.x, - &ev->before.end.y); - } - - /* Sometimes selection end marker is in body. Move it into next sibling */ - selection_end_marker_parent = e_editor_dom_get_parent_block_node_from_child ( - WEBKIT_DOM_NODE (selection_end_marker)); - if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (selection_end_marker_parent)) { - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node ( - WEBKIT_DOM_NODE (selection_start_marker)), - WEBKIT_DOM_NODE (selection_end_marker), - WEBKIT_DOM_NODE (selection_start_marker), - NULL); - if (ev && !e_editor_page_get_unicode_smileys_enabled (editor_page)) - e_editor_dom_selection_get_coordinates (editor_page, - &ev->before.start.x, - &ev->before.start.y, - &ev->before.end.x, - &ev->before.end.y); - } - selection_end_marker_parent = webkit_dom_node_get_parent_node ( - WEBKIT_DOM_NODE (selection_end_marker)); - - /* Determine before what node we have to insert the smiley */ - insert_before = WEBKIT_DOM_NODE (selection_start_marker); - prev_sibling = webkit_dom_node_get_previous_sibling ( - WEBKIT_DOM_NODE (selection_start_marker)); - if (prev_sibling) { - if (webkit_dom_node_is_same_node ( - prev_sibling, WEBKIT_DOM_NODE (selection_end_marker))) { - insert_before = WEBKIT_DOM_NODE (selection_end_marker); - } else { - prev_sibling = webkit_dom_node_get_previous_sibling (prev_sibling); - if (prev_sibling && - webkit_dom_node_is_same_node ( - prev_sibling, WEBKIT_DOM_NODE (selection_end_marker))) { - insert_before = WEBKIT_DOM_NODE (selection_end_marker); - } - } - } else - insert_before = WEBKIT_DOM_NODE (selection_start_marker); - - /* Look if selection is misplaced - that means that the selection was - * restored before the previously inserted smiley in situations when we - * are writing more smileys in a row */ - next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker)); - if (next_sibling && WEBKIT_DOM_IS_ELEMENT (next_sibling)) - if (element_has_class (WEBKIT_DOM_ELEMENT (next_sibling), "-x-evo-smiley-wrapper")) - misplaced_selection = TRUE; - - range = e_editor_dom_get_current_range (editor_page); - node = webkit_dom_range_get_end_container (range, NULL); - g_clear_object (&range); - if (WEBKIT_DOM_IS_TEXT (node)) - node_text = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (node)); - - if (misplaced_selection) { - /* Insert smiley and selection markers after it */ - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (insert_before), - WEBKIT_DOM_NODE (selection_start_marker), - webkit_dom_node_get_next_sibling (next_sibling), - NULL); - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (insert_before), - WEBKIT_DOM_NODE (selection_end_marker), - webkit_dom_node_get_next_sibling (next_sibling), - NULL); - if (e_editor_page_get_unicode_smileys_enabled (editor_page)) - inserted_node = webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (insert_before), - webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (span)), - webkit_dom_node_get_next_sibling (next_sibling), - NULL); - else - inserted_node = webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (insert_before), - WEBKIT_DOM_NODE (span), - webkit_dom_node_get_next_sibling (next_sibling), - NULL); - } else { - if (e_editor_page_get_unicode_smileys_enabled (editor_page)) - inserted_node = webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (insert_before), - webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (span)), - insert_before, - NULL); - else - inserted_node = webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (insert_before), - WEBKIT_DOM_NODE (span), - insert_before, - NULL); - } - - if (!e_editor_page_get_unicode_smileys_enabled (editor_page)) { - /* ​ == UNICODE_ZERO_WIDTH_SPACE */ - webkit_dom_element_insert_adjacent_html ( - WEBKIT_DOM_ELEMENT (span), "afterend", "​", NULL); - } - - if (ev) { - WebKitDOMDocumentFragment *fragment; - WebKitDOMNode *node; - - fragment = webkit_dom_document_create_document_fragment (document); - node = webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (fragment), - webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (inserted_node), TRUE, NULL), - NULL); - if (e_editor_page_get_unicode_smileys_enabled (editor_page)) { - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (fragment), - WEBKIT_DOM_NODE ( - dom_create_selection_marker (document, TRUE)), - NULL); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (fragment), - WEBKIT_DOM_NODE ( - dom_create_selection_marker (document, FALSE)), - NULL); - } else - webkit_dom_element_insert_adjacent_html ( - WEBKIT_DOM_ELEMENT (node), "afterend", "​", NULL); - ev->data.fragment = g_object_ref (fragment); - } - - /* Remove the text that represents the text version of smiley that was - * written into the composer. */ - if (node_text && smiley_written) { - emoticon_start = g_utf8_strrchr ( - node_text, -1, g_utf8_get_char (emoticon->text_face)); - /* Check if the written smiley is really the one that we inserted. */ - if (emoticon_start) { - /* The written smiley is the same as text version. */ - if (g_str_has_prefix (emoticon_start, emoticon->text_face)) { - webkit_dom_character_data_delete_data ( - WEBKIT_DOM_CHARACTER_DATA (node), - g_utf8_strlen (node_text, -1) - strlen (emoticon_start), - strlen (emoticon->text_face), - NULL); - } else if (strstr (emoticon->text_face, "-")) { - gboolean same = TRUE, compensate = FALSE; - gint ii = 0, jj = 0; - - /* Try to recognize smileys without the dash e.g. :). */ - while (emoticon_start[ii] && emoticon->text_face[jj]) { - if (emoticon_start[ii] == emoticon->text_face[jj]) { - if (emoticon->text_face[jj+1] && emoticon->text_face[jj+1] == '-') { - ii++; - jj+=2; - compensate = TRUE; - } else { - ii++; - jj++; - } - } else { - same = FALSE; - break; - } - } - - if (same) { - webkit_dom_character_data_delete_data ( - WEBKIT_DOM_CHARACTER_DATA (node), - g_utf8_strlen (node_text, -1) - strlen (emoticon_start), - ii, - NULL); - } - /* If we recognize smiley without dash, but we inserted - * the text version with dash we need it insert new - * history input event with that dash. */ - if (compensate) - e_editor_undo_redo_manager_insert_dash_history_event (manager); - } - } - - e_editor_page_set_is_smiley_written (editor_page, FALSE); - } - - if (ev) { - e_editor_dom_selection_get_coordinates (editor_page, - &ev->after.start.x, - &ev->after.start.y, - &ev->after.end.x, - &ev->after.end.y); - e_editor_undo_redo_manager_insert_history_event (manager, ev); - } - - e_editor_dom_selection_restore (editor_page); - - e_editor_page_emit_content_changed (editor_page); - - g_free (node_text); -} - -static void -emoticon_read_async_cb (GFile *file, - GAsyncResult *result, - EmoticonLoadContext *load_context) -{ - EEmoticon *emoticon = load_context->emoticon; - EEditorPage *editor_page = load_context->editor_page; - GError *error = NULL; - gboolean html_mode; - gchar *mime_type; - gchar *base64_encoded, *output, *data; - GFileInputStream *input_stream; - GOutputStream *output_stream; - gssize size; - WebKitDOMElement *wrapper, *image, *smiley_text; - WebKitDOMDocument *document; - - input_stream = g_file_read_finish (file, result, &error); - g_return_if_fail (!error && input_stream); - - output_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free); - - size = g_output_stream_splice ( - output_stream, G_INPUT_STREAM (input_stream), - G_OUTPUT_STREAM_SPLICE_NONE, NULL, &error); - - if (error || (size == -1)) - goto out; - - mime_type = g_content_type_get_mime_type (load_context->content_type); - - data = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (output_stream)); - base64_encoded = g_base64_encode ((const guchar *) data, size); - output = g_strconcat ("data:", mime_type, ";base64,", base64_encoded, NULL); - - html_mode = e_editor_page_get_html_mode (editor_page); - document = e_editor_page_get_document (editor_page); - - /* Insert span with image representation and another one with text - * representation and hide/show them dependant on active composer mode */ - wrapper = webkit_dom_document_create_element (document, "SPAN", NULL); - if (html_mode) - webkit_dom_element_set_attribute ( - wrapper, "class", "-x-evo-smiley-wrapper -x-evo-resizable-wrapper", NULL); - else - webkit_dom_element_set_attribute ( - wrapper, "class", "-x-evo-smiley-wrapper", NULL); - - image = webkit_dom_document_create_element (document, "IMG", NULL); - webkit_dom_element_set_attribute (image, "src", output, NULL); - webkit_dom_element_set_attribute (image, "data-inline", "", NULL); - webkit_dom_element_set_attribute (image, "data-name", load_context->name, NULL); - webkit_dom_element_set_attribute (image, "alt", emoticon->text_face, NULL); - webkit_dom_element_set_attribute (image, "class", "-x-evo-smiley-img", NULL); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (wrapper), WEBKIT_DOM_NODE (image), NULL); - - smiley_text = webkit_dom_document_create_element (document, "SPAN", NULL); - webkit_dom_element_set_attribute (smiley_text, "class", "-x-evo-smiley-text", NULL); - webkit_dom_html_element_set_inner_text ( - WEBKIT_DOM_HTML_ELEMENT (smiley_text), emoticon->text_face, NULL); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (wrapper), WEBKIT_DOM_NODE (smiley_text), NULL); - - emoticon_insert_span (emoticon, load_context, wrapper); - - g_free (base64_encoded); - g_free (output); - g_free (mime_type); - g_object_unref (output_stream); - out: - emoticon_load_context_free (load_context); -} - -static void -emoticon_query_info_async_cb (GFile *file, - GAsyncResult *result, - EmoticonLoadContext *load_context) -{ - GError *error = NULL; - GFileInfo *info; - - info = g_file_query_info_finish (file, result, &error); - g_return_if_fail (!error && info); - - load_context->content_type = g_strdup (g_file_info_get_content_type (info)); - load_context->name = g_strdup (g_file_info_get_name (info)); - - g_file_read_async ( - file, G_PRIORITY_DEFAULT, NULL, - (GAsyncReadyCallback) emoticon_read_async_cb, load_context); - - g_object_unref (info); -} - -void -e_editor_dom_insert_smiley (EEditorPage *editor_page, - EEmoticon *emoticon) -{ - WebKitDOMDocument *document; - GFile *file; - gchar *filename_uri; - EmoticonLoadContext *load_context; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - - if (e_editor_page_get_unicode_smileys_enabled (editor_page)) { - WebKitDOMElement *wrapper; - - wrapper = webkit_dom_document_create_element (document, "SPAN", NULL); - webkit_dom_html_element_set_inner_text ( - WEBKIT_DOM_HTML_ELEMENT (wrapper), emoticon->unicode_character, NULL); - - load_context = emoticon_load_context_new (editor_page, emoticon); - emoticon_insert_span (emoticon, load_context, wrapper); - emoticon_load_context_free (load_context); - } else { - filename_uri = e_emoticon_get_uri (emoticon); - g_return_if_fail (filename_uri != NULL); - - load_context = emoticon_load_context_new (editor_page, emoticon); - - file = g_file_new_for_uri (filename_uri); - g_file_query_info_async ( - file, "standard::*", G_FILE_QUERY_INFO_NONE, - G_PRIORITY_DEFAULT, NULL, - (GAsyncReadyCallback) emoticon_query_info_async_cb, load_context); - - g_free (filename_uri); - g_object_unref (file); - } -} - -void -e_editor_dom_insert_smiley_by_name (EEditorPage *editor_page, - const gchar *name) -{ - const EEmoticon *emoticon; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - emoticon = e_emoticon_chooser_lookup_emoticon (name); - e_editor_page_set_is_smiley_written (editor_page, FALSE); - e_editor_dom_insert_smiley (editor_page, (EEmoticon *) emoticon); -} - -void -e_editor_dom_check_magic_smileys (EEditorPage *editor_page) -{ - WebKitDOMNode *node; - WebKitDOMRange *range = NULL; - gint pos, state, relative, start; - gchar *node_text; - gunichar uc; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - if (!e_editor_page_get_magic_smileys_enabled (editor_page)) - return; - - range = e_editor_dom_get_current_range (editor_page); - node = webkit_dom_range_get_end_container (range, NULL); - if (!WEBKIT_DOM_IS_TEXT (node)) { - g_clear_object (&range); - return; - } - - node_text = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (node)); - if (node_text == NULL) { - g_clear_object (&range); - return; - } - - start = webkit_dom_range_get_end_offset (range, NULL) - 1; - pos = start; - state = 0; - while (pos >= 0) { - uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos)); - relative = 0; - while (emoticons_chars[state + relative]) { - if (emoticons_chars[state + relative] == uc) - break; - relative++; - } - state = emoticons_states[state + relative]; - /* 0 .. not found, -n .. found n-th */ - if (state <= 0) - break; - pos--; - } - - /* Special case needed to recognize angel and devilish. */ - if (pos > 0 && state == -14) { - uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos - 1)); - if (uc == 'O') { - state = -1; - pos--; - } else if (uc == '>') { - state = -5; - pos--; - } - } - - if (state < 0) { - const EEmoticon *emoticon; - - if (pos > 0) { - uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos - 1)); - if (!g_unichar_isspace (uc)) { - g_free (node_text); - g_clear_object (&range); - return; - } - } - - emoticon = e_emoticon_chooser_lookup_emoticon ( - emoticons_icon_names[-state - 1]); - e_editor_page_set_is_smiley_written (editor_page, TRUE); - e_editor_dom_insert_smiley (editor_page, (EEmoticon *) emoticon); - } - - g_clear_object (&range); - g_free (node_text); -} - -static void -dom_set_links_active (WebKitDOMDocument *document, - gboolean active) -{ - WebKitDOMElement *style; - - style = webkit_dom_document_get_element_by_id (document, "-x-evo-style-a"); - if (style) - remove_node (WEBKIT_DOM_NODE (style)); - - if (!active) { - WebKitDOMHTMLHeadElement *head; - head = webkit_dom_document_get_head (document); - - style = webkit_dom_document_create_element (document, "STYLE", NULL); - webkit_dom_element_set_id (style, "-x-evo-style-a"); - webkit_dom_element_set_attribute (style, "type", "text/css", NULL); - webkit_dom_html_element_set_inner_text ( - WEBKIT_DOM_HTML_ELEMENT (style), "a { cursor: text; }", NULL); - - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (head), WEBKIT_DOM_NODE (style), NULL); - } -} - -static void -fix_paragraph_structure_after_pressing_enter_after_smiley (WebKitDOMDocument *document) -{ - WebKitDOMElement *element; - - element = webkit_dom_document_query_selector ( - document, "span.-x-evo-smiley-wrapper > br", NULL); - - if (element) { - WebKitDOMNode *parent; - - parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)); - webkit_dom_element_set_inner_html ( - webkit_dom_node_get_parent_element (parent), - UNICODE_ZERO_WIDTH_SPACE, - NULL); - } -} - -static gboolean -fix_paragraph_structure_after_pressing_enter (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMNode *body, *prev_sibling, *node; - WebKitDOMElement *br; - gboolean prev_is_heading = FALSE; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE); - - document = e_editor_page_get_document (editor_page); - body = WEBKIT_DOM_NODE (webkit_dom_document_get_body (document)); - - e_editor_dom_selection_save (editor_page); - - /* When pressing Enter on empty line in the list (or after heading elements) - * WebKit will end that list and inserts

so replace it - * with the right paragraph element. */ - br = webkit_dom_document_query_selector ( - document, "body > div:not([data-evo-paragraph]) > #-x-evo-selection-end-marker + br", NULL); - - if (!br || webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (br)) || - webkit_dom_node_get_previous_sibling (webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (br)))) - goto out; - - node = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (br)); - - prev_sibling = webkit_dom_node_get_previous_sibling (node); - if (prev_sibling && WEBKIT_DOM_IS_HTML_HEADING_ELEMENT (prev_sibling)) - prev_is_heading = TRUE; - - webkit_dom_node_replace_child ( - body, - WEBKIT_DOM_NODE (e_editor_dom_prepare_paragraph (editor_page, FALSE)), - node, - NULL); - - out: - e_editor_dom_selection_restore (editor_page); - - return prev_is_heading; -} - -static gboolean -surround_text_with_paragraph_if_needed (EEditorPage *editor_page, - WebKitDOMNode *node) -{ - WebKitDOMNode *next_sibling = webkit_dom_node_get_next_sibling (node); - WebKitDOMNode *prev_sibling = webkit_dom_node_get_previous_sibling (node); - WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node); - WebKitDOMElement *element; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE); - - /* All text in composer has to be written in div elements, so if - * we are writing something straight to the body, surround it with - * paragraph */ - if (WEBKIT_DOM_IS_TEXT (node) && - (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent) || - WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent))) { - element = e_editor_dom_put_node_into_paragraph (editor_page, node, TRUE); - if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent)) - webkit_dom_element_remove_attribute (element, "style"); - - if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling)) - remove_node (next_sibling); - - /* Tab character */ - if (WEBKIT_DOM_IS_ELEMENT (prev_sibling) && - element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), "Apple-tab-span")) { - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (element), - prev_sibling, - webkit_dom_node_get_first_child ( - WEBKIT_DOM_NODE (element)), - NULL); - } - - return TRUE; - } - - return FALSE; -} - -static gboolean -selection_is_in_table (WebKitDOMDocument *document, - gboolean *first_cell, - WebKitDOMNode **table_node) -{ - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMNode *node, *parent; - WebKitDOMRange *range = NULL; - - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - g_clear_object (&dom_window); - - if (first_cell != NULL) - *first_cell = FALSE; - - if (table_node != NULL) - *table_node = NULL; - - if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) { - g_clear_object (&dom_selection); - return FALSE; - } - - range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - node = webkit_dom_range_get_start_container (range, NULL); - g_clear_object (&dom_selection); - - parent = node; - while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) { - if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent)) { - if (first_cell != NULL) { - if (!webkit_dom_node_get_previous_sibling (parent)) { - gboolean on_start = TRUE; - WebKitDOMNode *tmp; - - tmp = webkit_dom_node_get_previous_sibling (node); - if (!tmp && WEBKIT_DOM_IS_TEXT (node)) - on_start = webkit_dom_range_get_start_offset (range, NULL) == 0; - else if (tmp) - on_start = FALSE; - - if (on_start) { - node = webkit_dom_node_get_parent_node (parent); - if (node && WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (node)) - if (!webkit_dom_node_get_previous_sibling (node)) - *first_cell = TRUE; - } - } - } else { - g_clear_object (&range); - return TRUE; - } - } - if (WEBKIT_DOM_IS_HTML_TABLE_ELEMENT (parent)) { - if (table_node != NULL) - *table_node = parent; - else { - g_clear_object (&range); - return TRUE; - } - } - parent = webkit_dom_node_get_parent_node (parent); - } - - g_clear_object (&range); - - if (table_node == NULL) - return FALSE; - - return *table_node != NULL; -} - -static gboolean -jump_to_next_table_cell (WebKitDOMDocument *document, - gboolean jump_back) -{ - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMNode *node, *cell; - WebKitDOMRange *range = NULL; - - if (!selection_is_in_table (document, NULL, NULL)) - return FALSE; - - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - g_clear_object (&dom_window); - range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - node = webkit_dom_range_get_start_container (range, NULL); - - cell = node; - while (cell && !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (cell)) { - cell = webkit_dom_node_get_parent_node (cell); - } - - if (!WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (cell)) { - g_clear_object (&range); - g_clear_object (&dom_selection); - return FALSE; - } - - if (jump_back) { - /* Get previous cell */ - node = webkit_dom_node_get_previous_sibling (cell); - if (!node || !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node)) { - /* No cell, go one row up. */ - node = webkit_dom_node_get_parent_node (cell); - node = webkit_dom_node_get_previous_sibling (node); - if (node && WEBKIT_DOM_IS_HTML_TABLE_ROW_ELEMENT (node)) { - node = webkit_dom_node_get_last_child (node); - } else { - /* No row above, move to the block before table. */ - node = webkit_dom_node_get_parent_node (cell); - while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node (node))) - node = webkit_dom_node_get_parent_node (node); - - node = webkit_dom_node_get_previous_sibling (node); - } - } - } else { - /* Get next cell */ - node = webkit_dom_node_get_next_sibling (cell); - if (!node || !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node)) { - /* No cell, go one row below. */ - node = webkit_dom_node_get_parent_node (cell); - node = webkit_dom_node_get_next_sibling (node); - if (node && WEBKIT_DOM_IS_HTML_TABLE_ROW_ELEMENT (node)) { - node = webkit_dom_node_get_first_child (node); - } else { - /* No row below, move to the block after table. */ - node = webkit_dom_node_get_parent_node (cell); - while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node (node))) - node = webkit_dom_node_get_parent_node (node); - - node = webkit_dom_node_get_next_sibling (node); - } - } - } - - if (!node) { - g_clear_object (&range); - g_clear_object (&dom_selection); - return FALSE; - } - - webkit_dom_range_select_node_contents (range, node, NULL); - webkit_dom_range_collapse (range, TRUE, NULL); - webkit_dom_dom_selection_remove_all_ranges (dom_selection); - webkit_dom_dom_selection_add_range (dom_selection, range); - g_clear_object (&range); - g_clear_object (&dom_selection); - - return TRUE; -} - -static gboolean -save_history_before_event_in_table (EEditorPage *editor_page, - WebKitDOMRange *range) -{ - WebKitDOMNode *node; - WebKitDOMElement *block; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE); - - node = webkit_dom_range_get_start_container (range, NULL); - if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node)) - block = WEBKIT_DOM_ELEMENT (node); - else - block = get_parent_block_element (node); - - if (block && WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (block)) { - EEditorUndoRedoManager *manager; - EEditorHistoryEvent *ev; - - ev = g_new0 (EEditorHistoryEvent, 1); - ev->type = HISTORY_TABLE_INPUT; - - e_editor_dom_selection_save (editor_page); - ev->data.dom.from = g_object_ref (webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (block), TRUE, NULL)); - e_editor_dom_selection_restore (editor_page); - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->before.start.x, - &ev->before.start.y, - &ev->before.end.x, - &ev->before.end.y); - - manager = e_editor_page_get_undo_redo_manager (editor_page); - e_editor_undo_redo_manager_insert_history_event (manager, ev); - - return TRUE; - } - - return FALSE; -} - -static gboolean -insert_tabulator (EEditorPage *editor_page) -{ - EEditorUndoRedoManager *manager; - EEditorHistoryEvent *ev = NULL; - gboolean success; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE); - - manager = e_editor_page_get_undo_redo_manager (editor_page); - - if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) { - ev = g_new0 (EEditorHistoryEvent, 1); - ev->type = HISTORY_INPUT; - - if (!e_editor_dom_selection_is_collapsed (editor_page)) { - WebKitDOMRange *tmp_range = NULL; - - tmp_range = e_editor_dom_get_current_range (editor_page); - insert_delete_event (editor_page, tmp_range); - g_clear_object (&tmp_range); - } - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->before.start.x, - &ev->before.start.y, - &ev->before.end.x, - &ev->before.end.y); - - ev->before.end.x = ev->before.start.x; - ev->before.end.y = ev->before.start.y; - } - - success = e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, "\t"); - - if (ev) { - if (success) { - WebKitDOMDocument *document; - WebKitDOMElement *element; - WebKitDOMDocumentFragment *fragment; - - document = e_editor_page_get_document (editor_page); - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->after.start.x, - &ev->after.start.y, - &ev->after.end.x, - &ev->after.end.y); - - fragment = webkit_dom_document_create_document_fragment (document); - element = webkit_dom_document_create_element (document, "span", NULL); - webkit_dom_html_element_set_inner_text ( - WEBKIT_DOM_HTML_ELEMENT (element), "\t", NULL); - webkit_dom_element_set_attribute ( - element, "class", "Apple-tab-span", NULL); - webkit_dom_element_set_attribute ( - element, "style", "white-space:pre", NULL); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (fragment), WEBKIT_DOM_NODE (element), NULL); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (fragment), - WEBKIT_DOM_NODE (dom_create_selection_marker (document, TRUE)), - NULL); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (fragment), - WEBKIT_DOM_NODE (dom_create_selection_marker (document, FALSE)), - NULL); - ev->data.fragment = g_object_ref (fragment); - - e_editor_undo_redo_manager_insert_history_event (manager, ev); - e_editor_page_emit_content_changed (editor_page); - } else { - e_editor_undo_redo_manager_remove_current_history_event (manager); - e_editor_undo_redo_manager_remove_current_history_event (manager); - g_free (ev); - } - } - - return success; -} - -static void -body_keypress_event_cb (WebKitDOMElement *element, - WebKitDOMUIEvent *event, - EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMRange *range = NULL; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - e_editor_page_set_is_processing_keypress_event (editor_page, TRUE); - - document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element)); - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - g_clear_object (&dom_window); - range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - - if (range && !webkit_dom_range_get_collapsed (range, NULL)) - insert_delete_event (editor_page, range); - - g_clear_object (&dom_selection); - g_clear_object (&range); -} - -static void -body_keydown_event_cb (WebKitDOMElement *element, - WebKitDOMUIEvent *event, - EEditorPage *editor_page) -{ - gboolean backspace_key, delete_key, space_key, return_key; - gboolean shift_key, control_key, tabulator_key; - glong key_code; - WebKitDOMDocument *document; - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMRange *range = NULL; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element)); - - key_code = webkit_dom_ui_event_get_key_code (event); - delete_key = key_code == HTML_KEY_CODE_DELETE; - return_key = key_code == HTML_KEY_CODE_RETURN; - backspace_key = key_code == HTML_KEY_CODE_BACKSPACE; - space_key = key_code == HTML_KEY_CODE_SPACE; - tabulator_key = key_code == HTML_KEY_CODE_TABULATOR; - - if (key_code == HTML_KEY_CODE_CONTROL) { - dom_set_links_active (document, TRUE); - return; - } - - e_editor_page_set_dont_save_history_in_body_input (editor_page, delete_key || backspace_key); - - e_editor_page_set_return_key_pressed (editor_page, return_key); - e_editor_page_set_space_key_pressed (editor_page, space_key); - - if (!(delete_key || return_key || backspace_key || space_key || tabulator_key)) - return; - - shift_key = webkit_dom_keyboard_event_get_shift_key (WEBKIT_DOM_KEYBOARD_EVENT (event)); - control_key = webkit_dom_keyboard_event_get_ctrl_key (WEBKIT_DOM_KEYBOARD_EVENT (event)); - - if (tabulator_key) { - if (jump_to_next_table_cell (document, shift_key)) { - webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event)); - goto out; - } - - if (!shift_key && insert_tabulator (editor_page)) - webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event)); - - goto out; - } - - if (return_key && e_editor_dom_key_press_event_process_return_key (editor_page)) { - webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event)); - goto out; - } - - if (backspace_key && e_editor_dom_key_press_event_process_backspace_key (editor_page)) { - webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event)); - goto out; - } - - if (delete_key || backspace_key) { - if (e_editor_dom_key_press_event_process_delete_or_backspace_key (editor_page, key_code, control_key, delete_key)) - webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event)); - goto out; - } - - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - g_clear_object (&dom_window); - range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - - if (save_history_before_event_in_table (editor_page, range)) - goto out; - - if (return_key) { - EEditorHistoryEvent *ev; - EEditorUndoRedoManager *manager; - - /* Insert new history event for Return to have the right coordinates. - * The fragment will be added later. */ - ev = g_new0 (EEditorHistoryEvent, 1); - ev->type = HISTORY_INPUT; - - manager = e_editor_page_get_undo_redo_manager (editor_page); - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->before.start.x, - &ev->before.start.y, - &ev->before.end.x, - &ev->before.end.y); - e_editor_undo_redo_manager_insert_history_event (manager, ev); - } - out: - g_clear_object (&range); - g_clear_object (&dom_selection); -} - -static gboolean -save_history_after_event_in_table (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMElement *element; - WebKitDOMNode *node; - WebKitDOMRange *range = NULL; - EEditorHistoryEvent *ev; - EEditorUndoRedoManager *manager; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE); - - document = e_editor_page_get_document (editor_page); - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - g_clear_object (&dom_window); - - if (!webkit_dom_dom_selection_get_range_count (dom_selection)) { - g_clear_object (&dom_selection); - return FALSE; - } - range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - - /* Find if writing into table. */ - node = webkit_dom_range_get_start_container (range, NULL); - if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node)) - element = WEBKIT_DOM_ELEMENT (node); - else - element = get_parent_block_element (node); - - g_clear_object (&dom_selection); - g_clear_object (&range); - - manager = e_editor_page_get_undo_redo_manager (editor_page); - /* If writing to table we have to create different history event. */ - if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (element)) { - ev = e_editor_undo_redo_manager_get_current_history_event (manager); - if (ev->type != HISTORY_TABLE_INPUT) - return FALSE; - } else - return FALSE; - - e_editor_dom_selection_save (editor_page); - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->after.start.x, - &ev->after.start.y, - &ev->after.end.x, - &ev->after.end.y); - - ev->data.dom.to = g_object_ref (webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), TRUE, NULL)); - - e_editor_dom_selection_restore (editor_page); - - return TRUE; -} - -static void -save_history_for_input (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMDocumentFragment *fragment; - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMRange *range = NULL, *range_clone = NULL; - WebKitDOMNode *start_container; - EEditorHistoryEvent *ev; - EEditorUndoRedoManager *manager; - glong offset; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - manager = e_editor_page_get_undo_redo_manager (editor_page); - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - g_clear_object (&dom_window); - - if (!webkit_dom_dom_selection_get_range_count (dom_selection)) { - g_clear_object (&dom_selection); - return; - } - - if (e_editor_page_get_return_key_pressed (editor_page)) { - ev = e_editor_undo_redo_manager_get_current_history_event (manager); - if (ev->type != HISTORY_INPUT) { - g_clear_object (&dom_selection); - return; - } - } else { - ev = g_new0 (EEditorHistoryEvent, 1); - ev->type = HISTORY_INPUT; - } - - e_editor_page_block_selection_changed (editor_page); - - e_editor_dom_selection_get_coordinates (editor_page, - &ev->after.start.x, - &ev->after.start.y, - &ev->after.end.x, - &ev->after.end.y); - - range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - range_clone = webkit_dom_range_clone_range (range, NULL); - offset = webkit_dom_range_get_start_offset (range_clone, NULL); - start_container = webkit_dom_range_get_start_container (range_clone, NULL); - if (offset > 0) - webkit_dom_range_set_start ( - range_clone, - start_container, - offset - 1, - NULL); - fragment = webkit_dom_range_clone_contents (range_clone, NULL); - /* We have to specially handle Return key press */ - if (e_editor_page_get_return_key_pressed (editor_page)) { - WebKitDOMElement *element_start, *element_end; - WebKitDOMNode *parent_start, *parent_end, *node; - - element_start = webkit_dom_document_create_element (document, "span", NULL); - webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (element_start), NULL); - webkit_dom_dom_selection_modify (dom_selection, "move", "left", "character"); - g_clear_object (&range); - range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - element_end = webkit_dom_document_create_element (document, "span", NULL); - webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (element_end), NULL); - - parent_start = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element_start)); - parent_end = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element_end)); - - while (parent_start && parent_end && !webkit_dom_node_is_same_node (parent_start, parent_end) && - !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent_start) && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent_end)) { - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (fragment), - webkit_dom_node_clone_node_with_error (parent_start, FALSE, NULL), - webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)), - NULL); - parent_start = webkit_dom_node_get_parent_node (parent_start); - parent_end = webkit_dom_node_get_parent_node (parent_end); - } - - node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)); - while (webkit_dom_node_get_next_sibling (node)) { - WebKitDOMNode *last_child; - - last_child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment)); - webkit_dom_node_append_child ( - webkit_dom_node_get_previous_sibling (last_child), - last_child, - NULL); - } - - node = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment)); - while (webkit_dom_node_get_last_child (node)) { - node = webkit_dom_node_get_last_child (node); - } - - webkit_dom_node_append_child ( - node, - WEBKIT_DOM_NODE ( - webkit_dom_document_create_element (document, "br", NULL)), - NULL); - webkit_dom_node_append_child ( - node, - WEBKIT_DOM_NODE ( - dom_create_selection_marker (document, TRUE)), - NULL); - webkit_dom_node_append_child ( - node, - WEBKIT_DOM_NODE ( - dom_create_selection_marker (document, FALSE)), - NULL); - - remove_node (WEBKIT_DOM_NODE (element_start)); - remove_node (WEBKIT_DOM_NODE (element_end)); - - g_object_set_data ( - G_OBJECT (fragment), "history-return-key", GINT_TO_POINTER (1)); - - webkit_dom_dom_selection_modify (dom_selection, "move", "right", "character"); - } else { - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (fragment), - WEBKIT_DOM_NODE ( - dom_create_selection_marker (document, TRUE)), - NULL); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (fragment), - WEBKIT_DOM_NODE ( - dom_create_selection_marker (document, FALSE)), - NULL); - } - - g_clear_object (&dom_selection); - g_clear_object (&range); - g_clear_object (&range_clone); - - e_editor_page_unblock_selection_changed (editor_page); - - ev->data.fragment = g_object_ref (fragment); - - if (!e_editor_page_get_return_key_pressed (editor_page)) - e_editor_undo_redo_manager_insert_history_event (manager, ev); -} - -typedef struct _TimeoutContext TimeoutContext; - -struct _TimeoutContext { - EEditorPage *editor_page; -}; - -static void -timeout_context_free (TimeoutContext *context) -{ - g_slice_free (TimeoutContext, context); -} - -static gboolean -force_spell_check_on_timeout (TimeoutContext *context) -{ - e_editor_dom_force_spell_check_in_viewport (context->editor_page); - e_editor_page_set_spell_check_on_scroll_event_source_id (context->editor_page, 0); - return FALSE; -} - -static void -body_scroll_event_cb (WebKitDOMElement *element, - WebKitDOMEvent *event, - EEditorPage *editor_page) -{ - TimeoutContext *context; - guint id; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - if (!e_editor_page_get_inline_spelling_enabled (editor_page)) - return; - - context = g_slice_new0 (TimeoutContext); - context->editor_page = editor_page; - - id = e_editor_page_get_spell_check_on_scroll_event_source_id (editor_page); - if (id > 0) - g_source_remove (id); - - id = g_timeout_add_seconds_full ( - 1, - G_PRIORITY_DEFAULT, - (GSourceFunc)force_spell_check_on_timeout, - context, - (GDestroyNotify)timeout_context_free); - - e_editor_page_set_spell_check_on_scroll_event_source_id (editor_page, id); -} - -static void -remove_zero_width_spaces_on_body_input (EEditorPage *editor_page, - WebKitDOMNode *node) -{ - gboolean html_mode; - - html_mode = e_editor_page_get_html_mode (editor_page); - /* After toggling monospaced format, we are using UNICODE_ZERO_WIDTH_SPACE - * to move caret into right space. When this callback is called it is not - * necessary anymore so remove it */ - if (html_mode) { - WebKitDOMElement *parent = webkit_dom_node_get_parent_element (node); - - if (parent) { - WebKitDOMNode *prev_sibling; - - prev_sibling = webkit_dom_node_get_previous_sibling ( - WEBKIT_DOM_NODE (parent)); - - if (prev_sibling && WEBKIT_DOM_IS_TEXT (prev_sibling)) { - gchar *text = webkit_dom_node_get_text_content ( - prev_sibling); - - if (g_strcmp0 (text, UNICODE_ZERO_WIDTH_SPACE) == 0) - remove_node (prev_sibling); - - g_free (text); - } - - } - } - - /* If text before caret includes UNICODE_ZERO_WIDTH_SPACE character, remove it */ - if (WEBKIT_DOM_IS_TEXT (node)) { - gchar *text = webkit_dom_character_data_get_data (WEBKIT_DOM_CHARACTER_DATA (node)); - glong length = webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node)); - WebKitDOMNode *parent; - - /* We have to preserve empty paragraphs with just UNICODE_ZERO_WIDTH_SPACE - * character as when we will remove it it will collapse */ - if (length > 1) { - if (g_str_has_prefix (text, UNICODE_ZERO_WIDTH_SPACE)) - webkit_dom_character_data_replace_data ( - WEBKIT_DOM_CHARACTER_DATA (node), 0, 1, "", NULL); - else if (g_str_has_suffix (text, UNICODE_ZERO_WIDTH_SPACE)) - webkit_dom_character_data_replace_data ( - WEBKIT_DOM_CHARACTER_DATA (node), length - 1, 1, "", NULL); - } - g_free (text); - - parent = webkit_dom_node_get_parent_node (node); - if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (parent) && - !webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "data-evo-paragraph")) { - if (html_mode) - webkit_dom_element_set_attribute ( - WEBKIT_DOM_ELEMENT (parent), - "data-evo-paragraph", - "", - NULL); - else - e_editor_dom_set_paragraph_style ( - editor_page, WEBKIT_DOM_ELEMENT (parent), -1, 0, NULL); - } - - /* When new smiley is added we have to use UNICODE_HIDDEN_SPACE to set the - * caret position to right place. It is removed when user starts typing. But - * when the user will press left arrow he will move the caret into - * smiley wrapper. If he will start to write there we have to move the written - * text out of the wrapper and move caret to right place */ - if (WEBKIT_DOM_IS_ELEMENT (parent) && - element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-smiley-text")) { - gchar *text; - WebKitDOMCharacterData *data; - WebKitDOMText *text_node; - WebKitDOMDocument *document; - - document = e_editor_page_get_document (editor_page); - - /* Split out the newly written character to its own text node, */ - data = WEBKIT_DOM_CHARACTER_DATA (node); - parent = webkit_dom_node_get_parent_node (parent); - text = webkit_dom_character_data_substring_data ( - data, - webkit_dom_character_data_get_length (data) - 1, - 1, - NULL); - webkit_dom_character_data_delete_data ( - data, - webkit_dom_character_data_get_length (data) - 1, - 1, - NULL); - text_node = webkit_dom_document_create_text_node (document, text); - g_free (text); - - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent), - WEBKIT_DOM_NODE ( - dom_create_selection_marker (document, FALSE)), - webkit_dom_node_get_next_sibling (parent), - NULL); - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent), - WEBKIT_DOM_NODE ( - dom_create_selection_marker (document, TRUE)), - webkit_dom_node_get_next_sibling (parent), - NULL); - /* Move the text node outside of smiley. */ - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent), - WEBKIT_DOM_NODE (text_node), - webkit_dom_node_get_next_sibling (parent), - NULL); - e_editor_dom_selection_restore (editor_page); - } - } -} - -void -e_editor_dom_body_input_event_process (EEditorPage *editor_page, - WebKitDOMEvent *event) -{ - WebKitDOMDocument *document; - WebKitDOMNode *node; - WebKitDOMRange *range = NULL; - EEditorUndoRedoManager *manager; - gboolean do_spell_check = FALSE; - gboolean html_mode; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - range = e_editor_dom_get_current_range (editor_page); - node = webkit_dom_range_get_end_container (range, NULL); - - manager = e_editor_page_get_undo_redo_manager (editor_page); - - html_mode = e_editor_page_get_html_mode (editor_page); - e_editor_page_emit_content_changed (editor_page); - - if (e_editor_undo_redo_manager_is_operation_in_progress (manager)) { - e_editor_undo_redo_manager_set_operation_in_progress (manager, FALSE); - e_editor_page_set_dont_save_history_in_body_input (editor_page, FALSE); - remove_zero_width_spaces_on_body_input (editor_page, node); - do_spell_check = TRUE; - goto out; - } - - /* When the Backspace is pressed in a bulleted list item with just one - * character left in it, WebKit will create another BR element in the - * item. */ - if (!html_mode) { - WebKitDOMElement *element; - - element = webkit_dom_document_query_selector ( - document, "ul > li > br + br", NULL); - - if (element) - remove_node (WEBKIT_DOM_NODE (element)); - } - - if (!save_history_after_event_in_table (editor_page)) { - if (!e_editor_page_get_dont_save_history_in_body_input (editor_page)) - save_history_for_input (editor_page); - else - do_spell_check = TRUE; - } - - /* Don't try to look for smileys if we are deleting text. */ - if (!e_editor_page_get_dont_save_history_in_body_input (editor_page)) - e_editor_dom_check_magic_smileys (editor_page); - - e_editor_page_set_dont_save_history_in_body_input (editor_page, FALSE); - - if (e_editor_page_get_return_key_pressed (editor_page) || - e_editor_page_get_space_key_pressed (editor_page)) { - e_editor_dom_check_magic_links (editor_page, FALSE); - if (e_editor_page_get_return_key_pressed (editor_page)) { - if (fix_paragraph_structure_after_pressing_enter (editor_page) && - html_mode) { - /* When the return is pressed in a H1-6 element, WebKit doesn't - * continue with the same element, but creates normal paragraph, - * so we have to unset the bold font. */ - e_editor_undo_redo_manager_set_operation_in_progress (manager, TRUE); - e_editor_dom_selection_set_bold (editor_page, FALSE); - e_editor_undo_redo_manager_set_operation_in_progress (manager, FALSE); - } - - fix_paragraph_structure_after_pressing_enter_after_smiley (document); - - do_spell_check = TRUE; - } - } else { - WebKitDOMNode *node; - - node = webkit_dom_range_get_end_container (range, NULL); - - if (surround_text_with_paragraph_if_needed (editor_page, node)) { - WebKitDOMElement *element; - - element = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element)); - e_editor_dom_selection_restore (editor_page); - } - - if (WEBKIT_DOM_IS_TEXT (node)) { - WebKitDOMElement *parent; - gchar *text; - - text = webkit_dom_node_get_text_content (node); - - if (text && *text && *text != ' ' && !g_str_has_prefix (text, UNICODE_NBSP)) { - gboolean valid = FALSE; - - if (*text == '?' && strlen (text) > 1) - valid = TRUE; - else if (!strchr (URL_INVALID_TRAILING_CHARS, *text)) - valid = TRUE; - - if (valid) { - WebKitDOMNode *prev_sibling; - - prev_sibling = webkit_dom_node_get_previous_sibling (node); - - if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (prev_sibling)) - e_editor_dom_check_magic_links (editor_page, FALSE); - } - } - - parent = webkit_dom_node_get_parent_element (node); - if (element_has_class (parent, "-x-evo-resizable-wrapper") || - element_has_class (parent, "-x-evo-smiley-wrapper")) { - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMNode *prev_sibling; - gboolean writing_before = TRUE; - - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - - prev_sibling = webkit_dom_node_get_previous_sibling (node); - if (prev_sibling && WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (prev_sibling)) - writing_before = FALSE; - - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (parent)), - node, - writing_before ? - WEBKIT_DOM_NODE (parent) : - webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)), - NULL); - - g_clear_object (&range); - - range = webkit_dom_document_create_range (document); - webkit_dom_range_select_node_contents (range, node, NULL); - webkit_dom_range_collapse (range, FALSE, NULL); - - webkit_dom_dom_selection_remove_all_ranges (dom_selection); - webkit_dom_dom_selection_add_range (dom_selection, range); - - g_clear_object (&dom_window); - g_clear_object (&dom_selection); - } - - g_free (text); - } - } - - remove_zero_width_spaces_on_body_input (editor_page, node); - - /* Writing into quoted content */ - if (!html_mode) { - gint citation_level; - WebKitDOMElement *selection_start_marker, *selection_end_marker; - WebKitDOMNode *node, *parent; - - node = webkit_dom_range_get_end_container (range, NULL); - - citation_level = e_editor_dom_get_citation_level (node); - if (citation_level == 0) - goto out; - - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - if (selection_start_marker) - goto out; - - e_editor_dom_selection_save (editor_page); - - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - selection_end_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-end-marker"); - /* If the selection was not saved, move it into the first child of body */ - if (!selection_start_marker || !selection_end_marker) { - WebKitDOMHTMLElement *body; - WebKitDOMNode *child; - - body = webkit_dom_document_get_body (document); - child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)); - - dom_add_selection_markers_into_element_start ( - document, - WEBKIT_DOM_ELEMENT (child), - &selection_start_marker, - &selection_end_marker); - } - - /* We have to process elements only inside normal block */ - parent = WEBKIT_DOM_NODE (get_parent_block_element ( - WEBKIT_DOM_NODE (selection_start_marker))); - if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (parent)) { - e_editor_dom_selection_restore (editor_page); - goto out; - } - - if (selection_start_marker) { - gchar *content; - gint text_length, word_wrap_length, length; - WebKitDOMElement *block; - gboolean remove_quoting = FALSE; - - word_wrap_length = e_editor_page_get_word_wrap_length (editor_page); - length = word_wrap_length - 2 * citation_level; - - block = WEBKIT_DOM_ELEMENT (parent); - if (webkit_dom_element_query_selector ( - WEBKIT_DOM_ELEMENT (block), ".-x-evo-quoted", NULL)) { - WebKitDOMNode *prev_sibling; - - prev_sibling = webkit_dom_node_get_previous_sibling ( - WEBKIT_DOM_NODE (selection_end_marker)); - - if (WEBKIT_DOM_IS_ELEMENT (prev_sibling)) - remove_quoting = element_has_class ( - WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-quoted"); - } - - content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (block)); - text_length = g_utf8_strlen (content, -1); - g_free (content); - - /* Wrap and quote the line */ - if (!remove_quoting && text_length >= word_wrap_length) { - e_editor_dom_remove_quoting_from_element (block); - - block = e_editor_dom_wrap_paragraph_length (editor_page, block, length); - webkit_dom_node_normalize (WEBKIT_DOM_NODE (block)); - e_editor_dom_quote_plain_text_element_after_wrapping ( - editor_page, WEBKIT_DOM_ELEMENT (block), citation_level); - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - if (!selection_start_marker) - dom_add_selection_markers_into_element_end ( - document, - WEBKIT_DOM_ELEMENT (block), - NULL, - NULL); - - e_editor_dom_selection_restore (editor_page); - do_spell_check = TRUE; - goto out; - } - } - e_editor_dom_selection_restore (editor_page); - } - out: - if (do_spell_check) - e_editor_dom_force_spell_check_for_current_paragraph (editor_page); - - g_clear_object (&range); -} - -static void -body_input_event_cb (WebKitDOMElement *element, - WebKitDOMEvent *event, - EEditorPage *editor_page) -{ - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - /* Only process the input event if it was triggered by the key press - * and not i.e. by execCommand. This behavior changed when the support - * for beforeinput event was introduced in WebKit. */ - if (e_editor_page_is_processing_keypress_event (editor_page)) - e_editor_dom_body_input_event_process (editor_page, event); - - e_editor_page_set_is_processing_keypress_event (editor_page, FALSE); -} - -void -e_editor_dom_remove_input_event_listener_from_body (EEditorPage *editor_page) -{ - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - if (!e_editor_page_get_body_input_event_removed (editor_page)) { - WebKitDOMDocument *document; - - document = e_editor_page_get_document (editor_page); - - webkit_dom_event_target_remove_event_listener ( - WEBKIT_DOM_EVENT_TARGET (webkit_dom_document_get_body (document)), - "input", - G_CALLBACK (body_input_event_cb), - FALSE); - - e_editor_page_set_body_input_event_removed (editor_page, TRUE); - } -} - -void -e_editor_dom_register_input_event_listener_on_body (EEditorPage *editor_page) -{ - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - if (e_editor_page_get_body_input_event_removed (editor_page)) { - WebKitDOMDocument *document; - - document = e_editor_page_get_document (editor_page); - - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (webkit_dom_document_get_body (document)), - "input", - G_CALLBACK (body_input_event_cb), - FALSE, - editor_page); - - e_editor_page_set_body_input_event_removed (editor_page, FALSE); - } -} - -static void -remove_empty_blocks (WebKitDOMDocument *document) -{ - gint ii; - WebKitDOMNodeList *list = NULL; - - list = webkit_dom_document_query_selector_all ( - document, "blockquote[type=cite] > :empty:not(br)", NULL); - for (ii = webkit_dom_node_list_get_length (list); ii--;) - remove_node (webkit_dom_node_list_item (list, ii)); - g_clear_object (&list); - - list = webkit_dom_document_query_selector_all ( - document, "blockquote[type=cite]:empty", NULL); - for (ii = webkit_dom_node_list_get_length (list); ii--;) - remove_node (webkit_dom_node_list_item (list, ii)); - g_clear_object (&list); -} - -/* Following two functions are used when deleting the selection inside - * the quoted content. The thing is that normally the quote marks are not - * selectable by user. But this caused a lot of problems for WebKit when removing - * the selection. This will avoid it as when the delete or backspace key is pressed - * we will make the quote marks user selectable so they will act as any other text. - * On HTML keyup event callback we will make them again non-selectable. */ -void -e_editor_dom_disable_quote_marks_select (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMHTMLHeadElement *head; - WebKitDOMElement *style_element; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - head = webkit_dom_document_get_head (document); - - if (!webkit_dom_document_get_element_by_id (document, "-x-evo-quote-style")) { - style_element = webkit_dom_document_create_element (document, "style", NULL); - webkit_dom_element_set_id (style_element, "-x-evo-quote-style"); - webkit_dom_element_set_attribute (style_element, "type", "text/css", NULL); - webkit_dom_element_set_inner_html ( - style_element, - ".-x-evo-quoted { -webkit-user-select: none; }", - NULL); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (head), WEBKIT_DOM_NODE (style_element), NULL); - } -} - -static void -enable_quote_marks_select (WebKitDOMDocument *document) -{ - WebKitDOMElement *style_element; - - if ((style_element = webkit_dom_document_get_element_by_id (document, "-x-evo-quote-style"))) - remove_node (WEBKIT_DOM_NODE (style_element)); -} - -void -e_editor_dom_remove_node_and_parents_if_empty (WebKitDOMNode *node) -{ - WebKitDOMNode *parent; - - parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (node)); - - remove_node (WEBKIT_DOM_NODE (node)); - - while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) { - WebKitDOMNode *tmp; - - tmp = webkit_dom_node_get_parent_node (parent); - remove_node_if_empty (parent); - parent = tmp; - } -} - -void -e_editor_dom_merge_siblings_if_necessary (EEditorPage *editor_page, - WebKitDOMDocumentFragment *deleted_content) -{ - WebKitDOMDocument *document; - WebKitDOMElement *element, *prev_element; - WebKitDOMNode *child; - WebKitDOMNodeList *list = NULL; - gboolean equal_nodes; - gint ii; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = e_editor_page_get_document (editor_page); - - if ((element = webkit_dom_document_get_element_by_id (document, "-x-evo-main-cite"))) - webkit_dom_element_remove_attribute (element, "id"); - - element = webkit_dom_document_query_selector (document, "blockquote:not([data-evo-query-skip]) + blockquote:not([data-evo-query-skip])", NULL); - if (!element) - goto signature; - repeat: - child = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element)); - if (WEBKIT_DOM_IS_ELEMENT (child)) - prev_element = WEBKIT_DOM_ELEMENT (child); - else - goto signature; - - equal_nodes = webkit_dom_node_is_equal_node ( - webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), FALSE, NULL), - webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (prev_element), FALSE, NULL)); - - if (equal_nodes) { - if (webkit_dom_element_get_child_element_count (element) > - webkit_dom_element_get_child_element_count (prev_element)) { - while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)))) - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (prev_element), child, NULL); - remove_node (WEBKIT_DOM_NODE (element)); - } else { - while ((child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (prev_element)))) - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (element), - child, - webkit_dom_node_get_first_child ( - WEBKIT_DOM_NODE (element)), - NULL); - remove_node (WEBKIT_DOM_NODE (prev_element)); - } - } else - webkit_dom_element_set_attribute (element, "data-evo-query-skip", "", NULL); - - element = webkit_dom_document_query_selector (document, "blockquote:not([data-evo-query-skip]) + blockquote:not([data-evo-query-skip])", NULL); - if (element) - goto repeat; - - signature: - list = webkit_dom_document_query_selector_all ( - document, "blockquote[data-evo-query-skip]", NULL); - for (ii = webkit_dom_node_list_get_length (list); ii--;) { - WebKitDOMNode *node = webkit_dom_node_list_item (list, ii); - webkit_dom_element_remove_attribute ( - WEBKIT_DOM_ELEMENT (node), "data-evo-query-skip"); - } - g_clear_object (&list); - - if (!deleted_content) - return; - - /* Replace the corrupted signatures with the right one. */ - element = webkit_dom_document_query_selector ( - document, ".-x-evo-signature-wrapper + .-x-evo-signature-wrapper", NULL); - if (element) { - WebKitDOMElement *right_signature; - - right_signature = webkit_dom_document_fragment_query_selector ( - deleted_content, ".-x-evo-signature-wrapper", NULL); - remove_node (webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element))); - webkit_dom_node_replace_child ( - webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)), - webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (right_signature), TRUE, NULL), - WEBKIT_DOM_NODE (element), - NULL); - } -} - -/* This will fix the structure after the situations where some text - * inside the quoted content is selected and afterwards deleted with - * BackSpace or Delete. */ -void -e_editor_dom_body_key_up_event_process_backspace_or_delete (EEditorPage *editor_page, - gboolean delete) -{ - WebKitDOMDocument *document; - WebKitDOMElement *selection_start_marker, *selection_end_marker; - WebKitDOMNode *parent, *node; - gint level; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - if (e_editor_page_get_html_mode (editor_page)) { - if (!delete) { - e_editor_dom_selection_save (editor_page); - e_editor_dom_merge_siblings_if_necessary (editor_page, NULL); - e_editor_dom_selection_restore (editor_page); - } - return; - } - - document = e_editor_page_get_document (editor_page); - e_editor_dom_disable_quote_marks_select (editor_page); - /* Remove empty blocks if presented. */ - remove_empty_blocks (document); - - e_editor_dom_selection_save (editor_page); - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - selection_end_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-end-marker"); - - /* If we deleted a selection the caret will be inside the quote marks, fix it. */ - parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker)); - if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quote-character")) { - parent = webkit_dom_node_get_parent_node (parent); - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent), - WEBKIT_DOM_NODE (selection_end_marker), - webkit_dom_node_get_next_sibling (parent), - NULL); - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent), - WEBKIT_DOM_NODE (selection_start_marker), - webkit_dom_node_get_next_sibling (parent), - NULL); - } - - /* Under some circumstances we will end with block inside the citation - * that has the quote marks removed and we have to reinsert them back. */ - level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (selection_start_marker)); - node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker)); - if (level > 0 && node && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) { - WebKitDOMElement *block; - - block = WEBKIT_DOM_ELEMENT (e_editor_dom_get_parent_block_node_from_child ( - WEBKIT_DOM_NODE (selection_start_marker))); - - e_editor_dom_remove_quoting_from_element (block); - if (webkit_dom_element_has_attribute (block, "data-evo-paragraph")) { - gint length, word_wrap_length; - - word_wrap_length = e_editor_page_get_word_wrap_length (editor_page); - length = word_wrap_length - 2 * level; - block = e_editor_dom_wrap_paragraph_length (editor_page, block, length); - webkit_dom_node_normalize (WEBKIT_DOM_NODE (block)); - } - e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, block, level); - } else if (level > 0 && !node) { - WebKitDOMNode *prev_sibling; - - prev_sibling = webkit_dom_node_get_previous_sibling ( - WEBKIT_DOM_NODE (selection_start_marker)); - if (WEBKIT_DOM_IS_ELEMENT (prev_sibling) && - element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-quoted") && - !webkit_dom_node_get_previous_sibling (prev_sibling)) { - webkit_dom_node_append_child ( - webkit_dom_node_get_parent_node (parent), - WEBKIT_DOM_NODE (webkit_dom_document_create_element (document, "br", NULL)), - NULL); - } - } - - e_editor_dom_merge_siblings_if_necessary (editor_page, NULL); - - e_editor_dom_selection_restore (editor_page); - e_editor_dom_force_spell_check_for_current_paragraph (editor_page); -} - -void -e_editor_dom_body_key_up_event_process_return_key (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMElement *selection_start_marker, *selection_end_marker; - WebKitDOMNode *parent; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - /* If the return is pressed in an unordered list in plain text mode - * the caret is moved to the "*" character before the newly inserted - * item. It looks like it is not enough that the item has BR element - * inside, but we have to again use the zero width space character - * to fix the situation. */ - if (e_editor_page_get_html_mode (editor_page)) - return; - - document = e_editor_page_get_document (editor_page); - e_editor_dom_selection_save (editor_page); - - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - selection_end_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-end-marker"); - - parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker)); - if (!WEBKIT_DOM_IS_HTML_LI_ELEMENT (parent) || - !WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (webkit_dom_node_get_parent_node (parent))) { - e_editor_dom_selection_restore (editor_page); - return; - } - - if (!webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)) && - (!webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker)) || - WEBKIT_DOM_IS_HTML_BR_ELEMENT (webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker))))) - webkit_dom_element_insert_adjacent_text ( - WEBKIT_DOM_ELEMENT (parent), - "afterbegin", - UNICODE_ZERO_WIDTH_SPACE, - NULL); - - e_editor_dom_selection_restore (editor_page); -} - -static void -body_keyup_event_cb (WebKitDOMElement *element, - WebKitDOMUIEvent *event, - EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - glong key_code; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element)); - if (!e_editor_page_is_composition_in_progress (editor_page)) - e_editor_dom_register_input_event_listener_on_body (editor_page); - - if (!e_editor_dom_selection_is_collapsed (editor_page)) - return; - - key_code = webkit_dom_ui_event_get_key_code (event); - if (key_code == HTML_KEY_CODE_BACKSPACE || key_code == HTML_KEY_CODE_DELETE) { - e_editor_dom_body_key_up_event_process_backspace_or_delete (editor_page, key_code == HTML_KEY_CODE_DELETE); - - /* The content was wrapped and the coordinates - * of caret could be changed, so renew them. But - * only do that when we are not redoing a history - * event, otherwise it would modify the history. */ - if (e_editor_page_get_renew_history_after_coordinates (editor_page)) { - EEditorHistoryEvent *ev = NULL; - EEditorUndoRedoManager *manager; - - manager = e_editor_page_get_undo_redo_manager (editor_page); - ev = e_editor_undo_redo_manager_get_current_history_event (manager); - e_editor_dom_selection_get_coordinates (editor_page, - &ev->after.start.x, - &ev->after.start.y, - &ev->after.end.x, - &ev->after.end.y); - } - - e_editor_page_emit_content_changed (editor_page); - } else if (key_code == HTML_KEY_CODE_CONTROL) - dom_set_links_active (document, FALSE); - else if (key_code == HTML_KEY_CODE_RETURN) - e_editor_dom_body_key_up_event_process_return_key (editor_page); -} - -static void -fix_structure_after_pasting_multiline_content (WebKitDOMNode *node) -{ - WebKitDOMNode *first_child, *parent; - - /* When pasting content that does not contain just the - * one line text WebKit inserts all the content after the - * first line into one element. So we have to take it out - * of this element and insert it after that element. */ - parent = webkit_dom_node_get_parent_node (node); - if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) - return; - first_child = webkit_dom_node_get_first_child (parent); - while (first_child) { - WebKitDOMNode *next_child = - webkit_dom_node_get_next_sibling (first_child); - if (webkit_dom_node_has_child_nodes (first_child)) - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent), - first_child, - parent, - NULL); - first_child = next_child; - } -} - -static gboolean -delete_hidden_space (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMElement *selection_start_marker, *selection_end_marker, *block; - gint citation_level; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE); - - document = e_editor_page_get_document (editor_page); - - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - selection_end_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-end-marker"); - - if (!selection_start_marker || !selection_end_marker) - return FALSE; - - block = WEBKIT_DOM_ELEMENT (e_editor_dom_get_parent_block_node_from_child ( - WEBKIT_DOM_NODE (selection_start_marker))); - - citation_level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (selection_start_marker)); - - if (selection_start_marker && citation_level > 0) { - EEditorUndoRedoManager *manager; - EEditorHistoryEvent *ev = NULL; - WebKitDOMNode *node; - WebKitDOMDocumentFragment *fragment; - - manager = e_editor_page_get_undo_redo_manager (editor_page); - - node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)); - if (!(WEBKIT_DOM_IS_ELEMENT (node) && - element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-quoted"))) - return FALSE; - - node = webkit_dom_node_get_previous_sibling (node); - if (!(WEBKIT_DOM_IS_ELEMENT (node) && - element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-wrap-br"))) - return FALSE; - - node = webkit_dom_node_get_previous_sibling (node); - if (!(WEBKIT_DOM_IS_ELEMENT (node) && - webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (node), "data-hidden-space"))) - return FALSE; - - ev = g_new0 (EEditorHistoryEvent, 1); - ev->type = HISTORY_DELETE; - - e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, &ev->before.start.y, &ev->before.end.x, &ev->before.end.y); - - remove_node (node); - - e_editor_dom_wrap_and_quote_element (editor_page, block); - - fragment = webkit_dom_document_create_document_fragment (document); - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (fragment), - WEBKIT_DOM_NODE ( - webkit_dom_document_create_text_node (document, " ")), - NULL); - ev->data.fragment = g_object_ref (fragment); - - e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x, &ev->after.end.y); - - e_editor_undo_redo_manager_insert_history_event (manager, ev); - - return TRUE; - } - - return FALSE; -} - -static gboolean -caret_is_on_the_line_beginning_html (WebKitDOMDocument *document) -{ - gboolean ret_val = FALSE; - WebKitDOMDOMWindow *dom_window = NULL; - WebKitDOMDOMSelection *dom_selection = NULL; - WebKitDOMRange *tmp_range = NULL, *actual_range = NULL; - - dom_window = webkit_dom_document_get_default_view (document); - dom_selection = webkit_dom_dom_window_get_selection (dom_window); - - actual_range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - - webkit_dom_dom_selection_modify (dom_selection, "move", "left", "lineBoundary"); - - tmp_range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL); - - if (webkit_dom_range_compare_boundary_points (tmp_range, WEBKIT_DOM_RANGE_START_TO_START, actual_range, NULL) == 0) - ret_val = TRUE; - - webkit_dom_dom_selection_remove_all_ranges (dom_selection); - webkit_dom_dom_selection_add_range (dom_selection, actual_range); - - g_clear_object (&tmp_range); - g_clear_object (&actual_range); - - g_clear_object (&dom_window); - g_clear_object (&dom_selection); - - return ret_val; -} - -static gboolean -is_empty_quoted_element (WebKitDOMElement *element) -{ - WebKitDOMNode *node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)); - - if (!WEBKIT_DOM_IS_ELEMENT (node) || !element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-quoted")) - return FALSE; - - if (!(node = webkit_dom_node_get_next_sibling (node))) - return TRUE; - - if (WEBKIT_DOM_IS_TEXT (node)) { - gchar *content; - - content = webkit_dom_node_get_text_content (node); - if (content && *content) { - g_free (content); - return FALSE; - } - - g_free (content); - return webkit_dom_node_get_next_sibling (node) ? FALSE : TRUE; - } - - if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) - return webkit_dom_node_get_next_sibling (node) ? FALSE : TRUE; - - if (!WEBKIT_DOM_IS_ELEMENT (node) || !element_has_id (WEBKIT_DOM_ELEMENT (node), "-x-evo-selection-start-marker")) - return FALSE; - - if (!(node = webkit_dom_node_get_next_sibling (node))) - return FALSE; - - if (!WEBKIT_DOM_IS_ELEMENT (node) || !element_has_id (WEBKIT_DOM_ELEMENT (node), "-x-evo-selection-end-marker")) - return FALSE; - - if (!(node = webkit_dom_node_get_next_sibling (node))) - return TRUE; - - if (!WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) { - if (WEBKIT_DOM_IS_TEXT (node)) { - gchar *content; - - content = webkit_dom_node_get_text_content (node); - if (content && *content) { - g_free (content); - return FALSE; - } - - g_free (content); - return webkit_dom_node_get_next_sibling (node) ? FALSE : TRUE; - } - return FALSE; - } - - if (!(node = webkit_dom_node_get_next_sibling (node))) - return TRUE; - - return TRUE; -} - -gboolean -e_editor_dom_move_quoted_block_level_up (EEditorPage *editor_page) -{ - WebKitDOMDocument *document; - WebKitDOMElement *selection_start_marker, *selection_end_marker; - WebKitDOMNode *block; - EEditorHistoryEvent *ev = NULL; - EEditorUndoRedoManager *manager; - gboolean html_mode; - gint citation_level, success = FALSE; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE); - - document = e_editor_page_get_document (editor_page); - manager = e_editor_page_get_undo_redo_manager (editor_page); - html_mode = e_editor_page_get_html_mode (editor_page); - - selection_start_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-start-marker"); - selection_end_marker = webkit_dom_document_get_element_by_id ( - document, "-x-evo-selection-end-marker"); - - if (!selection_start_marker || !selection_end_marker) - return FALSE; - - block = e_editor_dom_get_parent_block_node_from_child (WEBKIT_DOM_NODE (selection_start_marker)); - - citation_level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (selection_start_marker)); - - if (selection_start_marker && citation_level > 0) { - if (webkit_dom_element_query_selector ( - WEBKIT_DOM_ELEMENT (block), ".-x-evo-quoted", NULL)) { - - WebKitDOMNode *prev_sibling; - - webkit_dom_node_normalize (block); - - prev_sibling = webkit_dom_node_get_previous_sibling ( - WEBKIT_DOM_NODE (selection_start_marker)); - - if (!prev_sibling) { - WebKitDOMNode *parent; - - parent = webkit_dom_node_get_parent_node ( - WEBKIT_DOM_NODE (selection_start_marker)); - if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent)) - prev_sibling = webkit_dom_node_get_previous_sibling (parent); - } - - if (WEBKIT_DOM_IS_ELEMENT (prev_sibling)) - success = element_has_class ( - WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-quoted"); - - /* We really have to be in the beginning of paragraph and - * not on the beginning of some line in the paragraph */ - if (success && webkit_dom_node_get_previous_sibling (prev_sibling)) - success = FALSE; - } - - if (html_mode) { - webkit_dom_node_normalize (block); - - success = caret_is_on_the_line_beginning_html (document); - if (webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker))) - block = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)); - } - } - - if (!success) - return FALSE; - - if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) { - ev = g_new0 (EEditorHistoryEvent, 1); - ev->type = HISTORY_UNQUOTE; - - e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, &ev->before.start.y, &ev->before.end.x, &ev->before.end.y); - ev->data.dom.from = g_object_ref (webkit_dom_node_clone_node_with_error (block, TRUE, NULL)); - } - - if (citation_level == 1) { - gboolean is_empty_quoted_block = FALSE; - gchar *inner_html = NULL; - WebKitDOMElement *paragraph, *element; - - if (WEBKIT_DOM_IS_ELEMENT (block)) { - is_empty_quoted_block = is_empty_quoted_element (WEBKIT_DOM_ELEMENT (block)); - inner_html = webkit_dom_element_get_inner_html (WEBKIT_DOM_ELEMENT (block)); - webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (block), "-x-evo-to-remove"); - } - - paragraph = e_editor_dom_insert_new_line_into_citation (editor_page, inner_html); - g_free (inner_html); - - if (paragraph) { - if (!(webkit_dom_element_query_selector (paragraph, "#-x-evo-selection-start-marker", NULL))) - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (paragraph), - WEBKIT_DOM_NODE (selection_start_marker), - webkit_dom_node_get_first_child ( - WEBKIT_DOM_NODE (paragraph)), - NULL); - - if (!(webkit_dom_element_query_selector (paragraph, "#-x-evo-selection-end-marker", NULL))) - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (paragraph), - WEBKIT_DOM_NODE (selection_end_marker), - webkit_dom_node_get_first_child ( - WEBKIT_DOM_NODE (paragraph)), - NULL); - - e_editor_dom_remove_quoting_from_element (paragraph); - e_editor_dom_remove_wrapping_from_element (paragraph); - - /* Moving PRE block from citation to body */ - if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (block) && !is_empty_quoted_block) { - WebKitDOMElement *pre; - WebKitDOMNode *child; - - pre = webkit_dom_document_create_element (document, "pre", NULL); - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node ( - WEBKIT_DOM_NODE (paragraph)), - WEBKIT_DOM_NODE (pre), - WEBKIT_DOM_NODE (paragraph), - NULL); - - while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (paragraph)))) - webkit_dom_node_append_child (WEBKIT_DOM_NODE (pre), child, NULL); - - remove_node (WEBKIT_DOM_NODE (paragraph)); - paragraph = pre; - } - } - - if (block) - remove_node (block); - - while ((element = webkit_dom_document_get_element_by_id (document, "-x-evo-to-remove"))) - remove_node (WEBKIT_DOM_NODE (element)); - - if (paragraph) - remove_node_if_empty ( - webkit_dom_node_get_next_sibling ( - WEBKIT_DOM_NODE (paragraph))); - } - - if (citation_level > 1) { - WebKitDOMNode *parent; - - if (html_mode) { - webkit_dom_node_insert_before ( - block, - WEBKIT_DOM_NODE (selection_start_marker), - webkit_dom_node_get_first_child (block), - NULL); - webkit_dom_node_insert_before ( - block, - WEBKIT_DOM_NODE (selection_end_marker), - webkit_dom_node_get_first_child (block), - NULL); - - } - - e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (block)); - e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (block)); - - parent = webkit_dom_node_get_parent_node (block); - - if (!webkit_dom_node_get_previous_sibling (block)) { - /* Currect block is in the beginning of citation, just move it - * before the citation where already is */ - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent), - block, - parent, - NULL); - } else if (!webkit_dom_node_get_next_sibling (block)) { - /* Currect block is at the end of the citation, just move it - * after the citation where already is */ - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent), - block, - webkit_dom_node_get_next_sibling (parent), - NULL); - } else { - /* Current block is somewhere in the middle of the citation - * so we need to split the citation and insert the block into - * the citation that is one level lower */ - WebKitDOMNode *clone, *child; - - clone = webkit_dom_node_clone_node_with_error (parent, FALSE, NULL); - - /* Move nodes that are after the currect block into the - * new blockquote */ - child = webkit_dom_node_get_next_sibling (block); - while (child) { - WebKitDOMNode *next = webkit_dom_node_get_next_sibling (child); - webkit_dom_node_append_child (clone, child, NULL); - child = next; - } - - clone = webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent), - clone, - webkit_dom_node_get_next_sibling (parent), - NULL); - - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (parent), - block, - clone, - NULL); - } - - e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (block)); - } - - remove_empty_blocks (document); - - if (ev) { - e_editor_dom_selection_get_coordinates (editor_page, - &ev->after.start.x, - &ev->after.start.y, - &ev->after.end.x, - &ev->after.end.y); - e_editor_undo_redo_manager_insert_history_event (manager, ev); - } - - return success; -} - -static gboolean -prevent_from_deleting_last_element_in_body (WebKitDOMDocument *document) -{ - gboolean ret_val = FALSE; - WebKitDOMHTMLElement *body; - WebKitDOMNode *node; - - body = webkit_dom_document_get_body (document); - - node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)); - if (!node || !webkit_dom_node_get_next_sibling (node)) { - gchar *content; - - content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (body)); - - if (!content || !*content) - ret_val = TRUE; - - g_free (content); - - if (webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (body), "img", NULL)) - ret_val = FALSE; - } - - return ret_val; -} - -static void -insert_quote_symbols (WebKitDOMDocument *document, - WebKitDOMHTMLElement *element, - gint quote_level) -{ - gchar *quotation; - WebKitDOMElement *quote_element; - - if (!WEBKIT_DOM_IS_ELEMENT (element)) - return; - - quotation = get_quotation_for_level (quote_level); - - quote_element = webkit_dom_document_create_element (document, "span", NULL); - element_add_class (quote_element, "-x-evo-quoted"); - - webkit_dom_element_set_inner_html (quote_element, quotation, NULL); - webkit_dom_node_insert_before ( - WEBKIT_DOM_NODE (element), - WEBKIT_DOM_NODE (quote_element), - webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)), - NULL); - - g_free (quotation); -} - -static void -quote_node (WebKitDOMDocument *document, - WebKitDOMNode *node, - gint quote_level) -{ - WebKitDOMNode *parent, *next_sibling; - - /* Don't quote when we are not in citation */ - if (quote_level == 0) - return; - - if (WEBKIT_DOM_IS_COMMENT (node)) - return; - - if (WEBKIT_DOM_IS_ELEMENT (node)) { - insert_quote_symbols (document, WEBKIT_DOM_HTML_ELEMENT (node), quote_level); - return; - } - - next_sibling = webkit_dom_node_get_next_sibling (node); - - /* Skip the BR between first blockquote and pre */ - if (quote_level == 1 && next_sibling && WEBKIT_DOM_IS_HTML_PRE_ELEMENT (next_sibling)) - return; - - parent = webkit_dom_node_get_parent_node (node); - - insert_quote_symbols ( - document, WEBKIT_DOM_HTML_ELEMENT (parent), quote_level); -} - -static void -insert_quote_symbols_before_node (WebKitDOMDocument *document, - WebKitDOMNode *node, - gint quote_level, - gboolean is_html_node) -{ - gboolean skip, wrap_br; - gchar *quotation; - WebKitDOMElement *element; - - quotation = get_quotation_for_level (quote_level); - element = webkit_dom_document_create_element (document, "SPAN", NULL); - element_add_class (element, "-x-evo-quoted"); - webkit_dom_element_set_inner_html (element, quotation, NULL); - - /* Don't insert temporary BR before BR that is used for wrapping */ - skip = WEBKIT_DOM_IS_HTML_BR_ELEMENT (node); - wrap_br = element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-wrap-br"); - skip = skip && wrap_br; - - if (is_html_node && !skip) { - WebKitDOMElement *new_br; - - new_br = webkit_dom_document_create_element (document, "br", NULL); - element_add_class (new_br, "-x-evo-temp-br"); - - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (node), - WEBKIT_DOM_NODE (new_br), - node, - NULL); - } - - webkit_dom_node_insert_before ( - webkit_dom_node_get_parent_node (node), - WEBKIT_DOM_NODE (element), - node, - NULL); - - if (is_html_node && !wrap_br) - remove_node (node); - - g_free (quotation); -} - -static gboolean -check_if_suppress_next_node (WebKitDOMNode *node) -{ - if (!node) - return FALSE; - - if (node && WEBKIT_DOM_IS_ELEMENT (node)) - if (e_editor_dom_is_selection_position_node (node)) - if (!webkit_dom_node_get_previous_sibling (node)) - return FALSE; - - return TRUE; -} - -static void -quote_br_node (WebKitDOMNode *node, - gint quote_level) -{ - gchar *quotation, *content; - - quotation = get_quotation_for_level (quote_level); - - content = g_strconcat ( - "", - quotation, - "
", - NULL); - - webkit_dom_element_set_outer_html ( - WEBKIT_DOM_ELEMENT (node), content, NULL); - - g_free (content); - g_free (quotation); -} - -static void -quote_plain_text_recursive (WebKitDOMDocument *document, - WebKitDOMNode *block, - WebKitDOMNode *start_node, - gint quote_level) -{ - gboolean skip_node = FALSE; - gboolean move_next = FALSE; - gboolean suppress_next = FALSE; - gboolean is_html_node = FALSE; - gboolean next = FALSE; - WebKitDOMNode *node, *next_sibling, *prev_sibling; - - node = webkit_dom_node_get_first_child (block); - - while (node) { - skip_node = FALSE; - move_next = FALSE; - is_html_node = FALSE; - - if (WEBKIT_DOM_IS_COMMENT (node) || - WEBKIT_DOM_IS_HTML_META_ELEMENT (node) || - WEBKIT_DOM_IS_HTML_STYLE_ELEMENT (node) || - WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (node)) { - - move_next = TRUE; - goto next_node; - } - - prev_sibling = webkit_dom_node_get_previous_sibling (node); - next_sibling = webkit_dom_node_get_next_sibling (node); - - if (WEBKIT_DOM_IS_TEXT (node)) { - /* Start quoting after we are in blockquote */ - if (quote_level > 0 && !suppress_next) { - /* When quoting text node, we are wrappering it and - * afterwards replacing it with that wrapper, thus asking - * for next_sibling after quoting will return NULL bacause - * that node don't exist anymore */ - quote_node (document, node, quote_level); - node = next_sibling; - skip_node = TRUE; - } - - goto next_node; - } - - if (!(WEBKIT_DOM_IS_ELEMENT (node) || WEBKIT_DOM_IS_HTML_ELEMENT (node))) - goto next_node; - - if (e_editor_dom_is_selection_position_node (node)) { - /* If there is collapsed selection in the beginning of line - * we cannot suppress first text that is after the end of - * selection */ - suppress_next = check_if_suppress_next_node (prev_sibling); - if (suppress_next) - next = FALSE; - move_next = TRUE; - goto next_node; - } - - if (!WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node) && - webkit_dom_element_get_child_element_count (WEBKIT_DOM_ELEMENT (node)) != 0) - goto with_children; - - /* Even in plain text mode we can have some basic html element - * like anchor and others. When Forwaring e-mail as Quoted EMFormat - * generates header that contains tags (bold font). - * We have to treat these elements separately to avoid - * modifications of theirs inner texts */ - is_html_node = - WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node) || - element_has_tag (WEBKIT_DOM_ELEMENT (node), "b") || - element_has_tag (WEBKIT_DOM_ELEMENT (node), "i") || - element_has_tag (WEBKIT_DOM_ELEMENT (node), "u") || - element_has_class (WEBKIT_DOM_ELEMENT (node), "Apple-tab-span"); - - if (is_html_node) { - gboolean wrap_br; - - wrap_br = - prev_sibling && - WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling) && - element_has_class ( - WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-wrap-br"); - - if (!prev_sibling || wrap_br) { - insert_quote_symbols_before_node ( - document, node, quote_level, FALSE); - if (!prev_sibling && next_sibling && WEBKIT_DOM_IS_TEXT (next_sibling)) - suppress_next = TRUE; - } - - if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling) && !wrap_br) - insert_quote_symbols_before_node ( - document, prev_sibling, quote_level, TRUE); - - move_next = TRUE; - goto next_node; - } - - /* If element doesn't have children, we can quote it */ - if (e_editor_dom_node_is_citation_node (node)) { - /* Citation with just text inside */ - quote_node (document, node, quote_level + 1); - - move_next = TRUE; - goto next_node; - } - - if (!WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) { - if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (prev_sibling)) { - move_next = TRUE; - goto next_node; - } - goto not_br; - } else if (element_has_id (WEBKIT_DOM_ELEMENT (node), "-x-evo-first-br") || - element_has_id (WEBKIT_DOM_ELEMENT (node), "-x-evo-last-br")) { - quote_br_node (node, quote_level); - node = next_sibling; - skip_node = TRUE; - goto next_node; - } - - if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling)) { - quote_br_node (prev_sibling, quote_level); - node = next_sibling; - skip_node = TRUE; - goto next_node; - } - - if (!prev_sibling && !next_sibling) { - WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node); - - if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (parent) || - WEBKIT_DOM_IS_HTML_PRE_ELEMENT (parent) || - (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) && - !e_editor_dom_node_is_citation_node (parent))) { - insert_quote_symbols_before_node ( - document, node, quote_level, FALSE); - - goto next_node; - } - } - - if (e_editor_dom_node_is_citation_node (prev_sibling)) { - insert_quote_symbols_before_node ( - document, node, quote_level, FALSE); - goto next_node; - } - - if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node) && - !next_sibling && WEBKIT_DOM_IS_ELEMENT (prev_sibling) && - e_editor_dom_is_selection_position_node (prev_sibling)) { - insert_quote_symbols_before_node ( - document, node, quote_level, FALSE); - goto next_node; - } - - if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) { - if (!prev_sibling && !next_sibling) { - insert_quote_symbols_before_node ( - document, node, quote_level, FALSE); - } else - move_next = TRUE; - goto next_node; - } - - not_br: - quote_node (document, node, quote_level); - - move_next = TRUE; - goto next_node; - - with_children: - if (e_editor_dom_node_is_citation_node (node)) { - /* Go deeper and increase level */ - quote_plain_text_recursive ( - document, node, start_node, quote_level + 1); - move_next = TRUE; - } else { - quote_plain_text_recursive ( - document, node, start_node, quote_level); - move_next = TRUE; - } - next_node: - if (next) { - suppress_next = FALSE; - next = FALSE; - } - - if (suppress_next) - next = TRUE; - - if (!skip_node) { - /* Move to next node */ - if (!move_next && webkit_dom_node_has_child_nodes (node)) { - node = webkit_dom_node_get_first_child (node); - } else if (webkit_dom_node_get_next_sibling (node)) { - node = webkit_dom_node_get_next_sibling (node); - } else { - return; - } - } - } -} - -WebKitDOMElement * -e_editor_dom_quote_plain_text_element (EEditorPage *editor_page, - WebKitDOMElement *element) -{ - WebKitDOMDocument *document; - WebKitDOMNode *element_clone; - WebKitDOMHTMLCollection *collection = NULL; - gint ii, level; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL); - - document = e_editor_page_get_document (editor_page); - element_clone = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), TRUE, NULL); - level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (element)); - - /* Remove old quote characters if the exists */ - collection = webkit_dom_element_get_elements_by_class_name_as_html_collection ( - WEBKIT_DOM_ELEMENT (element_clone), "-x-evo-quoted"); - for (ii = webkit_dom_html_collection_get_length (collection); ii--;) - remove_node (webkit_dom_html_collection_item (collection, ii)); - g_clear_object (&collection); - - webkit_dom_node_normalize (element_clone); - quote_plain_text_recursive ( - document, element_clone, element_clone, level); - - /* Replace old element with one, that is quoted */ - webkit_dom_node_replace_child ( - webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)), - element_clone, - WEBKIT_DOM_NODE (element), - NULL); - - return WEBKIT_DOM_ELEMENT (element_clone); -} - -/* - * dom_quote_plain_text: - * - * Quote text inside citation blockquotes in plain text mode. - * - * As this function is cloning and replacing all citation blockquotes keep on - * mind that any pointers to nodes inside these blockquotes will be invalidated. - */ -static WebKitDOMElement * -dom_quote_plain_text (WebKitDOMDocument *document) -{ - WebKitDOMHTMLElement *body; - WebKitDOMNode *body_clone; - WebKitDOMNamedNodeMap *attributes = NULL; - WebKitDOMNodeList *list = NULL; - WebKitDOMElement *element; - gint ii; - gulong attributes_length; - - /* Check if the document is already quoted */ - element = webkit_dom_document_query_selector ( - document, ".-x-evo-quoted", NULL); - if (element) - return NULL; - - body = webkit_dom_document_get_body (document); - body_clone = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), TRUE, NULL); - - /* Clean unwanted spaces before and after blockquotes */ - list = webkit_dom_element_query_selector_all ( - WEBKIT_DOM_ELEMENT (body_clone), "blockquote[type|=cite]", NULL); - for (ii = webkit_dom_node_list_get_length (list); ii--;) { - WebKitDOMNode *blockquote = webkit_dom_node_list_item (list, ii); - WebKitDOMNode *prev_sibling = webkit_dom_node_get_previous_sibling (blockquote); - WebKitDOMNode *next_sibling = webkit_dom_node_get_next_sibling (blockquote); - - if (prev_sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling)) - remove_node (prev_sibling); - - if (next_sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling)) - remove_node (next_sibling); - - if (webkit_dom_node_has_child_nodes (blockquote)) { - WebKitDOMNode *child = webkit_dom_node_get_first_child (blockquote); - if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child)) - remove_node (child); - } - } - g_clear_object (&list); - - webkit_dom_node_normalize (body_clone); - quote_plain_text_recursive (document, body_clone, body_clone, 0); - - /* Copy attributes */ - attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body)); - attributes_length = webkit_dom_named_node_map_get_length (attributes); - for (ii = 0; ii < attributes_length; ii++) { - gchar *name, *value; - WebKitDOMNode *node = webkit_dom_named_node_map_item (attributes, ii); - - name = webkit_dom_attr_get_name (WEBKIT_DOM_ATTR (node)); - value = webkit_dom_node_get_node_value (node); - - webkit_dom_element_set_attribute ( - WEBKIT_DOM_ELEMENT (body_clone), name, value, NULL); - - g_free (name); - g_free (value); - } - g_clear_object (&attributes); - - /* Replace old BODY with one, that is quoted */ - webkit_dom_node_replace_child ( - webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (body)), - body_clone, - WEBKIT_DOM_NODE (body), - NULL); - - return WEBKIT_DOM_ELEMENT (body_clone); -} - -/* - * dom_dequote_plain_text: - * - * Dequote already quoted plain text in editor. - * Editor have to be quoted with e_html_editor_view_quote_plain_text otherwise - * it's not working. - */ -static void -dom_dequote_plain_text (WebKitDOMDocument *document) -{ - WebKitDOMNodeList *paragraphs = NULL; - gint ii; - - paragraphs = webkit_dom_document_query_selector_all ( - document, "blockquote[type=cite]", NULL); - for (ii = webkit_dom_node_list_get_length (paragraphs); ii--;) { - WebKitDOMElement *element; - - element = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (paragraphs, ii)); - - if (e_editor_dom_node_is_citation_node (WEBKIT_DOM_NODE (element))) - e_editor_dom_remove_quoting_from_element (element); - } - g_clear_object (¶graphs); -} - -static gboolean -create_anchor_for_link (const GMatchInfo *info, - GString *res, - gpointer data) -{ - gboolean link_surrounded, ending_with_nbsp = FALSE; - gint offset = 0, truncate_from_end = 0; - gint match_start, match_end; - gchar *match; - const gchar *end_of_match = NULL; - const gchar *nbsp_match = NULL; - - match = g_match_info_fetch (info, 0); - g_match_info_fetch_pos (info, 0, &match_start, &match_end); - - if (g_str_has_suffix (match, " ")) { - ending_with_nbsp = TRUE; - truncate_from_end = 6; - } - - if (g_str_has_prefix (match, " ")) - offset += 6; - - end_of_match = match + match_end - match_start - 1; - /* Taken from camel-url-scanner.c */ - /* URLs are extremely unlikely to end with any punctuation, so - * strip any trailing punctuation off from link and put it after - * the link. Do the same for any closing double-quotes as well. */ - while (end_of_match && end_of_match != match && strchr (URL_INVALID_TRAILING_CHARS, *end_of_match)) { - truncate_from_end++; - end_of_match--; - } - end_of_match++; - - link_surrounded = - g_str_has_suffix (res->str, "<"); - - if (link_surrounded) { - if (end_of_match && *end_of_match && strlen (match) > strlen (end_of_match) + 3) - link_surrounded = link_surrounded && g_str_has_prefix (end_of_match - 3, ">"); - else - link_surrounded = link_surrounded && g_str_has_suffix (match, ">"); - - if (link_surrounded) { - truncate_from_end += 4; - end_of_match -= 4; - } - } - - /* The ending ';' was counted when looking for the invalid trailing characters, substract it. */ - if (link_surrounded || ending_with_nbsp) { - truncate_from_end -= 1; - end_of_match += 1; - } - - /* If there is non-breaking space in the match, remove it and everything - * after it from the match */ - if (!g_str_has_prefix (match, " ") && !g_str_has_suffix (match, " ") && (nbsp_match = strstr (match, " "))) { - glong after_nbsp_length = g_utf8_strlen (nbsp_match, -1); - truncate_from_end = after_nbsp_length; - end_of_match -= after_nbsp_length; - if (link_surrounded) - end_of_match += 4; - } - - g_string_append (res, " 0) - g_string_truncate (res, res->len - truncate_from_end); - - g_string_append (res, "\">"); - g_string_append (res, match + offset); - if (truncate_from_end > 0) - g_string_truncate (res, res->len - truncate_from_end); - - g_string_append (res, ""); - - if (truncate_from_end > 0) - g_string_append (res, end_of_match); - - if (ending_with_nbsp) - g_string_append (res, " "); - - g_free (match); - - return FALSE; -} - -static gboolean -replace_to_nbsp (const GMatchInfo *info, - GString *res) -{ - gchar *match; - gint ii = 0; - - match = g_match_info_fetch (info, 0); - - while (match[ii] != '\0') { - if (match[ii] == ' ') { - /* Alone spaces or spaces before/after tabulator. */ - g_string_append (res, " "); - } else if (match[ii] == '\t') { - /* Replace tabs with their WebKit HTML representation. */ - g_string_append (res, "\t"); - } - - ii++; - } - - g_free (match); - - return FALSE; -} - -static gboolean -surround_links_with_anchor (const gchar *text) -{ - return (strstr (text, "http") || strstr (text, "ftp") || - strstr (text, "www") || strstr (text, "@")); -} - -static void -append_new_block (WebKitDOMElement *parent, - WebKitDOMElement **block) -{ - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (parent), - WEBKIT_DOM_NODE (*block), - NULL); - - *block = NULL; -} - -static WebKitDOMElement * -create_and_append_new_block (EEditorPage *editor_page, - WebKitDOMElement *parent, - WebKitDOMElement *block_template, - const gchar *content) -{ - WebKitDOMElement *block; - - g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL); - - block = WEBKIT_DOM_ELEMENT (webkit_dom_node_clone_node_with_error ( - WEBKIT_DOM_NODE (block_template), FALSE, NULL)); - - webkit_dom_element_set_inner_html (block, content, NULL); - - append_new_block (parent, &block); - - return block; -} - -static void -append_citation_mark (WebKitDOMDocument *document, - WebKitDOMElement *parent, - const gchar *citation_mark_text) -{ - WebKitDOMText *text; - - text = webkit_dom_document_create_text_node (document, citation_mark_text); - - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (parent), - WEBKIT_DOM_NODE (text), - NULL); -} - -static void -replace_selection_markers (gchar **text) -{ - if (!text) - return; - - if (strstr (*text, "##SELECTION_START##")) { - GString *tmp; - - tmp = e_str_replace_string ( - *text, - "##SELECTION_START##", - ""); - - g_free (*text); - *text = g_string_free (tmp, FALSE); - } - - if (strstr (*text, "##SELECTION_END##")) { - GString *tmp; - - tmp = e_str_replace_string ( - *text, - "##SELECTION_END##", - ""); - - g_free (*text); - *text = g_string_free (tmp, FALSE); - } -} - -static GString * -remove_new_lines_around_citations (const gchar *input) -{ - GString *str = NULL; - const gchar *p, *next; - - str = g_string_new (""); - - /* Remove the new lines around citations: - * Replace

##CITATION_START## with
##CITATION_START## - * Replace ##CITATION_START##

with ##CITATION_START##
- * Replace ##CITATION_END##

with ##CITATION_END##
- * Replace
##CITATION_END## with ##CITATION_END## - * Replace
##CITATION_START## with ##CITATION_START## */ - p = input; - while (next = strstr (p, "##CITATION_"), next) { - gchar citation_type = 0; - - if (p < next) - g_string_append_len (str, p, next - p); - - if (next + 11) - citation_type = next[11]; - /* ##CITATION_START## */ - if (citation_type == 'S') { - if (g_str_has_suffix (str->str, "

") || - g_str_has_suffix (str->str, "
")) - g_string_truncate (str, str->len - 4); - - if (g_str_has_prefix (next + 11, "START##

")) { - g_string_append (str, "##CITATION_START##
"); - p = next + 26; - continue; - } - } else if (citation_type == 'E') { - if (g_str_has_suffix (str->str, "
")) - g_string_truncate (str, str->len - 4); - - if (g_str_has_prefix (next + 11, "END##

")) { - g_string_append (str, "##CITATION_END##
"); - p = next + 24; - continue; - } - } - - g_string_append (str, "##CITATION_"); - - p = next + 11; - } - - g_string_append (str, p); - - if (camel_debug ("webkit:editor")) { - printf ("EWebKitContentEditor - %s\n", G_STRFUNC); - printf ("\toutput: '%s'\n", str->str); - } - - return str; -} - -static GString * -replace_citation_marks_to_citations (const gchar *input) -{ - GString *str = NULL; - const gchar *p, *next; - - str = g_string_new (""); - - /* Replaces text markers with actual HTML blockquotes */ - p = input; - while (next = strstr (p, "##CITATION_"), next) { - gchar citation_type = 0; - - if (p < next) - g_string_append_len (str, p, next - p); - - if (next + 11) - citation_type = next[11]; - /* ##CITATION_START## */ - if (citation_type == 'S') { - g_string_append (str, "
"); - p = next + 18; - } else if (citation_type == 'E') { - g_string_append (str, "
"); - p = next + 16; - } else - p = next + 11; - } - - g_string_append (str, p); - - return str; -} - -/* This parses the HTML code (that contains just text,   and BR elements) - * into blocks. - * HTML code in that format we can get by taking innerText from some element, - * setting it to another one and finally getting innerHTML from it */ -static void -parse_html_into_blocks (EEditorPage *editor_page, - WebKitDOMElement *parent, - WebKitDOMElement *passed_block_template, - const gchar *input) -{ - gboolean has_citation = FALSE, processing_last = FALSE; - const gchar *prev_token, *next_token; - const gchar *next_br_token = NULL, *next_citation_token = NULL; - GString *html = NULL; - GRegex *regex_nbsp = NULL, *regex_link = NULL, *regex_email = NULL; - WebKitDOMDocument *document; - WebKitDOMElement *block_template = passed_block_template; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - if (!(input && *input)) - return; - - document = e_editor_page_get_document (editor_page); - webkit_dom_element_set_inner_html (parent, "", NULL); - - if (!block_template) { - gboolean use_paragraphs; - GSettings *settings; - - settings = e_util_ref_settings ("org.gnome.evolution.mail"); - - use_paragraphs = g_settings_get_boolean ( - settings, "composer-wrap-quoted-text-in-replies"); - - if (use_paragraphs) - block_template = e_editor_dom_get_paragraph_element (editor_page, -1, 0); - else - block_template = webkit_dom_document_create_element (document, "pre", NULL); - - g_object_unref (settings); - } - - /* Replace the tabulators with SPAN elements that corresponds to them. - * If not inserting the content into the PRE element also replace single - * spaces on the beginning of line, 2+ spaces and with non breaking - * spaces. */ - if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (block_template)) - regex_nbsp = g_regex_new ("\x9", 0, 0, NULL); - else - regex_nbsp = g_regex_new ("^\\s{1}|\\s{2,}|\x9|\\s$", 0, 0, NULL); - - if (camel_debug ("webkit:editor")) { - printf ("EWebKitContentEditor - %s\n", G_STRFUNC); - printf ("\tinput: '%s'\n", input); - } - html = remove_new_lines_around_citations (input); - - prev_token = html->str; - next_br_token = (prev_token && *prev_token) ? strstr (prev_token + 1, "
") : NULL; - next_citation_token = (prev_token && *prev_token) ? strstr (prev_token + 1, "##CITATION_") : NULL; - if (next_br_token) { - if (next_citation_token) - next_token = next_br_token < next_citation_token ? next_br_token : next_citation_token; - else - next_token = next_br_token; - } else { - next_token = next_citation_token; - } - processing_last = !next_token; - - while (next_token || processing_last) { - const gchar *citation_start = NULL, *citation_end = NULL; - const gchar *rest = NULL, *with_br = NULL; - gchar *to_process = NULL, *to_insert = NULL; - guint to_insert_start = 0, to_insert_end = 0; - - if (!next_token) { - to_process = g_strdup (prev_token); - processing_last = TRUE; - } else if ((to_process = g_utf8_substring (prev_token, 0, g_utf8_pointer_to_offset (prev_token, next_token))) && - !*to_process && !processing_last) { - g_free (to_process); - to_process = g_strdup (next_token); - next_token = NULL; - processing_last = TRUE; - } - - if (camel_debug ("webkit:editor")) - printf ("\tto_process: '%s'\n", to_process); - - if (to_process && !*to_process && processing_last) { - g_free (to_process); - to_process = g_strdup (next_token); - next_token = NULL; - } - - to_insert_end = g_utf8_strlen (to_process, -1); - - if ((with_br = strstr (to_process, "
"))) { - if (with_br == to_process) - to_insert_start += 4; - } - - if ((citation_start = strstr (to_process, "##CITATION_START"))) { - if (with_br && citation_start == with_br + 4) - to_insert_start += 18; /* + ## */ - else if (!with_br && citation_start == to_process) - to_insert_start += 18; /* + ## */ - else - to_insert_end -= 18; /* + ## */ - has_citation = TRUE; - } - - if ((citation_end = strstr (to_process, "##CITATION_END"))) { - if (citation_end == to_process) - to_insert_start += 16; - else - to_insert_end -= 16; /* + ## */ - } - - /* First BR */ - if (with_br && prev_token == html->str) - create_and_append_new_block ( - editor_page, parent, block_template, "
"); - - if (with_br && citation_start && citation_start == with_br + 4) { - create_and_append_new_block ( - editor_page, parent, block_template, "
"); - - append_citation_mark (document, parent, "##CITATION_START##"); - } else if (!with_br && citation_start == to_process) { - append_citation_mark (document, parent, "##CITATION_START##"); - } - - if (citation_end && citation_end == to_process) { - append_citation_mark (document, parent, "##CITATION_END##"); - } - - if ((to_insert = g_utf8_substring (to_process, to_insert_start, to_insert_end)) && *to_insert) { - gboolean empty = FALSE; - gchar *truncated = g_strdup (to_insert); - gchar *rest_to_insert; - - if (camel_debug ("webkit:editor")) - printf ("\tto_insert: '%s'\n", to_insert); - - empty = !*truncated && strlen (to_insert) > 0; - - rest_to_insert = g_regex_replace_eval ( - regex_nbsp, - empty ? rest : truncated, - -1, - 0, - 0, - (GRegexEvalCallback) replace_to_nbsp, - NULL, - NULL); - g_free (truncated); - - replace_selection_markers (&rest_to_insert); - - if (surround_links_with_anchor (rest_to_insert)) { - gboolean is_email_address = - strstr (rest_to_insert, "@") && - !strstr (rest_to_insert, "://"); - - if (is_email_address && !regex_email) - regex_email = g_regex_new (E_MAIL_PATTERN, 0, 0, NULL); - if (!is_email_address && !regex_link) - regex_link = g_regex_new (URL_PATTERN, 0, 0, NULL); - - truncated = g_regex_replace_eval ( - is_email_address ? regex_email : regex_link, - rest_to_insert, - -1, - 0, - G_REGEX_MATCH_NOTEMPTY, - create_anchor_for_link, - NULL, - NULL); - - g_free (rest_to_insert); - rest_to_insert = truncated; - } - - create_and_append_new_block ( - editor_page, parent, block_template, rest_to_insert); - - g_free (rest_to_insert); - } else if (to_insert) { - if (!citation_start && (with_br || !citation_end)) - create_and_append_new_block ( - editor_page, parent, block_template, "
"); - else if (citation_end && citation_end == to_process && - next_token && g_str_has_prefix (next_token, "
")) { - create_and_append_new_block ( - editor_page, parent, block_template, "
"); - } - } - - g_free (to_insert); - - if (with_br && citation_start && citation_start != with_br + 4) - append_citation_mark (document, parent, "##CITATION_START##"); - - if (!with_br && citation_start && citation_start != to_process) - append_citation_mark (document, parent, "##CITATION_START##"); - - if (citation_end && citation_end != to_process) - append_citation_mark (document, parent, "##CITATION_END##"); - - g_free (to_process); - - prev_token = next_token; - next_br_token = (prev_token && *prev_token) ? strstr (prev_token + 1, "
") : NULL; - next_citation_token = (prev_token && *prev_token) ? strstr (prev_token + 1, "##CITATION_") : NULL; - if (next_br_token) { - if (next_citation_token) - next_token = next_br_token < next_citation_token ? next_br_token : next_citation_token; - else - next_token = next_br_token; - } else { - next_token = next_citation_token; - } - - if (!next_token && !processing_last) { - if (!prev_token) - break; - - if (g_utf8_strlen (prev_token, -1) > 4) { - next_token = prev_token; - } else { - WebKitDOMNode *child; - - if (g_strcmp0 (prev_token, "
") == 0) - create_and_append_new_block ( - editor_page, parent, block_template, "
"); - - child = webkit_dom_node_get_last_child ( - WEBKIT_DOM_NODE (parent)); - if (child) { - child = webkit_dom_node_get_first_child (child); - if (child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (child)) { - /* If the processed HTML contained just - * the BR don't overwrite its id. */ - if (!element_has_id (WEBKIT_DOM_ELEMENT (child), "-x-evo-first-br")) - webkit_dom_element_set_id ( - WEBKIT_DOM_ELEMENT (child), - "-x-evo-last-br"); - } - } else { - create_and_append_new_block ( - editor_page, parent, block_template, "
"); - } - break; - } - processing_last = TRUE; - } else if (processing_last && !prev_token && !next_token) { - break; - } - } - - if (has_citation) { - gchar *inner_html; - GString *parsed; - - /* Replace text markers with actual HTML blockquotes */ - inner_html = webkit_dom_element_get_inner_html (parent); - parsed = replace_citation_marks_to_citations (inner_html); - webkit_dom_element_set_inner_html (parent, parsed->str, NULL); - - if (camel_debug ("webkit:editor")) - printf ("\tparsed content: '%s'\n", inner_html); - - g_free (inner_html); - g_string_free (parsed, TRUE); - } else if (camel_debug ("webkit:editor")) { - gchar *inner_html; - - inner_html = webkit_dom_element_get_inner_html (parent); - printf ("\tparsed content: '%s'\n", inner_html); - g_free (inner_html); - } - - g_string_free (html, TRUE); - - if (regex_email != NULL) - g_regex_unref (regex_email); - if (regex_link != NULL) - g_regex_unref (regex_link); - g_regex_unref (regex_nbsp); -} - -void -e_editor_dom_quote_and_insert_text_into_selection (EEditorPage *editor_page, - const gchar *text, - gboolean is_html) -{ - WebKitDOMDocument *document; - WebKitDOMElement *blockquote, *element, *selection_start; - WebKitDOMNode *node; - EEditorHistoryEvent *ev = NULL; - EEditorUndoRedoManager *manager; - gchar *inner_html; - gboolean node_added = FALSE; - - g_return_if_fail (E_IS_EDITOR_PAGE (editor_page)); - - if (!text || !*text) - return; - - document = e_editor_page_get_document (editor_page); - - if (is_html) { - element = webkit_dom_document_create_element (document, "div", NULL); - webkit_dom_element_set_inner_html (element, text, NULL); - } else { - /* This is a trick to escape any HTML characters (like <, > or &). - *