Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

server.go 39KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  1. // Copyright (c) 2012-2014 Jeremy Latt
  2. // Copyright (c) 2014-2015 Edmund Huber
  3. // Copyright (c) 2016-2017 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. "errors"
  11. "fmt"
  12. "log"
  13. "math/rand"
  14. "net"
  15. "os"
  16. "os/signal"
  17. "strconv"
  18. "strings"
  19. "sync"
  20. "syscall"
  21. "time"
  22. "github.com/goshuirc/irc-go/ircfmt"
  23. "github.com/goshuirc/irc-go/ircmsg"
  24. "github.com/oragono/oragono/irc/caps"
  25. "github.com/oragono/oragono/irc/connection_limits"
  26. "github.com/oragono/oragono/irc/isupport"
  27. "github.com/oragono/oragono/irc/languages"
  28. "github.com/oragono/oragono/irc/logger"
  29. "github.com/oragono/oragono/irc/modes"
  30. "github.com/oragono/oragono/irc/passwd"
  31. "github.com/oragono/oragono/irc/sno"
  32. "github.com/oragono/oragono/irc/utils"
  33. "github.com/tidwall/buntdb"
  34. )
  35. var (
  36. // common error line to sub values into
  37. errorMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "%s ")}[0]).Line()
  38. // common error responses
  39. couldNotParseIPMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "Unable to parse your IP address")}[0]).Line()
  40. RenamePrivsNeeded = errors.New("Only chanops can rename channels")
  41. // supportedUserModesString acts as a cache for when we introduce users
  42. supportedUserModesString = modes.SupportedUserModes.String()
  43. // supportedChannelModesString acts as a cache for when we introduce users
  44. supportedChannelModesString = modes.SupportedChannelModes.String()
  45. // SupportedCapabilities are the caps we advertise.
  46. // MaxLine, SASL and STS are set during server startup.
  47. SupportedCapabilities = caps.NewSet(caps.AccountTag, caps.AccountNotify, caps.AwayNotify, caps.CapNotify, caps.ChgHost, caps.EchoMessage, caps.ExtendedJoin, caps.InviteNotify, caps.Languages, caps.MessageTags, caps.MultiPrefix, caps.Rename, caps.Resume, caps.ServerTime, caps.UserhostInNames)
  48. // CapValues are the actual values we advertise to v3.2 clients.
  49. // actual values are set during server startup.
  50. CapValues = caps.NewValues()
  51. )
  52. // Limits holds the maximum limits for various things such as topic lengths.
  53. type Limits struct {
  54. AwayLen int
  55. ChannelLen int
  56. KickLen int
  57. MonitorEntries int
  58. NickLen int
  59. TopicLen int
  60. ChanListModes int
  61. LineLen LineLenLimits
  62. }
  63. // LineLenLimits holds the maximum limits for IRC lines.
  64. type LineLenLimits struct {
  65. Tags int
  66. Rest int
  67. }
  68. // ListenerWrapper wraps a listener so it can be safely reconfigured or stopped
  69. type ListenerWrapper struct {
  70. listener net.Listener
  71. tlsConfig *tls.Config
  72. shouldStop bool
  73. // lets the ListenerWrapper inform the server that it has stopped:
  74. stopEvent chan bool
  75. // protects atomic update of tlsConfig and shouldStop:
  76. configMutex sync.Mutex // tier 1
  77. }
  78. // Server is the main Oragono server.
  79. type Server struct {
  80. accountAuthenticationEnabled bool
  81. accountRegistration *AccountRegistration
  82. accounts map[string]*ClientAccount
  83. channelRegistrationEnabled bool
  84. channels *ChannelManager
  85. channelRegistry *ChannelRegistry
  86. checkIdent bool
  87. clients *ClientManager
  88. configFilename string
  89. configurableStateMutex sync.RWMutex // tier 1; generic protection for server state modified by rehash()
  90. connectionLimiter *connection_limits.Limiter
  91. connectionThrottler *connection_limits.Throttler
  92. ctime time.Time
  93. defaultChannelModes modes.Modes
  94. dlines *DLineManager
  95. loggingRawIO bool
  96. isupport *isupport.List
  97. klines *KLineManager
  98. languages *languages.Manager
  99. limits Limits
  100. listeners map[string]*ListenerWrapper
  101. logger *logger.Manager
  102. MaxSendQBytes uint64
  103. monitorManager *MonitorManager
  104. motdLines []string
  105. name string
  106. nameCasefolded string
  107. networkName string
  108. operators map[string]Oper
  109. operclasses map[string]OperClass
  110. password []byte
  111. passwords *passwd.SaltedManager
  112. recoverFromErrors bool
  113. rehashMutex sync.Mutex // tier 3
  114. rehashSignal chan os.Signal
  115. proxyAllowedFrom []string
  116. signals chan os.Signal
  117. snomasks *SnoManager
  118. store *buntdb.DB
  119. stsEnabled bool
  120. webirc []webircConfig
  121. whoWas *WhoWasList
  122. }
  123. var (
  124. // ServerExitSignals are the signals the server will exit on.
  125. ServerExitSignals = []os.Signal{
  126. syscall.SIGINT,
  127. syscall.SIGTERM,
  128. syscall.SIGQUIT,
  129. }
  130. )
  131. type clientConn struct {
  132. Conn net.Conn
  133. IsTLS bool
  134. }
  135. // NewServer returns a new Oragono server.
  136. func NewServer(config *Config, logger *logger.Manager) (*Server, error) {
  137. // initialize data structures
  138. server := &Server{
  139. accounts: make(map[string]*ClientAccount),
  140. channels: NewChannelManager(),
  141. clients: NewClientManager(),
  142. connectionLimiter: connection_limits.NewLimiter(),
  143. connectionThrottler: connection_limits.NewThrottler(),
  144. languages: languages.NewManager(config.Languages.Default, config.Languages.Data),
  145. listeners: make(map[string]*ListenerWrapper),
  146. logger: logger,
  147. monitorManager: NewMonitorManager(),
  148. rehashSignal: make(chan os.Signal, 1),
  149. signals: make(chan os.Signal, len(ServerExitSignals)),
  150. snomasks: NewSnoManager(),
  151. whoWas: NewWhoWasList(config.Limits.WhowasEntries),
  152. }
  153. if err := server.applyConfig(config, true); err != nil {
  154. return nil, err
  155. }
  156. // generate help info
  157. if err := GenerateHelpIndices(server.languages); err != nil {
  158. return nil, err
  159. }
  160. // Attempt to clean up when receiving these signals.
  161. signal.Notify(server.signals, ServerExitSignals...)
  162. signal.Notify(server.rehashSignal, syscall.SIGHUP)
  163. return server, nil
  164. }
  165. // setISupport sets up our RPL_ISUPPORT reply.
  166. func (server *Server) setISupport() {
  167. maxTargetsString := strconv.Itoa(maxTargets)
  168. server.configurableStateMutex.RLock()
  169. // add RPL_ISUPPORT tokens
  170. isupport := isupport.NewList()
  171. isupport.Add("AWAYLEN", strconv.Itoa(server.limits.AwayLen))
  172. isupport.Add("CASEMAPPING", "ascii")
  173. isupport.Add("CHANMODES", strings.Join([]string{modes.Modes{modes.BanMask, modes.ExceptMask, modes.InviteMask}.String(), "", modes.Modes{modes.UserLimit, modes.Key}.String(), modes.Modes{modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.ChanRoleplaying, modes.Secret}.String()}, ","))
  174. isupport.Add("CHANNELLEN", strconv.Itoa(server.limits.ChannelLen))
  175. isupport.Add("CHANTYPES", "#")
  176. isupport.Add("ELIST", "U")
  177. isupport.Add("EXCEPTS", "")
  178. isupport.Add("INVEX", "")
  179. isupport.Add("KICKLEN", strconv.Itoa(server.limits.KickLen))
  180. isupport.Add("MAXLIST", fmt.Sprintf("beI:%s", strconv.Itoa(server.limits.ChanListModes)))
  181. isupport.Add("MAXTARGETS", maxTargetsString)
  182. isupport.Add("MODES", "")
  183. isupport.Add("MONITOR", strconv.Itoa(server.limits.MonitorEntries))
  184. isupport.Add("NETWORK", server.networkName)
  185. isupport.Add("NICKLEN", strconv.Itoa(server.limits.NickLen))
  186. isupport.Add("PREFIX", "(qaohv)~&@%+")
  187. isupport.Add("RPCHAN", "E")
  188. isupport.Add("RPUSER", "E")
  189. isupport.Add("STATUSMSG", "~&@%+")
  190. isupport.Add("TARGMAX", fmt.Sprintf("NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:%s,TAGMSG:%s,NOTICE:%s,MONITOR:", maxTargetsString, maxTargetsString, maxTargetsString))
  191. isupport.Add("TOPICLEN", strconv.Itoa(server.limits.TopicLen))
  192. isupport.Add("UTF8MAPPING", casemappingName)
  193. // account registration
  194. if server.accountRegistration.Enabled {
  195. // 'none' isn't shown in the REGCALLBACKS vars
  196. var enabledCallbacks []string
  197. for _, name := range server.accountRegistration.EnabledCallbacks {
  198. if name != "*" {
  199. enabledCallbacks = append(enabledCallbacks, name)
  200. }
  201. }
  202. isupport.Add("REGCOMMANDS", "CREATE,VERIFY")
  203. isupport.Add("REGCALLBACKS", strings.Join(enabledCallbacks, ","))
  204. isupport.Add("REGCREDTYPES", "passphrase,certfp")
  205. }
  206. server.configurableStateMutex.RUnlock()
  207. isupport.RegenerateCachedReply()
  208. server.configurableStateMutex.Lock()
  209. server.isupport = isupport
  210. server.configurableStateMutex.Unlock()
  211. }
  212. func loadChannelList(channel *Channel, list string, maskMode modes.Mode) {
  213. if list == "" {
  214. return
  215. }
  216. channel.lists[maskMode].AddAll(strings.Split(list, " "))
  217. }
  218. // Shutdown shuts down the server.
  219. func (server *Server) Shutdown() {
  220. //TODO(dan): Make sure we disallow new nicks
  221. for _, client := range server.clients.AllClients() {
  222. client.Notice("Server is shutting down")
  223. }
  224. if err := server.store.Close(); err != nil {
  225. server.logger.Error("shutdown", fmt.Sprintln("Could not close datastore:", err))
  226. }
  227. }
  228. // Run starts the server.
  229. func (server *Server) Run() {
  230. // defer closing db/store
  231. defer server.store.Close()
  232. for {
  233. select {
  234. case <-server.signals:
  235. server.Shutdown()
  236. return
  237. case <-server.rehashSignal:
  238. go func() {
  239. server.logger.Info("rehash", "Rehashing due to SIGHUP")
  240. err := server.rehash()
  241. if err != nil {
  242. server.logger.Error("rehash", fmt.Sprintln("Failed to rehash:", err.Error()))
  243. }
  244. }()
  245. }
  246. }
  247. }
  248. func (server *Server) acceptClient(conn clientConn) {
  249. // check IP address
  250. ipaddr := utils.AddrToIP(conn.Conn.RemoteAddr())
  251. if ipaddr != nil {
  252. isBanned, banMsg := server.checkBans(ipaddr)
  253. if isBanned {
  254. // this might not show up properly on some clients, but our objective here is just to close the connection out before it has a load impact on us
  255. conn.Conn.Write([]byte(fmt.Sprintf(errorMsg, banMsg)))
  256. conn.Conn.Close()
  257. return
  258. }
  259. }
  260. server.logger.Debug("localconnect-ip", fmt.Sprintf("Client connecting from %v", ipaddr))
  261. // prolly don't need to alert snomasks on this, only on connection reg
  262. NewClient(server, conn.Conn, conn.IsTLS)
  263. }
  264. func (server *Server) checkBans(ipaddr net.IP) (banned bool, message string) {
  265. // check DLINEs
  266. isBanned, info := server.dlines.CheckIP(ipaddr)
  267. if isBanned {
  268. server.logger.Info("localconnect-ip", fmt.Sprintf("Client from %v rejected by d-line", ipaddr))
  269. return true, info.BanMessage("You are banned from this server (%s)")
  270. }
  271. // check connection limits
  272. err := server.connectionLimiter.AddClient(ipaddr, false)
  273. if err != nil {
  274. // too many connections from one client, tell the client and close the connection
  275. server.logger.Info("localconnect-ip", fmt.Sprintf("Client from %v rejected for connection limit", ipaddr))
  276. return true, "Too many clients from your network"
  277. }
  278. // check connection throttle
  279. err = server.connectionThrottler.AddClient(ipaddr)
  280. if err != nil {
  281. // too many connections too quickly from client, tell them and close the connection
  282. duration := server.connectionThrottler.BanDuration()
  283. length := &IPRestrictTime{
  284. Duration: duration,
  285. Expires: time.Now().Add(duration),
  286. }
  287. server.dlines.AddIP(ipaddr, length, server.connectionThrottler.BanMessage(), "Exceeded automated connection throttle", "auto.connection.throttler")
  288. // they're DLINE'd for 15 minutes or whatever, so we can reset the connection throttle now,
  289. // and once their temporary DLINE is finished they can fill up the throttler again
  290. server.connectionThrottler.ResetFor(ipaddr)
  291. // this might not show up properly on some clients, but our objective here is just to close it out before it has a load impact on us
  292. server.logger.Info(
  293. "localconnect-ip",
  294. fmt.Sprintf("Client from %v exceeded connection throttle, d-lining for %v", ipaddr, duration))
  295. return true, server.connectionThrottler.BanMessage()
  296. }
  297. return false, ""
  298. }
  299. //
  300. // IRC protocol listeners
  301. //
  302. // createListener starts the given listeners.
  303. func (server *Server) createListener(addr string, tlsConfig *tls.Config) *ListenerWrapper {
  304. // make listener
  305. var listener net.Listener
  306. var err error
  307. optional_unix_prefix := "unix:"
  308. optional_prefix_len := len(optional_unix_prefix)
  309. if len(addr) >= optional_prefix_len && strings.ToLower(addr[0:optional_prefix_len]) == optional_unix_prefix {
  310. addr = addr[optional_prefix_len:]
  311. if len(addr) == 0 || addr[0] != '/' {
  312. log.Fatal("Bad unix socket address", addr)
  313. }
  314. }
  315. if len(addr) > 0 && addr[0] == '/' {
  316. // https://stackoverflow.com/a/34881585
  317. os.Remove(addr)
  318. listener, err = net.Listen("unix", addr)
  319. } else {
  320. listener, err = net.Listen("tcp", addr)
  321. }
  322. if err != nil {
  323. log.Fatal(server, "listen error: ", err)
  324. }
  325. // throw our details to the server so we can be modified/killed later
  326. wrapper := ListenerWrapper{
  327. listener: listener,
  328. tlsConfig: tlsConfig,
  329. shouldStop: false,
  330. stopEvent: make(chan bool, 1),
  331. }
  332. var shouldStop bool
  333. // setup accept goroutine
  334. go func() {
  335. for {
  336. conn, err := listener.Accept()
  337. // synchronously access config data:
  338. // whether TLS is enabled and whether we should stop listening
  339. wrapper.configMutex.Lock()
  340. shouldStop = wrapper.shouldStop
  341. tlsConfig = wrapper.tlsConfig
  342. wrapper.configMutex.Unlock()
  343. if err == nil {
  344. if tlsConfig != nil {
  345. conn = tls.Server(conn, tlsConfig)
  346. }
  347. newConn := clientConn{
  348. Conn: conn,
  349. IsTLS: tlsConfig != nil,
  350. }
  351. // hand off the connection
  352. go server.acceptClient(newConn)
  353. }
  354. if shouldStop {
  355. listener.Close()
  356. wrapper.stopEvent <- true
  357. return
  358. }
  359. }
  360. }()
  361. return &wrapper
  362. }
  363. // generateMessageID returns a network-unique message ID.
  364. func (server *Server) generateMessageID() string {
  365. // we don't need the full like 30 chars since the unixnano below handles
  366. // most of our uniqueness requirements, so just truncate at 5
  367. lastbit := strconv.FormatInt(rand.Int63(), 36)
  368. if 5 < len(lastbit) {
  369. lastbit = lastbit[:4]
  370. }
  371. return fmt.Sprintf("%s%s", strconv.FormatInt(time.Now().UTC().UnixNano(), 36), lastbit)
  372. }
  373. //
  374. // server functionality
  375. //
  376. func (server *Server) tryRegister(c *Client) {
  377. if c.registered || !c.HasNick() || !c.HasUsername() ||
  378. (c.capState == caps.NegotiatingState) {
  379. return
  380. }
  381. // check KLINEs
  382. isBanned, info := server.klines.CheckMasks(c.AllNickmasks()...)
  383. if isBanned {
  384. reason := info.Reason
  385. if info.Time != nil {
  386. reason += fmt.Sprintf(" [%s]", info.Time.Duration.String())
  387. }
  388. c.Quit(fmt.Sprintf(c.t("You are banned from this server (%s)"), reason))
  389. c.destroy(false)
  390. return
  391. }
  392. // continue registration
  393. server.logger.Debug("localconnect", fmt.Sprintf("Client registered [%s] [u:%s] [r:%s]", c.nick, c.username, c.realname))
  394. server.snomasks.Send(sno.LocalConnects, fmt.Sprintf(ircfmt.Unescape("Client registered $c[grey][$r%s$c[grey]] [u:$r%s$c[grey]] [h:$r%s$c[grey]] [r:$r%s$c[grey]]"), c.nick, c.username, c.rawHostname, c.realname))
  395. c.Register()
  396. // send welcome text
  397. //NOTE(dan): we specifically use the NICK here instead of the nickmask
  398. // see http://modern.ircdocs.horse/#rplwelcome-001 for details on why we avoid using the nickmask
  399. c.Send(nil, server.name, RPL_WELCOME, c.nick, fmt.Sprintf(c.t("Welcome to the Internet Relay Network %s"), c.nick))
  400. c.Send(nil, server.name, RPL_YOURHOST, c.nick, fmt.Sprintf(c.t("Your host is %[1]s, running version %[2]s"), server.name, Ver))
  401. c.Send(nil, server.name, RPL_CREATED, c.nick, fmt.Sprintf(c.t("This server was created %s"), server.ctime.Format(time.RFC1123)))
  402. //TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
  403. c.Send(nil, server.name, RPL_MYINFO, c.nick, server.name, Ver, supportedUserModesString, supportedChannelModesString)
  404. c.RplISupport()
  405. server.MOTD(c)
  406. c.Send(nil, c.nickMaskString, RPL_UMODEIS, c.nick, c.ModeString())
  407. if server.logger.IsLoggingRawIO() {
  408. c.Notice(c.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
  409. }
  410. // if resumed, send fake channel joins
  411. if c.resumeDetails != nil {
  412. for _, name := range c.resumeDetails.SendFakeJoinsFor {
  413. channel := server.channels.Get(name)
  414. if channel == nil {
  415. continue
  416. }
  417. if c.capabilities.Has(caps.ExtendedJoin) {
  418. c.Send(nil, c.nickMaskString, "JOIN", channel.name, c.account.Name, c.realname)
  419. } else {
  420. c.Send(nil, c.nickMaskString, "JOIN", channel.name)
  421. }
  422. channel.SendTopic(c)
  423. channel.Names(c)
  424. // construct and send fake modestring if necessary
  425. c.stateMutex.RLock()
  426. myModes := channel.members[c]
  427. c.stateMutex.RUnlock()
  428. if myModes == nil {
  429. continue
  430. }
  431. oldModes := myModes.String()
  432. if 0 < len(oldModes) {
  433. params := []string{channel.name, "+" + oldModes}
  434. for _ = range oldModes {
  435. params = append(params, c.nick)
  436. }
  437. c.Send(nil, server.name, "MODE", params...)
  438. }
  439. }
  440. }
  441. }
  442. // t returns the translated version of the given string, based on the languages configured by the client.
  443. func (client *Client) t(originalString string) string {
  444. // grab this mutex to protect client.languages
  445. client.stateMutex.RLock()
  446. defer client.stateMutex.RUnlock()
  447. return client.server.languages.Translate(client.languages, originalString)
  448. }
  449. // MOTD serves the Message of the Day.
  450. func (server *Server) MOTD(client *Client) {
  451. server.configurableStateMutex.RLock()
  452. motdLines := server.motdLines
  453. server.configurableStateMutex.RUnlock()
  454. if len(motdLines) < 1 {
  455. client.Send(nil, server.name, ERR_NOMOTD, client.nick, client.t("MOTD File is missing"))
  456. return
  457. }
  458. client.Send(nil, server.name, RPL_MOTDSTART, client.nick, fmt.Sprintf(client.t("- %s Message of the day - "), server.name))
  459. for _, line := range motdLines {
  460. client.Send(nil, server.name, RPL_MOTD, client.nick, line)
  461. }
  462. client.Send(nil, server.name, RPL_ENDOFMOTD, client.nick, client.t("End of MOTD command"))
  463. }
  464. // wordWrap wraps the given text into a series of lines that don't exceed lineWidth characters.
  465. func wordWrap(text string, lineWidth int) []string {
  466. var lines []string
  467. var cacheLine, cacheWord string
  468. for _, char := range text {
  469. if char == '\r' {
  470. continue
  471. } else if char == '\n' {
  472. cacheLine += cacheWord
  473. lines = append(lines, cacheLine)
  474. cacheWord = ""
  475. cacheLine = ""
  476. } else if (char == ' ' || char == '-') && len(cacheLine)+len(cacheWord)+1 < lineWidth {
  477. // natural word boundary
  478. cacheLine += cacheWord + string(char)
  479. cacheWord = ""
  480. } else if lineWidth <= len(cacheLine)+len(cacheWord)+1 {
  481. // time to wrap to next line
  482. if len(cacheLine) < (lineWidth / 2) {
  483. // this word takes up more than half a line... just split in the middle of the word
  484. cacheLine += cacheWord + string(char)
  485. cacheWord = ""
  486. } else {
  487. cacheWord += string(char)
  488. }
  489. lines = append(lines, cacheLine)
  490. cacheLine = ""
  491. } else {
  492. // normal character
  493. cacheWord += string(char)
  494. }
  495. }
  496. if 0 < len(cacheWord) {
  497. cacheLine += cacheWord
  498. }
  499. if 0 < len(cacheLine) {
  500. lines = append(lines, cacheLine)
  501. }
  502. return lines
  503. }
  504. // SplitMessage represents a message that's been split for sending.
  505. type SplitMessage struct {
  506. For512 []string
  507. ForMaxLine string
  508. }
  509. func (server *Server) splitMessage(original string, origIs512 bool) SplitMessage {
  510. var newSplit SplitMessage
  511. newSplit.ForMaxLine = original
  512. if !origIs512 {
  513. newSplit.For512 = wordWrap(original, 400)
  514. } else {
  515. newSplit.For512 = []string{original}
  516. }
  517. return newSplit
  518. }
  519. // WhoisChannelsNames returns the common channel names between two users.
  520. func (client *Client) WhoisChannelsNames(target *Client) []string {
  521. isMultiPrefix := target.capabilities.Has(caps.MultiPrefix)
  522. var chstrs []string
  523. for _, channel := range client.Channels() {
  524. // channel is secret and the target can't see it
  525. if !target.flags[modes.Operator] && channel.HasMode(modes.Secret) && !channel.hasClient(target) {
  526. continue
  527. }
  528. chstrs = append(chstrs, channel.ClientPrefixes(client, isMultiPrefix)+channel.name)
  529. }
  530. return chstrs
  531. }
  532. func (client *Client) getWhoisOf(target *Client) {
  533. target.stateMutex.RLock()
  534. defer target.stateMutex.RUnlock()
  535. client.Send(nil, client.server.name, RPL_WHOISUSER, client.nick, target.nick, target.username, target.hostname, "*", target.realname)
  536. whoischannels := client.WhoisChannelsNames(target)
  537. if whoischannels != nil {
  538. client.Send(nil, client.server.name, RPL_WHOISCHANNELS, client.nick, target.nick, strings.Join(whoischannels, " "))
  539. }
  540. if target.class != nil {
  541. client.Send(nil, client.server.name, RPL_WHOISOPERATOR, client.nick, target.nick, target.whoisLine)
  542. }
  543. if client.flags[modes.Operator] || client == target {
  544. client.Send(nil, client.server.name, RPL_WHOISACTUALLY, client.nick, target.nick, fmt.Sprintf("%s@%s", target.username, utils.LookupHostname(target.IPString())), target.IPString(), client.t("Actual user@host, Actual IP"))
  545. }
  546. if target.flags[modes.TLS] {
  547. client.Send(nil, client.server.name, RPL_WHOISSECURE, client.nick, target.nick, client.t("is using a secure connection"))
  548. }
  549. accountName := target.AccountName()
  550. if accountName != "" {
  551. client.Send(nil, client.server.name, RPL_WHOISACCOUNT, client.nick, accountName, client.t("is logged in as"))
  552. }
  553. if target.flags[modes.Bot] {
  554. client.Send(nil, client.server.name, RPL_WHOISBOT, client.nick, target.nick, ircfmt.Unescape(fmt.Sprintf(client.t("is a $bBot$b on %s"), client.server.networkName)))
  555. }
  556. if 0 < len(target.languages) {
  557. params := []string{client.nick, target.nick}
  558. for _, str := range client.server.languages.Codes(target.languages) {
  559. params = append(params, str)
  560. }
  561. params = append(params, client.t("can speak these languages"))
  562. client.Send(nil, client.server.name, RPL_WHOISLANGUAGE, params...)
  563. }
  564. if target.certfp != "" && (client.flags[modes.Operator] || client == target) {
  565. client.Send(nil, client.server.name, RPL_WHOISCERTFP, client.nick, target.nick, fmt.Sprintf(client.t("has client certificate fingerprint %s"), target.certfp))
  566. }
  567. client.Send(nil, client.server.name, RPL_WHOISIDLE, client.nick, target.nick, strconv.FormatUint(target.IdleSeconds(), 10), strconv.FormatInt(target.SignonTime(), 10), client.t("seconds idle, signon time"))
  568. }
  569. // rplWhoReply returns the WHO reply between one user and another channel/user.
  570. // <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
  571. // :<hopcount> <real name>
  572. func (target *Client) rplWhoReply(channel *Channel, client *Client) {
  573. channelName := "*"
  574. flags := ""
  575. if client.HasMode(modes.Away) {
  576. flags = "G"
  577. } else {
  578. flags = "H"
  579. }
  580. if client.HasMode(modes.Operator) {
  581. flags += "*"
  582. }
  583. if channel != nil {
  584. flags += channel.ClientPrefixes(client, target.capabilities.Has(caps.MultiPrefix))
  585. channelName = channel.name
  586. }
  587. target.Send(nil, target.server.name, RPL_WHOREPLY, target.nick, channelName, client.Username(), client.Hostname(), client.server.name, client.Nick(), flags, strconv.Itoa(client.hops)+" "+client.Realname())
  588. }
  589. func whoChannel(client *Client, channel *Channel, friends ClientSet) {
  590. for _, member := range channel.Members() {
  591. if !client.flags[modes.Invisible] || friends[client] {
  592. client.rplWhoReply(channel, member)
  593. }
  594. }
  595. }
  596. // rehash reloads the config and applies the changes from the config file.
  597. func (server *Server) rehash() error {
  598. server.logger.Debug("rehash", "Starting rehash")
  599. // only let one REHASH go on at a time
  600. server.rehashMutex.Lock()
  601. defer server.rehashMutex.Unlock()
  602. server.logger.Debug("rehash", "Got rehash lock")
  603. config, err := LoadConfig(server.configFilename)
  604. if err != nil {
  605. return fmt.Errorf("Error loading config file config: %s", err.Error())
  606. }
  607. err = server.applyConfig(config, false)
  608. if err != nil {
  609. return fmt.Errorf("Error applying config changes: %s", err.Error())
  610. }
  611. return nil
  612. }
  613. func (server *Server) applyConfig(config *Config, initial bool) error {
  614. if initial {
  615. server.ctime = time.Now()
  616. server.configFilename = config.Filename
  617. } else {
  618. // enforce configs that can't be changed after launch:
  619. if server.limits.LineLen.Tags != config.Limits.LineLen.Tags || server.limits.LineLen.Rest != config.Limits.LineLen.Rest {
  620. return fmt.Errorf("Maximum line length (linelen) cannot be changed after launching the server, rehash aborted")
  621. } else if server.name != config.Server.Name {
  622. return fmt.Errorf("Server name cannot be changed after launching the server, rehash aborted")
  623. }
  624. }
  625. casefoldedName, err := Casefold(config.Server.Name)
  626. if err != nil {
  627. return fmt.Errorf("Server name isn't valid [%s]: %s", config.Server.Name, err.Error())
  628. }
  629. // confirm operator stuff all exists and is fine
  630. operclasses, err := config.OperatorClasses()
  631. if err != nil {
  632. return fmt.Errorf("Error rehashing config file operclasses: %s", err.Error())
  633. }
  634. opers, err := config.Operators(operclasses)
  635. if err != nil {
  636. return fmt.Errorf("Error rehashing config file opers: %s", err.Error())
  637. }
  638. // TODO: support rehash of existing operator perms?
  639. // sanity checks complete, start modifying server state
  640. if initial {
  641. server.name = config.Server.Name
  642. server.nameCasefolded = casefoldedName
  643. }
  644. server.configurableStateMutex.Lock()
  645. server.networkName = config.Network.Name
  646. if config.Server.Password != "" {
  647. server.password = config.Server.PasswordBytes()
  648. } else {
  649. server.password = nil
  650. }
  651. // apply new WebIRC command restrictions
  652. server.webirc = config.Server.WebIRC
  653. // apply new PROXY command restrictions
  654. server.proxyAllowedFrom = config.Server.ProxyAllowedFrom
  655. server.recoverFromErrors = true
  656. if config.Debug.RecoverFromErrors != nil {
  657. server.recoverFromErrors = *config.Debug.RecoverFromErrors
  658. }
  659. server.configurableStateMutex.Unlock()
  660. err = server.connectionLimiter.ApplyConfig(config.Server.ConnectionLimiter)
  661. if err != nil {
  662. return err
  663. }
  664. err = server.connectionThrottler.ApplyConfig(config.Server.ConnectionThrottler)
  665. if err != nil {
  666. return err
  667. }
  668. // setup new and removed caps
  669. addedCaps := caps.NewSet()
  670. removedCaps := caps.NewSet()
  671. updatedCaps := caps.NewSet()
  672. // Translations
  673. currentLanguageValue, _ := CapValues.Get(caps.Languages)
  674. langCodes := []string{strconv.Itoa(len(config.Languages.Data) + 1), "en"}
  675. for _, info := range config.Languages.Data {
  676. if info.Incomplete {
  677. langCodes = append(langCodes, "~"+info.Code)
  678. } else {
  679. langCodes = append(langCodes, info.Code)
  680. }
  681. }
  682. newLanguageValue := strings.Join(langCodes, ",")
  683. server.logger.Debug("rehash", "Languages:", newLanguageValue)
  684. if currentLanguageValue != newLanguageValue {
  685. updatedCaps.Add(caps.Languages)
  686. CapValues.Set(caps.Languages, newLanguageValue)
  687. }
  688. lm := languages.NewManager(config.Languages.Default, config.Languages.Data)
  689. server.logger.Debug("rehash", "Regenerating HELP indexes for new languages")
  690. GenerateHelpIndices(lm)
  691. server.languages = lm
  692. // SASL
  693. if config.Accounts.AuthenticationEnabled && !server.accountAuthenticationEnabled {
  694. // enabling SASL
  695. SupportedCapabilities.Enable(caps.SASL)
  696. CapValues.Set(caps.SASL, "PLAIN,EXTERNAL")
  697. addedCaps.Add(caps.SASL)
  698. }
  699. if !config.Accounts.AuthenticationEnabled && server.accountAuthenticationEnabled {
  700. // disabling SASL
  701. SupportedCapabilities.Disable(caps.SASL)
  702. removedCaps.Add(caps.SASL)
  703. }
  704. server.accountAuthenticationEnabled = config.Accounts.AuthenticationEnabled
  705. // STS
  706. stsValue := config.Server.STS.Value()
  707. var stsDisabled bool
  708. stsCurrentCapValue, _ := CapValues.Get(caps.STS)
  709. server.logger.Debug("rehash", "STS Vals", stsCurrentCapValue, stsValue, fmt.Sprintf("server[%v] config[%v]", server.stsEnabled, config.Server.STS.Enabled))
  710. if config.Server.STS.Enabled && !server.stsEnabled {
  711. // enabling STS
  712. SupportedCapabilities.Enable(caps.STS)
  713. addedCaps.Add(caps.STS)
  714. CapValues.Set(caps.STS, stsValue)
  715. } else if !config.Server.STS.Enabled && server.stsEnabled {
  716. // disabling STS
  717. SupportedCapabilities.Disable(caps.STS)
  718. removedCaps.Add(caps.STS)
  719. stsDisabled = true
  720. } else if config.Server.STS.Enabled && server.stsEnabled && stsValue != stsCurrentCapValue {
  721. // STS policy updated
  722. CapValues.Set(caps.STS, stsValue)
  723. updatedCaps.Add(caps.STS)
  724. }
  725. server.stsEnabled = config.Server.STS.Enabled
  726. // burst new and removed caps
  727. var capBurstClients ClientSet
  728. added := make(map[caps.Version]string)
  729. var removed string
  730. // updated caps get DEL'd and then NEW'd
  731. // so, we can just add updated ones to both removed and added lists here and they'll be correctly handled
  732. server.logger.Debug("rehash", "Updated Caps", updatedCaps.String(caps.Cap301, CapValues), strconv.Itoa(updatedCaps.Count()))
  733. for _, capab := range updatedCaps.List() {
  734. addedCaps.Enable(capab)
  735. removedCaps.Enable(capab)
  736. }
  737. if 0 < addedCaps.Count() || 0 < removedCaps.Count() {
  738. capBurstClients = server.clients.AllWithCaps(caps.CapNotify)
  739. added[caps.Cap301] = addedCaps.String(caps.Cap301, CapValues)
  740. added[caps.Cap302] = addedCaps.String(caps.Cap302, CapValues)
  741. // removed never has values, so we leave it as Cap301
  742. removed = removedCaps.String(caps.Cap301, CapValues)
  743. }
  744. for sClient := range capBurstClients {
  745. if stsDisabled {
  746. // remove STS policy
  747. //TODO(dan): this is an ugly hack. we can write this better.
  748. stsPolicy := "sts=duration=0"
  749. if 0 < addedCaps.Count() {
  750. added[caps.Cap302] = added[caps.Cap302] + " " + stsPolicy
  751. } else {
  752. addedCaps.Enable(caps.STS)
  753. added[caps.Cap302] = stsPolicy
  754. }
  755. }
  756. // DEL caps and then send NEW ones so that updated caps get removed/added correctly
  757. if 0 < removedCaps.Count() {
  758. sClient.Send(nil, server.name, "CAP", sClient.nick, "DEL", removed)
  759. }
  760. if 0 < addedCaps.Count() {
  761. sClient.Send(nil, server.name, "CAP", sClient.nick, "NEW", added[sClient.capVersion])
  762. }
  763. }
  764. // set server options
  765. server.configurableStateMutex.Lock()
  766. lineLenConfig := LineLenLimits{
  767. Tags: config.Limits.LineLen.Tags,
  768. Rest: config.Limits.LineLen.Rest,
  769. }
  770. server.limits = Limits{
  771. AwayLen: int(config.Limits.AwayLen),
  772. ChannelLen: int(config.Limits.ChannelLen),
  773. KickLen: int(config.Limits.KickLen),
  774. MonitorEntries: int(config.Limits.MonitorEntries),
  775. NickLen: int(config.Limits.NickLen),
  776. TopicLen: int(config.Limits.TopicLen),
  777. ChanListModes: int(config.Limits.ChanListModes),
  778. LineLen: lineLenConfig,
  779. }
  780. server.operclasses = *operclasses
  781. server.operators = opers
  782. server.checkIdent = config.Server.CheckIdent
  783. // registration
  784. accountReg := NewAccountRegistration(config.Accounts.Registration)
  785. server.accountRegistration = &accountReg
  786. server.channelRegistrationEnabled = config.Channels.Registration.Enabled
  787. server.defaultChannelModes = ParseDefaultChannelModes(config)
  788. server.configurableStateMutex.Unlock()
  789. // set new sendqueue size
  790. if config.Server.MaxSendQBytes != server.MaxSendQBytes {
  791. server.configurableStateMutex.Lock()
  792. server.MaxSendQBytes = config.Server.MaxSendQBytes
  793. server.configurableStateMutex.Unlock()
  794. // update on all clients
  795. for _, sClient := range server.clients.AllClients() {
  796. sClient.socket.MaxSendQBytes = config.Server.MaxSendQBytes
  797. }
  798. }
  799. // set RPL_ISUPPORT
  800. var newISupportReplies [][]string
  801. oldISupportList := server.isupport
  802. server.setISupport()
  803. if oldISupportList != nil {
  804. newISupportReplies = oldISupportList.GetDifference(server.isupport)
  805. }
  806. server.loadMOTD(config.Server.MOTD, config.Server.MOTDFormatting)
  807. // reload logging config
  808. err = server.logger.ApplyConfig(config.Logging)
  809. if err != nil {
  810. return err
  811. }
  812. nowLoggingRawIO := server.logger.IsLoggingRawIO()
  813. // notify clients if raw i/o logging was enabled by a rehash
  814. sendRawOutputNotice := !initial && !server.loggingRawIO && nowLoggingRawIO
  815. server.loggingRawIO = nowLoggingRawIO
  816. if initial {
  817. if err := server.loadDatastore(config.Datastore.Path); err != nil {
  818. return err
  819. }
  820. }
  821. // we are now open for business
  822. server.setupListeners(config)
  823. if !initial {
  824. // push new info to all of our clients
  825. for _, sClient := range server.clients.AllClients() {
  826. for _, tokenline := range newISupportReplies {
  827. sClient.Send(nil, server.name, RPL_ISUPPORT, append([]string{sClient.nick}, tokenline...)...)
  828. }
  829. if sendRawOutputNotice {
  830. sClient.Notice(sClient.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
  831. }
  832. }
  833. }
  834. return nil
  835. }
  836. func (server *Server) loadMOTD(motdPath string, useFormatting bool) error {
  837. server.logger.Debug("rehash", "Loading MOTD")
  838. motdLines := make([]string, 0)
  839. if motdPath != "" {
  840. file, err := os.Open(motdPath)
  841. if err == nil {
  842. defer file.Close()
  843. reader := bufio.NewReader(file)
  844. for {
  845. line, err := reader.ReadString('\n')
  846. if err != nil {
  847. break
  848. }
  849. line = strings.TrimRight(line, "\r\n")
  850. if useFormatting {
  851. line = ircfmt.Unescape(line)
  852. }
  853. // "- " is the required prefix for MOTD, we just add it here to make
  854. // bursting it out to clients easier
  855. line = fmt.Sprintf("- %s", line)
  856. motdLines = append(motdLines, line)
  857. }
  858. } else {
  859. return err
  860. }
  861. }
  862. server.configurableStateMutex.Lock()
  863. server.motdLines = motdLines
  864. server.configurableStateMutex.Unlock()
  865. return nil
  866. }
  867. func (server *Server) loadDatastore(datastorePath string) error {
  868. // open the datastore and load server state for which it (rather than config)
  869. // is the source of truth
  870. server.logger.Debug("startup", "Opening datastore")
  871. db, err := OpenDatabase(datastorePath)
  872. if err == nil {
  873. server.store = db
  874. } else {
  875. return fmt.Errorf("Failed to open datastore: %s", err.Error())
  876. }
  877. // load *lines (from the datastores)
  878. server.logger.Debug("startup", "Loading D/Klines")
  879. server.loadDLines()
  880. server.loadKLines()
  881. // load password manager
  882. server.logger.Debug("startup", "Loading passwords")
  883. err = server.store.View(func(tx *buntdb.Tx) error {
  884. saltString, err := tx.Get(keySalt)
  885. if err != nil {
  886. return fmt.Errorf("Could not retrieve salt string: %s", err.Error())
  887. }
  888. salt, err := base64.StdEncoding.DecodeString(saltString)
  889. if err != nil {
  890. return err
  891. }
  892. pwm := passwd.NewSaltedManager(salt)
  893. server.passwords = &pwm
  894. return nil
  895. })
  896. if err != nil {
  897. return fmt.Errorf("Could not load salt: %s", err.Error())
  898. }
  899. server.channelRegistry = NewChannelRegistry(server)
  900. return nil
  901. }
  902. func (server *Server) setupListeners(config *Config) {
  903. logListener := func(addr string, tlsconfig *tls.Config) {
  904. server.logger.Info("listeners",
  905. fmt.Sprintf("now listening on %s, tls=%t.", addr, (tlsconfig != nil)),
  906. )
  907. }
  908. // update or destroy all existing listeners
  909. tlsListeners := config.TLSListeners()
  910. for addr := range server.listeners {
  911. currentListener := server.listeners[addr]
  912. var stillConfigured bool
  913. for _, newaddr := range config.Server.Listen {
  914. if newaddr == addr {
  915. stillConfigured = true
  916. break
  917. }
  918. }
  919. // pass new config information to the listener, to be picked up after
  920. // its next Accept(). this is like sending over a buffered channel of
  921. // size 1, but where sending a second item overwrites the buffered item
  922. // instead of blocking.
  923. currentListener.configMutex.Lock()
  924. currentListener.shouldStop = !stillConfigured
  925. currentListener.tlsConfig = tlsListeners[addr]
  926. currentListener.configMutex.Unlock()
  927. if stillConfigured {
  928. logListener(addr, currentListener.tlsConfig)
  929. } else {
  930. // tell the listener it should stop by interrupting its Accept() call:
  931. currentListener.listener.Close()
  932. // TODO(golang1.10) delete stopEvent once issue #21856 is released
  933. <-currentListener.stopEvent
  934. delete(server.listeners, addr)
  935. server.logger.Info("listeners", fmt.Sprintf("stopped listening on %s.", addr))
  936. }
  937. }
  938. // create new listeners that were not previously configured
  939. for _, newaddr := range config.Server.Listen {
  940. _, exists := server.listeners[newaddr]
  941. if !exists {
  942. // make new listener
  943. tlsConfig := tlsListeners[newaddr]
  944. server.listeners[newaddr] = server.createListener(newaddr, tlsConfig)
  945. logListener(newaddr, tlsConfig)
  946. }
  947. }
  948. if len(tlsListeners) == 0 {
  949. server.logger.Warning("startup", "You are not exposing an SSL/TLS listening port. You should expose at least one port (typically 6697) to accept TLS connections")
  950. }
  951. var usesStandardTLSPort bool
  952. for addr := range config.TLSListeners() {
  953. if strings.Contains(addr, "6697") {
  954. usesStandardTLSPort = true
  955. break
  956. }
  957. }
  958. if 0 < len(tlsListeners) && !usesStandardTLSPort {
  959. server.logger.Warning("startup", "Port 6697 is the standard TLS port for IRC. You should (also) expose port 6697 as a TLS port to ensure clients can connect securely")
  960. }
  961. }
  962. // GetDefaultChannelModes returns our default channel modes.
  963. func (server *Server) GetDefaultChannelModes() modes.Modes {
  964. server.configurableStateMutex.RLock()
  965. defer server.configurableStateMutex.RUnlock()
  966. return server.defaultChannelModes
  967. }
  968. // elistMatcher takes and matches ELIST conditions
  969. type elistMatcher struct {
  970. MinClientsActive bool
  971. MinClients int
  972. MaxClientsActive bool
  973. MaxClients int
  974. }
  975. // Matches checks whether the given channel matches our matches.
  976. func (matcher *elistMatcher) Matches(channel *Channel) bool {
  977. if matcher.MinClientsActive {
  978. if len(channel.Members()) < matcher.MinClients {
  979. return false
  980. }
  981. }
  982. if matcher.MaxClientsActive {
  983. if len(channel.Members()) < len(channel.members) {
  984. return false
  985. }
  986. }
  987. return true
  988. }
  989. // RplList returns the RPL_LIST numeric for the given channel.
  990. func (target *Client) RplList(channel *Channel) {
  991. // get the correct number of channel members
  992. var memberCount int
  993. if target.flags[modes.Operator] || channel.hasClient(target) {
  994. memberCount = len(channel.Members())
  995. } else {
  996. for _, member := range channel.Members() {
  997. if !member.HasMode(modes.Invisible) {
  998. memberCount++
  999. }
  1000. }
  1001. }
  1002. target.Send(nil, target.server.name, RPL_LIST, target.nick, channel.name, strconv.Itoa(memberCount), channel.topic)
  1003. }
  1004. // NAMES [<channel>{,<channel>}]
  1005. func namesHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  1006. var channels []string
  1007. if len(msg.Params) > 0 {
  1008. channels = strings.Split(msg.Params[0], ",")
  1009. }
  1010. //var target string
  1011. //if len(msg.Params) > 1 {
  1012. // target = msg.Params[1]
  1013. //}
  1014. if len(channels) == 0 {
  1015. for _, channel := range server.channels.Channels() {
  1016. channel.Names(client)
  1017. }
  1018. return false
  1019. }
  1020. // limit regular users to only listing one channel
  1021. if !client.flags[modes.Operator] {
  1022. channels = channels[:1]
  1023. }
  1024. for _, chname := range channels {
  1025. casefoldedChname, err := CasefoldChannel(chname)
  1026. channel := server.channels.Get(casefoldedChname)
  1027. if err != nil || channel == nil {
  1028. if len(chname) > 0 {
  1029. client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, client.t("No such channel"))
  1030. }
  1031. continue
  1032. }
  1033. channel.Names(client)
  1034. }
  1035. return false
  1036. }
  1037. // ResumeDetails are the details that we use to resume connections.
  1038. type ResumeDetails struct {
  1039. OldNick string
  1040. Timestamp *time.Time
  1041. SendFakeJoinsFor []string
  1042. }
  1043. var (
  1044. infoString1 = strings.Split(` ▄▄▄ ▄▄▄· ▄▄ • ▐ ▄
  1045. ▪ ▀▄ █·▐█ ▀█ ▐█ ▀ ▪▪ •█▌▐█▪
  1046. ▄█▀▄ ▐▀▀▄ ▄█▀▀█ ▄█ ▀█▄ ▄█▀▄▪▐█▐▐▌ ▄█▀▄
  1047. ▐█▌.▐▌▐█•█▌▐█ ▪▐▌▐█▄▪▐█▐█▌ ▐▌██▐█▌▐█▌.▐▌
  1048. ▀█▄▀▪.▀ ▀ ▀ ▀ ·▀▀▀▀ ▀█▄▀ ▀▀ █▪ ▀█▄▀▪
  1049. https://oragono.io/
  1050. https://github.com/oragono/oragono
  1051. https://crowdin.com/project/oragono
  1052. `, "\n")
  1053. infoString2 = strings.Split(` Daniel Oakley, DanielOaks, <daniel@danieloaks.net>
  1054. Shivaram Lingamneni, slingamn, <slingamn@cs.stanford.edu>
  1055. `, "\n")
  1056. infoString3 = strings.Split(` 3onyc
  1057. Edmund Huber
  1058. Euan Kemp (euank)
  1059. Jeremy Latt
  1060. Martin Lindhe (martinlindhe)
  1061. Roberto Besser (besser)
  1062. Robin Burchell (rburchell)
  1063. Sean Enck (enckse)
  1064. soul9
  1065. Vegax
  1066. `, "\n")
  1067. )