protocols/ircv3/purpleircv3messagehandlers.c

changeset 43199
99b283ab8116
parent 43198
570996d7ad96
child 43205
1400ae254c24
--- a/protocols/ircv3/purpleircv3messagehandlers.c	Mon Mar 17 21:21:06 2025 -0500
+++ b/protocols/ircv3/purpleircv3messagehandlers.c	Mon Mar 17 21:22:42 2025 -0500
@@ -60,82 +60,127 @@
 	return member;
 }
 
+static PurpleBadge *
+purple_ircv3_badge_for_prefix(const char prefix) {
+	PurpleBadge *badge = NULL;
+	PurpleBadgeManager *manager = NULL;
+	const char *description = NULL;
+	const char *id = NULL;
+	const char *mnemonic = NULL;
+	int priority = 0;
+
+	manager = purple_badge_manager_get_default();
+
+	switch(prefix) {
+	case '~':
+		description = _("Founder");
+		id = "ircv3-badge-founder";
+		priority = 500;
+		mnemonic = "~";
+		break;
+	case '&':
+		description = _("Protected");
+		id = "ircv3-badge-protected";
+		priority = 400;
+		mnemonic = "&";
+		break;
+	case '@':
+		description = _("Operator");
+		id = "ircv3-badge-operator";
+		priority = 300;
+		mnemonic = "@";
+		break;
+	case '%':
+		description = _("Half Operator");
+		id = "ircv3-badge-halfop";
+		priority = 200;
+		mnemonic = "%%";
+		break;
+	case '+':
+		description = _("Voice");
+		id = "ircv3-badge-voice";
+		priority = 100;
+		mnemonic = "+";
+		break;
+	}
+
+	if(id == NULL) {
+		return NULL;
+	}
+
+	badge = purple_badge_manager_find(manager, id);
+	if(!PURPLE_IS_BADGE(badge)) {
+		badge = purple_badge_new(id, priority, id, mnemonic);
+		if(!purple_strempty(description)) {
+			purple_badge_set_description(badge, description);
+		}
+
+		purple_badge_manager_add(manager, badge);
+
+		/* This is transfer none and the manager has a reference, so we unref
+		 * our reference to the badge.
+		 */
+		g_object_unref(badge);
+	}
+
+	return badge;
+}
+
 static void
-purple_ircv3_add_badges_to_member(PurpleConversationMember *member,
-                                  IbisClient *client, const char *nick)
+purple_ircv3_add_badge_to_member(PurpleConversationMember *member,
+                                 IbisClient *client, const char prefix)
 {
-	PurpleBadgeManager *manager = NULL;
-	PurpleBadges *badges = NULL;
-	char *prefixes = NULL;
-	char *iter = NULL;
+	PurpleBadge *badge = NULL;
 
 	g_return_if_fail(PURPLE_IS_CONVERSATION_MEMBER(member));
 	g_return_if_fail(IBIS_IS_CLIENT(client));
 
-	badges = purple_conversation_member_get_badges(member);
-	manager = purple_badge_manager_get_default();
-	prefixes = ibis_client_get_source_prefix(client, nick);
-	iter = prefixes;
+	badge = purple_ircv3_badge_for_prefix(prefix);
+	if(PURPLE_IS_BADGE(badge)) {
+		PurpleBadges *badges = NULL;
+
+		badges = purple_conversation_member_get_badges(member);
+		purple_badges_add_badge(badges, badge);
+	}
+}
 
