Example #1
0
gchar *
e_composer_dom_get_active_signature_uid (EEditorPage *editor_page)
{
	WebKitDOMDocument *document;
	WebKitDOMElement *element;
	gchar *uid = NULL;

	g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);

	document = e_editor_page_get_document (editor_page);

	if ((element = webkit_dom_document_query_selector (document, ".-x-evo-signature[id]", NULL)))
		uid = webkit_dom_element_get_id (element);

	return uid;
}
Example #2
0
gboolean
element_has_id (WebKitDOMElement *element,
                const gchar* id)
{
	gchar *element_id;

	if (!element)
		return FALSE;

	if (!WEBKIT_DOM_IS_ELEMENT (element))
		return FALSE;

	element_id = webkit_dom_element_get_id (element);

	if (g_ascii_strcasecmp (element_id, id) != 0) {
		g_free (element_id);
		return FALSE;
	}
	g_free (element_id);

	return TRUE;
}
Example #3
0
gchar *
e_composer_dom_insert_signature (EEditorPage *editor_page,
                                 const gchar *content,
                                 gboolean is_html,
                                 const gchar *id,
                                 gboolean *set_signature_from_message,
                                 gboolean *check_if_signature_is_changed,
                                 gboolean *ignore_next_signature_change)
{
	WebKitDOMDocument *document;
	WebKitDOMElement *signature_to_insert;
	WebKitDOMElement *insert_signature_in = NULL;
	WebKitDOMElement *signature_wrapper = NULL;
	WebKitDOMElement *element, *converted_signature = NULL;
	WebKitDOMHTMLElement *body;
	WebKitDOMHTMLCollection *signatures = NULL;
	gchar *new_signature_id = NULL;
	gchar *signature_text = NULL;
	gboolean top_signature, html_mode;
	gulong ii;

	g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
	g_return_val_if_fail (set_signature_from_message != NULL, NULL);
	g_return_val_if_fail (check_if_signature_is_changed != NULL, NULL);
	g_return_val_if_fail (ignore_next_signature_change != NULL, NULL);

	document = e_editor_page_get_document (editor_page);
	body = webkit_dom_document_get_body (document);

	/* "Edit as New Message" sets is_message_from_edit_as_new.
	 * Always put the signature at the bottom for that case. */
	top_signature = use_top_signature ();

	html_mode = e_editor_page_get_html_mode (editor_page);

	/* Create the DOM signature that is the same across all types of signatures. */
	signature_to_insert = webkit_dom_document_create_element (document, "span", NULL);
	webkit_dom_element_set_class_name (signature_to_insert, "-x-evo-signature");
	/* The combo box active ID is the signature's ESource UID. */
	webkit_dom_element_set_id (signature_to_insert, id);
	insert_signature_in = signature_to_insert;

	/* The signature has no content usually it means it is set to None. */
	if (!(content && *content))
		goto insert;

	if (!is_html) {
		gchar *html;

		html = camel_text_to_html (content, 0, 0);
		if (html) {
			signature_text = html;
		} else
			signature_text = g_strdup (content);

		insert_signature_in = webkit_dom_document_create_element (document, "pre", NULL);
		webkit_dom_node_append_child (
			WEBKIT_DOM_NODE (signature_to_insert),
			WEBKIT_DOM_NODE (insert_signature_in),
			NULL);
	} else
		signature_text = g_strdup (content);

	/* If inserting HTML signature in the plain text composer we have to convert it. */
	if (is_html && !html_mode && !strstr (signature_text, "data-evo-signature-plain-text-mode")) {
		gchar *inner_text;

		/* Save the converted signature to avoid parsing it later again
		 * while inserting it into the view. */
		converted_signature = webkit_dom_document_create_element (document, "pre", NULL);
		webkit_dom_element_set_inner_html (converted_signature, signature_text, NULL);
		e_editor_dom_convert_element_from_html_to_plain_text (editor_page, converted_signature);
		inner_text = webkit_dom_html_element_get_inner_text (WEBKIT_DOM_HTML_ELEMENT (converted_signature));

		g_free (signature_text);
		signature_text = inner_text ? g_strstrip (inner_text) : g_strdup ("");
		/* because of the -- \n check */
		is_html = FALSE;
	}

	/* The signature dash convention ("-- \n") is specified
	 * in the "Son of RFC 1036", section 4.3.2.
	 * http://www.chemie.fu-berlin.de/outerspace/netnews/son-of-1036.html
	 */
	if (add_signature_delimiter ()) {
		const gchar *delim;
		const gchar *delim_nl;

		if (is_html) {
			delim = "-- <BR>";
			delim_nl = "\n-- <BR>";
		} else {
			delim = "-- \n";
			delim_nl = "\n-- \n";
		}

		/* Skip the delimiter if the signature already has one. */
		if (g_ascii_strncasecmp (signature_text, delim, strlen (delim)) == 0)
			;  /* skip */
		else if (e_util_strstrcase (signature_text, delim_nl) != NULL)
			;  /* skip */
		else {
			WebKitDOMElement *pre_delimiter;

			pre_delimiter = webkit_dom_document_create_element (document, "pre", NULL);
                       /* Always use the HTML delimiter as we are never in anything
                        * like a strict plain text mode. */
			webkit_dom_element_set_inner_html (pre_delimiter, "-- <br>", NULL);
			webkit_dom_node_append_child (
				WEBKIT_DOM_NODE (insert_signature_in),
				WEBKIT_DOM_NODE (pre_delimiter),
				NULL);
		}
	}

	if (converted_signature) {
		WebKitDOMNode *node;

		while ((node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (converted_signature))))
			webkit_dom_node_append_child (
				WEBKIT_DOM_NODE (insert_signature_in), node, NULL);
		remove_node (WEBKIT_DOM_NODE (converted_signature));
	} else
		webkit_dom_element_insert_adjacent_html (
			insert_signature_in,
			"beforeend",
			signature_text,
			NULL);

	element = webkit_dom_element_query_selector (
		insert_signature_in, "[data-evo-signature-plain-text-mode]", NULL);
	if (element)
		webkit_dom_element_remove_attribute (
			element, "data-evo-signature-plain-text-mode");
	g_free (signature_text);

