package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"regexp"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"gopkg.in/sorcix/irc.v2"
|
|
)
|
|
|
|
const disconnectExitStatus int = 2
|
|
|
|
const PushoverAPI string = "https://api.pushover.net/1/messages.json"
|
|
|
|
func main() {
|
|
config, err := LoadConfig()
|
|
if err != nil {
|
|
log.Fatalf("Unable to configure: %s", err)
|
|
}
|
|
//TODO (noah): probably should check for protocol + port or something
|
|
conn, err := irc.DialTLS(config.Host, &tls.Config{})
|
|
if err != nil {
|
|
log.Fatalf("Unable to connect to IRC server: %s", err)
|
|
}
|
|
|
|
running := true
|
|
//Register signal so we can clean up the socket before we exit
|
|
c := make(chan os.Signal)
|
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
|
signal.Notify(c, os.Interrupt, syscall.SIGINT)
|
|
|
|
go func() {
|
|
<-c
|
|
log.Printf("Exiting")
|
|
running = false
|
|
conn.Close()
|
|
os.Exit(0)
|
|
}()
|
|
if config.Pass != "" {
|
|
_, err = conn.Write([]byte("PASS " + config.Pass))
|
|
if err != nil {
|
|
log.Fatalf("Unable to authenticate to server: %s", err)
|
|
}
|
|
}
|
|
log.Printf("User: %s", config.User)
|
|
_, err = conn.Write([]byte("USER " + config.User))
|
|
if err != nil {
|
|
log.Fatalf("Unable to send message to server: %s", err)
|
|
}
|
|
log.Printf("Nick: %s", config.Nick)
|
|
_, err = conn.Write([]byte("NICK " + config.Nick))
|
|
if err != nil {
|
|
log.Fatalf("Unable to send message to server: %s", err)
|
|
}
|
|
_, err = conn.Write([]byte("WHOIS " + config.Nick))
|
|
if err != nil {
|
|
log.Fatalf("Unable to send message to server: %s", err)
|
|
}
|
|
userRegexp, err := regexp.Compile(`(\w+)!(\w+)@\S+`)
|
|
if err != nil {
|
|
log.Fatalf("Unable to compile user regexp: %s", err)
|
|
}
|
|
|
|
away := false
|
|
for running {
|
|
message, err := conn.Decode()
|
|
if err != nil {
|
|
log.Printf("Unable to decode: %s", err)
|
|
os.Exit(disconnectExitStatus)
|
|
}
|
|
if message == nil {
|
|
continue
|
|
}
|
|
if message.Command == irc.QUIT && message.Prefix.Name == config.Nick {
|
|
log.Printf("Server sent QUIT, exiting")
|
|
running = false
|
|
//Exit with a non-zero status so the system process restarts this process
|
|
os.Exit(disconnectExitStatus)
|
|
}
|
|
for _, user := range config.ExcludeUsers {
|
|
if user == message.Prefix.Name {
|
|
log.Printf("User %s is in excluded users, skipping message", message.Prefix.Name)
|
|
continue
|
|
}
|
|
}
|
|
for _, excludedChannel := range config.ExcludeChannels {
|
|
if message.Params[0] == excludedChannel {
|
|
log.Printf("Channel %s is in excluded channels, skipping message", message.Params[0])
|
|
continue
|
|
}
|
|
}
|
|
if away && message.Command == irc.PRIVMSG {
|
|
matched := false
|
|
for _, matchString := range config.Match {
|
|
if strings.Contains(message.Params[1], matchString) {
|
|
log.Printf("match %s is contained in %s", matchString, message.Params[1])
|
|
matched = true
|
|
break
|
|
}
|
|
}
|
|
if matched {
|
|
log.Print("Message contains search word, sending notification")
|
|
err = sendNotification(config.UserToken, config.AppToken, message)
|
|
if err != nil {
|
|
log.Printf("Unable to send notification: %s", err)
|
|
}
|
|
}
|
|
} else if message.Command == irc.RPL_NOWAWAY {
|
|
log.Printf("Marking as away, will notify")
|
|
away = true
|
|
} else if message.Command == irc.RPL_UNAWAY {
|
|
log.Printf("No longer away, won't notify")
|
|
away = false
|
|
} else if message.Command == irc.RPL_WELCOME {
|
|
matches := userRegexp.FindSubmatch([]byte(message.Params[0]))
|
|
if matches != nil {
|
|
config.Nick = string(matches[0])
|
|
log.Printf("Nick: %s\tUsername %s\tHost: %s", matches[0], matches[1], matches[2])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func sendNotification(user_token, app_token string, message *irc.Message) error {
|
|
body := map[string]string{
|
|
"token": app_token,
|
|
"user": user_token,
|
|
"title": fmt.Sprintf("%s on %s mentioned you", message.Prefix.User, message.Params[0]),
|
|
"message": message.Params[1],
|
|
}
|
|
json_body, err := json.Marshal(body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resp, err := http.Post(PushoverAPI, "application/json", bytes.NewBuffer(json_body))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Printf("Pushover API notify resp code: %d %s", resp.StatusCode, resp.Status)
|
|
return nil
|
|
}
|