111 lines
2.0 KiB
Go
111 lines
2.0 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"flag"
|
||
|
"fmt"
|
||
|
"git.sr.ht/~emersion/soju"
|
||
|
"gopkg.in/irc.v4"
|
||
|
"log"
|
||
|
"net"
|
||
|
"net/url"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
|
||
|
"git.sr.ht/~emersion/soju/config"
|
||
|
)
|
||
|
|
||
|
const usage = `usage: sojuctl [-config path] <command>
|
||
|
`
|
||
|
|
||
|
func init() {
|
||
|
flag.Usage = func() {
|
||
|
fmt.Fprintf(flag.CommandLine.Output(), usage)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func run(ctx context.Context, cfg *config.Server, words []string) error {
|
||
|
var path string
|
||
|
for _, listen := range cfg.Listen {
|
||
|
u, err := url.Parse(listen)
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
if u.Scheme != "unix+admin" {
|
||
|
continue
|
||
|
}
|
||
|
if u.Path != "" {
|
||
|
path = u.Path
|
||
|
} else {
|
||
|
path = soju.DefaultUnixAdminPath
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
if path == "" {
|
||
|
return fmt.Errorf("no listen unix+admin directive found in config")
|
||
|
}
|
||
|
var d net.Dialer
|
||
|
uc, err := d.DialContext(ctx, "unix", path)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("dial %v: %v", path, err)
|
||
|
}
|
||
|
defer uc.Close()
|
||
|
c := irc.NewConn(uc)
|
||
|
if err := c.WriteMessage(&irc.Message{
|
||
|
Command: "BOUNCERSERV",
|
||
|
Params: []string{quoteWords(words)},
|
||
|
}); err != nil {
|
||
|
return fmt.Errorf("write: %v", err)
|
||
|
}
|
||
|
for {
|
||
|
m, err := c.ReadMessage()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("read: %v", err)
|
||
|
}
|
||
|
switch m.Command {
|
||
|
case "PRIVMSG":
|
||
|
fmt.Println(m.Trailing())
|
||
|
case "BOUNCERSERV":
|
||
|
if m.Param(0) == "OK" {
|
||
|
return nil
|
||
|
}
|
||
|
return fmt.Errorf(m.Trailing())
|
||
|
default:
|
||
|
return fmt.Errorf(m.Trailing())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
var configPath string
|
||
|
flag.StringVar(&configPath, "config", config.DefaultPath, "path to configuration file")
|
||
|
flag.Parse()
|
||
|
|
||
|
var cfg *config.Server
|
||
|
if configPath != "" {
|
||
|
var err error
|
||
|
cfg, err = config.Load(configPath)
|
||
|
if err != nil {
|
||
|
log.Fatalf("failed to load config file: %v", err)
|
||
|
}
|
||
|
} else {
|
||
|
cfg = config.Defaults()
|
||
|
}
|
||
|
|
||
|
ctx := context.Background()
|
||
|
if err := run(ctx, cfg, flag.Args()); err != nil {
|
||
|
log.Fatalln(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func quoteWords(words []string) string {
|
||
|
var s strings.Builder
|
||
|
for _, word := range words {
|
||
|
if s.Len() > 0 {
|
||
|
s.WriteRune(' ')
|
||
|
}
|
||
|
s.WriteString(strconv.Quote(word))
|
||
|
}
|
||
|
return s.String()
|
||
|
}
|