insert:
	/* Remove the old signature and insert the new one. */
	signatures = webkit_dom_document_get_elements_by_class_name_as_html_collection (
		document, "-x-evo-signature-wrapper");
	for (ii = webkit_dom_html_collection_get_length (signatures); ii--;) {
		WebKitDOMNode *wrapper, *signature;

		wrapper = webkit_dom_html_collection_item (signatures, ii);
		signature = webkit_dom_node_get_first_child (wrapper);

		/* Old messages will have the signature id in the name attribute, correct it. */
		element_rename_attribute (WEBKIT_DOM_ELEMENT (signature), "name", "id");

		/* When we are editing a message with signature, we need to unset the
		 * active signature id as if the signature in the message was edited
		 * by the user we would discard these changes. */
		if (*set_signature_from_message && content) {
			if (*check_if_signature_is_changed) {
				/* Normalize the signature that we want to insert as the one in the
				 * message already is normalized. */
				webkit_dom_node_normalize (WEBKIT_DOM_NODE (signature_to_insert));
				if (!webkit_dom_node_is_equal_node (WEBKIT_DOM_NODE (signature_to_insert), signature)) {
					/* Signature in the body is different than the one with the
					 * same id, so set the active signature to None and leave
					 * the signature that is in the body. */
					new_signature_id = g_strdup ("none");
					*ignore_next_signature_change = TRUE;
				}

				*check_if_signature_is_changed = FALSE;
				*set_signature_from_message = FALSE;
			} else {
				/* Load the signature and check if is it the same
				 * as the signature in body or the user previously
				 * changed it. */
				new_signature_id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (signature));
				*check_if_signature_is_changed = TRUE;
			}
			g_clear_object (&signatures);

			return new_signature_id;
		}

		/* If the top signature was set we have to remove the newline
		 * that was inserted after it */
		if (top_signature) {
			WebKitDOMElement *spacer;

			spacer = webkit_dom_document_query_selector (
				document, ".-x-evo-top-signature-spacer", NULL);
			if (spacer)
				remove_node_if_empty (WEBKIT_DOM_NODE (spacer));
		}

		/* Leave just one signature wrapper there as it will be reused. */
		if (ii != 0) {
			remove_node (wrapper);
		} else {
			remove_node (signature);
			signature_wrapper = WEBKIT_DOM_ELEMENT (wrapper);
		}
	}

	if (signature_wrapper) {
		webkit_dom_node_append_child (
			WEBKIT_DOM_NODE (signature_wrapper),
			WEBKIT_DOM_NODE (signature_to_insert),
			NULL);

		/* Insert a spacer below the top signature */
		if (top_signature && content) {
			WebKitDOMElement *spacer;

			spacer = prepare_top_signature_spacer (editor_page);
			webkit_dom_node_insert_before (
				WEBKIT_DOM_NODE (body),
				WEBKIT_DOM_NODE (spacer),
				webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (signature_wrapper)),
				NULL);
		}
	} else {
		signature_wrapper = webkit_dom_document_create_element (document, "div", NULL);
		webkit_dom_element_set_class_name (signature_wrapper, "-x-evo-signature-wrapper");

		webkit_dom_node_append_child (
			WEBKIT_DOM_NODE (signature_wrapper),
			WEBKIT_DOM_NODE (signature_to_insert),
			NULL);

		if (top_signature) {
			WebKitDOMNode *child;

			child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));

			if (start_typing_at_bottom ()) {
				webkit_dom_node_insert_before (
					WEBKIT_DOM_NODE (body),
					WEBKIT_DOM_NODE (signature_wrapper),
					child,
					NULL);
			} else {
				/* When we are using signature on top the caret
				 * should be before the signature */
				webkit_dom_node_insert_before (
					WEBKIT_DOM_NODE (body),
					WEBKIT_DOM_NODE (signature_wrapper),
					child,
					NULL);
			}
		} else {
			webkit_dom_node_append_child (
				WEBKIT_DOM_NODE (body),
				WEBKIT_DOM_NODE (signature_wrapper),
				NULL);
		}

		move_caret_after_signature_inserted (editor_page);
	}
	g_clear_object (&signatures);

	if (is_html && html_mode)
		e_editor_dom_fix_file_uri_images (editor_page);

	/* Make sure the flag will be unset and won't influence user's choice */
	*set_signature_from_message = FALSE;

	return NULL;
}
static void
composer_load_signature_cb (EMailSignatureComboBox *combo_box,
                            GAsyncResult *result,
                            EMsgComposer *composer)
{
	GString *html_buffer = NULL;
	gchar *contents = NULL;
	gsize length = 0;
	const gchar *active_id;
	gboolean top_signature, is_html, html_mode;
	gboolean start_bottom, is_message_from_edit_as_new;
	GError *error = NULL;
	EHTMLEditor *editor;
	EHTMLEditorView *view;
	WebKitDOMDocument *document;
	WebKitDOMElement *element = NULL;
	WebKitDOMNodeList *signatures;
	gulong list_length, ii;
	GSettings *settings;

	e_mail_signature_combo_box_load_selected_finish (
		combo_box, result, &contents, &length, &is_html, &error);

	/* FIXME Use an EAlert here. */
	if (error != NULL) {
		g_warning ("%s: %s", G_STRFUNC, error->message);
		g_error_free (error);
		goto exit;
	}

	if (composer->priv->ignore_next_signature_change) {
		composer->priv->ignore_next_signature_change = FALSE;
		goto exit;
	}

	editor = e_msg_composer_get_editor (composer);
	view = e_html_editor_get_view (editor);
	is_message_from_edit_as_new =
		e_html_editor_view_is_message_from_edit_as_new (view);

	/* "Edit as New Message" sets is_message_from_edit_as_new.
	 * Always put the signature at the bottom for that case. */
	top_signature =
		use_top_signature (composer) &&
		!is_message_from_edit_as_new &&
		!composer->priv->is_from_new_message;

	settings = e_util_ref_settings ("org.gnome.evolution.mail");
	start_bottom = g_settings_get_boolean (settings, "composer-reply-start-bottom");
	g_object_unref (settings);

	document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
	html_mode = e_html_editor_view_get_html_mode (view);

	if (contents == NULL)
		goto insert;

	/* If inserting HTML signature in plain text composer we have to convert it. */
	if (is_html && !html_mode) {
		WebKitDOMElement *tmp_element;
		gchar *inner_text;

		tmp_element = webkit_dom_document_create_element (document, "div", NULL);
		webkit_dom_html_element_set_inner_html (
			WEBKIT_DOM_HTML_ELEMENT (tmp_element), contents, NULL);
		inner_text = webkit_dom_html_element_get_inner_text (
			WEBKIT_DOM_HTML_ELEMENT (tmp_element));

		g_free (contents);
		contents = inner_text ? g_strstrip (inner_text) : g_strdup ("");
		is_html = FALSE;
	}

	if (!is_html) {
		gchar *html;

		html = camel_text_to_html (contents, 0, 0);
		if (html) {
			g_free (contents);

			contents = html;
			length = strlen (contents);
		}
	}

	/* Generate HTML code for the signature. */

	html_buffer = g_string_sized_new (1024);

	/* The combo box active ID is the signature's ESource UID. */
	active_id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (combo_box));

	g_string_append_printf (
		html_buffer,
		"<SPAN class=\"-x-evo-signature\" id=\"1\" name=\"%s\">",
		(active_id != NULL) ? active_id : "");

	if (!is_html)
		g_string_append (html_buffer, "<PRE>");

	/* The signature dash convention ("-- \n") is specified
	 * in the "Son of RFC 1036", section 4.3.2.
	 * http://www.chemie.fu-berlin.de/outerspace/netnews/son-of-1036.html
	 */
	if (add_signature_delimiter (composer)) {
		const gchar *delim;
		const gchar *delim_nl;

		if (is_html) {
			delim = "-- <BR>";
			delim_nl = "\n-- <BR>";
		} else {
			delim = "-- \n";
			delim_nl = "\n-- \n";
		}

		/* Skip the delimiter if the signature already has one. */
		if (g_ascii_strncasecmp (contents, delim, strlen (delim)) == 0)
			;  /* skip */
		else if (e_util_strstrcase (contents, delim_nl) != NULL)
			;  /* skip */
		else
			g_string_append (html_buffer, delim);
	}

	g_string_append_len (html_buffer, contents, length);

	if (!is_html)
		g_string_append (html_buffer, "</PRE>");

	g_string_append (html_buffer, "</SPAN>");
	g_free (contents);

