# HG changeset patch
# Node ID a48ae11fea5d
# Parent  51a419226147
diff --git a/ChangeLog.API b/ChangeLog.API
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -561,6 +561,7 @@
 		* purple_marshal_POINTER__POINTER_POINTER_BOOLEAN
 		* purple_marshal_VOID__INT
 		* purple_marshal_VOID__INT_INT
+		* purple_message_meify
 		* PurpleMimeDocument, PurpleMimePart,
 		  purple_mime_document_new, purple_mime_document_free,
 		  purple_mime_document_parse, purple_mime_document_parsen,
diff --git a/finch/gntconv.c b/finch/gntconv.c
--- a/finch/gntconv.c
+++ b/finch/gntconv.c
@@ -891,7 +891,7 @@
 		gboolean me = FALSE;
 		gchar *msg_text = g_strdup(purple_message_get_contents(msg));
 
-		if (purple_message_meify(msg_text, -1)) {
+		if(purple_message_get_action(msg)) {
 			name = g_strdup_printf("*** %s", purple_message_get_author_alias(msg));
 			if (!(flags & PURPLE_MESSAGE_SEND) &&
 					(flags & PURPLE_MESSAGE_NICK))
diff --git a/libpurple/purplemessage.h b/libpurple/purplemessage.h
--- a/libpurple/purplemessage.h
+++ b/libpurple/purplemessage.h
@@ -458,6 +458,33 @@
  */
 void purple_message_clear_attachments(PurpleMessage *message);
 
+/**
+ * purple_message_get_action:
+ * @message: The instance.
+ *
+ * Gets whether or not @message is an action.
+ *
+ * See also [property@Message:action] for more information.
+ *
+ * Returns: %TRUE if @message is an action, otherwise %FALSE.
+ *
+ * Since: 3.0.0
+ */
+gboolean purple_message_get_action(PurpleMessage *message);
+
+/**
+ * purple_message_set_action:
+ * @message: The instance.
+ * @action: Whether or not @message is an action.
+ *
+ * Sets whether or not @message is an action.
+ *
+ * See also: [property@Message:action] for more information.
+ *
+ * Since: 3.0.0
+ */
+void purple_message_set_action(PurpleMessage *message, gboolean action);
+
 G_END_DECLS
 
 #endif /* PURPLE_MESSAGE_H */
diff --git a/libpurple/purplemessage.c b/libpurple/purplemessage.c
--- a/libpurple/purplemessage.c
+++ b/libpurple/purplemessage.c
@@ -38,6 +38,7 @@
 
 	gchar *contents;
 	PurpleMessageContentType content_type;
+	gboolean action;
 
 	GDateTime *timestamp;
 	PurpleMessageFlags flags;
@@ -56,6 +57,7 @@
 	PROP_RECIPIENT,
 	PROP_CONTENTS,
 	PROP_CONTENT_TYPE,
+	PROP_ACTION,
 	PROP_TIMESTAMP,
 	PROP_FLAGS,
 	PROP_ERROR,
@@ -116,6 +118,9 @@
 		case PROP_CONTENT_TYPE:
 			g_value_set_enum(value, purple_message_get_content_type(message));
 			break;
+		case PROP_ACTION:
+			g_value_set_boolean(value, purple_message_get_action(message));
+			break;
 		case PROP_TIMESTAMP:
 			g_value_set_boxed(value, purple_message_get_timestamp(message));
 			break;
@@ -160,6 +165,9 @@
 		case PROP_CONTENT_TYPE:
 			purple_message_set_content_type(message, g_value_get_enum(value));
 			break;
+		case PROP_ACTION:
+			purple_message_set_action(message, g_value_get_boolean(value));
+			break;
 		case PROP_TIMESTAMP:
 			purple_message_set_timestamp(message, g_value_get_boxed(value));
 			break;
@@ -212,7 +220,7 @@
 	obj_class->finalize = purple_message_finalize;
 
 	/**
-	 * PurpleMessage::id:
+	 * PurpleMessage:id:
 	 *
 	 * The protocol specific identifier of the message.
 	 *
@@ -225,7 +233,7 @@
 		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleMessage::author:
+	 * PurpleMessage:author:
 	 *
 	 * The author of the message.
 	 *
@@ -238,7 +246,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleMessage::author-name-color:
+	 * PurpleMessage:author-name-color:
 	 *
 	 * The hex color for the author's name.
 	 *
@@ -251,7 +259,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleMessage::author-alias:
+	 * PurpleMessage:author-alias:
 	 *
 	 * The alias of the author.
 	 *
@@ -264,7 +272,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleMessage::recipient:
+	 * PurpleMessage:recipient:
 	 *
 	 * The recipient of the message.
 	 *
@@ -277,7 +285,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleMessage::content:
+	 * PurpleMessage:content:
 	 *
 	 * The contents of the message.
 	 *
@@ -290,7 +298,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleMessage::content-type:
+	 * PurpleMessage:content-type:
 	 *
 	 * The content-type of the message.
 	 *
@@ -303,7 +311,25 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleMessage::timestamp:
+	 * PurpleMessage:action:
+	 *
+	 * Whether or not the message is an action.
+	 *
+	 * Typically a message is considered an action when the body starts with
+	 * `/me`. Some protocols handle this differently but this is mostly a user
+	 * interface hint that this message is different than a normal text
+	 * message.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_ACTION] = g_param_spec_boolean(
+		"action", "action",
+		"Whether or not the message is an action.",
+		FALSE,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleMessage:timestamp:
 	 *
 	 * The timestamp of the message.
 	 *
@@ -316,7 +342,7 @@
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleMessage::flags:
+	 * PurpleMessage:flags:
 	 *
 	 * The #PurpleMessageFlags for the message.
 	 *
@@ -670,3 +696,21 @@
 
 	g_hash_table_remove_all(message->attachments);
 }
+
+gboolean
+purple_message_get_action(PurpleMessage *message) {
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), FALSE);
+
+	return message->action;
+}
+
+void
+purple_message_set_action(PurpleMessage *message, gboolean action) {
+	g_return_if_fail(PURPLE_IS_MESSAGE(message));
+
+	if(action != message->action) {
+		message->action = action;
+
+		g_object_notify_by_pspec(G_OBJECT(message), properties[PROP_ACTION]);
+	}
+}
diff --git a/libpurple/tests/test_message.c b/libpurple/tests/test_message.c
--- a/libpurple/tests/test_message.c
+++ b/libpurple/tests/test_message.c
@@ -38,6 +38,7 @@
 	char *author_name_color = NULL;
 	char *recipient = NULL;
 	char *contents = NULL;
+	gboolean action = FALSE;
 
 	timestamp = g_date_time_new_from_unix_utc(911347200);
 	error = g_error_new(g_quark_from_static_string("test-message"), 0,
@@ -46,6 +47,7 @@
 	message = g_object_new(
 		PURPLE_TYPE_MESSAGE,
 		"id", "id",
+		"action", TRUE,
 		"author", "author",
 		"author-alias", "alias",
 		"author-name-color", "purple",
@@ -60,6 +62,7 @@
 	g_object_get(
 		message,
 		"id", &id,
+		"action", &action,
 		"author", &author,
 		"author-alias", &author_alias,
 		"author-name-color", &author_name_color,
@@ -72,6 +75,7 @@
 		NULL);
 
 	g_assert_cmpstr(id, ==, "id");
+	g_assert_true(action);
 	g_assert_cmpstr(author, ==, "author");
 	g_assert_cmpstr(author_alias, ==, "alias");
 	g_assert_cmpstr(author_name_color, ==, "purple");
diff --git a/libpurple/util.h b/libpurple/util.h
--- a/libpurple/util.h
+++ b/libpurple/util.h
@@ -438,18 +438,6 @@
 gboolean purple_utf8_has_word(const char *haystack, const char *needle);
 
 /**
- * purple_message_meify:
- * @message: The message to check
- * @len:     The message length, or -1
- *
- * Checks for messages starting (post-HTML) with "/me ", including the space.
- *
- * Returns: TRUE if it starts with "/me ", and it has been removed, otherwise
- *         FALSE
- */
-gboolean purple_message_meify(char *message, gssize len);
-
-/**
  * purple_text_strip_mnemonic:
  * @in:  The string to strip
  *
diff --git a/libpurple/util.c b/libpurple/util.c
--- a/libpurple/util.c
+++ b/libpurple/util.c
@@ -757,35 +757,6 @@
 	return ret;
 }
 
-gboolean purple_message_meify(char *message, gssize len)
-{
-	char *c;
-	gboolean inside_html = FALSE;
-
-	g_return_val_if_fail(message != NULL, FALSE);
-
-	if(len == -1)
-		len = strlen(message);
-
-	for (c = message; *c; c++, len--) {
-		if(inside_html) {
-			if(*c == '>')
-				inside_html = FALSE;
-		} else {
-			if(*c == '<')
-				inside_html = TRUE;
-			else
-				break;
-		}
-	}
-
-	if(*c && !g_ascii_strncasecmp(c, "/me ", 4)) {
-		memmove(c, c+4, len-3);
-		return TRUE;
-	}
-
-	return FALSE;
-}
 
 char *purple_text_strip_mnemonic(const char *in)
 {
