You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

commands.go 20KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. package irc
  2. import (
  3. "errors"
  4. "fmt"
  5. "regexp"
  6. "strconv"
  7. "strings"
  8. )
  9. type Command interface {
  10. Client() *Client
  11. Code() StringCode
  12. SetClient(*Client)
  13. SetCode(StringCode)
  14. }
  15. type checkPasswordCommand interface {
  16. LoadPassword(*Server)
  17. CheckPassword()
  18. }
  19. type parseCommandFunc func([]string) (Command, error)
  20. var (
  21. NotEnoughArgsError = errors.New("not enough arguments")
  22. ErrParseCommand = errors.New("failed to parse message")
  23. parseCommandFuncs = map[StringCode]parseCommandFunc{
  24. AWAY: NewAwayCommand,
  25. CAP: NewCapCommand,
  26. DEBUG: NewDebugCommand,
  27. INVITE: NewInviteCommand,
  28. ISON: NewIsOnCommand,
  29. JOIN: NewJoinCommand,
  30. KICK: NewKickCommand,
  31. KILL: NewKillCommand,
  32. LIST: NewListCommand,
  33. MODE: NewModeCommand,
  34. MOTD: NewMOTDCommand,
  35. NAMES: NewNamesCommand,
  36. NICK: NewNickCommand,
  37. NOTICE: NewNoticeCommand,
  38. ONICK: NewOperNickCommand,
  39. OPER: NewOperCommand,
  40. PART: NewPartCommand,
  41. PASS: NewPassCommand,
  42. PING: NewPingCommand,
  43. PONG: NewPongCommand,
  44. PRIVMSG: NewPrivMsgCommand,
  45. PROXY: NewProxyCommand,
  46. QUIT: NewQuitCommand,
  47. THEATER: NewTheaterCommand, // nonstandard
  48. TIME: NewTimeCommand,
  49. TOPIC: NewTopicCommand,
  50. USER: NewUserCommand,
  51. VERSION: NewVersionCommand,
  52. WHO: NewWhoCommand,
  53. WHOIS: NewWhoisCommand,
  54. WHOWAS: NewWhoWasCommand,
  55. }
  56. )
  57. type BaseCommand struct {
  58. client *Client
  59. code StringCode
  60. }
  61. func (command *BaseCommand) Client() *Client {
  62. return command.client
  63. }
  64. func (command *BaseCommand) SetClient(client *Client) {
  65. command.client = client
  66. }
  67. func (command *BaseCommand) Code() StringCode {
  68. return command.code
  69. }
  70. func (command *BaseCommand) SetCode(code StringCode) {
  71. command.code = code
  72. }
  73. func ParseCommand(line string) (cmd Command, err error) {
  74. code, args := ParseLine(line)
  75. constructor := parseCommandFuncs[code]
  76. if constructor == nil {
  77. cmd = NewUnknownCommand(args)
  78. } else {
  79. cmd, err = constructor(args)
  80. }
  81. if cmd != nil {
  82. cmd.SetCode(code)
  83. }
  84. return
  85. }
  86. var (
  87. spacesExpr = regexp.MustCompile(` +`)
  88. )
  89. func splitArg(line string) (arg string, rest string) {
  90. parts := spacesExpr.Split(line, 2)
  91. if len(parts) > 0 {
  92. arg = parts[0]
  93. }
  94. if len(parts) > 1 {
  95. rest = parts[1]
  96. }
  97. return
  98. }
  99. func ParseLine(line string) (command StringCode, args []string) {
  100. args = make([]string, 0)
  101. if strings.HasPrefix(line, ":") {
  102. _, line = splitArg(line)
  103. }
  104. arg, line := splitArg(line)
  105. command = StringCode(NewName(strings.ToUpper(arg)))
  106. for len(line) > 0 {
  107. if strings.HasPrefix(line, ":") {
  108. args = append(args, line[len(":"):])
  109. break
  110. }
  111. arg, line = splitArg(line)
  112. args = append(args, arg)
  113. }
  114. return
  115. }
  116. // <command> [args...]
  117. type UnknownCommand struct {
  118. BaseCommand
  119. args []string
  120. }
  121. func (cmd *UnknownCommand) String() string {
  122. return fmt.Sprintf("UNKNOWN(command=%s, args=%s)", cmd.Code(), cmd.args)
  123. }
  124. func NewUnknownCommand(args []string) *UnknownCommand {
  125. return &UnknownCommand{
  126. args: args,
  127. }
  128. }
  129. // PING <server1> [ <server2> ]
  130. type PingCommand struct {
  131. BaseCommand
  132. server Name
  133. server2 Name
  134. }
  135. func (cmd *PingCommand) String() string {
  136. return fmt.Sprintf("PING(server=%s, server2=%s)", cmd.server, cmd.server2)
  137. }
  138. func NewPingCommand(args []string) (Command, error) {
  139. if len(args) < 1 {
  140. return nil, NotEnoughArgsError
  141. }
  142. msg := &PingCommand{
  143. server: NewName(args[0]),
  144. }
  145. if len(args) > 1 {
  146. msg.server2 = NewName(args[1])
  147. }
  148. return msg, nil
  149. }
  150. // PONG <server> [ <server2> ]
  151. type PongCommand struct {
  152. BaseCommand
  153. server1 Name
  154. server2 Name
  155. }
  156. func (cmd *PongCommand) String() string {
  157. return fmt.Sprintf("PONG(server1=%s, server2=%s)", cmd.server1, cmd.server2)
  158. }
  159. func NewPongCommand(args []string) (Command, error) {
  160. if len(args) < 1 {
  161. return nil, NotEnoughArgsError
  162. }
  163. message := &PongCommand{
  164. server1: NewName(args[0]),
  165. }
  166. if len(args) > 1 {
  167. message.server2 = NewName(args[1])
  168. }
  169. return message, nil
  170. }
  171. // PASS <password>
  172. type PassCommand struct {
  173. BaseCommand
  174. hash []byte
  175. password []byte
  176. err error
  177. }
  178. func (cmd *PassCommand) String() string {
  179. return fmt.Sprintf("PASS(password=%s)", cmd.password)
  180. }
  181. func (cmd *PassCommand) LoadPassword(server *Server) {
  182. cmd.hash = server.password
  183. }
  184. func (cmd *PassCommand) CheckPassword() {
  185. if cmd.hash == nil {
  186. return
  187. }
  188. cmd.err = ComparePassword(cmd.hash, cmd.password)
  189. }
  190. func NewPassCommand(args []string) (Command, error) {
  191. if len(args) < 1 {
  192. return nil, NotEnoughArgsError
  193. }
  194. return &PassCommand{
  195. password: []byte(args[0]),
  196. }, nil
  197. }
  198. // NICK <nickname>
  199. func NewNickCommand(args []string) (Command, error) {
  200. if len(args) != 1 {
  201. return nil, NotEnoughArgsError
  202. }
  203. return &NickCommand{
  204. nickname: NewName(args[0]),
  205. }, nil
  206. }
  207. type UserCommand struct {
  208. BaseCommand
  209. username Name
  210. realname Text
  211. }
  212. // USER <username> <hostname> <servername> <realname>
  213. type RFC1459UserCommand struct {
  214. UserCommand
  215. hostname Name
  216. servername Name
  217. }
  218. func (cmd *RFC1459UserCommand) String() string {
  219. return fmt.Sprintf("USER(username=%s, hostname=%s, servername=%s, realname=%s)",
  220. cmd.username, cmd.hostname, cmd.servername, cmd.realname)
  221. }
  222. // USER <user> <mode> <unused> <realname>
  223. type RFC2812UserCommand struct {
  224. UserCommand
  225. mode uint8
  226. unused string
  227. }
  228. func (cmd *RFC2812UserCommand) String() string {
  229. return fmt.Sprintf("USER(username=%s, mode=%d, unused=%s, realname=%s)",
  230. cmd.username, cmd.mode, cmd.unused, cmd.realname)
  231. }
  232. func (cmd *RFC2812UserCommand) Flags() []UserMode {
  233. flags := make([]UserMode, 0)
  234. if (cmd.mode & 4) == 4 {
  235. flags = append(flags, WallOps)
  236. }
  237. if (cmd.mode & 8) == 8 {
  238. flags = append(flags, Invisible)
  239. }
  240. return flags
  241. }
  242. func NewUserCommand(args []string) (Command, error) {
  243. if len(args) != 4 {
  244. return nil, NotEnoughArgsError
  245. }
  246. mode, err := strconv.ParseUint(args[1], 10, 8)
  247. if err == nil {
  248. msg := &RFC2812UserCommand{
  249. mode: uint8(mode),
  250. unused: args[2],
  251. }
  252. msg.username = NewName(args[0])
  253. msg.realname = NewText(args[3])
  254. return msg, nil
  255. }
  256. msg := &RFC1459UserCommand{
  257. hostname: NewName(args[1]),
  258. servername: NewName(args[2]),
  259. }
  260. msg.username = NewName(args[0])
  261. msg.realname = NewText(args[3])
  262. return msg, nil
  263. }
  264. // QUIT [ <Quit Command> ]
  265. type QuitCommand struct {
  266. BaseCommand
  267. message Text
  268. }
  269. func (cmd *QuitCommand) String() string {
  270. return fmt.Sprintf("QUIT(message=%s)", cmd.message)
  271. }
  272. func NewQuitCommand(args []string) (Command, error) {
  273. msg := &QuitCommand{}
  274. if len(args) > 0 {
  275. msg.message = NewText(args[0])
  276. }
  277. return msg, nil
  278. }
  279. // JOIN ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0"
  280. type JoinCommand struct {
  281. BaseCommand
  282. channels map[Name]Text
  283. zero bool
  284. }
  285. func (cmd *JoinCommand) String() string {
  286. return fmt.Sprintf("JOIN(channels=%s, zero=%t)", cmd.channels, cmd.zero)
  287. }
  288. func NewJoinCommand(args []string) (Command, error) {
  289. msg := &JoinCommand{
  290. channels: make(map[Name]Text),
  291. }
  292. if len(args) == 0 {
  293. return nil, NotEnoughArgsError
  294. }
  295. if args[0] == "0" {
  296. msg.zero = true
  297. return msg, nil
  298. }
  299. channels := strings.Split(args[0], ",")
  300. keys := make([]string, len(channels))
  301. if len(args) > 1 {
  302. for i, key := range strings.Split(args[1], ",") {
  303. keys[i] = key
  304. }
  305. }
  306. for i, channel := range channels {
  307. msg.channels[NewName(channel)] = NewText(keys[i])
  308. }
  309. return msg, nil
  310. }
  311. // PART <channel> *( "," <channel> ) [ <Part Command> ]
  312. type PartCommand struct {
  313. BaseCommand
  314. channels []Name
  315. message Text
  316. }
  317. func (cmd *PartCommand) Message() Text {
  318. if cmd.message == "" {
  319. return cmd.Client().Nick().Text()
  320. }
  321. return cmd.message
  322. }
  323. func (cmd *PartCommand) String() string {
  324. return fmt.Sprintf("PART(channels=%s, message=%s)", cmd.channels, cmd.message)
  325. }
  326. func NewPartCommand(args []string) (Command, error) {
  327. if len(args) < 1 {
  328. return nil, NotEnoughArgsError
  329. }
  330. msg := &PartCommand{
  331. channels: NewNames(strings.Split(args[0], ",")),
  332. }
  333. if len(args) > 1 {
  334. msg.message = NewText(args[1])
  335. }
  336. return msg, nil
  337. }
  338. // PRIVMSG <target> <message>
  339. type PrivMsgCommand struct {
  340. BaseCommand
  341. target Name
  342. message Text
  343. }
  344. func (cmd *PrivMsgCommand) String() string {
  345. return fmt.Sprintf("PRIVMSG(target=%s, message=%s)", cmd.target, cmd.message)
  346. }
  347. func NewPrivMsgCommand(args []string) (Command, error) {
  348. if len(args) < 2 {
  349. return nil, NotEnoughArgsError
  350. }
  351. return &PrivMsgCommand{
  352. target: NewName(args[0]),
  353. message: NewText(args[1]),
  354. }, nil
  355. }
  356. // TOPIC [newtopic]
  357. type TopicCommand struct {
  358. BaseCommand
  359. channel Name
  360. setTopic bool
  361. topic Text
  362. }
  363. func (cmd *TopicCommand) String() string {
  364. return fmt.Sprintf("TOPIC(channel=%s, topic=%s)", cmd.channel, cmd.topic)
  365. }
  366. func NewTopicCommand(args []string) (Command, error) {
  367. if len(args) < 1 {
  368. return nil, NotEnoughArgsError
  369. }
  370. msg := &TopicCommand{
  371. channel: NewName(args[0]),
  372. }
  373. if len(args) > 1 {
  374. msg.setTopic = true
  375. msg.topic = NewText(args[1])
  376. }
  377. return msg, nil
  378. }
  379. type ModeChange struct {
  380. mode UserMode
  381. op ModeOp
  382. }
  383. func (change *ModeChange) String() string {
  384. return fmt.Sprintf("%s%s", change.op, change.mode)
  385. }
  386. type ModeChanges []*ModeChange
  387. func (changes ModeChanges) String() string {
  388. if len(changes) == 0 {
  389. return ""
  390. }
  391. op := changes[0].op
  392. str := changes[0].op.String()
  393. for _, change := range changes {
  394. if change.op == op {
  395. str += change.mode.String()
  396. } else {
  397. op = change.op
  398. str += " " + change.op.String()
  399. }
  400. }
  401. return str
  402. }
  403. type ModeCommand struct {
  404. BaseCommand
  405. nickname Name
  406. changes ModeChanges
  407. }
  408. // MODE <nickname> *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
  409. func NewUserModeCommand(nickname Name, args []string) (Command, error) {
  410. cmd := &ModeCommand{
  411. nickname: nickname,
  412. changes: make(ModeChanges, 0),
  413. }
  414. for _, modeChange := range args {
  415. if len(modeChange) == 0 {
  416. continue
  417. }
  418. op := ModeOp(modeChange[0])
  419. if (op != Add) && (op != Remove) {
  420. return nil, ErrParseCommand
  421. }
  422. for _, mode := range modeChange[1:] {
  423. cmd.changes = append(cmd.changes, &ModeChange{
  424. mode: UserMode(mode),
  425. op: op,
  426. })
  427. }
  428. }
  429. return cmd, nil
  430. }
  431. func (cmd *ModeCommand) String() string {
  432. return fmt.Sprintf("MODE(nickname=%s, changes=%s)", cmd.nickname, cmd.changes)
  433. }
  434. type ChannelModeChange struct {
  435. mode ChannelMode
  436. op ModeOp
  437. arg string
  438. }
  439. func (change *ChannelModeChange) String() (str string) {
  440. if (change.op == Add) || (change.op == Remove) {
  441. str = change.op.String()
  442. }
  443. str += change.mode.String()
  444. if change.arg != "" {
  445. str += " " + change.arg
  446. }
  447. return
  448. }
  449. type ChannelModeChanges []*ChannelModeChange
  450. func (changes ChannelModeChanges) String() (str string) {
  451. if len(changes) == 0 {
  452. return
  453. }
  454. str = "+"
  455. if changes[0].op == Remove {
  456. str = "-"
  457. }
  458. for _, change := range changes {
  459. str += change.mode.String()
  460. }
  461. for _, change := range changes {
  462. if change.arg == "" {
  463. continue
  464. }
  465. str += " " + change.arg
  466. }
  467. return
  468. }
  469. type ChannelModeCommand struct {
  470. BaseCommand
  471. channel Name
  472. changes ChannelModeChanges
  473. }
  474. // MODE <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
  475. func NewChannelModeCommand(channel Name, args []string) (Command, error) {
  476. cmd := &ChannelModeCommand{
  477. channel: channel,
  478. changes: make(ChannelModeChanges, 0),
  479. }
  480. for len(args) > 0 {
  481. if len(args[0]) == 0 {
  482. args = args[1:]
  483. continue
  484. }
  485. modeArg := args[0]
  486. op := ModeOp(modeArg[0])
  487. if (op == Add) || (op == Remove) {
  488. modeArg = modeArg[1:]
  489. } else {
  490. op = List
  491. }
  492. skipArgs := 1
  493. for _, mode := range modeArg {
  494. change := &ChannelModeChange{
  495. mode: ChannelMode(mode),
  496. op: op,
  497. }
  498. switch change.mode {
  499. case Key, BanMask, ExceptMask, InviteMask, UserLimit,
  500. ChannelOperator, ChannelCreator, Voice:
  501. if len(args) > skipArgs {
  502. change.arg = args[skipArgs]
  503. skipArgs += 1
  504. }
  505. }
  506. cmd.changes = append(cmd.changes, change)
  507. }
  508. args = args[skipArgs:]
  509. }
  510. return cmd, nil
  511. }
  512. func (msg *ChannelModeCommand) String() string {
  513. return fmt.Sprintf("MODE(channel=%s, changes=%s)", msg.channel, msg.changes)
  514. }
  515. func NewModeCommand(args []string) (Command, error) {
  516. if len(args) == 0 {
  517. return nil, NotEnoughArgsError
  518. }
  519. name := NewName(args[0])
  520. if name.IsChannel() {
  521. return NewChannelModeCommand(name, args[1:])
  522. } else {
  523. return NewUserModeCommand(name, args[1:])
  524. }
  525. }
  526. type WhoisCommand struct {
  527. BaseCommand
  528. target Name
  529. masks []Name
  530. }
  531. // WHOIS [ <target> ] <mask> *( "," <mask> )
  532. func NewWhoisCommand(args []string) (Command, error) {
  533. if len(args) < 1 {
  534. return nil, NotEnoughArgsError
  535. }
  536. var masks string
  537. var target string
  538. if len(args) > 1 {
  539. target = args[0]
  540. masks = args[1]
  541. } else {
  542. masks = args[0]
  543. }
  544. return &WhoisCommand{
  545. target: NewName(target),
  546. masks: NewNames(strings.Split(masks, ",")),
  547. }, nil
  548. }
  549. func (msg *WhoisCommand) String() string {
  550. return fmt.Sprintf("WHOIS(target=%s, masks=%s)", msg.target, msg.masks)
  551. }
  552. type WhoCommand struct {
  553. BaseCommand
  554. mask Name
  555. operatorOnly bool
  556. }
  557. // WHO [ <mask> [ "o" ] ]
  558. func NewWhoCommand(args []string) (Command, error) {
  559. cmd := &WhoCommand{}
  560. if len(args) > 0 {
  561. cmd.mask = NewName(args[0])
  562. }
  563. if (len(args) > 1) && (args[1] == "o") {
  564. cmd.operatorOnly = true
  565. }
  566. return cmd, nil
  567. }
  568. func (msg *WhoCommand) String() string {
  569. return fmt.Sprintf("WHO(mask=%s, operatorOnly=%t)", msg.mask, msg.operatorOnly)
  570. }
  571. type OperCommand struct {
  572. PassCommand
  573. name Name
  574. }
  575. func (msg *OperCommand) String() string {
  576. return fmt.Sprintf("OPER(name=%s, password=%s)", msg.name, msg.password)
  577. }
  578. func (msg *OperCommand) LoadPassword(server *Server) {
  579. msg.hash = server.operators[msg.name]
  580. }
  581. // OPER <name> <password>
  582. func NewOperCommand(args []string) (Command, error) {
  583. if len(args) < 2 {
  584. return nil, NotEnoughArgsError
  585. }
  586. cmd := &OperCommand{
  587. name: NewName(args[0]),
  588. }
  589. cmd.password = []byte(args[1])
  590. return cmd, nil
  591. }
  592. type CapCommand struct {
  593. BaseCommand
  594. subCommand CapSubCommand
  595. capabilities CapabilitySet
  596. }
  597. func (msg *CapCommand) String() string {
  598. return fmt.Sprintf("CAP(subCommand=%s, capabilities=%s)",
  599. msg.subCommand, msg.capabilities)
  600. }
  601. func NewCapCommand(args []string) (Command, error) {
  602. if len(args) < 1 {
  603. return nil, NotEnoughArgsError
  604. }
  605. cmd := &CapCommand{
  606. subCommand: CapSubCommand(strings.ToUpper(args[0])),
  607. capabilities: make(CapabilitySet),
  608. }
  609. if len(args) > 1 {
  610. strs := spacesExpr.Split(args[1], -1)
  611. for _, str := range strs {
  612. cmd.capabilities[Capability(str)] = true
  613. }
  614. }
  615. return cmd, nil
  616. }
  617. // HAPROXY support
  618. type ProxyCommand struct {
  619. BaseCommand
  620. net Name
  621. sourceIP Name
  622. destIP Name
  623. sourcePort Name
  624. destPort Name
  625. hostname Name // looked up in socket thread
  626. }
  627. func (msg *ProxyCommand) String() string {
  628. return fmt.Sprintf("PROXY(sourceIP=%s, sourcePort=%s)", msg.sourceIP, msg.sourcePort)
  629. }
  630. func NewProxyCommand(args []string) (Command, error) {
  631. if len(args) < 5 {
  632. return nil, NotEnoughArgsError
  633. }
  634. return &ProxyCommand{
  635. net: NewName(args[0]),
  636. sourceIP: NewName(args[1]),
  637. destIP: NewName(args[2]),
  638. sourcePort: NewName(args[3]),
  639. destPort: NewName(args[4]),
  640. hostname: LookupHostname(NewName(args[1])),
  641. }, nil
  642. }
  643. type AwayCommand struct {
  644. BaseCommand
  645. text Text
  646. away bool
  647. }
  648. func (msg *AwayCommand) String() string {
  649. return fmt.Sprintf("AWAY(%s)", msg.text)
  650. }
  651. func NewAwayCommand(args []string) (Command, error) {
  652. cmd := &AwayCommand{}
  653. if len(args) > 0 {
  654. cmd.text = NewText(args[0])
  655. cmd.away = true
  656. }
  657. return cmd, nil
  658. }
  659. type IsOnCommand struct {
  660. BaseCommand
  661. nicks []Name
  662. }
  663. func (msg *IsOnCommand) String() string {
  664. return fmt.Sprintf("ISON(nicks=%s)", msg.nicks)
  665. }
  666. func NewIsOnCommand(args []string) (Command, error) {
  667. if len(args) == 0 {
  668. return nil, NotEnoughArgsError
  669. }
  670. return &IsOnCommand{
  671. nicks: NewNames(args),
  672. }, nil
  673. }
  674. type MOTDCommand struct {
  675. BaseCommand
  676. target Name
  677. }
  678. func NewMOTDCommand(args []string) (Command, error) {
  679. cmd := &MOTDCommand{}
  680. if len(args) > 0 {
  681. cmd.target = NewName(args[0])
  682. }
  683. return cmd, nil
  684. }
  685. type NoticeCommand struct {
  686. BaseCommand
  687. target Name
  688. message Text
  689. }
  690. func (cmd *NoticeCommand) String() string {
  691. return fmt.Sprintf("NOTICE(target=%s, message=%s)", cmd.target, cmd.message)
  692. }
  693. func NewNoticeCommand(args []string) (Command, error) {
  694. if len(args) < 2 {
  695. return nil, NotEnoughArgsError
  696. }
  697. return &NoticeCommand{
  698. target: NewName(args[0]),
  699. message: NewText(args[1]),
  700. }, nil
  701. }
  702. type KickCommand struct {
  703. BaseCommand
  704. kicks map[Name]Name
  705. comment Text
  706. }
  707. func (msg *KickCommand) Comment() Text {
  708. if msg.comment == "" {
  709. return msg.Client().Nick().Text()
  710. }
  711. return msg.comment
  712. }
  713. func NewKickCommand(args []string) (Command, error) {
  714. if len(args) < 2 {
  715. return nil, NotEnoughArgsError
  716. }
  717. channels := NewNames(strings.Split(args[0], ","))
  718. users := NewNames(strings.Split(args[1], ","))
  719. if (len(channels) != len(users)) && (len(users) != 1) {
  720. return nil, NotEnoughArgsError
  721. }
  722. cmd := &KickCommand{
  723. kicks: make(map[Name]Name),
  724. }
  725. for index, channel := range channels {
  726. if len(users) == 1 {
  727. cmd.kicks[channel] = users[0]
  728. } else {
  729. cmd.kicks[channel] = users[index]
  730. }
  731. }
  732. if len(args) > 2 {
  733. cmd.comment = NewText(args[2])
  734. }
  735. return cmd, nil
  736. }
  737. type ListCommand struct {
  738. BaseCommand
  739. channels []Name
  740. target Name
  741. }
  742. func NewListCommand(args []string) (Command, error) {
  743. cmd := &ListCommand{}
  744. if len(args) > 0 {
  745. cmd.channels = NewNames(strings.Split(args[0], ","))
  746. }
  747. if len(args) > 1 {
  748. cmd.target = NewName(args[1])
  749. }
  750. return cmd, nil
  751. }
  752. type NamesCommand struct {
  753. BaseCommand
  754. channels []Name
  755. target Name
  756. }
  757. func NewNamesCommand(args []string) (Command, error) {
  758. cmd := &NamesCommand{}
  759. if len(args) > 0 {
  760. cmd.channels = NewNames(strings.Split(args[0], ","))
  761. }
  762. if len(args) > 1 {
  763. cmd.target = NewName(args[1])
  764. }
  765. return cmd, nil
  766. }
  767. type DebugCommand struct {
  768. BaseCommand
  769. subCommand Name
  770. }
  771. func NewDebugCommand(args []string) (Command, error) {
  772. if len(args) == 0 {
  773. return nil, NotEnoughArgsError
  774. }
  775. return &DebugCommand{
  776. subCommand: NewName(strings.ToUpper(args[0])),
  777. }, nil
  778. }
  779. type VersionCommand struct {
  780. BaseCommand
  781. target Name
  782. }
  783. func NewVersionCommand(args []string) (Command, error) {
  784. cmd := &VersionCommand{}
  785. if len(args) > 0 {
  786. cmd.target = NewName(args[0])
  787. }
  788. return cmd, nil
  789. }
  790. type InviteCommand struct {
  791. BaseCommand
  792. nickname Name
  793. channel Name
  794. }
  795. func NewInviteCommand(args []string) (Command, error) {
  796. if len(args) < 2 {
  797. return nil, NotEnoughArgsError
  798. }
  799. return &InviteCommand{
  800. nickname: NewName(args[0]),
  801. channel: NewName(args[1]),
  802. }, nil
  803. }
  804. func NewTheaterCommand(args []string) (Command, error) {
  805. if len(args) < 1 {
  806. return nil, NotEnoughArgsError
  807. } else if upperSubCmd := strings.ToUpper(args[0]); upperSubCmd == "IDENTIFY" && len(args) == 3 {
  808. return &TheaterIdentifyCommand{
  809. channel: NewName(args[1]),
  810. PassCommand: PassCommand{password: []byte(args[2])},
  811. }, nil
  812. } else if upperSubCmd == "PRIVMSG" && len(args) == 4 {
  813. return &TheaterPrivMsgCommand{
  814. channel: NewName(args[1]),
  815. asNick: NewName(args[2]),
  816. message: NewText(args[3]),
  817. }, nil
  818. } else if upperSubCmd == "ACTION" && len(args) == 4 {
  819. return &TheaterActionCommand{
  820. channel: NewName(args[1]),
  821. asNick: NewName(args[2]),
  822. action: NewCTCPText(args[3]),
  823. }, nil
  824. } else {
  825. return nil, ErrParseCommand
  826. }
  827. }
  828. type TimeCommand struct {
  829. BaseCommand
  830. target Name
  831. }
  832. func NewTimeCommand(args []string) (Command, error) {
  833. cmd := &TimeCommand{}
  834. if len(args) > 0 {
  835. cmd.target = NewName(args[0])
  836. }
  837. return cmd, nil
  838. }
  839. type KillCommand struct {
  840. BaseCommand
  841. nickname Name
  842. comment Text
  843. }
  844. func NewKillCommand(args []string) (Command, error) {
  845. if len(args) < 2 {
  846. return nil, NotEnoughArgsError
  847. }
  848. return &KillCommand{
  849. nickname: NewName(args[0]),
  850. comment: NewText(args[1]),
  851. }, nil
  852. }
  853. type WhoWasCommand struct {
  854. BaseCommand
  855. nicknames []Name
  856. count int64
  857. target Name
  858. }
  859. func NewWhoWasCommand(args []string) (Command, error) {
  860. if len(args) < 1 {
  861. return nil, NotEnoughArgsError
  862. }
  863. cmd := &WhoWasCommand{
  864. nicknames: NewNames(strings.Split(args[0], ",")),
  865. }
  866. if len(args) > 1 {
  867. cmd.count, _ = strconv.ParseInt(args[1], 10, 64)
  868. }
  869. if len(args) > 2 {
  870. cmd.target = NewName(args[2])
  871. }
  872. return cmd, nil
  873. }
  874. func NewOperNickCommand(args []string) (Command, error) {
  875. if len(args) < 2 {
  876. return nil, NotEnoughArgsError
  877. }
  878. return &OperNickCommand{
  879. target: NewName(args[0]),
  880. nick: NewName(args[1]),
  881. }, nil
  882. }