| 
					
				 | 
			
			
				@@ -1,3 +1,4 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// An IRC-Client library. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 package ircclient 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import ( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -19,8 +20,19 @@ import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"time" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-const VERSION string = "red-green.com/irc-client 0.1.0" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// get client version information from runtime package. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+var VERSION string = GetModuleVersion() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func GetModuleVersion() string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	modules := GetModules() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	version, has := modules["git.red-green.com/RedGreen/irc-client"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if has { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return version 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return "git.red-green.com/irc-client" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Is string in slice? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func StrInArray(strings []string, str string) bool { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	for _, s := range strings { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if s == str { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -30,14 +42,16 @@ func StrInArray(strings []string, str string) bool { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// IRC Message 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type IRCMsg struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	MsgParts []string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	From     string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	To       string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Cmd      string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Msg      string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	MsgParts []string // Message parts 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	From     string   // Message From 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	To       string   // Message To 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Cmd      string   // Command 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Msg      string   // Message 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Convert nick to lowercase following IRC capitalization rules. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func NameLower(name string) string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	// uppercase:  []\- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	// lowercase:  {}|^ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -57,6 +71,8 @@ func Match(name1 string, name2 string) bool { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // Strip out the NICK part of the From message. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // :[email protected] => NickServ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// IRCNick return just the NICK from :Nick!name@host 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func IRCNick(from string) string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if from[0] == ':' { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		from = from[1:] 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -74,30 +90,33 @@ IRCParse - split line into IRCMsg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 Everything after " :" is the Msg. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 Everything before " :" is split into MsgParts[]. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-If >= 3 MsgParts { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	To = MsgParts[2] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-if >= 2 MsgParts { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	From = IrcNic(MsgParts[0]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Cmd = MsgParts[1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Cmd = MsgParts[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	If >= 3 MsgParts { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		To = MsgParts[2] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if >= 2 MsgParts { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		From = IrcNic(MsgParts[0]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Cmd = MsgParts[1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Cmd = MsgParts[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 Example Messages: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 :irc.red-green.com 001 test :Welcome to IRC 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ^From              ^Cmd     ^Msg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                       ^To 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	^To 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ^0                 ^1  ^2   MsgParts[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 PING :1234567890 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ^Cmd ^Msg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ^0 MsgParts[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// IRCParse Parse an IRC line into the IRCMsg struct. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func IRCParse(line string) IRCMsg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var pos int = strings.Index(line, " :") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var results IRCMsg 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -119,6 +138,19 @@ func IRCParse(line string) IRCMsg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if len(results.MsgParts) >= 3 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		results.To = results.MsgParts[2] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// Translate CTCP and ACTION 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if results.Cmd == "PRIVMSG" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (results.Msg[0] == '\x01') && (results.Msg[len(results.Msg)-1] == '\x01') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			results.Cmd = "CTCP" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			results.Msg = results.Msg[1 : len(results.Msg)-1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if strings.HasPrefix(results.Msg, "ACTION ") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				results.Cmd = "ACTION" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				results.Msg = results.Msg[7:] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return results 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -140,20 +172,25 @@ func oldIRCParse(line string) []string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Sent to writer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//	The To part allows the writer to throttle messages to a specific target. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//	When throttled, it delays and alternates between the targets. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type IRCWrite struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	To     string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Output string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	To     string // Write To 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Output string // Output 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Configuration 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type IRCConfig struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Port           int      `json:"Port"` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Hostname       string   `json:"Hostname"` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	UseTLS         bool     `json:"UseTLS"`   // Use TLS Secure connection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	UseSASL        bool     `json:"UseSASL"`  // Authenticate via SASL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Insecure       bool     `json:"Insecure"` // Allow self-signed certificates 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Nick           string   `json:"Nick"` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Username       string   `json:"Username"` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Realname       string   `json:"Realname"` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Port           int      `json:"Port"`           // IRC Connection port 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Hostname       string   `json:"Hostname"`       // Hostname for connection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	UseTLS         bool     `json:"UseTLS"`         // Use TLS Secure connection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	UseSASL        bool     `json:"UseSASL"`        // Authenticate via SASL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Insecure       bool     `json:"Insecure"`       // Allow self-signed certificates 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Nick           string   `json:"Nick"`           // Client's nick 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Username       string   `json:"Username"`       // Client's username 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Realname       string   `json:"Realname"`       // Client's realname 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Password       string   `json:"Password"`       // Password for nickserv 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	ServerPassword string   `json:"ServerPassword"` // Password for server 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	AutoJoin       []string `json:"AutoJoin"`       // Channels to auto-join 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -162,45 +199,57 @@ type IRCConfig struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Flood_Num      int      `json:"FloodNum"`       // Number of lines sent before considered a flood 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Flood_Time     int      `json:"FloodTime"`      // Number of Seconds to track previous messages 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Flood_Delay    int      `json:"FloodDelay"`     // Delay between sending when flood protection on (Milliseconds) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Debug_Output   bool     `json:"Debug"` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Debug_Output   bool     `json:"Debug"`          // Enable debug output 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type IRCClient struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	IRCConfig 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	MyNick       string // Client's current nick 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	OnExit       func() // Called on exit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Socket       net.Conn 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Reader       *bufio.Reader 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	ReadChannel  chan IRCMsg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	ReadEvents   []string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	WriteChannel chan IRCWrite 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	DelChannel   chan string // For deleting channel or nicks that are missing. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Registered   bool 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	ISupport     map[string]string // 005 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	wg           sync.WaitGroup 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Mutex        sync.Mutex 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	MyNick       string            // Client's current nick 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	OnExit       func()            // Called on exit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Socket       net.Conn          // Connection to IRCD 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Reader       *bufio.Reader     // For reading a line at a time from the IRCD 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	ReadChannel  chan IRCMsg       // Channel of parsed IRC Messages 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	ReadEvents   []string          // 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	WriteChannel chan IRCWrite     // Channel for writing messages to IRCD 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	DelChannel   chan string       // For deleting channel or nicks that are missing. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Registered   bool              // Registered with services? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	ISupport     map[string]string // IRCD capabilities (005) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	wg           sync.WaitGroup    // Safe shutdown of goroutines 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Mutex        sync.Mutex        // Guards MyNick 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Get the current nick of the client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (Config *IRCClient) GetNick() string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Config.Mutex.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	defer Config.Mutex.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return Config.MyNick 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Sets the current nick of the client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (Config *IRCClient) SetNick(nick string) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Config.Mutex.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	defer Config.Mutex.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Config.MyNick = nick 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func (Config *IRCClient) IsAuto(ch string) bool { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return StrInArray(Config.AutoJoin, ch) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Is channel in the AutoJoin list? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (Config *IRCClient) IsAuto(channel string) bool { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return StrInArray(Config.AutoJoin, channel) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Connect to IRCD and authenticate. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// This starts the ReaderRoutine to handle processing the lines from the IRCD. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// You must setup ReadChannel if you want to process any messages. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (Config *IRCClient) Connect() bool { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var err error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	// Set sensible defaults (if not provided), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if Config.Version == "" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Config.Version = VERSION 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if Config.Flood_Num == 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Config.Flood_Num = 5 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -277,7 +326,7 @@ func (Config *IRCClient) Connect() bool { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// Low level write to [TLS]Socket routine. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Write to IRCD 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (Config *IRCClient) write(output string) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var err error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if Config.Debug_Output { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -289,6 +338,7 @@ func (Config *IRCClient) write(output string) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// WriterRoutine a goroutine that handles flood control 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (Config *IRCClient) WriterRoutine() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var err error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var throttle ThrottleBuffer 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -297,7 +347,7 @@ func (Config *IRCClient) WriterRoutine() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Flood.Init(Config.Flood_Num, Config.Flood_Time) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	defer Config.wg.Done() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	throttle.init() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	throttle.Init() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	// signal handler 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var sigChannel chan os.Signal = make(chan os.Signal, 1) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -386,6 +436,7 @@ func (Config *IRCClient) WriterRoutine() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Shutdown the client. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (Config *IRCClient) Close() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Config.Socket.Close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Config.PriorityWrite("") 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -395,6 +446,7 @@ func (Config *IRCClient) Close() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Config.wg.Wait() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Generate random nick to change to (upon collision/433) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func RandomNick(nick string) string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var result string = nick + "-" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	result += strconv.Itoa(rand.Intn(1000)) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -402,6 +454,8 @@ func RandomNick(nick string) string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // PriorityWrite: Send output command to server immediately. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// This is never throttled. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (Config *IRCClient) PriorityWrite(output string) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Config.WriteChannel <- IRCWrite{To: "", Output: output} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -426,6 +480,14 @@ func (Config *IRCClient) Action(to string, message string) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	Config.WriteTo(to, fmt.Sprintf("PRIVMSG %s :\x01ACTION %s\x01", to, message)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Goroutine reader routine 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//	This reads a line at a time, delimited by '\n'. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//	Auto-replies to server PING. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//	Converts CTCP & ACTION messages to type CTCP/ACTION. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//	Automatically answers /VERSION and /TIME. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//	Handles SASL authentication. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//	Rejoins AutoJoin channels kicked from. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (Config *IRCClient) ReaderRoutine() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	defer Config.wg.Done() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var registering bool 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -465,52 +527,29 @@ func (Config *IRCClient) ReaderRoutine() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					Config.MyNick = newNick 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					Config.PriorityWrite("NICK " + newNick) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			case "PRIVMSG": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				// Convert Cmd "PRIVMSG" to "CTCP" or "ACTION". 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if (results.Msg[0] == '\x01') && (results.Msg[len(results.Msg)-1] == '\x01') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					// ACTION 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					results.Cmd = "CTCP" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					results.Msg = results.Msg[1 : len(results.Msg)-1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if Config.Debug_Output { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						log.Println("CTCP:", results.Msg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					// Process CTCP commands 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if strings.HasPrefix(results.Msg, "ACTION ") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						results.Cmd = "ACTION" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						results.Msg = results.Msg[7:] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if strings.HasPrefix(results.Msg, "PING ") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						Config.WriteTo(IRCNick(results.From), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							fmt.Sprintf("NOTICE %s :\x01PING %s\x01", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								IRCNick(results.From), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								results.Msg[5:])) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if results.Msg == "VERSION" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						// Send version reply 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						var version string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						if Config.Version != "" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							version = Config.Version + " " + VERSION 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							version = VERSION 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						Config.WriteTo(IRCNick(results.From), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							fmt.Sprintf("NOTICE %s :\x01VERSION %s\x01", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								IRCNick(results.From), version)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if results.Msg == "TIME" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						// Send time reply 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						var now time.Time = time.Now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						Config.WriteTo(IRCNick(results.From), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							fmt.Sprintf("NOTICE %s :\x01TIME %s\x01", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								IRCNick(results.From), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								now.Format(time.ANSIC))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			case "CTCP": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if strings.HasPrefix(results.Msg, "PING ") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					Config.WriteTo(IRCNick(results.From), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						fmt.Sprintf("NOTICE %s :\x01%s\x01", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							IRCNick(results.From), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							results.Msg)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} else if strings.HasPrefix(results.Msg, "VERSION") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					var version string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if Config.Version != "" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						version = Config.Version + " " + VERSION 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						version = VERSION 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					Config.WriteTo(IRCNick(results.From), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						fmt.Sprintf("NOTICE %s :\x01VERSION %s\x01", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							IRCNick(results.From), version)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} else if strings.HasPrefix(results.Msg, "TIME") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					var now time.Time = time.Now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					Config.WriteTo(IRCNick(results.From), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						fmt.Sprintf("NOTICE %s :\x01TIME %s\x01", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							IRCNick(results.From), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							now.Format(time.ANSIC))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			// This is likely, 2022/04/05 10:11:41 ReadString: EOF 
			 |