1// This program is free software: you can redistribute it and/or modify2// it under the terms of the GNU Affero General Public License as3// published by the Free Software Foundation, either version 3 of the4// License, or (at your option) any later version.5//6// This program is distributed in the hope that it will be useful, but7// WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU9// Affero General Public License for more details.10//11// You should have received a copy of the GNU Affero General Public12// License along with this program. If not, see <http://www.gnu.org/licenses/>.1314package main1516import (17 "bufio"18 "crypto/tls"19 "crypto/x509"20 "flag"21 "fmt"22 "github.com/nmeum/marvin/irc"23 "github.com/nmeum/marvin/modules"24 "io/ioutil"25 "log"26 "net"27 "os"28 "strings"29 "time"30)3132const (33 appName = "marvin"34)3536var (37 conf = flag.String("c", "marvin.json", "configuration file")38 verb = flag.Bool("v", false, "verbose output")39)4041func main() {42 flag.Parse()43 logger := log.New(os.Stderr, "ERROR: ", 0)4445 config, err := readConfig(*conf)46 if err != nil && !os.IsNotExist(err) {47 logger.Fatal(err)48 }4950 conn, err := connect(config)51 if err != nil {52 logger.Fatal(err)53 }54 defer conn.Close()5556 errChan := make(chan error)57 go func() {58 for err := range errChan {59 logger.Println(err)60 }61 }()6263 ircBot, err := setup(conn, config)64 if err != nil {65 logger.Fatal(err)66 }6768 reader := bufio.NewReader(conn)69 for {70 line, err := reader.ReadString('\n')71 if err != nil {72 logger.Println(err)73 break74 }7576 line = strings.Trim(line, "\n")77 line = strings.Trim(line, "\r")7879 if *verb {80 fmt.Println(line)81 }8283 ircBot.Handle(line, errChan)84 }85}8687func setup(conn net.Conn, config config) (client *irc.Client, err error) {88 client = irc.NewClient(conn)89 client.CmdHook("001", func(c *irc.Client, m irc.Message) error {90 time.Sleep(3 * time.Second) // Wait for NickServ etc91 return c.Write("JOIN %s", strings.Join(config.Chan, ","))92 })9394 moduleSet := modules.NewModuleSet(client, config.Conf)95 for _, fn := range moduleInits {96 fn(moduleSet)97 }9899 client.Setup(config.Nick, config.Name, config.Host)100 return client, moduleSet.LoadAll()101}102103func connect(config config) (conn net.Conn, err error) {104 netw := "tcp"105 addr := fmt.Sprintf("%s:%d", config.Host, config.Port)106107 if len(config.Cert) >= 1 {108 certFile, err := ioutil.ReadFile(config.Cert)109 if err != nil {110 return nil, err111 }112113 caCertPool := x509.NewCertPool()114 caCertPool.AppendCertsFromPEM(certFile)115116 tlsConfig := &tls.Config{RootCAs: caCertPool}117 if len(config.ClientCert) >= 1 && len(config.ClientKey) >= 1 {118 clientCert, err := tls.LoadX509KeyPair(config.ClientCert, config.ClientKey)119 if err != nil {120 return nil, err121 }122123 tlsConfig.Certificates = []tls.Certificate{ clientCert }124 }125 return tls.Dial(netw, addr, tlsConfig)126 }127128 return net.Dial(netw, addr)129}