1/*2Maddy Mail Server - Composable all-in-one email server.3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors45This program is free software: you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation, either version 3 of the License, or8(at your option) any later version.910This program is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with this program. If not, see <https://www.gnu.org/licenses/>.17*/1819package table2021import (22 "context"23 "fmt"24 "regexp"25 "strings"2627 "github.com/foxcpp/maddy/framework/config"28 "github.com/foxcpp/maddy/framework/module"29)3031type Regexp struct {32 modName string33 instName string34 inlineArgs []string3536 re *regexp.Regexp37 replacements []string3839 expandPlaceholders bool40}4142func NewRegexp(modName, instName string, _, inlineArgs []string) (module.Module, error) {43 return &Regexp{44 modName: modName,45 instName: instName,46 inlineArgs: inlineArgs,47 }, nil48}4950func (r *Regexp) Init(cfg *config.Map) error {51 var (52 fullMatch bool53 caseInsensitive bool54 )55 cfg.Bool("full_match", false, true, &fullMatch)56 cfg.Bool("case_insensitive", false, true, &caseInsensitive)57 cfg.Bool("expand_replaceholders", false, true, &r.expandPlaceholders)58 if _, err := cfg.Process(); err != nil {59 return err60 }6162 regex := r.inlineArgs[0]63 if len(r.inlineArgs) > 1 {64 r.replacements = r.inlineArgs[1:]65 }6667 if fullMatch {68 if !strings.HasPrefix(regex, "^") {69 regex = "^" + regex70 }71 if !strings.HasSuffix(regex, "$") {72 regex = regex + "$"73 }74 }7576 if caseInsensitive {77 regex = "(?i)" + regex78 }7980 var err error81 r.re, err = regexp.Compile(regex)82 if err != nil {83 return fmt.Errorf("%s: %v", r.modName, err)84 }85 return nil86}8788func (r *Regexp) Name() string {89 return r.modName90}9192func (r *Regexp) InstanceName() string {93 return r.modName94}9596func (r *Regexp) LookupMulti(_ context.Context, key string) ([]string, error) {97 matches := r.re.FindStringSubmatchIndex(key)98 if matches == nil {99 return []string{}, nil100 }101102 result := []string{}103 for _, replacement := range r.replacements {104 if !r.expandPlaceholders {105 result = append(result, replacement)106 } else {107 result = append(result, string(r.re.ExpandString([]byte{}, replacement, key, matches)))108 }109 }110 return result, nil111}112113func (r *Regexp) Lookup(ctx context.Context, key string) (string, bool, error) {114 newVal, err := r.LookupMulti(ctx, key)115 if err != nil {116 return "", false, err117 }118 if len(newVal) == 0 {119 return "", false, nil120 }121122 return newVal[0], true, nil123}124125func init() {126 module.Register("table.regexp", NewRegexp)127}