2020-01-31 19:57:40 -07:00
|
|
|
package plugins
|
|
|
|
|
|
|
|
import (
|
2020-02-19 18:03:29 -07:00
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2020-03-09 20:47:11 -06:00
|
|
|
"image"
|
|
|
|
"image/png"
|
|
|
|
"io"
|
2020-02-19 18:03:29 -07:00
|
|
|
"net/http"
|
2020-01-31 19:57:40 -07:00
|
|
|
"regexp"
|
|
|
|
"strings"
|
2020-02-19 18:03:29 -07:00
|
|
|
"time"
|
2020-01-31 19:57:40 -07:00
|
|
|
|
2020-02-26 16:15:02 -07:00
|
|
|
"github.com/gomarkdown/markdown"
|
2020-01-31 19:57:40 -07:00
|
|
|
"github.com/matrix-org/gomatrix"
|
|
|
|
)
|
|
|
|
|
2020-02-10 17:10:57 -07:00
|
|
|
// PluginStore matches MCStore. This allows the main store to be used by
|
|
|
|
// plugins.
|
2020-02-05 22:04:04 -07:00
|
|
|
type PluginStore interface {
|
|
|
|
Set(key, values string)
|
|
|
|
Get(key string) (string, error)
|
|
|
|
}
|
|
|
|
|
2020-02-10 17:10:57 -07:00
|
|
|
// Plugin defines the interface a plugin must implement to be used by
|
2020-02-02 13:55:18 -07:00
|
|
|
// mcchunkie.
|
2020-01-31 19:57:40 -07:00
|
|
|
type Plugin interface {
|
2020-02-11 07:56:19 -07:00
|
|
|
// Descr returns a brief description of the plugin.
|
|
|
|
Descr() string
|
2020-02-10 17:10:57 -07:00
|
|
|
|
|
|
|
// Match determines if the plugin's main Respond function should be
|
|
|
|
// called
|
|
|
|
Match(user, message string) bool
|
|
|
|
|
2020-02-11 07:56:19 -07:00
|
|
|
// Name should return the human readable name of the bot
|
|
|
|
Name() string
|
|
|
|
|
|
|
|
// Re returns the regular expression that a plugin uses to "match"
|
|
|
|
Re() string
|
|
|
|
|
2021-04-01 08:23:59 -06:00
|
|
|
// RespondMatrix responds to a Matrix "m.text" event
|
2020-05-13 16:53:31 -06:00
|
|
|
RespondText(c *gomatrix.Client, ev *gomatrix.Event, user, path string) error
|
2020-02-11 07:56:19 -07:00
|
|
|
|
2021-04-01 08:23:59 -06:00
|
|
|
// Process is the processed response from the plugin. This is useful for
|
|
|
|
// running the plugins outside of the context of Matrix.
|
2021-04-01 16:15:25 -06:00
|
|
|
Process(from, message string) string
|
2021-04-01 08:23:59 -06:00
|
|
|
|
2020-02-10 17:10:57 -07:00
|
|
|
// SetStore exposes the top level MCStore to a plugin
|
2020-02-05 22:04:04 -07:00
|
|
|
SetStore(s PluginStore)
|
2020-01-31 19:57:40 -07:00
|
|
|
}
|
|
|
|
|
2020-02-02 13:55:18 -07:00
|
|
|
// NameRE matches the "friendly" name. This is typically used in tab
|
|
|
|
// completion.
|
2020-01-31 19:57:40 -07:00
|
|
|
var NameRE = regexp.MustCompile(`@(.+):.+$`)
|
|
|
|
|
|
|
|
// ToMe returns true of the message pertains to the bot
|
|
|
|
func ToMe(user, message string) bool {
|
2020-02-10 17:10:57 -07:00
|
|
|
u := NameRE.ReplaceAllString(user, "$1")
|
|
|
|
return strings.Contains(message, u)
|
2020-01-31 19:57:40 -07:00
|
|
|
}
|
|
|
|
|
2020-05-07 19:34:24 -06:00
|
|
|
// RemoveName removes the friendly name from a given message
|
|
|
|
func RemoveName(user, message string) string {
|
|
|
|
n := NameRE.ReplaceAllString(user, "$1")
|
2020-05-13 16:53:31 -06:00
|
|
|
return strings.ReplaceAll(message, n+": ", "")
|
2020-05-07 19:34:24 -06:00
|
|
|
}
|
|
|
|
|
2020-02-19 18:03:29 -07:00
|
|
|
// HTTPRequest has the bits for making http requests
|
|
|
|
type HTTPRequest struct {
|
|
|
|
Client http.Client
|
|
|
|
Request *http.Request
|
|
|
|
Timeout time.Duration
|
|
|
|
URL string
|
|
|
|
Method string
|
|
|
|
ReqBody interface{}
|
|
|
|
ResBody interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// DoJSON is a general purpose http mechanic that can be used to get, post..
|
|
|
|
// what evs. The response is always expected to be json
|
|
|
|
func (h *HTTPRequest) DoJSON() (err error) {
|
|
|
|
h.Client.Timeout = h.Timeout
|
|
|
|
|
|
|
|
if h.Method == "" {
|
|
|
|
h.Method = "GET"
|
|
|
|
}
|
|
|
|
|
|
|
|
if h.ReqBody != nil {
|
|
|
|
// We have a request to send to the server
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
err = json.NewEncoder(buf).Encode(h.ReqBody)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
h.Request, err = http.NewRequest(h.Method, h.URL, buf)
|
|
|
|
} else {
|
|
|
|
// Just gimme dem datas
|
|
|
|
h.Request, err = http.NewRequest(h.Method, h.URL, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
h.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
res, err := h.Client.Do(h.Request)
|
|
|
|
if res != nil {
|
|
|
|
defer res.Body.Close()
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if h.ResBody != nil && res.Body != nil {
|
|
|
|
return json.NewDecoder(res.Body).Decode(&h.ResBody)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-02-02 13:55:18 -07:00
|
|
|
// SendText sends a text message to a given room. It pretends to be
|
|
|
|
// "typing" by calling UserTyping for the caller.
|
|
|
|
func SendText(c *gomatrix.Client, roomID, message string) error {
|
2020-01-31 19:57:40 -07:00
|
|
|
_, err := c.UserTyping(roomID, true, 3)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-05-13 17:36:26 -06:00
|
|
|
_, err = c.SendText(roomID, message)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-01-31 19:57:40 -07:00
|
|
|
|
|
|
|
_, err = c.UserTyping(roomID, false, 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-11 12:38:28 -07:00
|
|
|
// SendEmote sends an emote to a given room. It pretends to be
|
|
|
|
// "typing" by calling UserTyping for the caller.
|
|
|
|
func SendEmote(c *gomatrix.Client, roomID, message string) error {
|
|
|
|
_, err := c.UserTyping(roomID, true, 3)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = c.SendMessageEvent(roomID, "m.room.message", gomatrix.GetHTMLMessage("m.emote", message))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = c.UserTyping(roomID, false, 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-02-26 16:15:02 -07:00
|
|
|
// SendHTML sends an html message to a given room. It pretends to be
|
|
|
|
// "typing" by calling UserTyping for the caller.
|
|
|
|
func SendHTML(c *gomatrix.Client, roomID, message string) error {
|
|
|
|
_, err := c.UserTyping(roomID, true, 3)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-05-13 17:36:26 -06:00
|
|
|
_, err = c.SendMessageEvent(roomID, "m.room.message", gomatrix.GetHTMLMessage("m.text", message))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-02-26 16:15:02 -07:00
|
|
|
|
|
|
|
_, err = c.UserTyping(roomID, false, 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-04-06 16:38:39 -06:00
|
|
|
// SendMDNotice sends an html notice to a given room. It pretends to be
|
|
|
|
// "typing" by calling UserTyping for the caller.
|
|
|
|
func SendMDNotice(c *gomatrix.Client, roomID, message string) error {
|
|
|
|
_, err := c.UserTyping(roomID, true, 3)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
md := []byte(message)
|
|
|
|
html := markdown.ToHTML(md, nil, nil)
|
2020-05-13 17:36:26 -06:00
|
|
|
_, err = c.SendMessageEvent(roomID, "m.room.message", gomatrix.GetHTMLMessage("m.notice", string(html)))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-04-06 16:38:39 -06:00
|
|
|
|
|
|
|
_, err = c.UserTyping(roomID, false, 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-03-22 14:53:30 -06:00
|
|
|
// SendUnescNotice sends an text notice to a given room. It pretends to be
|
|
|
|
// "typing" by calling UserTyping for the caller.
|
|
|
|
func SendUnescNotice(c *gomatrix.Client, roomID, message string) error {
|
|
|
|
_, err := c.UserTyping(roomID, true, 3)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Undo the escaping
|
|
|
|
_, err = c.SendMessageEvent(roomID, "m.room.message", gomatrix.HTMLMessage{
|
|
|
|
Body: message,
|
|
|
|
MsgType: "m.notice",
|
|
|
|
Format: "org.matrix.custom.text",
|
|
|
|
FormattedBody: message,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = c.UserTyping(roomID, false, 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-10-01 15:27:46 -06:00
|
|
|
// SendNotice sends an text notice to a given room. It pretends to be
|
|
|
|
// "typing" by calling UserTyping for the caller.
|
|
|
|
func SendNotice(c *gomatrix.Client, roomID, message string) error {
|
|
|
|
_, err := c.UserTyping(roomID, true, 3)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = c.SendMessageEvent(roomID, "m.room.message", gomatrix.GetHTMLMessage("m.notice", message))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = c.UserTyping(roomID, false, 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-02-26 16:15:02 -07:00
|
|
|
// SendMD takes markdown and converts it to an html message.
|
|
|
|
func SendMD(c *gomatrix.Client, roomID, message string) error {
|
|
|
|
md := []byte(message)
|
|
|
|
html := markdown.ToHTML(md, nil, nil)
|
2020-05-13 17:36:26 -06:00
|
|
|
return SendHTML(c, roomID, string(html))
|
2020-02-26 16:15:02 -07:00
|
|
|
}
|
|
|
|
|
2020-03-09 20:47:11 -06:00
|
|
|
// SendImage takes an image and sends it!.
|
|
|
|
func SendImage(c *gomatrix.Client, roomID string, img *image.RGBA) error {
|
|
|
|
r, w := io.Pipe()
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
defer w.Close()
|
2020-05-13 17:36:26 -06:00
|
|
|
_ = png.Encode(w, img)
|
2020-03-09 20:47:11 -06:00
|
|
|
}()
|
|
|
|
|
|
|
|
mediaURL, err := c.UploadToContentRepo(r, "image/png", 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = c.SendImage(roomID, "", mediaURL.ContentURI)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-02-02 13:55:18 -07:00
|
|
|
// Plugins is a collection of our plugins. An instance of this is iterated
|
|
|
|
// over for each message the bot receives.
|
2020-01-31 19:57:40 -07:00
|
|
|
type Plugins []Plugin
|
|
|
|
|
2020-02-02 13:55:18 -07:00
|
|
|
// Plugs defines the "enabled" plugins.
|
2020-01-31 19:57:40 -07:00
|
|
|
var Plugs = Plugins{
|
2022-03-11 12:38:28 -07:00
|
|
|
&BananaStab{},
|
2020-02-12 20:12:44 -07:00
|
|
|
&Beat{},
|
2020-02-01 15:14:46 -07:00
|
|
|
&Beer{},
|
2020-01-31 20:27:22 -07:00
|
|
|
&BotSnack{},
|
2020-03-17 18:52:53 -06:00
|
|
|
&Covid{},
|
2021-01-03 12:14:22 -07:00
|
|
|
&DMR{},
|
2020-02-18 20:20:01 -07:00
|
|
|
&Feder{},
|
2020-06-11 17:13:33 -06:00
|
|
|
&Groan{},
|
2020-03-04 08:33:11 -07:00
|
|
|
&Ham{},
|
2020-01-31 19:57:40 -07:00
|
|
|
&HighFive{},
|
|
|
|
&Hi{},
|
2020-02-01 15:15:01 -07:00
|
|
|
&LoveYou{},
|
2020-02-03 16:19:04 -07:00
|
|
|
&OpenBSDMan{},
|
2020-12-22 07:31:45 -07:00
|
|
|
&PGP{},
|
2020-03-09 20:47:43 -06:00
|
|
|
&Palette{},
|
2020-12-22 07:31:45 -07:00
|
|
|
&RFC{},
|
2020-02-23 14:35:07 -07:00
|
|
|
&Snap{},
|
2020-02-01 20:53:56 -07:00
|
|
|
&Source{},
|
2020-02-12 20:13:05 -07:00
|
|
|
&Thanks{},
|
2021-04-01 16:15:25 -06:00
|
|
|
&Homestead{},
|
2020-04-07 16:52:58 -06:00
|
|
|
&Toki{},
|
2020-02-02 07:23:59 -07:00
|
|
|
&Version{},
|
2020-02-07 16:06:24 -07:00
|
|
|
&Wb{},
|
2020-02-05 22:13:23 -07:00
|
|
|
&Weather{},
|
2020-01-31 19:57:40 -07:00
|
|
|
}
|