mirror of
				https://github.com/ergochat/ergo.git
				synced 2025-10-31 05:47:22 +01:00 
			
		
		
		
	rudimentary (broken) invite support
This commit is contained in:
		
							parent
							
								
									55f7c89468
								
							
						
					
					
						commit
						d7d6263e35
					
				| @ -119,3 +119,20 @@ func (ch *Channel) ChangeTopic(cl *Client, newTopic string) { | ||||
| 		ch.Send(RplNoTopic(ch), nil) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (ch *Channel) Invite(inviter *Client, invitee *Client) { | ||||
| 	if !ch.members[inviter] { | ||||
| 		inviter.send <- ErrNotOnChannel(ch) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if ch.members[invitee] { | ||||
| 		inviter.send <- ErrUserOnChannel(ch, invitee) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ch.invites[invitee.nick] = true | ||||
| 
 | ||||
| 	invitee.send <- RplInviteMsg(ch, inviter) | ||||
| 	inviter.send <- RplInvitingMsg(ch, invitee) | ||||
| } | ||||
|  | ||||
| @ -15,6 +15,19 @@ type Message interface { | ||||
| var ( | ||||
| 	ErrNotEnoughArgs    = errors.New("not enough arguments") | ||||
| 	ErrUModeUnknownFlag = errors.New("unknown umode flag") | ||||
| 	parseCommandFuncs   = map[string]ParseFunc{ | ||||
| 		"INVITE":  NewInviteMessage, | ||||
| 		"JOIN":    NewJoinMessage, | ||||
| 		"MODE":    NewModeMessage, | ||||
| 		"NICK":    NewNickMessage, | ||||
| 		"PART":    NewPartMessage, | ||||
| 		"PING":    NewPingMessage, | ||||
| 		"PONG":    NewPongMessage, | ||||
| 		"PRIVMSG": NewPrivMsgMessage, | ||||
| 		"QUIT":    NewQuitMessage, | ||||
| 		"TOPIC":   NewTopicMessage, | ||||
| 		"USER":    NewUserMessage, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| // unknown | ||||
| @ -319,3 +332,36 @@ func (m *TopicMessage) Handle(s *Server, c *Client) { | ||||
| 		channel.ChangeTopic(c, m.topic) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // INVITE <nickname> <channel> | ||||
| 
 | ||||
| type InviteMessage struct { | ||||
| 	nickname string | ||||
| 	channel  string | ||||
| } | ||||
| 
 | ||||
| func NewInviteMessage(args []string) (Message, error) { | ||||
| 	if len(args) < 2 { | ||||
| 		return nil, ErrNotEnoughArgs | ||||
| 	} | ||||
| 	return &InviteMessage{ | ||||
| 		nickname: args[0], | ||||
| 		channel:  args[1], | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (m *InviteMessage) Handle(s *Server, c *Client) { | ||||
| 	channel := s.channels[m.channel] | ||||
| 	if channel == nil { | ||||
| 		c.send <- ErrNoSuchNick(s, m.channel) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	invitee := s.nicks[m.nickname] | ||||
| 	if invitee == nil { | ||||
| 		c.send <- ErrNoSuchNick(s, m.nickname) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	channel.Invite(c, invitee) | ||||
| } | ||||
|  | ||||
| @ -5,31 +5,145 @@ const ( | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// # numeric codes | ||||
| 	// ## reply codes | ||||
| 	RPL_WELCOME    = "001" | ||||
| 	RPL_YOURHOST   = "002" | ||||
| 	RPL_CREATED    = "003" | ||||
| 	RPL_MYINFO     = "004" | ||||
| 	RPL_UMODEIS    = "221" | ||||
| 	RPL_NOTOPIC    = "331" | ||||
| 	RPL_TOPIC      = "332" | ||||
| 	RPL_NAMREPLY   = "353" | ||||
| 	RPL_ENDOFNAMES = "366" | ||||
| 	RPL_INFO       = "371" | ||||
| 	// ## error codes | ||||
| 	// numeric codes | ||||
| 	RPL_WELCOME           = "001" | ||||
| 	RPL_YOURHOST          = "002" | ||||
| 	RPL_CREATED           = "003" | ||||
| 	RPL_MYINFO            = "004" | ||||
| 	RPL_BOUNCE            = "005" | ||||
| 	RPL_TRACELINK         = "200" | ||||
| 	RPL_TRACECONNECTING   = "201" | ||||
| 	RPL_TRACEHANDSHAKE    = "202" | ||||
| 	RPL_TRACEUNKNOWN      = "203" | ||||
| 	RPL_TRACEOPERATOR     = "204" | ||||
| 	RPL_TRACEUSER         = "205" | ||||
| 	RPL_TRACESERVER       = "206" | ||||
| 	RPL_TRACESERVICE      = "207" | ||||
| 	RPL_TRACENEWTYPE      = "208" | ||||
| 	RPL_TRACECLASS        = "209" | ||||
| 	RPL_TRACERECONNECT    = "210" | ||||
| 	RPL_STATSLINKINFO     = "211" | ||||
| 	RPL_STATSCOMMANDS     = "212" | ||||
| 	RPL_ENDOFSTATS        = "219" | ||||
| 	RPL_UMODEIS           = "221" | ||||
| 	RPL_SERVLIST          = "234" | ||||
| 	RPL_SERVLISTEND       = "235" | ||||
| 	RPL_STATSUPTIME       = "242" | ||||
| 	RPL_STATSOLINE        = "243" | ||||
| 	RPL_LUSERCLIENT       = "251" | ||||
| 	RPL_LUSEROP           = "252" | ||||
| 	RPL_LUSERUNKNOWN      = "253" | ||||
| 	RPL_LUSERCHANNELS     = "254" | ||||
| 	RPL_LUSERME           = "255" | ||||
| 	RPL_ADMINME           = "256" | ||||
| 	RPL_ADMINLOC1         = "257" | ||||
| 	RPL_ADMINLOC2         = "258" | ||||
| 	RPL_ADMINEMAIL        = "259" | ||||
| 	RPL_TRACELOG          = "261" | ||||
| 	RPL_TRACEEND          = "262" | ||||
| 	RPL_TRYAGAIN          = "263" | ||||
| 	RPL_AWAY              = "301" | ||||
| 	RPL_USERHOST          = "302" | ||||
| 	RPL_ISON              = "303" | ||||
| 	RPL_UNAWAY            = "305" | ||||
| 	RPL_NOWAWAY           = "306" | ||||
| 	RPL_WHOISUSER         = "311" | ||||
| 	RPL_WHOISSERVER       = "312" | ||||
| 	RPL_WHOISOPERATOR     = "313" | ||||
| 	RPL_WHOWASUSER        = "314" | ||||
| 	RPL_ENDOFWHO          = "315" | ||||
| 	RPL_WHOISIDLE         = "317" | ||||
| 	RPL_ENDOFWHOIS        = "318" | ||||
| 	RPL_WHOISCHANNELS     = "319" | ||||
| 	RPL_LIST              = "322" | ||||
| 	RPL_LISTEND           = "323" | ||||
| 	RPL_CHANNELMODEIS     = "324" | ||||
| 	RPL_UNIQOPIS          = "325" | ||||
| 	RPL_NOTOPIC           = "331" | ||||
| 	RPL_TOPIC             = "332" | ||||
| 	RPL_INVITING          = "341" | ||||
| 	RPL_SUMMONING         = "342" | ||||
| 	RPL_INVITELIST        = "346" | ||||
| 	RPL_ENDOFINVITELIST   = "347" | ||||
| 	RPL_EXCEPTLIST        = "348" | ||||
| 	RPL_ENDOFEXCEPTLIST   = "349" | ||||
| 	RPL_VERSION           = "351" | ||||
| 	RPL_WHOREPLY          = "352" | ||||
| 	RPL_NAMREPLY          = "353" | ||||
| 	RPL_LINKS             = "364" | ||||
| 	RPL_ENDOFLINKS        = "365" | ||||
| 	RPL_ENDOFNAMES        = "366" | ||||
| 	RPL_BANLIST           = "367" | ||||
| 	RPL_ENDOFBANLIST      = "368" | ||||
| 	RPL_ENDOFWHOWAS       = "369" | ||||
| 	RPL_INFO              = "371" | ||||
| 	RPL_MOTD              = "372" | ||||
| 	RPL_ENDOFINFO         = "374" | ||||
| 	RPL_MOTDSTART         = "375" | ||||
| 	RPL_ENDOFMOTD         = "376" | ||||
| 	RPL_YOUREOPER         = "381" | ||||
| 	RPL_REHASHING         = "382" | ||||
| 	RPL_YOURESERVICE      = "383" | ||||
| 	RPL_TIME              = "391" | ||||
| 	RPL_USERSSTART        = "392" | ||||
| 	RPL_USERS             = "393" | ||||
| 	RPL_ENDOFUSERS        = "394" | ||||
| 	RPL_NOUSERS           = "395" | ||||
| 	ERR_NOSUCHNICK        = "401" | ||||
| 	ERR_NOSUCHSERVER      = "402" | ||||
| 	ERR_NOSUCHCHANNEL     = "403" | ||||
| 	ERR_CANNOTSENDTOCHAN  = "404" | ||||
| 	ERR_TOOMANYCHANNELS   = "405" | ||||
| 	ERR_WASNOSUCHNICK     = "406" | ||||
| 	ERR_TOOMANYTARGETS    = "407" | ||||
| 	ERR_NOSUCHSERVICE     = "408" | ||||
| 	ERR_NOORIGIN          = "409" | ||||
| 	ERR_NORECIPIENT       = "411" | ||||
| 	ERR_NOTEXTTOSEND      = "412" | ||||
| 	ERR_NOTOPLEVEL        = "413" | ||||
| 	ERR_WILDTOPLEVEL      = "414" | ||||
| 	ERR_BADMASK           = "415" | ||||
| 	ERR_UNKNOWNCOMMAND    = "421" | ||||
| 	ERR_NOMOTD            = "422" | ||||
| 	ERR_NOADMININFO       = "423" | ||||
| 	ERR_FILEERROR         = "424" | ||||
| 	ERR_NONICKNAMEGIVEN   = "431" | ||||
| 	ERR_ERRONEUSNICKNAME  = "432" | ||||
| 	ERR_NICKNAMEINUSE     = "433" | ||||
| 	ERR_NICKCOLLISION     = "436" | ||||
| 	ERR_UNAVAILRESOURCE   = "437" | ||||
| 	ERR_USERNOTINCHANNEL  = "441" | ||||
| 	ERR_NOTONCHANNEL      = "442" | ||||
| 	ERR_USERONCHANNEL     = "443" | ||||
| 	ERR_NOLOGIN           = "444" | ||||
| 	ERR_SUMMONDISABLED    = "445" | ||||
| 	ERR_USERSDISABLED     = "446" | ||||
| 	ERR_NOTREGISTERED     = "451" | ||||
| 	ERR_NEEDMOREPARAMS    = "461" | ||||
| 	ERR_ALREADYREGISTRED  = "462" | ||||
| 	ERR_INVITEONLYCHANNEL = "473" | ||||
| 	ERR_NOPERMFORHOST     = "463" | ||||
| 	ERR_PASSWDMISMATCH    = "464" | ||||
| 	ERR_YOUREBANNEDCREEP  = "465" | ||||
| 	ERR_YOUWILLBEBANNED   = "466" | ||||
| 	ERR_KEYSET            = "467" | ||||
| 	ERR_CHANNELISFULL     = "471" | ||||
| 	ERR_UNKNOWNMODE       = "472" | ||||
| 	ERR_INVITEONLYCHAN    = "473" | ||||
| 	ERR_BANNEDFROMCHAN    = "474" | ||||
| 	ERR_BADCHANNELKEY     = "475" | ||||
| 	ERR_BADCHANMASK       = "476" | ||||
| 	ERR_NOCHANMODES       = "477" | ||||
| 	ERR_BANLISTFULL       = "478" | ||||
| 	ERR_NOPRIVILEGES      = "481" | ||||
| 	ERR_CHANOPRIVSNEEDED  = "482" | ||||
| 	ERR_CANTKILLSERVER    = "483" | ||||
| 	ERR_RESTRICTED        = "484" | ||||
| 	ERR_UNIQOPPRIVSNEEDED = "485" | ||||
| 	ERR_NOOPERHOST        = "491" | ||||
| 	ERR_UMODEUNKNOWNFLAG  = "501" | ||||
| 	ERR_USERSDONTMATCH    = "502" | ||||
| 	// # message codes | ||||
| 	// message codes | ||||
| 	RPL_INVITE  = "INVITE" | ||||
| 	RPL_JOIN    = "JOIN" | ||||
| 	RPL_NICK    = "NICK" | ||||
| 	RPL_PART    = "PART" | ||||
|  | ||||
| @ -5,18 +5,7 @@ import ( | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| var commands = map[string]func([]string) (Message, error){ | ||||
| 	"JOIN":    NewJoinMessage, | ||||
| 	"MODE":    NewModeMessage, | ||||
| 	"NICK":    NewNickMessage, | ||||
| 	"PART":    NewPartMessage, | ||||
| 	"PING":    NewPingMessage, | ||||
| 	"PONG":    NewPongMessage, | ||||
| 	"PRIVMSG": NewPrivMsgMessage, | ||||
| 	"QUIT":    NewQuitMessage, | ||||
| 	"TOPIC":   NewTopicMessage, | ||||
| 	"USER":    NewUserMessage, | ||||
| } | ||||
| type ParseFunc func([]string) (Message, error) | ||||
| 
 | ||||
| var ( | ||||
| 	ErrParseMessage = errors.New("failed to parse message") | ||||
| @ -24,7 +13,7 @@ var ( | ||||
| 
 | ||||
| func ParseMessage(line string) (msg Message, err error) { | ||||
| 	command, args := parseLine(line) | ||||
| 	constructor, ok := commands[command] | ||||
| 	constructor, ok := parseCommandFuncs[command] | ||||
| 	if !ok { | ||||
| 		msg = &UnknownMessage{command} | ||||
| 		return | ||||
|  | ||||
| @ -49,6 +49,15 @@ func RplNick(client *Client, newNick string) Reply { | ||||
| 	return NewReply(client, RPL_NICK, ":"+newNick) | ||||
| } | ||||
| 
 | ||||
| func RplInviteMsg(channel *Channel, inviter *Client) Reply { | ||||
| 	return NewReply(inviter, RPL_INVITE, channel.name) | ||||
| } | ||||
| 
 | ||||
| func RplInvitingMsg(channel *Channel, invitee *Client) Reply { | ||||
| 	return NewReply(channel.server, RPL_INVITING, | ||||
| 		fmt.Sprintf("%s %s", channel.name, invitee.Nick())) | ||||
| } | ||||
| 
 | ||||
| func RplPrivMsgChannel(channel *Channel, source *Client, message string) Reply { | ||||
| 	return &ChannelReply{NewReply(source, RPL_PRIVMSG, ":"+message), channel} | ||||
| } | ||||
| @ -64,19 +73,23 @@ func RplPart(channel *Channel, client *Client, message string) Reply { | ||||
| // Server Info | ||||
| 
 | ||||
| func RplWelcome(source Identifier, client *Client) Reply { | ||||
| 	return NewReply(source, RPL_WELCOME, "Welcome to the Internet Relay Network "+client.Id()) | ||||
| 	return NewReply(source, RPL_WELCOME, | ||||
| 		"Welcome to the Internet Relay Network "+client.Id()) | ||||
| } | ||||
| 
 | ||||
| func RplYourHost(server *Server, target *Client) Reply { | ||||
| 	return NewReply(server, RPL_YOURHOST, fmt.Sprintf("Your host is %s, running version %s", server.hostname, VERSION)) | ||||
| 	return NewReply(server, RPL_YOURHOST, | ||||
| 		fmt.Sprintf("Your host is %s, running version %s", server.hostname, VERSION)) | ||||
| } | ||||
| 
 | ||||
| func RplCreated(server *Server) Reply { | ||||
| 	return NewReply(server, RPL_CREATED, "This server was created "+server.ctime.Format(time.RFC1123)) | ||||
| 	return NewReply(server, RPL_CREATED, | ||||
| 		"This server was created "+server.ctime.Format(time.RFC1123)) | ||||
| } | ||||
| 
 | ||||
| func RplMyInfo(server *Server) Reply { | ||||
| 	return NewReply(server, RPL_MYINFO, fmt.Sprintf("%s %s i ik", server.name, VERSION)) | ||||
| 	return NewReply(server, RPL_MYINFO, | ||||
| 		fmt.Sprintf("%s %s i ik", server.name, VERSION)) | ||||
| } | ||||
| 
 | ||||
| func RplUModeIs(server *Server, client *Client) Reply { | ||||
| @ -86,20 +99,24 @@ func RplUModeIs(server *Server, client *Client) Reply { | ||||
| // channel operations | ||||
| 
 | ||||
| func RplNoTopic(channel *Channel) Reply { | ||||
| 	return &ChannelReply{NewReply(channel.server, RPL_NOTOPIC, channel.name+" :No topic is set"), channel} | ||||
| 	return &ChannelReply{NewReply(channel.server, RPL_NOTOPIC, | ||||
| 		channel.name+" :No topic is set"), channel} | ||||
| } | ||||
| 
 | ||||
| func RplTopic(channel *Channel) Reply { | ||||
| 	return &ChannelReply{NewReply(channel.server, RPL_TOPIC, fmt.Sprintf("%s :%s", channel.name, channel.topic)), channel} | ||||
| 	return &ChannelReply{NewReply(channel.server, RPL_TOPIC, | ||||
| 		fmt.Sprintf("%s :%s", channel.name, channel.topic)), channel} | ||||
| } | ||||
| 
 | ||||
| func RplNamReply(channel *Channel) Reply { | ||||
| 	// TODO multiple names and splitting based on message size | ||||
| 	return NewReply(channel.server, RPL_NAMREPLY, fmt.Sprintf("= %s :%s", channel.name, strings.Join(channel.Nicks(), " "))) | ||||
| 	return NewReply(channel.server, RPL_NAMREPLY, | ||||
| 		fmt.Sprintf("= %s :%s", channel.name, strings.Join(channel.Nicks(), " "))) | ||||
| } | ||||
| 
 | ||||
| func RplEndOfNames(source Identifier) Reply { | ||||
| 	return NewReply(source, RPL_ENDOFNAMES, ":End of NAMES list") | ||||
| 	return NewReply(source, RPL_ENDOFNAMES, | ||||
| 		":End of NAMES list") | ||||
| } | ||||
| 
 | ||||
| func RplPong(server *Server) Reply { | ||||
| @ -109,41 +126,56 @@ func RplPong(server *Server) Reply { | ||||
| // errors | ||||
| 
 | ||||
| func ErrAlreadyRegistered(source Identifier) Reply { | ||||
| 	return NewReply(source, ERR_ALREADYREGISTRED, ":You may not reregister") | ||||
| 	return NewReply(source, ERR_ALREADYREGISTRED, | ||||
| 		":You may not reregister") | ||||
| } | ||||
| 
 | ||||
| func ErrNickNameInUse(source Identifier, nick string) Reply { | ||||
| 	return NewReply(source, ERR_NICKNAMEINUSE, nick+" :Nickname is already in use") | ||||
| 	return NewReply(source, ERR_NICKNAMEINUSE, | ||||
| 		nick+" :Nickname is already in use") | ||||
| } | ||||
| 
 | ||||
| func ErrUnknownCommand(source Identifier, command string) Reply { | ||||
| 	return NewReply(source, ERR_UNKNOWNCOMMAND, command+" :Unknown command") | ||||
| 	return NewReply(source, ERR_UNKNOWNCOMMAND, | ||||
| 		command+" :Unknown command") | ||||
| } | ||||
| 
 | ||||
| func ErrUsersDontMatch(source Identifier) Reply { | ||||
| 	return NewReply(source, ERR_USERSDONTMATCH, ":Cannot change mode for other users") | ||||
| 	return NewReply(source, ERR_USERSDONTMATCH, | ||||
| 		":Cannot change mode for other users") | ||||
| } | ||||
| 
 | ||||
| func ErrNeedMoreParams(source Identifier, command string) Reply { | ||||
| 	return NewReply(source, ERR_NEEDMOREPARAMS, command+"%s :Not enough parameters") | ||||
| 	return NewReply(source, ERR_NEEDMOREPARAMS, | ||||
| 		command+"%s :Not enough parameters") | ||||
| } | ||||
| 
 | ||||
| func ErrNoSuchChannel(source Identifier, channel string) Reply { | ||||
| 	return NewReply(source, ERR_NOSUCHCHANNEL, channel+" :No such channel") | ||||
| 	return NewReply(source, ERR_NOSUCHCHANNEL, | ||||
| 		channel+" :No such channel") | ||||
| } | ||||
| 
 | ||||
| func ErrUserOnChannel(channel *Channel, member *Client) Reply { | ||||
| 	return NewReply(channel.server, ERR_USERONCHANNEL, | ||||
| 		fmt.Sprintf("%s %s :is already on channel", member.nick, channel.name)) | ||||
| } | ||||
| 
 | ||||
| func ErrNotOnChannel(channel *Channel) Reply { | ||||
| 	return NewReply(channel.server, ERR_NOTONCHANNEL, channel.name+" :You're not on that channel") | ||||
| 	return NewReply(channel.server, ERR_NOTONCHANNEL, | ||||
| 		channel.name+" :You're not on that channel") | ||||
| } | ||||
| 
 | ||||
| func ErrInviteOnlyChannel(channel *Channel) Reply { | ||||
| 	return NewReply(channel.server, ERR_INVITEONLYCHANNEL, channel.name+" :Cannot join channel (+i)") | ||||
| 	return NewReply(channel.server, ERR_INVITEONLYCHAN, | ||||
| 		channel.name+" :Cannot join channel (+i)") | ||||
| } | ||||
| 
 | ||||
| func ErrBadChannelKey(channel *Channel) Reply { | ||||
| 	return NewReply(channel.server, ERR_BADCHANNELKEY, channel.name+" :Cannot join channel (+k)") | ||||
| 	return NewReply(channel.server, ERR_BADCHANNELKEY, | ||||
| 		channel.name+" :Cannot join channel (+k)") | ||||
| } | ||||
| 
 | ||||
| func ErrNoSuchNick(source Identifier, nick string) Reply { | ||||
| 	return NewReply(source, ERR_NOSUCHNICK, nick+" :No such nick/channel") | ||||
| 	return NewReply(source, ERR_NOSUCHNICK, | ||||
| 		nick+" :No such nick/channel") | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jeremy Latt
						Jeremy Latt