gomuks/matrix/pushrules/condition.go
2018-03-22 23:46:43 +02:00

148 lines
4.3 KiB
Go

// gomuks - A terminal Matrix client written in Go.
// Copyright (C) 2018 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package pushrules
import (
"regexp"
"strconv"
"strings"
"github.com/zyedidia/glob"
"maunium.net/go/gomatrix"
"maunium.net/go/gomuks/matrix/rooms"
)
// PushCondKind is the type of a push condition.
type PushCondKind string
// The allowed push condition kinds as specified in section 11.12.1.4.3 of r0.3.0 of the Client-Server API.
const (
KindEventMatch PushCondKind = "event_match"
KindContainsDisplayName PushCondKind = "contains_display_name"
KindRoomMemberCount PushCondKind = "room_member_count"
)
// PushCondition wraps a condition that is required for a specific PushRule to be used.
type PushCondition struct {
// The type of the condition.
Kind PushCondKind `json:"kind"`
// The dot-separated field of the event to match. Only applicable if kind is EventMatch.
Key string `json:"key,omitempty"`
// The glob-style pattern to match the field against. Only applicable if kind is EventMatch.
Pattern string `json:"pattern,omitempty"`
// The condition that needs to be fulfilled for RoomMemberCount-type conditions.
// A decimal integer optionally prefixed by ==, <, >, >= or <=. Prefix "==" is assumed if no prefix found.
MemberCountCondition string `json:"is,omitempty"`
}
// MemberCountFilterRegex is the regular expression to parse the MemberCountCondition of PushConditions.
var MemberCountFilterRegex = regexp.MustCompile("^(==|[<>]=?)?([0-9]+)$")
// Match checks if this condition is fulfilled for the given event in the given room.
func (cond *PushCondition) Match(room *rooms.Room, event *gomatrix.Event) bool {
switch cond.Kind {
case KindEventMatch:
return cond.matchValue(room, event)
case KindContainsDisplayName:
return cond.matchDisplayName(room, event)
case KindRoomMemberCount:
return cond.matchMemberCount(room, event)
default:
return false
}
}
func (cond *PushCondition) matchValue(room *rooms.Room, event *gomatrix.Event) bool {
index := strings.IndexRune(cond.Key, '.')
key := cond.Key
subkey := ""
if index > 0 {
subkey = key[index+1:]
key = key[0:index]
}
pattern, err := glob.Compile(cond.Pattern)
if err != nil {
return false
}
switch key {
case "type":
return pattern.MatchString(event.Type)
case "sender":
return pattern.MatchString(event.Sender)
case "room_id":
return pattern.MatchString(event.RoomID)
case "state_key":
if event.StateKey == nil {
return cond.Pattern == ""
}
return pattern.MatchString(*event.StateKey)
case "content":
val, _ := event.Content[subkey].(string)
return pattern.MatchString(val)
default:
return false
}
}
func (cond *PushCondition) matchDisplayName(room *rooms.Room, event *gomatrix.Event) bool {
member := room.GetMember(room.SessionUserID)
if member == nil {
return false
}
text, _ := event.Content["body"].(string)
return strings.Contains(text, member.DisplayName)
}
func (cond *PushCondition) matchMemberCount(room *rooms.Room, event *gomatrix.Event) bool {
groupGroups := MemberCountFilterRegex.FindAllStringSubmatch(cond.MemberCountCondition, -1)
if len(groupGroups) != 1 {
return false
}
operator := "=="
wantedMemberCount := 0
group := groupGroups[0]
if len(group) == 0 {
return false
} else if len(group) == 1 {
wantedMemberCount, _ = strconv.Atoi(group[0])
} else {
operator = group[0]
wantedMemberCount, _ = strconv.Atoi(group[1])
}
memberCount := len(room.GetMembers())
switch operator {
case "==":
return wantedMemberCount == memberCount
case ">":
return wantedMemberCount > memberCount
case ">=":
return wantedMemberCount >= memberCount
case "<":
return wantedMemberCount < memberCount
case "<=":
return wantedMemberCount <= memberCount
default:
return false
}
}