Changeset 293 in code for trunk/irc.go


Ignore:
Timestamp:
May 21, 2020, 8:36:54 PM (5 years ago)
Author:
delthas
Message:

Fix parsing MODE messages by updating channel memberships

Previously, we only considered channel modes in the modes of a MODE
messages, which means channel membership changes were ignored. This
resulted in bugs where users channel memberships would not be properly
updated and cached with wrong values. Further, mode arguments
representing entities were not properly marshaled.

This adds support for correctly parsing and updating channel memberships
when processing MODE messages. Mode arguments corresponding to channel
memberships updates are now also properly marshaled.

MODE messages can't be easily sent from history because marshaling these
messages require knowing about the upstream available channel types and
channel membership types, which is currently only possible when
connected. For now this is not an issue since we do not send MODE
messages in history.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/irc.go

    r292 r293  
    8585type channelModes map[byte]string
    8686
    87 func (cm channelModes) Apply(modeTypes map[byte]channelModeType, modeStr string, arguments ...string) error {
     87// applyChannelModes parses a mode string and mode arguments from a MODE message,
     88// and applies the corresponding channel mode and user membership changes on that channel.
     89//
     90// If ch.modes is nil, channel modes are not updated.
     91//
     92// needMarshaling is a list of indexes of mode arguments that represent entities
     93// that must be marshaled when sent downstream.
     94func applyChannelModes(ch *upstreamChannel, modeStr string, arguments []string) (needMarshaling map[int]struct{}, err error) {
     95        needMarshaling = make(map[int]struct{}, len(arguments))
    8896        nextArgument := 0
    8997        var plusMinus byte
     98outer:
    9099        for i := 0; i < len(modeStr); i++ {
    91100                mode := modeStr[i]
     
    95104                }
    96105                if plusMinus != '+' && plusMinus != '-' {
    97                         return fmt.Errorf("malformed modestring %q: missing plus/minus", modeStr)
    98                 }
    99 
    100                 mt, ok := modeTypes[mode]
     106                        return nil, fmt.Errorf("malformed modestring %q: missing plus/minus", modeStr)
     107                }
     108
     109                for _, membership := range ch.conn.availableMemberships {
     110                        if membership.Mode == mode {
     111                                if nextArgument >= len(arguments) {
     112                                        return nil, fmt.Errorf("malformed modestring %q: missing mode argument for %c%c", modeStr, plusMinus, mode)
     113                                }
     114                                member := arguments[nextArgument]
     115                                if _, ok := ch.Members[member]; ok {
     116                                        if plusMinus == '+' {
     117                                                ch.Members[member].Add(ch.conn.availableMemberships, membership)
     118                                        } else {
     119                                                // TODO: for upstreams without multi-prefix, query the user modes again
     120                                                ch.Members[member].Remove(membership)
     121                                        }
     122                                }
     123                                needMarshaling[nextArgument] = struct{}{}
     124                                nextArgument++
     125                                continue outer
     126                        }
     127                }
     128
     129                mt, ok := ch.conn.availableChannelModes[mode]
    101130                if !ok {
    102131                        continue
     
    110139                                        argument = arguments[nextArgument]
    111140                                }
    112                                 cm[mode] = argument
     141                                if ch.modes != nil {
     142                                        ch.modes[mode] = argument
     143                                }
    113144                        } else {
    114                                 delete(cm, mode)
     145                                delete(ch.modes, mode)
    115146                        }
    116147                        nextArgument++
    117148                } else if mt == modeTypeC || mt == modeTypeD {
    118149                        if plusMinus == '+' {
    119                                 cm[mode] = ""
     150                                if ch.modes != nil {
     151                                        ch.modes[mode] = ""
     152                                }
    120153                        } else {
    121                                 delete(cm, mode)
    122                         }
    123                 }
    124         }
    125         return nil
     154                                delete(ch.modes, mode)
     155                        }
     156                }
     157        }
     158        return needMarshaling, nil
    126159}
    127160
Note: See TracChangeset for help on using the changeset viewer.