insert:
	/* Remove the old signature and insert the new one. */
	signatures = webkit_dom_document_get_elements_by_class_name (
		document, "-x-evo-signature-wrapper");
	list_length = webkit_dom_node_list_get_length (signatures);
	for (ii = 0; ii < list_length; ii++) {
		WebKitDOMNode *wrapper, *signature;
		gchar *id;

		wrapper = webkit_dom_node_list_item (signatures, ii);
		signature = webkit_dom_node_get_first_child (wrapper);

		/* When we are editing a message with signature, we need to unset the
		 * active signature id as if the signature in the message was edited
		 * by the user we would discard these changes. */
		if (composer->priv->set_signature_from_message &&
		    (is_message_from_edit_as_new || e_html_editor_view_is_message_from_draft (view))) {
			if (composer->priv->check_if_signature_is_changed) {
				if (html_buffer && *html_buffer->str) {
					gchar *body_signature_text, *signature_text;

					element = webkit_dom_document_create_element (document, "div", NULL);
					webkit_dom_html_element_set_inner_html (
						WEBKIT_DOM_HTML_ELEMENT (element), html_buffer->str, NULL);

					body_signature_text = webkit_dom_html_element_get_inner_text (
						WEBKIT_DOM_HTML_ELEMENT (signature));
					signature_text = webkit_dom_html_element_get_inner_text (
						WEBKIT_DOM_HTML_ELEMENT (element));

					/* Signature in the body is different than the one with the
					 * same id, so set the active signature to None and leave
					 * the signature that is in the body. */
					if (g_strcmp0 (body_signature_text, signature_text) != 0) {
						gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
						composer->priv->ignore_next_signature_change = TRUE;
					}

					g_free (body_signature_text);
					g_free (signature_text);
				} else {
					gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
					composer->priv->ignore_next_signature_change = TRUE;
				}

				composer->priv->check_if_signature_is_changed = FALSE;
				composer->priv->set_signature_from_message = FALSE;
			} else {
				gchar *name;

				/* Load the signature and check if is it the same
				 * as the signature in body or the user previously
				 * changed it. */
				name = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (signature), "name");
				gtk_combo_box_set_active_id (GTK_COMBO_BOX (combo_box), name);
				g_free (name);

				composer->priv->check_if_signature_is_changed = TRUE;
			}
			g_object_unref (wrapper);
			g_object_unref (signatures);

			g_object_unref (composer);

			return;
		}

		id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (signature));
		if (id && (strlen (id) == 1) && (*id == '1')) {
			/* If the top signature was set we have to remove the NL
			 * that was inserted after it */
			if (top_signature) {
				WebKitDOMElement *spacer;

				spacer = webkit_dom_document_query_selector (
					document, ".-x-evo-top-signature-spacer", NULL);
				if (spacer)
					remove_node_if_empty (WEBKIT_DOM_NODE (spacer));
			}
			/* We have to remove the div containing the span with signature */
			remove_node (wrapper);
			g_object_unref (wrapper);

			g_free (id);
			break;
		}

		g_object_unref (wrapper);
		g_free (id);
	}
	g_object_unref (signatures);

	if (html_buffer != NULL) {
		if (*html_buffer->str) {
			WebKitDOMHTMLElement *body;

			body = webkit_dom_document_get_body (document);
			if (!element) {
				element = webkit_dom_document_create_element (document, "DIV", NULL);

				webkit_dom_html_element_set_inner_html (
					WEBKIT_DOM_HTML_ELEMENT (element), html_buffer->str, NULL);
			}

			webkit_dom_element_set_class_name (element, "-x-evo-signature-wrapper");

			if (top_signature) {
				WebKitDOMNode *child =
					webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));

				if (start_bottom) {
					webkit_dom_node_insert_before (
						WEBKIT_DOM_NODE (body),
						WEBKIT_DOM_NODE (element),
						child,
						NULL);
				} else {
					/* When we are using signature on top the caret
					 * should be before the signature */
					webkit_dom_node_insert_before (
						WEBKIT_DOM_NODE (body),
						WEBKIT_DOM_NODE (element),
						child,
						NULL);
				}
			} else {
				webkit_dom_node_append_child (
					WEBKIT_DOM_NODE (body),
					WEBKIT_DOM_NODE (element),
					NULL);
			}
		}

		g_string_free (html_buffer, TRUE);
	}

	if (is_html && html_mode)
		e_html_editor_view_fix_file_uri_images (view);

	composer_move_caret (composer);

 exit:
	/* Make sure the flag will be unset and won't influence user's choice */
	composer->priv->set_signature_from_message = FALSE;

	g_object_unref (composer);
}