- Timestamp:
- Feb 6, 2020, 6:22:04 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/cmd/jounce/main.go
r10 r19 25 25 Username: "jounce", 26 26 Realname: "jounce", 27 Channels: []string{"#jounce"}, 27 28 }}, 28 29 } -
trunk/server.go
r13 r19 18 18 Username string 19 19 Realname string 20 Channels []string 20 21 } 21 22 -
trunk/upstream.go
r18 r19 6 6 "io" 7 7 "net" 8 "strconv" 8 9 "strings" 10 "time" 9 11 10 12 "gopkg.in/irc.v3" … … 12 14 13 15 const ( 14 rpl_localusers = "265" 15 rpl_globalusers = "266" 16 rpl_localusers = "265" 17 rpl_globalusers = "266" 18 rpl_topicwhotime = "333" 16 19 ) 17 20 … … 55 58 } 56 59 60 type channelStatus byte 61 62 const ( 63 channelPublic channelStatus = '=' 64 channelSecret channelStatus = '@' 65 channelPrivate channelStatus = '*' 66 ) 67 68 func parseChannelStatus(s string) (channelStatus, error) { 69 if len(s) > 1 { 70 return 0, fmt.Errorf("invalid channel status %q: more than one character", s) 71 } 72 switch cs := channelStatus(s[0]); cs { 73 case channelPublic, channelSecret, channelPrivate: 74 return cs, nil 75 default: 76 return 0, fmt.Errorf("invalid channel status %q: unknown status", s) 77 } 78 } 79 80 type membership byte 81 82 const ( 83 membershipFounder membership = '~' 84 membershipProtected membership = '&' 85 membershipOperator membership = '@' 86 membershipHalfOp membership = '%' 87 membershipVoice membership = '+' 88 ) 89 90 const stdMembershipPrefixes = "~&@%+" 91 92 func parseMembershipPrefix(s string) (prefix membership, nick string) { 93 // TODO: any prefix from PREFIX RPL_ISUPPORT 94 if strings.IndexByte(stdMembershipPrefixes, s[0]) >= 0 { 95 return membership(s[0]), s[1:] 96 } else { 97 return 0, s 98 } 99 } 100 101 type upstreamChannel struct { 102 Name string 103 Topic string 104 TopicWho string 105 TopicTime time.Time 106 Status channelStatus 107 Members map[string]membership 108 } 109 57 110 type upstreamConn struct { 58 upstream *Upstream 59 net net.Conn 60 irc *irc.Conn 61 srv *Server 62 registered bool 63 modes modeSet 111 upstream *Upstream 112 net net.Conn 113 irc *irc.Conn 114 srv *Server 64 115 65 116 serverName string … … 67 118 availableChannelModes string 68 119 channelModesWithParam string 120 121 registered bool 122 modes modeSet 123 channels map[string]*upstreamChannel 124 } 125 126 func (c *upstreamConn) getChannel(name string) (*upstreamChannel, error) { 127 ch, ok := c.channels[name] 128 if !ok { 129 return nil, fmt.Errorf("unknown channel %q", name) 130 } 131 return ch, nil 69 132 } 70 133 … … 90 153 c.registered = true 91 154 c.srv.Logger.Printf("Connection to %q registered", c.upstream.Addr) 155 156 for _, ch := range c.upstream.Channels { 157 err := c.irc.WriteMessage(&irc.Message{ 158 Command: "JOIN", 159 Params: []string{ch}, 160 }) 161 if err != nil { 162 return err 163 } 164 } 92 165 case irc.RPL_MYINFO: 93 166 if len(msg.Params) < 5 { … … 100 173 c.channelModesWithParam = msg.Params[5] 101 174 } 175 case "JOIN": 176 if len(msg.Params) < 1 { 177 return newNeedMoreParamsError(msg.Command) 178 } 179 for _, ch := range strings.Split(msg.Params[0], ",") { 180 c.srv.Logger.Printf("Joined channel %q", ch) 181 c.channels[ch] = &upstreamChannel{ 182 Name: ch, 183 Members: make(map[string]membership), 184 } 185 } 186 case irc.RPL_TOPIC, irc.RPL_NOTOPIC: 187 if len(msg.Params) < 3 { 188 return newNeedMoreParamsError(msg.Command) 189 } 190 ch, err := c.getChannel(msg.Params[1]) 191 if err != nil { 192 return err 193 } 194 if msg.Command == irc.RPL_TOPIC { 195 ch.Topic = msg.Params[2] 196 } else { 197 ch.Topic = "" 198 } 199 case "TOPIC": 200 if len(msg.Params) < 1 { 201 return newNeedMoreParamsError(msg.Command) 202 } 203 ch, err := c.getChannel(msg.Params[0]) 204 if err != nil { 205 return err 206 } 207 if len(msg.Params) > 1 { 208 ch.Topic = msg.Params[1] 209 } else { 210 ch.Topic = "" 211 } 212 case rpl_topicwhotime: 213 if len(msg.Params) < 4 { 214 return newNeedMoreParamsError(msg.Command) 215 } 216 ch, err := c.getChannel(msg.Params[1]) 217 if err != nil { 218 return err 219 } 220 ch.TopicWho = msg.Params[2] 221 sec, err := strconv.ParseInt(msg.Params[3], 10, 64) 222 if err != nil { 223 return fmt.Errorf("failed to parse topic time: %v", err) 224 } 225 ch.TopicTime = time.Unix(sec, 0) 226 case irc.RPL_NAMREPLY: 227 if len(msg.Params) < 4 { 228 return newNeedMoreParamsError(msg.Command) 229 } 230 ch, err := c.getChannel(msg.Params[2]) 231 if err != nil { 232 return err 233 } 234 235 status, err := parseChannelStatus(msg.Params[1]) 236 if err != nil { 237 return err 238 } 239 ch.Status = status 240 241 for _, s := range strings.Split(msg.Params[3], " ") { 242 membership, nick := parseMembershipPrefix(s) 243 ch.Members[nick] = membership 244 } 245 case irc.RPL_ENDOFNAMES: 246 // TODO 102 247 case irc.RPL_YOURHOST, irc.RPL_CREATED: 103 248 // Ignore … … 129 274 irc: irc.NewConn(netConn), 130 275 srv: s, 276 channels: make(map[string]*upstreamChannel), 131 277 } 132 278 defer netConn.Close()
Note:
See TracChangeset
for help on using the changeset viewer.