--- 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; +}