mirror of https://github.com/fluffle/goirc
264 lines
5.6 KiB
Go
264 lines
5.6 KiB
Go
package main
|
|
|
|
import (
|
|
irc "github.com/fluffle/goirc/client"
|
|
"fmt"
|
|
"strings"
|
|
"runtime"
|
|
"reflect"
|
|
"http"
|
|
"xml"
|
|
"strconv"
|
|
)
|
|
|
|
var commands = map [string]func(*irc.Conn, *irc.Nick, string, string) {
|
|
// access
|
|
"flags": flags,
|
|
"add": add,
|
|
"remove": remove,
|
|
"ignore": ignore,
|
|
"unignore": unignore,
|
|
"list": accesslist,
|
|
|
|
// admin
|
|
"nick": nick,
|
|
"say": csay,
|
|
|
|
// op
|
|
"halfop": halfop,
|
|
"hop": halfop,
|
|
"op": op,
|
|
"deop": deop,
|
|
"dehalfop": dehalfop,
|
|
"dehop": dehalfop,
|
|
"voice": voice,
|
|
"devoice": devoice,
|
|
"kick": kick,
|
|
"k": kick,
|
|
"b": ban,
|
|
"ban": ban,
|
|
"unban": unban,
|
|
"u": unban,
|
|
"kb": kickban,
|
|
"topic": topic,
|
|
"appendtopic": appendtopic,
|
|
"part": part,
|
|
"ops": highlightOps,
|
|
|
|
// google
|
|
"tr": translate,
|
|
"roman": roman,
|
|
"calc": calc,
|
|
}
|
|
|
|
func handlePrivmsg(conn *irc.Conn, line *irc.Line) {
|
|
nick := conn.GetNick(line.Nick)
|
|
if nick == nil {
|
|
return
|
|
}
|
|
nick.Host = line.Host
|
|
if ignores[conn.Network][nick.Host] {
|
|
return
|
|
}
|
|
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
fmt.Println("Recovered from", r)
|
|
callers := make([]uintptr, 10)
|
|
runtime.Callers(4, callers)
|
|
cutoff := runtime.FuncForPC(reflect.ValueOf(handlePrivmsg).Pointer()).Entry()
|
|
for _, pc := range callers {
|
|
function := runtime.FuncForPC(pc - 1)
|
|
if function.Entry() == cutoff{
|
|
break
|
|
}
|
|
file, line := function.FileLine(pc - 1)
|
|
fmt.Printf("%s:%d\n\t%s\n", file, line, function.Name())
|
|
}
|
|
}
|
|
}()
|
|
|
|
target := line.Args[0]
|
|
if isChannel(target) {
|
|
// message to a channel
|
|
if !command(conn, nick, line.Args[1], target) {
|
|
var video string
|
|
if start := strings.Index(line.Args[1], "youtube.com/watch?v="); start > -1 {
|
|
video = line.Args[1][start+20:]
|
|
}
|
|
if start := strings.Index(line.Args[1], "youtu.be/"); start > -1 {
|
|
video = line.Args[1][start+9:]
|
|
}
|
|
if video != "" {
|
|
if end := strings.IndexAny(video, " &#"); end > -1 {
|
|
video = video[0:end]
|
|
}
|
|
youtube(conn, nick, video, target)
|
|
}
|
|
}
|
|
} else if target == conn.Me.Nick {
|
|
// message to us
|
|
command(conn, nick, line.Args[1], line.Nick)
|
|
}
|
|
}
|
|
|
|
func handleMode(conn *irc.Conn, line *irc.Line) {
|
|
if line.Args[0] == conn.Me.Nick && line.Args[1] == "+r" {
|
|
autojoin(conn)
|
|
}
|
|
}
|
|
|
|
func handleJoin(conn *irc.Conn, line *irc.Line) {
|
|
// autovoice users with v flag
|
|
if line.Nick == conn.Me.Nick {
|
|
return
|
|
}
|
|
|
|
channel := conn.GetChannel(line.Args[0])
|
|
if channel == nil || !channel.Modes.Moderated {
|
|
return
|
|
}
|
|
|
|
privs := conn.Me.Channels[channel]
|
|
if !(privs.Op || privs.Admin || privs.HalfOp || privs.Owner) {
|
|
return
|
|
}
|
|
nick := conn.GetNick(line.Nick)
|
|
if nick == nil {
|
|
return
|
|
}
|
|
if hasAccess(conn, nick, line.Nick, "v") {
|
|
conn.Mode(line.Args[0], "+v " + line.Nick)
|
|
}
|
|
}
|
|
|
|
func handleInvite(conn *irc.Conn, line *irc.Line) {
|
|
if line.Args[0] != conn.Me.Nick {
|
|
return
|
|
}
|
|
|
|
user := line.Src[strings.Index(line.Src, "!")+1:]
|
|
if user[0] == '~' {
|
|
user = user[1:]
|
|
}
|
|
|
|
owner, _ := auth.String(conn.Network, "owner")
|
|
if user == owner {
|
|
conn.Join(line.Args[1])
|
|
}
|
|
}
|
|
|
|
func isChannel(target string) bool {
|
|
return target[0] == '#' || target[0] == '&'
|
|
}
|
|
|
|
func command(conn *irc.Conn, nick *irc.Nick, text, target string) bool {
|
|
if !strings.HasPrefix(text, trigger) {
|
|
return false
|
|
}
|
|
split := strings.Split(text, " ", 2)
|
|
if len(split[0]) < 2 {
|
|
return false
|
|
}
|
|
handler := commands[split[0][1:]]
|
|
if handler != nil {
|
|
if len(split) > 1 {
|
|
handler(conn, nick, split[1], target)
|
|
} else {
|
|
handler(conn, nick, "", target)
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func say(conn *irc.Conn, target, message string, a ...interface{}) {
|
|
if len(a) > 0 {
|
|
message = fmt.Sprintf(message, a...)
|
|
}
|
|
text := strings.Replace(message, "\n", " ", -1)
|
|
if isChannel(target) {
|
|
conn.Privmsg(target, text)
|
|
} else {
|
|
conn.Notice(target, text)
|
|
}
|
|
}
|
|
|
|
func youtube(conn *irc.Conn, nick *irc.Nick, video, channel string) {
|
|
url := fmt.Sprintf("http://gdata.youtube.com/feeds/api/videos/%s?v=2", video)
|
|
response, _, err := http.Get(url)
|
|
defer response.Body.Close()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
type duration struct {
|
|
Seconds string "attr"
|
|
}
|
|
type group struct {
|
|
Duration duration
|
|
}
|
|
type entry struct {
|
|
Title string
|
|
Group group
|
|
}
|
|
var yte = entry{"", group{duration{""}}}
|
|
|
|
err = xml.Unmarshal(response.Body, &yte)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
seconds, err := strconv.Atoui(yte.Group.Duration.Seconds)
|
|
if err == nil {
|
|
minutes := seconds / 60
|
|
seconds = seconds % 60
|
|
hours := minutes / 60
|
|
minutes = minutes % 60
|
|
var durationStr string
|
|
if hours > 0 {
|
|
durationStr = fmt.Sprintf("%d:%02d:%02d", hours, minutes, seconds)
|
|
} else {
|
|
durationStr = fmt.Sprintf("%02d:%02d", minutes, seconds)
|
|
}
|
|
say(conn, channel, "%s's video: %s, %s", nick.Nick, yte.Title, durationStr)
|
|
} else {
|
|
say(conn, channel, "%s's video: %s", nick.Nick, yte.Title)
|
|
}
|
|
}
|
|
|
|
// this allows target to be a channel or a privmsg in which the channel is the first argument
|
|
// passing a flag of "" will check if the user has any access
|
|
// returns the channel the user has access on and remaining args
|
|
// or a blank channel if the user doesn't have access on that channel
|
|
func parseAccess(conn *irc.Conn, nick *irc.Nick, target, args, flag string) (string, string) {
|
|
channel, args := parseChannel(target, args)
|
|
if channel == "" {
|
|
return "", args
|
|
}
|
|
if hasAccess(conn, nick, channel, flag) {
|
|
return channel, args
|
|
}
|
|
return "", args
|
|
}
|
|
|
|
func parseChannel(target, args string) (string, string) {
|
|
var channel string
|
|
if isChannel(target) {
|
|
channel = target
|
|
} else {
|
|
split := strings.Split(args, " ", 2)
|
|
if split[0] != "" && isChannel(split[0]) {
|
|
channel = split[0]
|
|
if len(split) == 2 {
|
|
args = split[1]
|
|
} else {
|
|
args = ""
|
|
}
|
|
} else {
|
|
return "", args
|
|
}
|
|
}
|
|
return channel, args
|
|
}
|