-	while(iter != NULL) {
-		PurpleBadge *badge = NULL;
-		const char *description = NULL;
-		const char *id = NULL;
-		const char *mnemonic = NULL;
-		int priority = 0;
+static void
+purple_ircv3_remove_badge_from_member(PurpleConversationMember *member,
+                                      IbisClient *client, const char prefix)
+{
+	PurpleBadge *badge = NULL;
+
+	g_return_if_fail(PURPLE_IS_CONVERSATION_MEMBER(member));
+	g_return_if_fail(IBIS_IS_CLIENT(client));
+
+	badge = purple_ircv3_badge_for_prefix(prefix);
+	if(PURPLE_IS_BADGE(badge)) {
+		PurpleBadges *badges = purple_conversation_member_get_badges(member);
 
-		switch(g_utf8_get_char(iter)) {
-		case '~':
-			description = _("Founder");
-			id = "ircv3-badge-founder";
-			priority = 500;
-			mnemonic = "~";
-			break;
-		case '&':
-			description = _("Protected");
-			id = "ircv3-badge-protected";
-			priority = 400;
-			mnemonic = "&";
-			break;
-		case '@':
-			description = _("Operator");
-			id = "ircv3-badge-operator";
-			priority = 300;
-			mnemonic = "@";
-			break;
-		case '%':
-			description = _("Half Operator");
-			id = "ircv3-badge-halfop";
-			priority = 200;
-			mnemonic = "%%";
-			break;
-		case '+':
-			description = _("Voice");
-			id = "ircv3-badge-voice";
-			priority = 100;
-			mnemonic = "+";
-			break;
-		}
+		/* I know this is gross, but we need to rework badges here and I wanted
+		 * to get this done sooner rather than later.
+		 * -- gk 2025-03-14
+		 */
+		purple_badges_remove_badge(badges, purple_badge_get_id(badge));
+	}
+}
 
-		if(id == NULL) {
-			break;
-		}
+static void
+purple_ircv3_add_badges_to_member(PurpleConversationMember *member,
+                                  IbisClient *client, const char *nick)
+{
+	char *prefixes = NULL;
 
-		badge = purple_badge_manager_find(manager, id);
-		if(PURPLE_IS_BADGE(badge)) {
-			purple_badges_add_badge(badges, badge);
-		} else {
-			badge = purple_badge_new(id, priority, id, mnemonic);
-			if(!purple_strempty(description)) {
-				purple_badge_set_description(badge, description);
-			}
+	g_return_if_fail(PURPLE_IS_CONVERSATION_MEMBER(member));
+	g_return_if_fail(IBIS_IS_CLIENT(client));
 
-			purple_badge_manager_add(manager, badge);
-			purple_badges_add_badge(badges, badge);
-			g_clear_object(&badge);
-		}
+	prefixes = ibis_client_get_source_prefix(client, nick);
+	if(purple_strempty(prefixes)) {
+		return;
+	}
 
-		iter = g_utf8_next_char(iter);
+	for(guint i = 0; prefixes[i] != '\0'; i++) {
+		purple_ircv3_add_badge_to_member(member, client, prefixes[i]);
 	}
 
 	g_free(prefixes);
@@ -884,3 +929,97 @@
 
 	return TRUE;
 }
+
+gboolean
+purple_ircv3_message_handler_mode(IbisClient *client,
+                                  G_GNUC_UNUSED const char *command,
+                                  IbisMessage *ibis_message,
+                                  gpointer data)
+{
+	PurpleIRCv3Connection *v3_connection = data;
+	PurpleContact *contact = NULL;
+	PurpleConversation *conversation = NULL;
+	PurpleConversationMember *author = NULL;
+	PurpleMessage *message = NULL;
+	IbisModeChange *mode_changes = NULL;
+	GError *error = NULL;
+	GStrv params = NULL;
+	char *contents = NULL;
+	char *parts = NULL;
+	guint n_params = 0;
+	guint n_mode_changes = 0;
+	const char *target = NULL;
+
+	params = ibis_message_get_params(ibis_message);
+	n_params = g_strv_length(params);
+
+	if(n_params < 2) {
+		g_message("received MODE with %u params, need at least 2", n_params);
+		return FALSE;
+	}
+
+	target = params[0];
+	if(!ibis_client_is_channel(client, target)) {
+		return FALSE;
+	}
+
+	conversation = purple_ircv3_connection_find_or_create_conversation(v3_connection,
+	                                                                   target);
+
+	contact = purple_ircv3_connection_find_or_create_contact(v3_connection,
+	                                                         ibis_message);
+	author = purple_conversation_find_or_add_member(conversation,
+	                                                PURPLE_CONTACT_INFO(contact),
+	                                                FALSE, NULL);
+
+	mode_changes = ibis_client_parse_mode_string(client, params[1], params + 2,
+	                                             &n_mode_changes, &error);
+	if(error != NULL) {
+		g_warning("failed to parse mode string: %s", error->message);
+
+		g_clear_error(&error);
+
+		return FALSE;
+	}
+
+	for(guint i = 0; i < n_mode_changes; i++) {
+		PurpleContact *subject = NULL;
+		PurpleConversationMember *member = NULL;
+		IbisModeChange change = mode_changes[i];
+		char prefix = '\0';
+
+		prefix = ibis_client_get_prefix_for_mode(client, change.mode);
+		if(prefix == '\0') {
+			continue;
+		}
+
+		subject = purple_ircv3_connection_find_or_create_contact_from_nick(v3_connection,
+		                                                                   change.parameter);
+		member = purple_conversation_find_or_add_member(conversation,
+		                                                PURPLE_CONTACT_INFO(subject),
+		                                                FALSE, NULL);
+
+		if(change.add) {
+			purple_ircv3_add_badge_to_member(member, client, prefix);
+		} else {
+			purple_ircv3_remove_badge_from_member(member, client, prefix);
+		}
+	}
+
+	parts = g_strjoinv(" ", params + 1);
+	contents = g_strdup_printf(_("mode %s"), parts);
+	g_free(parts);
+
+	message = g_object_new(
+		PURPLE_TYPE_MESSAGE,
+		"author", author,
+		"contents", contents,
+		"event", TRUE,
+		NULL);
+	g_free(contents);
+
+	purple_conversation_write_message(conversation, message);
+	g_clear_object(&message);
+
+	return TRUE;
+}

mercurial