Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. package irc
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. )
  7. type Identifier interface {
  8. Id() string
  9. PublicId() string
  10. Nick() string
  11. }
  12. type Replier interface {
  13. Replies() chan<- Reply
  14. }
  15. type Reply interface {
  16. Format(*Client, chan<- string)
  17. Source() Identifier
  18. }
  19. type BaseReply struct {
  20. source Identifier
  21. message string
  22. }
  23. func (reply *BaseReply) Source() Identifier {
  24. return reply.source
  25. }
  26. type StringReply struct {
  27. *BaseReply
  28. code string
  29. }
  30. func NewStringReply(source Identifier, code string,
  31. format string, args ...interface{}) *StringReply {
  32. message := fmt.Sprintf(format, args...)
  33. fullMessage := fmt.Sprintf(":%s %s %s", source.Id(), code, message)
  34. return &StringReply{
  35. BaseReply: &BaseReply{source, fullMessage},
  36. code: code,
  37. }
  38. }
  39. func (reply *StringReply) Format(client *Client, write chan<- string) {
  40. write <- reply.message
  41. }
  42. func (reply *StringReply) String() string {
  43. return fmt.Sprintf("Reply(source=%s, code=%s, message=%s)",
  44. reply.source, reply.code, reply.message)
  45. }
  46. type NumericReply struct {
  47. *BaseReply
  48. code int
  49. }
  50. func NewNumericReply(source Identifier, code int, format string,
  51. args ...interface{}) *NumericReply {
  52. return &NumericReply{
  53. BaseReply: &BaseReply{source, fmt.Sprintf(format, args...)},
  54. code: code,
  55. }
  56. }
  57. func (reply *NumericReply) Format(client *Client, write chan<- string) {
  58. write <- reply.FormatString(client)
  59. }
  60. func (reply *NumericReply) FormatString(client *Client) string {
  61. return fmt.Sprintf(":%s %03d %s %s", reply.Source().Id(), reply.code,
  62. client.Nick(), reply.message)
  63. }
  64. func (reply *NumericReply) String() string {
  65. return fmt.Sprintf("Reply(source=%s, code=%d, message=%s)",
  66. reply.source, reply.code, reply.message)
  67. }
  68. // names reply
  69. type NamesReply struct {
  70. *BaseReply
  71. channel *Channel
  72. }
  73. func NewNamesReply(channel *Channel) Reply {
  74. return &NamesReply{
  75. BaseReply: &BaseReply{
  76. source: channel,
  77. },
  78. channel: channel,
  79. }
  80. }
  81. const (
  82. MAX_REPLY_LEN = 510 // 512 - CRLF
  83. )
  84. func joinedLen(names []string) int {
  85. var l = len(names) - 1 // " " between names
  86. for _, name := range names {
  87. l += len(name)
  88. }
  89. return l
  90. }
  91. func (reply *NamesReply) Format(client *Client, write chan<- string) {
  92. base := RplNamReply(reply.channel, []string{})
  93. baseLen := len(base.FormatString(client))
  94. tooLong := func(names []string) bool {
  95. return (baseLen + joinedLen(names)) > MAX_REPLY_LEN
  96. }
  97. from, to := 0, 1
  98. nicks := reply.channel.Nicks()
  99. for to < len(nicks) {
  100. if (from < (to - 1)) && tooLong(nicks[from:to]) {
  101. RplNamReply(reply.channel, nicks[from:to-1]).Format(client, write)
  102. from, to = to-1, to
  103. } else {
  104. to += 1
  105. }
  106. }
  107. if from < len(nicks) {
  108. RplNamReply(reply.channel, nicks[from:]).Format(client, write)
  109. }
  110. RplEndOfNames(reply.channel).Format(client, write)
  111. }
  112. func (reply *NamesReply) String() string {
  113. return fmt.Sprintf("NamesReply(channel=%s, names=%s)",
  114. reply.channel, reply.channel.Nicks())
  115. }
  116. // messaging replies
  117. func RplPrivMsg(source Identifier, target Identifier, message string) Reply {
  118. return NewStringReply(source, RPL_PRIVMSG, "%s :%s", target.Nick(), message)
  119. }
  120. func RplNick(source Identifier, newNick string) Reply {
  121. return NewStringReply(source, RPL_NICK, newNick)
  122. }
  123. func RplPrivMsgChannel(channel *Channel, source Identifier, message string) Reply {
  124. return NewStringReply(source, RPL_PRIVMSG, "%s :%s", channel.name, message)
  125. }
  126. func RplJoin(channel *Channel, client *Client) Reply {
  127. return NewStringReply(client, RPL_JOIN, channel.name)
  128. }
  129. func RplPart(channel *Channel, client *Client, message string) Reply {
  130. return NewStringReply(client, RPL_PART, "%s :%s", channel.name, message)
  131. }
  132. func RplPong(server *Server) Reply {
  133. return NewStringReply(server, RPL_PONG, server.Id())
  134. }
  135. func RplQuit(client *Client, message string) Reply {
  136. return NewStringReply(client, RPL_QUIT, ":%s", message)
  137. }
  138. func RplInviteMsg(channel *Channel, inviter *Client) Reply {
  139. return NewStringReply(inviter, RPL_INVITE, channel.name)
  140. }
  141. // numeric replies
  142. func RplWelcome(source Identifier, client *Client) Reply {
  143. return NewNumericReply(source, RPL_WELCOME,
  144. "Welcome to the Internet Relay Network %s", client.Id())
  145. }
  146. func RplYourHost(server *Server) Reply {
  147. return NewNumericReply(server, RPL_YOURHOST,
  148. "Your host is %s, running version %s", server.name, VERSION)
  149. }
  150. func RplCreated(server *Server) Reply {
  151. return NewNumericReply(server, RPL_CREATED,
  152. "This server was created %s", server.ctime.Format(time.RFC1123))
  153. }
  154. func RplMyInfo(server *Server) Reply {
  155. return NewNumericReply(server, RPL_MYINFO,
  156. "%s %s a kn", server.name, VERSION)
  157. }
  158. func RplUModeIs(server *Server, client *Client) Reply {
  159. return NewNumericReply(server, RPL_UMODEIS, client.UModeString())
  160. }
  161. func RplNoTopic(channel *Channel) Reply {
  162. return NewNumericReply(channel.server, RPL_NOTOPIC,
  163. "%s :No topic is set", channel.name)
  164. }
  165. func RplTopic(channel *Channel) Reply {
  166. return NewNumericReply(channel.server, RPL_TOPIC,
  167. "%s :%s", channel.name, channel.topic)
  168. }
  169. func RplInvitingMsg(channel *Channel, invitee *Client) Reply {
  170. return NewNumericReply(channel.server, RPL_INVITING,
  171. "%s %s", channel.name, invitee.Nick())
  172. }
  173. func RplNamReply(channel *Channel, names []string) *NumericReply {
  174. return NewNumericReply(channel.server, RPL_NAMREPLY, "= %s :%s",
  175. channel.name, strings.Join(names, " "))
  176. }
  177. func RplEndOfNames(channel *Channel) Reply {
  178. return NewNumericReply(channel, RPL_ENDOFNAMES,
  179. "%s :End of NAMES list", channel.name)
  180. }
  181. func RplYoureOper(server *Server) Reply {
  182. return NewNumericReply(server, RPL_YOUREOPER,
  183. ":You are now an IRC operator")
  184. }
  185. // errors (also numeric)
  186. func ErrAlreadyRegistered(source Identifier) Reply {
  187. return NewNumericReply(source, ERR_ALREADYREGISTRED,
  188. ":You may not reregister")
  189. }
  190. func ErrNickNameInUse(source Identifier, nick string) Reply {
  191. return NewNumericReply(source, ERR_NICKNAMEINUSE,
  192. "%s :Nickname is already in use", nick)
  193. }
  194. func ErrUnknownCommand(source Identifier, command string) Reply {
  195. return NewNumericReply(source, ERR_UNKNOWNCOMMAND,
  196. "%s :Unknown command", command)
  197. }
  198. func ErrUsersDontMatch(source Identifier) Reply {
  199. return NewNumericReply(source, ERR_USERSDONTMATCH,
  200. ":Cannot change mode for other users")
  201. }
  202. func ErrNeedMoreParams(source Identifier, command string) Reply {
  203. return NewNumericReply(source, ERR_NEEDMOREPARAMS,
  204. "%s :Not enough parameters", command)
  205. }
  206. func ErrNoSuchChannel(source Identifier, channel string) Reply {
  207. return NewNumericReply(source, ERR_NOSUCHCHANNEL,
  208. "%s :No such channel", channel)
  209. }
  210. func ErrUserOnChannel(channel *Channel, member *Client) Reply {
  211. return NewNumericReply(channel.server, ERR_USERONCHANNEL,
  212. "%s %s :is already on channel", member.nick, channel.name)
  213. }
  214. func ErrNotOnChannel(channel *Channel) Reply {
  215. return NewNumericReply(channel.server, ERR_NOTONCHANNEL,
  216. "%s :You're not on that channel", channel.name)
  217. }
  218. func ErrInviteOnlyChannel(channel *Channel) Reply {
  219. return NewNumericReply(channel.server, ERR_INVITEONLYCHAN,
  220. "%s :Cannot join channel (+i)", channel.name)
  221. }
  222. func ErrBadChannelKey(channel *Channel) Reply {
  223. return NewNumericReply(channel.server, ERR_BADCHANNELKEY,
  224. "%s :Cannot join channel (+k)", channel.name)
  225. }
  226. func ErrNoSuchNick(source Identifier, nick string) Reply {
  227. return NewNumericReply(source, ERR_NOSUCHNICK,
  228. "%s :No such nick/channel", nick)
  229. }
  230. func ErrPasswdMismatch(server *Server) Reply {
  231. return NewNumericReply(server, ERR_PASSWDMISMATCH, ":Password incorrect")
  232. }
  233. func ErrNoChanModes(channel *Channel) Reply {
  234. return NewNumericReply(channel.server, ERR_NOCHANMODES,
  235. "%s :Channel doesn't support modes", channel.name)
  236. }
  237. func ErrNoPrivileges(server *Server) Reply {
  238. return NewNumericReply(server, ERR_NOPRIVILEGES, ":Permission Denied")
  239. }
  240. func ErrRestricted(server *Server) Reply {
  241. return NewNumericReply(server, ERR_RESTRICTED, ":Your connection is restricted!")
  242. }