You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

server.go 33KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  1. // Copyright (c) 2012-2014 Jeremy Latt
  2. // Copyright (c) 2014-2015 Edmund Huber
  3. // Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
  4. // released under the MIT license
  5. package irc
  6. import (
  7. "bufio"
  8. "crypto/tls"
  9. "encoding/base64"
  10. "fmt"
  11. "log"
  12. "net"
  13. "net/http"
  14. "os"
  15. "os/signal"
  16. "strconv"
  17. "strings"
  18. "syscall"
  19. "time"
  20. "github.com/DanielOaks/girc-go/ircmsg"
  21. "github.com/tidwall/buntdb"
  22. )
  23. // Limits holds the maximum limits for various things such as topic lengths
  24. type Limits struct {
  25. AwayLen int
  26. ChannelLen int
  27. KickLen int
  28. NickLen int
  29. TopicLen int
  30. }
  31. type Server struct {
  32. accounts map[string]*ClientAccount
  33. channels ChannelNameMap
  34. clients *ClientLookupSet
  35. commands chan Command
  36. ctime time.Time
  37. store buntdb.DB
  38. idle chan *Client
  39. limits Limits
  40. motdLines []string
  41. name string
  42. nameCasefolded string
  43. newConns chan clientConn
  44. operators map[string][]byte
  45. password []byte
  46. passwords *PasswordManager
  47. accountRegistration *AccountRegistration
  48. signals chan os.Signal
  49. proxyAllowedFrom []string
  50. whoWas *WhoWasList
  51. isupport *ISupportList
  52. checkIdent bool
  53. }
  54. var (
  55. SERVER_SIGNALS = []os.Signal{
  56. syscall.SIGINT,
  57. syscall.SIGHUP, // eventually we expect to use HUP to reload config
  58. syscall.SIGTERM,
  59. syscall.SIGQUIT,
  60. }
  61. )
  62. type clientConn struct {
  63. Conn net.Conn
  64. IsTLS bool
  65. }
  66. func NewServer(config *Config) *Server {
  67. casefoldedName, err := Casefold(config.Server.Name)
  68. if err != nil {
  69. log.Println(fmt.Sprintf("Server name isn't valid: []", config.Server.Name), err.Error())
  70. return nil
  71. }
  72. server := &Server{
  73. accounts: make(map[string]*ClientAccount),
  74. channels: make(ChannelNameMap),
  75. clients: NewClientLookupSet(),
  76. commands: make(chan Command),
  77. ctime: time.Now(),
  78. idle: make(chan *Client),
  79. limits: Limits{
  80. AwayLen: config.Limits.AwayLen,
  81. ChannelLen: config.Limits.ChannelLen,
  82. KickLen: config.Limits.KickLen,
  83. NickLen: config.Limits.NickLen,
  84. TopicLen: config.Limits.TopicLen,
  85. },
  86. name: config.Server.Name,
  87. nameCasefolded: casefoldedName,
  88. newConns: make(chan clientConn),
  89. operators: config.Operators(),
  90. signals: make(chan os.Signal, len(SERVER_SIGNALS)),
  91. proxyAllowedFrom: config.Server.ProxyAllowedFrom,
  92. whoWas: NewWhoWasList(config.Limits.WhowasEntries),
  93. checkIdent: config.Server.CheckIdent,
  94. }
  95. // open data store
  96. db, err := buntdb.Open(config.Datastore.Path)
  97. if err != nil {
  98. log.Fatal(fmt.Sprintf("Failed to open datastore: %s", err.Error()))
  99. }
  100. server.store = *db
  101. // load password manager
  102. err = server.store.View(func(tx *buntdb.Tx) error {
  103. saltString, err := tx.Get(keySalt)
  104. if err != nil {
  105. return fmt.Errorf("Could not retrieve salt string: %s", err.Error())
  106. }
  107. salt, err := base64.StdEncoding.DecodeString(saltString)
  108. if err != nil {
  109. return err
  110. }
  111. pwm := NewPasswordManager(salt)
  112. server.passwords = &pwm
  113. return nil
  114. })
  115. if err != nil {
  116. log.Fatal(fmt.Sprintf("Could not load salt: %s", err.Error()))
  117. }
  118. if config.Server.MOTD != "" {
  119. file, err := os.Open(config.Server.MOTD)
  120. if err == nil {
  121. defer file.Close()
  122. reader := bufio.NewReader(file)
  123. for {
  124. line, err := reader.ReadString('\n')
  125. if err != nil {
  126. break
  127. }
  128. line = strings.TrimRight(line, "\r\n")
  129. // "- " is the required prefix for MOTD, we just add it here to make
  130. // bursting it out to clients easier
  131. line = fmt.Sprintf("- %s", line)
  132. server.motdLines = append(server.motdLines, line)
  133. }
  134. }
  135. }
  136. if config.Server.Password != "" {
  137. server.password = config.Server.PasswordBytes()
  138. }
  139. server.loadChannels()
  140. for _, addr := range config.Server.Listen {
  141. server.listen(addr, config.TLSListeners())
  142. }
  143. if config.Server.Wslisten != "" {
  144. server.wslisten(config.Server.Wslisten, config.Server.TLSListeners)
  145. }
  146. // registration
  147. accountReg := NewAccountRegistration(config.Registration.Accounts)
  148. server.accountRegistration = &accountReg
  149. // Attempt to clean up when receiving these signals.
  150. signal.Notify(server.signals, SERVER_SIGNALS...)
  151. // add RPL_ISUPPORT tokens
  152. server.isupport = NewISupportList()
  153. server.isupport.Add("AWAYLEN", strconv.Itoa(server.limits.AwayLen))
  154. server.isupport.Add("CASEMAPPING", "rfc7700")
  155. server.isupport.Add("CHANMODES", strings.Join([]string{ChannelModes{BanMask, ExceptMask, InviteMask}.String(), "", ChannelModes{UserLimit, Key}.String(), ChannelModes{InviteOnly, Moderated, NoOutside, OpOnlyTopic, Persistent, Secret}.String()}, ","))
  156. server.isupport.Add("CHANNELLEN", strconv.Itoa(config.Limits.ChannelLen))
  157. server.isupport.Add("CHANTYPES", "#")
  158. server.isupport.Add("EXCEPTS", "")
  159. server.isupport.Add("INVEX", "")
  160. server.isupport.Add("KICKLEN", strconv.Itoa(server.limits.KickLen))
  161. // server.isupport.Add("MAXLIST", "") //TODO(dan): Support max list length?
  162. // server.isupport.Add("MODES", "") //TODO(dan): Support max modes?
  163. server.isupport.Add("NETWORK", config.Network.Name)
  164. server.isupport.Add("NICKLEN", strconv.Itoa(config.Limits.NickLen))
  165. server.isupport.Add("PREFIX", "(qaohv)~&@%+")
  166. // server.isupport.Add("STATUSMSG", "@+") //TODO(dan): Support STATUSMSG
  167. // server.isupport.Add("TARGMAX", "") //TODO(dan): Support this
  168. server.isupport.Add("TOPICLEN", strconv.Itoa(server.limits.TopicLen))
  169. // account registration
  170. if server.accountRegistration.Enabled {
  171. // 'none' isn't shown in the REGCALLBACKS vars
  172. var enabledCallbacks []string
  173. for _, name := range server.accountRegistration.EnabledCallbacks {
  174. if name != "*" {
  175. enabledCallbacks = append(enabledCallbacks, name)
  176. }
  177. }
  178. server.isupport.Add("REGCOMMANDS", "CREATE,VERIFY")
  179. server.isupport.Add("REGCALLBACKS", strings.Join(enabledCallbacks, ","))
  180. server.isupport.Add("REGCREDTYPES", "passphrase,certfp")
  181. }
  182. server.isupport.RegenerateCachedReply()
  183. return server
  184. }
  185. func loadChannelList(channel *Channel, list string, maskMode ChannelMode) {
  186. if list == "" {
  187. return
  188. }
  189. channel.lists[maskMode].AddAll(strings.Split(list, " "))
  190. }
  191. func (server *Server) loadChannels() {
  192. //TODO(dan): Fix channel persistence
  193. /*
  194. rows, err := server.db.Query(`
  195. SELECT name, flags, key, topic, user_limit, ban_list, except_list,
  196. invite_list
  197. FROM channel`)
  198. if err != nil {
  199. log.Fatal("error loading channels: ", err)
  200. }
  201. for rows.Next() {
  202. var name, flags, key, topic string
  203. var userLimit uint64
  204. var banList, exceptList, inviteList string
  205. err = rows.Scan(&name, &flags, &key, &topic, &userLimit, &banList,
  206. &exceptList, &inviteList)
  207. if err != nil {
  208. log.Println("Server.loadChannels:", err)
  209. continue
  210. }
  211. channel := NewChannel(server, NewName(name), false)
  212. for _, flag := range flags {
  213. channel.flags[ChannelMode(flag)] = true
  214. }
  215. channel.key = key
  216. channel.topic = topic
  217. channel.userLimit = userLimit
  218. loadChannelList(channel, banList, BanMask)
  219. loadChannelList(channel, exceptList, ExceptMask)
  220. loadChannelList(channel, inviteList, InviteMask)
  221. }
  222. */
  223. }
  224. func (server *Server) Shutdown() {
  225. //TODO(dan): Make sure we disallow new nicks
  226. for _, client := range server.clients.byNick {
  227. client.Notice("Server is shutting down")
  228. }
  229. if err := server.store.Close(); err != nil {
  230. Log.error.Println("Server.Shutdown store.Close: error:", err)
  231. }
  232. }
  233. func (server *Server) Run() {
  234. // defer closing db/store
  235. defer server.store.Close()
  236. done := false
  237. for !done {
  238. select {
  239. case <-server.signals:
  240. server.Shutdown()
  241. done = true
  242. case conn := <-server.newConns:
  243. NewClient(server, conn.Conn, conn.IsTLS)
  244. /*TODO(dan): LOOK AT THIS MORE CLOSELY
  245. case cmd := <-server.commands:
  246. server.processCommand(cmd)
  247. */
  248. case client := <-server.idle:
  249. client.Idle()
  250. }
  251. }
  252. }
  253. //
  254. // listen goroutine
  255. //
  256. func (s *Server) listen(addr string, tlsMap map[string]*tls.Config) {
  257. //TODO(dan): we could casemap this but... eh
  258. config, listenTLS := tlsMap[addr]
  259. listener, err := net.Listen("tcp", addr)
  260. if err != nil {
  261. log.Fatal(s, "listen error: ", err)
  262. }
  263. tlsString := "plaintext"
  264. if listenTLS {
  265. config.ClientAuth = tls.RequestClientCert
  266. listener = tls.NewListener(listener, config)
  267. tlsString = "TLS"
  268. }
  269. Log.info.Printf("%s listening on %s using %s.", s.name, addr, tlsString)
  270. go func() {
  271. for {
  272. conn, err := listener.Accept()
  273. if err != nil {
  274. Log.error.Printf("%s accept error: %s", s.name, err)
  275. continue
  276. }
  277. Log.debug.Printf("%s accept: %s", s.name, conn.RemoteAddr())
  278. newConn := clientConn{
  279. Conn: conn,
  280. IsTLS: listenTLS,
  281. }
  282. s.newConns <- newConn
  283. }
  284. }()
  285. }
  286. //
  287. // websocket listen goroutine
  288. //
  289. func (s *Server) wslisten(addr string, tlsMap map[string]*TLSListenConfig) {
  290. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  291. if r.Method != "GET" {
  292. Log.error.Printf("%s method not allowed", s.name)
  293. return
  294. }
  295. // We don't have any subprotocols, so if someone attempts to `new
  296. // WebSocket(server, "subprotocol")` they'll break here, instead of
  297. // getting the default, ambiguous, response from gorilla.
  298. if v, ok := r.Header["Sec-Websocket-Protocol"]; ok {
  299. http.Error(w, fmt.Sprintf("WebSocket subprocotols (e.g. %s) not supported", v), 400)
  300. }
  301. ws, err := upgrader.Upgrade(w, r, nil)
  302. if err != nil {
  303. Log.error.Printf("%s websocket upgrade error: %s", s.name, err)
  304. return
  305. }
  306. newConn := clientConn{
  307. Conn: WSContainer{ws},
  308. IsTLS: false, //TODO(dan): track TLS or not here properly
  309. }
  310. s.newConns <- newConn
  311. })
  312. go func() {
  313. config, listenTLS := tlsMap[addr]
  314. tlsString := "plaintext"
  315. var err error
  316. if listenTLS {
  317. tlsString = "TLS"
  318. }
  319. Log.info.Printf("%s websocket listening on %s using %s.", s.name, addr, tlsString)
  320. if listenTLS {
  321. err = http.ListenAndServeTLS(addr, config.Cert, config.Key, nil)
  322. } else {
  323. err = http.ListenAndServe(addr, nil)
  324. }
  325. if err != nil {
  326. Log.error.Printf("%s listenAndServe (%s) error: %s", s.name, tlsString, err)
  327. }
  328. }()
  329. }
  330. //
  331. // server functionality
  332. //
  333. func (s *Server) tryRegister(c *Client) {
  334. if c.registered || !c.HasNick() || !c.HasUsername() ||
  335. (c.capState == CapNegotiating) {
  336. return
  337. }
  338. c.Register()
  339. // send welcome text
  340. //NOTE(dan): we specifically use the NICK here instead of the nickmask
  341. // see http://modern.ircdocs.horse/#rplwelcome-001 for details on why we avoid using the nickmask
  342. c.Send(nil, s.name, RPL_WELCOME, c.nick, fmt.Sprintf("Welcome to the Internet Relay Network %s", c.nick))
  343. c.Send(nil, s.name, RPL_YOURHOST, c.nick, fmt.Sprintf("Your host is %s, running version %s", s.name, Ver))
  344. c.Send(nil, s.name, RPL_CREATED, c.nick, fmt.Sprintf("This server was created %s", s.ctime.Format(time.RFC1123)))
  345. //TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
  346. c.Send(nil, s.name, RPL_MYINFO, c.nick, s.name, Ver, supportedUserModesString, supportedChannelModesString)
  347. c.RplISupport()
  348. s.MOTD(c)
  349. c.Send(nil, c.nickMaskString, RPL_UMODEIS, c.nick, c.ModeString())
  350. }
  351. func (server *Server) MOTD(client *Client) {
  352. if len(server.motdLines) < 1 {
  353. client.Send(nil, server.name, ERR_NOMOTD, client.nick, "MOTD File is missing")
  354. return
  355. }
  356. client.Send(nil, server.name, RPL_MOTDSTART, client.nick, fmt.Sprintf("- %s Message of the day - ", server.name))
  357. for _, line := range server.motdLines {
  358. client.Send(nil, server.name, RPL_MOTD, client.nick, line)
  359. }
  360. client.Send(nil, server.name, RPL_ENDOFMOTD, client.nick, "End of MOTD command")
  361. }
  362. func (s *Server) Id() string {
  363. return s.name
  364. }
  365. func (s *Server) Nick() string {
  366. return s.Id()
  367. }
  368. //
  369. // registration commands
  370. //
  371. // PASS <password>
  372. func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  373. if client.registered {
  374. client.Send(nil, server.name, ERR_ALREADYREGISTRED, client.nick, "You may not reregister")
  375. return false
  376. }
  377. // if no password exists, skip checking
  378. if len(server.password) == 0 {
  379. client.authorized = true
  380. return false
  381. }
  382. // check the provided password
  383. password := []byte(msg.Params[0])
  384. if ComparePassword(server.password, password) != nil {
  385. client.Send(nil, server.name, ERR_PASSWDMISMATCH, client.nick, "Password incorrect")
  386. client.Send(nil, server.name, "ERROR", "Password incorrect")
  387. return true
  388. }
  389. client.authorized = true
  390. return false
  391. }
  392. // PROXY TCP4/6 SOURCEIP DESTIP SOURCEPORT DESTPORT
  393. // http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
  394. func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  395. clientAddress := IPString(client.socket.conn.RemoteAddr())
  396. clientHostname := client.hostname
  397. for _, address := range server.proxyAllowedFrom {
  398. if clientHostname == address || clientAddress == address {
  399. client.hostname = LookupHostname(msg.Params[1])
  400. return false
  401. }
  402. }
  403. client.Quit("PROXY command is not usable from your address")
  404. return true
  405. }
  406. // USER <username> * 0 <realname>
  407. func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  408. if client.registered {
  409. client.Send(nil, server.name, ERR_ALREADYREGISTRED, client.nick, "You may not reregister")
  410. return false
  411. }
  412. if !client.authorized {
  413. client.Quit("Bad password")
  414. return true
  415. }
  416. if client.username != "" && client.realname != "" {
  417. return false
  418. }
  419. // confirm that username is valid
  420. //
  421. _, err := CasefoldName(msg.Params[0])
  422. if err != nil {
  423. client.Send(nil, "", "ERROR", "Malformed username")
  424. return true
  425. }
  426. // set user info and log client in
  427. //TODO(dan): Could there be a race condition here with adding/removing the client?
  428. //TODO(dan): we should do something like server.clients.Replace(client) instead
  429. // we do it this way to ONLY replace what hasn't already been set
  430. server.clients.Remove(client)
  431. if !client.HasUsername() {
  432. client.username = "~" + msg.Params[0]
  433. client.updateNickMask()
  434. }
  435. if client.realname == "" {
  436. client.realname = msg.Params[3]
  437. }
  438. server.clients.Add(client)
  439. server.tryRegister(client)
  440. return false
  441. }
  442. // QUIT [<reason>]
  443. func quitHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  444. reason := "Quit"
  445. if len(msg.Params) > 0 {
  446. reason += ": " + msg.Params[0]
  447. }
  448. client.Quit(reason)
  449. return true
  450. }
  451. //
  452. // normal commands
  453. //
  454. // PING <server1> [<server2>]
  455. func pingHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  456. client.Send(nil, server.name, "PONG", msg.Params...)
  457. return false
  458. }
  459. // PONG <server> [ <server2> ]
  460. func pongHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  461. // client gets touched when they send this command, so we don't need to do anything
  462. return false
  463. }
  464. // JOIN <channel>{,<channel>} [<key>{,<key>}]
  465. // JOIN 0
  466. func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  467. // handle JOIN 0
  468. if msg.Params[0] == "0" {
  469. for channel := range client.channels {
  470. channel.Part(client, client.nickCasefolded)
  471. }
  472. return false
  473. }
  474. // handle regular JOINs
  475. channels := strings.Split(msg.Params[0], ",")
  476. var keys []string
  477. if len(msg.Params) > 1 {
  478. keys = strings.Split(msg.Params[1], ",")
  479. }
  480. for i, name := range channels {
  481. casefoldedName, err := CasefoldChannel(name)
  482. if err != nil {
  483. log.Println("ISN'T CHANNEL NAME:", name)
  484. client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, name, "No such channel")
  485. continue
  486. }
  487. channel := server.channels.Get(casefoldedName)
  488. if channel == nil {
  489. channel = NewChannel(server, name, true)
  490. }
  491. var key string
  492. if len(keys) > i {
  493. key = keys[i]
  494. }
  495. channel.Join(client, key)
  496. }
  497. return false
  498. }
  499. // PART <channel>{,<channel>} [<reason>]
  500. func partHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  501. channels := strings.Split(msg.Params[0], ",")
  502. var reason string //TODO(dan): if this isn't supplied here, make sure the param doesn't exist in the PART message sent to other users
  503. if len(msg.Params) > 1 {
  504. reason = msg.Params[1]
  505. }
  506. for _, chname := range channels {
  507. casefoldedChannelName, err := CasefoldChannel(chname)
  508. channel := server.channels.Get(casefoldedChannelName)
  509. if err != nil || channel == nil {
  510. client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel")
  511. continue
  512. }
  513. channel.Part(client, reason)
  514. }
  515. return false
  516. }
  517. // TOPIC <channel> [<topic>]
  518. func topicHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  519. name, err := CasefoldChannel(msg.Params[0])
  520. channel := server.channels.Get(name)
  521. if err != nil || channel == nil {
  522. client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], "No such channel")
  523. return false
  524. }
  525. if len(msg.Params) > 1 {
  526. channel.SetTopic(client, msg.Params[1])
  527. } else {
  528. channel.GetTopic(client)
  529. }
  530. return false
  531. }
  532. // PRIVMSG <target>{,<target>} <message>
  533. func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  534. targets := strings.Split(msg.Params[0], ",")
  535. message := msg.Params[1]
  536. for _, targetString := range targets {
  537. target, err := CasefoldChannel(targetString)
  538. if err != nil {
  539. channel := server.channels.Get(target)
  540. if channel == nil {
  541. client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, "No such channel")
  542. continue
  543. }
  544. channel.PrivMsg(client, message)
  545. } else {
  546. target, err = CasefoldName(targetString)
  547. user := server.clients.Get(target)
  548. if err != nil || user == nil {
  549. client.Send(nil, server.name, ERR_NOSUCHNICK, target, "No such nick")
  550. continue
  551. }
  552. user.Send(nil, client.nickMaskString, "PRIVMSG", user.nick, message)
  553. if user.flags[Away] {
  554. //TODO(dan): possibly implement cooldown of away notifications to users
  555. client.Send(nil, server.name, RPL_AWAY, user.nick, user.awayMessage)
  556. }
  557. }
  558. }
  559. return false
  560. }
  561. func (client *Client) WhoisChannelsNames(target *Client) []string {
  562. isMultiPrefix := target.capabilities[MultiPrefix]
  563. var chstrs []string
  564. index := 0
  565. for channel := range client.channels {
  566. // channel is secret and the target can't see it
  567. if !target.flags[Operator] && channel.flags[Secret] && !channel.members.Has(target) {
  568. continue
  569. }
  570. chstrs = append(chstrs, channel.members[client].Prefixes(isMultiPrefix)+channel.name)
  571. index++
  572. }
  573. return chstrs
  574. }
  575. // WHOIS [ <target> ] <mask> *( "," <mask> )
  576. func whoisHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  577. var masksString string
  578. //var target string
  579. if len(msg.Params) > 1 {
  580. //target = msg.Params[0]
  581. masksString = msg.Params[1]
  582. } else {
  583. masksString = msg.Params[0]
  584. }
  585. if client.flags[Operator] {
  586. masks := strings.Split(masksString, ",")
  587. for _, mask := range masks {
  588. casefoldedMask, err := Casefold(mask)
  589. if err != nil {
  590. client.Send(nil, client.server.name, ERR_NOSUCHNICK, mask, "No such nick")
  591. continue
  592. }
  593. matches := server.clients.FindAll(casefoldedMask)
  594. if len(matches) == 0 {
  595. client.Send(nil, client.server.name, ERR_NOSUCHNICK, mask, "No such nick")
  596. continue
  597. }
  598. for mclient := range matches {
  599. client.getWhoisOf(mclient)
  600. }
  601. }
  602. } else {
  603. // specifically treat this as a single lookup rather than splitting as we do above
  604. // this is by design
  605. casefoldedMask, err := Casefold(masksString)
  606. mclient := server.clients.Get(casefoldedMask)
  607. if err != nil || mclient == nil {
  608. client.Send(nil, client.server.name, ERR_NOSUCHNICK, masksString, "No such nick")
  609. // fall through, ENDOFWHOIS is always sent
  610. } else {
  611. client.getWhoisOf(mclient)
  612. }
  613. }
  614. client.Send(nil, server.name, RPL_ENDOFWHOIS, client.nick, masksString, "End of /WHOIS list")
  615. return false
  616. }
  617. func (client *Client) getWhoisOf(target *Client) {
  618. client.Send(nil, client.server.name, RPL_WHOISUSER, client.nick, target.nick, target.username, target.hostname, "*", target.realname)
  619. //TODO(dan): ...one channel per reply? really?
  620. for _, line := range client.WhoisChannelsNames(target) {
  621. client.Send(nil, client.server.name, RPL_WHOISCHANNELS, client.nick, target.nick, line)
  622. }
  623. if target.flags[Operator] {
  624. client.Send(nil, client.server.name, RPL_WHOISOPERATOR, client.nick, target.nick, "is an IRC operator")
  625. }
  626. if target.certfp != "" && (client.flags[Operator] || client == target) {
  627. client.Send(nil, client.server.name, RPL_WHOISCERTFP, client.nick, target.nick, fmt.Sprintf("has client certificate fingerprint %s", target.certfp))
  628. }
  629. client.Send(nil, client.server.name, RPL_WHOISIDLE, client.nick, target.nick, strconv.FormatUint(target.IdleSeconds(), 10), strconv.FormatInt(target.SignonTime(), 10), "seconds idle, signon time")
  630. }
  631. // <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
  632. // :<hopcount> <real name>
  633. func (target *Client) RplWhoReply(channel *Channel, client *Client) {
  634. channelName := "*"
  635. flags := ""
  636. if client.flags[Away] {
  637. flags = "G"
  638. } else {
  639. flags = "H"
  640. }
  641. if client.flags[Operator] {
  642. flags += "*"
  643. }
  644. if channel != nil {
  645. flags += channel.members[client].Prefixes(target.capabilities[MultiPrefix])
  646. channelName = channel.name
  647. }
  648. target.Send(nil, target.server.name, RPL_WHOREPLY, target.nick, channelName, client.username, client.hostname, client.server.name, client.nick, flags, string(client.hops), client.realname)
  649. }
  650. func whoChannel(client *Client, channel *Channel, friends ClientSet) {
  651. for member := range channel.members {
  652. if !client.flags[Invisible] || friends[client] {
  653. client.RplWhoReply(channel, member)
  654. }
  655. }
  656. }
  657. // WHO [ <mask> [ "o" ] ]
  658. func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  659. friends := client.Friends()
  660. var mask string
  661. if len(msg.Params) > 0 {
  662. casefoldedMask, err := Casefold(msg.Params[0])
  663. if err != nil {
  664. client.Send(nil, server.name, ERR_UNKNOWNERROR, "WHO", "Mask isn't valid")
  665. return false
  666. }
  667. mask = casefoldedMask
  668. }
  669. //TODO(dan): is this used and would I put this param in the Modern doc?
  670. // if not, can we remove it?
  671. //var operatorOnly bool
  672. //if len(msg.Params) > 1 && msg.Params[1] == "o" {
  673. // operatorOnly = true
  674. //}
  675. if mask == "" {
  676. for _, channel := range server.channels {
  677. whoChannel(client, channel, friends)
  678. }
  679. } else if mask[0] == '#' {
  680. // TODO implement wildcard matching
  681. //TODO(dan): ^ only for opers
  682. channel := server.channels.Get(mask)
  683. if channel != nil {
  684. whoChannel(client, channel, friends)
  685. }
  686. } else {
  687. for mclient := range server.clients.FindAll(mask) {
  688. client.RplWhoReply(nil, mclient)
  689. }
  690. }
  691. client.Send(nil, server.name, RPL_ENDOFWHO, client.nick, mask, "End of WHO list")
  692. return false
  693. }
  694. // OPER <name> <password>
  695. func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  696. name, err := CasefoldName(msg.Params[0])
  697. if err != nil {
  698. client.Send(nil, server.name, ERR_PASSWDMISMATCH, client.nick, "Password incorrect")
  699. return true
  700. }
  701. hash := server.operators[name]
  702. password := []byte(msg.Params[1])
  703. err = ComparePassword(hash, password)
  704. if (hash == nil) || (err != nil) {
  705. client.Send(nil, server.name, ERR_PASSWDMISMATCH, client.nick, "Password incorrect")
  706. return true
  707. }
  708. client.flags[Operator] = true
  709. client.Send(nil, server.name, RPL_YOUREOPER, client.nick, "You are now an IRC operator")
  710. //TODO(dan): Should this be sent automagically as part of setting the flag/mode?
  711. modech := ModeChanges{&ModeChange{
  712. mode: Operator,
  713. op: Add,
  714. }}
  715. client.Send(nil, server.name, "MODE", client.nick, modech.String())
  716. return false
  717. }
  718. // AWAY [<message>]
  719. func awayHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  720. var isAway bool
  721. var text string
  722. if len(msg.Params) > 0 {
  723. isAway = true
  724. text = msg.Params[0]
  725. if len(text) > server.limits.AwayLen {
  726. text = text[:server.limits.AwayLen]
  727. }
  728. }
  729. if isAway {
  730. client.flags[Away] = true
  731. } else {
  732. delete(client.flags, Away)
  733. }
  734. client.awayMessage = text
  735. var op ModeOp
  736. if client.flags[Away] {
  737. op = Add
  738. client.Send(nil, server.name, RPL_NOWAWAY, client.nick, "You have been marked as being away")
  739. } else {
  740. op = Remove
  741. client.Send(nil, server.name, RPL_UNAWAY, client.nick, "You are no longer marked as being away")
  742. }
  743. //TODO(dan): Should this be sent automagically as part of setting the flag/mode?
  744. modech := ModeChanges{&ModeChange{
  745. mode: Away,
  746. op: op,
  747. }}
  748. client.Send(nil, server.name, "MODE", client.nick, client.nick, modech.String())
  749. // dispatch away-notify
  750. for friend := range client.Friends(AwayNotify) {
  751. if client.flags[Away] {
  752. friend.SendFromClient(client, nil, client.nickMaskString, "AWAY", client.awayMessage)
  753. } else {
  754. friend.SendFromClient(client, nil, client.nickMaskString, "AWAY")
  755. }
  756. }
  757. return false
  758. }
  759. // ISON <nick>{ <nick>}
  760. func isonHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  761. var nicks = msg.Params
  762. var err error
  763. var casefoldedNick string
  764. ison := make([]string, 0)
  765. for _, nick := range nicks {
  766. casefoldedNick, err = CasefoldName(nick)
  767. if err != nil {
  768. continue
  769. }
  770. if iclient := server.clients.Get(casefoldedNick); iclient != nil {
  771. ison = append(ison, iclient.nick)
  772. }
  773. }
  774. client.Send(nil, server.name, RPL_ISON, client.nick, strings.Join(nicks, " "))
  775. return false
  776. }
  777. // MOTD [<target>]
  778. func motdHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  779. //TODO(dan): hook this up when we have multiple servers I guess???
  780. //var target string
  781. //if len(msg.Params) > 0 {
  782. // target = msg.Params[0]
  783. //}
  784. server.MOTD(client)
  785. return false
  786. }
  787. // NOTICE <target>{,<target>} <message>
  788. func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  789. targets := strings.Split(msg.Params[0], ",")
  790. message := msg.Params[1]
  791. for _, targetString := range targets {
  792. target, cerr := CasefoldChannel(targetString)
  793. if cerr == nil {
  794. channel := server.channels.Get(target)
  795. if channel == nil {
  796. // errors silently ignored with NOTICE as per RFC
  797. continue
  798. }
  799. channel.PrivMsg(client, message)
  800. } else {
  801. target, err := CasefoldName(targetString)
  802. if err != nil {
  803. continue
  804. }
  805. user := server.clients.Get(target)
  806. if user == nil {
  807. // errors silently ignored with NOTICE as per RFC
  808. continue
  809. }
  810. user.Send(nil, client.nickMaskString, "NOTICE", user.nick, message)
  811. }
  812. }
  813. return false
  814. }
  815. // KICK <channel>{,<channel>} <user>{,<user>} [<comment>]
  816. func kickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  817. channels := strings.Split(msg.Params[0], ",")
  818. users := strings.Split(msg.Params[1], ",")
  819. if (len(channels) != len(users)) && (len(users) != 1) {
  820. client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, "KICK", "Not enough parameters")
  821. return false
  822. }
  823. kicks := make(map[string]string)
  824. for index, channel := range channels {
  825. if len(users) == 1 {
  826. kicks[channel] = users[0]
  827. } else {
  828. kicks[channel] = users[index]
  829. }
  830. }
  831. var comment string
  832. if len(msg.Params) > 2 {
  833. comment = msg.Params[2]
  834. }
  835. for chname, nickname := range kicks {
  836. casefoldedChname, err := CasefoldChannel(chname)
  837. channel := server.channels.Get(casefoldedChname)
  838. if err != nil || channel == nil {
  839. client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel")
  840. continue
  841. }
  842. casefoldedNickname, err := CasefoldName(nickname)
  843. target := server.clients.Get(casefoldedNickname)
  844. if err != nil || target == nil {
  845. client.Send(nil, server.name, ERR_NOSUCHNICK, nickname, "No such nick")
  846. continue
  847. }
  848. // make sure client has privs to kick the given user
  849. //TODO(dan): split this into a separate function that checks if users have privs
  850. // over other users, useful for things like -aoh as well
  851. var hasPrivs bool
  852. for _, mode := range ChannelPrivModes {
  853. if channel.members[client][mode] {
  854. hasPrivs = true
  855. // admins cannot kick other admins
  856. if mode == ChannelAdmin && channel.members[target][ChannelAdmin] {
  857. hasPrivs = false
  858. }
  859. break
  860. } else if channel.members[target][mode] {
  861. break
  862. }
  863. }
  864. if hasPrivs {
  865. if comment == "" {
  866. comment = nickname
  867. }
  868. channel.Kick(client, target, comment)
  869. } else {
  870. client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, chname, "You're not a channel operator")
  871. }
  872. }
  873. return false
  874. }
  875. // LIST [<channel>{,<channel>} [<server>]]
  876. func listHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  877. var channels []string
  878. if len(msg.Params) > 0 {
  879. channels = strings.Split(msg.Params[0], ",")
  880. }
  881. var target string
  882. if len(msg.Params) > 1 {
  883. target = msg.Params[1]
  884. }
  885. //TODO(dan): target server when we have multiple servers
  886. //TODO(dan): we should continue just fine if it's this current server though
  887. if target != "" {
  888. client.Send(nil, server.name, ERR_NOSUCHSERVER, client.nick, target, "No such server")
  889. return false
  890. }
  891. if len(channels) == 0 {
  892. for _, channel := range server.channels {
  893. if !client.flags[Operator] && channel.flags[Secret] {
  894. continue
  895. }
  896. client.RplList(channel)
  897. }
  898. } else {
  899. for _, chname := range channels {
  900. casefoldedChname, err := CasefoldChannel(chname)
  901. channel := server.channels.Get(casefoldedChname)
  902. if err != nil || channel == nil || (!client.flags[Operator] && channel.flags[Secret]) {
  903. client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel")
  904. continue
  905. }
  906. client.RplList(channel)
  907. }
  908. }
  909. client.Send(nil, server.name, RPL_LISTEND, client.nick, "End of LIST")
  910. return false
  911. }
  912. func (target *Client) RplList(channel *Channel) {
  913. // get the correct number of channel members
  914. var memberCount int
  915. if target.flags[Operator] || channel.members.Has(target) {
  916. memberCount = len(channel.members)
  917. } else {
  918. for member := range channel.members {
  919. if !member.flags[Invisible] {
  920. memberCount += 1
  921. }
  922. }
  923. }
  924. target.Send(nil, target.server.name, RPL_LIST, target.nick, channel.name, string(memberCount), channel.topic)
  925. }
  926. // NAMES [<channel>{,<channel>}]
  927. func namesHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  928. var channels []string
  929. if len(msg.Params) > 0 {
  930. channels = strings.Split(msg.Params[0], ",")
  931. }
  932. //var target string
  933. //if len(msg.Params) > 1 {
  934. // target = msg.Params[1]
  935. //}
  936. if len(channels) == 0 {
  937. for _, channel := range server.channels {
  938. channel.Names(client)
  939. }
  940. return false
  941. }
  942. for _, chname := range channels {
  943. casefoldedChname, err := CasefoldChannel(chname)
  944. channel := server.channels.Get(casefoldedChname)
  945. if err != nil || channel == nil {
  946. client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel")
  947. continue
  948. }
  949. channel.Names(client)
  950. }
  951. return false
  952. }
  953. // VERSION [<server>]
  954. func versionHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  955. var target string
  956. if len(msg.Params) > 0 {
  957. target = msg.Params[0]
  958. }
  959. casefoldedTarget, err := Casefold(target)
  960. if (target != "") && err != nil || (casefoldedTarget != server.nameCasefolded) {
  961. client.Send(nil, server.name, ERR_NOSUCHSERVER, client.nick, target, "No such server")
  962. return false
  963. }
  964. client.Send(nil, server.name, RPL_VERSION, client.nick, Ver, server.name)
  965. client.RplISupport()
  966. return false
  967. }
  968. // INVITE <nickname> <channel>
  969. func inviteHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  970. nickname := msg.Params[0]
  971. channelName := msg.Params[1]
  972. casefoldedNickname, err := CasefoldName(nickname)
  973. target := server.clients.Get(casefoldedNickname)
  974. if err != nil || target == nil {
  975. client.Send(nil, server.name, ERR_NOSUCHNICK, client.nick, nickname, "No such nick")
  976. return false
  977. }
  978. casefoldedChannelName, err := CasefoldChannel(channelName)
  979. channel := server.channels.Get(casefoldedChannelName)
  980. if err != nil || channel == nil {
  981. client.Send(nil, server.name, RPL_INVITING, client.nick, target.nick, channelName)
  982. target.Send(nil, client.nickMaskString, "INVITE", target.nick, channel.name)
  983. return true
  984. }
  985. channel.Invite(target, client)
  986. return false
  987. }
  988. // TIME [<server>]
  989. func timeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  990. var target string
  991. if len(msg.Params) > 0 {
  992. target = msg.Params[0]
  993. }
  994. casefoldedTarget, err := Casefold(target)
  995. if (target != "") && err != nil || (casefoldedTarget != server.nameCasefolded) {
  996. client.Send(nil, server.name, ERR_NOSUCHSERVER, client.nick, target, "No such server")
  997. return false
  998. }
  999. client.Send(nil, server.name, RPL_TIME, client.nick, server.name, time.Now().Format(time.RFC1123))
  1000. return false
  1001. }
  1002. // KILL <nickname> <comment>
  1003. func killHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  1004. nickname := msg.Params[0]
  1005. comment := "<no reason supplied>"
  1006. if len(msg.Params) > 1 {
  1007. comment = msg.Params[1]
  1008. }
  1009. casefoldedNickname, err := CasefoldName(nickname)
  1010. target := server.clients.Get(casefoldedNickname)
  1011. if err != nil || target == nil {
  1012. client.Send(nil, client.server.name, ERR_NOSUCHNICK, nickname, "No such nick")
  1013. return false
  1014. }
  1015. quitMsg := fmt.Sprintf("Killed (%s (%s))", client.nick, comment)
  1016. target.Quit(quitMsg)
  1017. target.destroy()
  1018. return false
  1019. }
  1020. // WHOWAS <nickname> [<count> [<server>]]
  1021. func whowasHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  1022. nicknames := strings.Split(msg.Params[0], ",")
  1023. var count int64
  1024. if len(msg.Params) > 1 {
  1025. count, _ = strconv.ParseInt(msg.Params[1], 10, 64)
  1026. }
  1027. //var target string
  1028. //if len(msg.Params) > 2 {
  1029. // target = msg.Params[2]
  1030. //}
  1031. for _, nickname := range nicknames {
  1032. results := server.whoWas.Find(nickname, count)
  1033. if len(results) == 0 {
  1034. client.Send(nil, server.name, ERR_WASNOSUCHNICK, client.nick, nickname, "There was no such nickname")
  1035. } else {
  1036. for _, whoWas := range results {
  1037. client.Send(nil, server.name, RPL_WHOWASUSER, client.nick, whoWas.nickname, whoWas.username, whoWas.hostname, "*", whoWas.realname)
  1038. }
  1039. }
  1040. client.Send(nil, server.name, RPL_ENDOFWHOWAS, client.nick, nickname, "End of WHOWAS")
  1041. }
  1042. return false
  1043. }