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 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. package irc
  2. import (
  3. "code.google.com/p/go.text/unicode/norm"
  4. "errors"
  5. "fmt"
  6. "regexp"
  7. "strconv"
  8. "strings"
  9. )
  10. type checkPasswordCommand interface {
  11. LoadPassword(*Server)
  12. CheckPassword()
  13. }
  14. type parseCommandFunc func([]string) (Command, error)
  15. var (
  16. NotEnoughArgsError = errors.New("not enough arguments")
  17. ErrParseCommand = errors.New("failed to parse message")
  18. parseCommandFuncs = map[StringCode]parseCommandFunc{
  19. AWAY: NewAwayCommand,
  20. CAP: NewCapCommand,
  21. DEBUG: NewDebugCommand,
  22. INVITE: NewInviteCommand,
  23. ISON: NewIsOnCommand,
  24. JOIN: NewJoinCommand,
  25. KICK: NewKickCommand,
  26. KILL: NewKillCommand,
  27. LIST: NewListCommand,
  28. MODE: NewModeCommand,
  29. MOTD: NewMOTDCommand,
  30. NAMES: NewNamesCommand,
  31. NICK: NewNickCommand,
  32. NOTICE: NewNoticeCommand,
  33. OPER: NewOperCommand,
  34. PART: NewPartCommand,
  35. PASS: NewPassCommand,
  36. PING: NewPingCommand,
  37. PONG: NewPongCommand,
  38. PRIVMSG: NewPrivMsgCommand,
  39. PROXY: NewProxyCommand,
  40. QUIT: NewQuitCommand,
  41. TIME: NewTimeCommand,
  42. TOPIC: NewTopicCommand,
  43. USER: NewUserCommand,
  44. VERSION: NewVersionCommand,
  45. WHO: NewWhoCommand,
  46. WHOIS: NewWhoisCommand,
  47. WHOWAS: NewWhoWasCommand,
  48. }
  49. )
  50. type BaseCommand struct {
  51. client *Client
  52. code StringCode
  53. }
  54. func (command *BaseCommand) Client() *Client {
  55. return command.client
  56. }
  57. func (command *BaseCommand) SetClient(client *Client) {
  58. command.client = client
  59. }
  60. func (command *BaseCommand) Code() StringCode {
  61. return command.code
  62. }
  63. func (command *BaseCommand) SetCode(code StringCode) {
  64. command.code = code
  65. }
  66. func ParseCommand(line string) (cmd Command, err error) {
  67. code, args := ParseLine(line)
  68. constructor := parseCommandFuncs[code]
  69. if constructor == nil {
  70. cmd = NewUnknownCommand(args)
  71. } else {
  72. cmd, err = constructor(args)
  73. }
  74. if cmd != nil {
  75. cmd.SetCode(code)
  76. }
  77. return
  78. }
  79. var (
  80. spacesExpr = regexp.MustCompile(` +`)
  81. )
  82. func splitArg(line string) (arg string, rest string) {
  83. parts := spacesExpr.Split(line, 2)
  84. if len(parts) > 0 {
  85. arg = parts[0]
  86. }
  87. if len(parts) > 1 {
  88. rest = parts[1]
  89. }
  90. return
  91. }
  92. func ParseLine(line string) (command StringCode, args []string) {
  93. args = make([]string, 0)
  94. if strings.HasPrefix(line, ":") {
  95. _, line = splitArg(line)
  96. }
  97. arg, line := splitArg(line)
  98. command = StringCode(strings.ToUpper(arg))
  99. for len(line) > 0 {
  100. if strings.HasPrefix(line, ":") {
  101. args = append(args, norm.NFC.String(line[len(":"):]))
  102. break
  103. }
  104. arg, line = splitArg(line)
  105. args = append(args, norm.NFKC.String(arg))
  106. }
  107. return
  108. }
  109. // <command> [args...]
  110. type UnknownCommand struct {
  111. BaseCommand
  112. args []string
  113. }
  114. func (cmd *UnknownCommand) String() string {
  115. return fmt.Sprintf("UNKNOWN(command=%s, args=%s)", cmd.Code(), cmd.args)
  116. }
  117. func NewUnknownCommand(args []string) *UnknownCommand {
  118. return &UnknownCommand{
  119. args: args,
  120. }
  121. }
  122. // PING <server1> [ <server2> ]
  123. type PingCommand struct {
  124. BaseCommand
  125. server string
  126. server2 string
  127. }
  128. func (cmd *PingCommand) String() string {
  129. return fmt.Sprintf("PING(server=%s, server2=%s)", cmd.server, cmd.server2)
  130. }
  131. func NewPingCommand(args []string) (Command, error) {
  132. if len(args) < 1 {
  133. return nil, NotEnoughArgsError
  134. }
  135. msg := &PingCommand{
  136. server: args[0],
  137. }
  138. if len(args) > 1 {
  139. msg.server2 = args[1]
  140. }
  141. return msg, nil
  142. }
  143. // PONG <server> [ <server2> ]
  144. type PongCommand struct {
  145. BaseCommand
  146. server1 string
  147. server2 string
  148. }
  149. func (cmd *PongCommand) String() string {
  150. return fmt.Sprintf("PONG(server1=%s, server2=%s)", cmd.server1, cmd.server2)
  151. }
  152. func NewPongCommand(args []string) (Command, error) {
  153. if len(args) < 1 {
  154. return nil, NotEnoughArgsError
  155. }
  156. message := &PongCommand{
  157. server1: args[0],
  158. }
  159. if len(args) > 1 {
  160. message.server2 = args[1]
  161. }
  162. return message, nil
  163. }
  164. // PASS <password>
  165. type PassCommand struct {
  166. BaseCommand
  167. hash []byte
  168. password []byte
  169. err error
  170. }
  171. func (cmd *PassCommand) String() string {
  172. return fmt.Sprintf("PASS(password=%s)", cmd.password)
  173. }
  174. func (cmd *PassCommand) LoadPassword(server *Server) {
  175. cmd.hash = server.password
  176. }
  177. func (cmd *PassCommand) CheckPassword() {
  178. if cmd.hash == nil {
  179. return
  180. }
  181. cmd.err = ComparePassword(cmd.hash, cmd.password)
  182. }
  183. func NewPassCommand(args []string) (Command, error) {
  184. if len(args) < 1 {
  185. return nil, NotEnoughArgsError
  186. }
  187. return &PassCommand{
  188. password: []byte(args[0]),
  189. }, nil
  190. }
  191. // NICK <nickname>
  192. type NickCommand struct {
  193. BaseCommand
  194. nickname string
  195. }
  196. func (m *NickCommand) String() string {
  197. return fmt.Sprintf("NICK(nickname=%s)", m.nickname)
  198. }
  199. func NewNickCommand(args []string) (Command, error) {
  200. if len(args) != 1 {
  201. return nil, NotEnoughArgsError
  202. }
  203. return &NickCommand{
  204. nickname: args[0],
  205. }, nil
  206. }
  207. type UserCommand struct {
  208. BaseCommand
  209. username string
  210. realname string
  211. }
  212. // USER <username> <hostname> <servername> <realname>
  213. type RFC1459UserCommand struct {
  214. UserCommand
  215. hostname string
  216. servername string
  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 = args[0]
  253. msg.realname = args[3]
  254. return msg, nil
  255. }
  256. msg := &RFC1459UserCommand{
  257. hostname: args[1],
  258. servername: args[2],
  259. }
  260. msg.username = args[0]
  261. msg.realname = args[3]
  262. return msg, nil
  263. }
  264. // QUIT [ <Quit Command> ]
  265. type QuitCommand struct {
  266. BaseCommand
  267. message string
  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 = args[0]
  276. }
  277. return msg, nil
  278. }
  279. // JOIN ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0"
  280. type JoinCommand struct {
  281. BaseCommand
  282. channels map[string]string
  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[string]string),
  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[channel] = keys[i]
  308. }
  309. return msg, nil
  310. }
  311. // PART <channel> *( "," <channel> ) [ <Part Command> ]
  312. type PartCommand struct {
  313. BaseCommand
  314. channels []string
  315. message string
  316. }
  317. func (cmd *PartCommand) Message() string {
  318. if cmd.message == "" {
  319. return cmd.Client().Nick()
  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: strings.Split(args[0], ","),
  332. }
  333. if len(args) > 1 {
  334. msg.message = args[1]
  335. }
  336. return msg, nil
  337. }
  338. // PRIVMSG <target> <message>
  339. type PrivMsgCommand struct {
  340. BaseCommand
  341. target string
  342. message string
  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: args[0],
  353. message: args[1],
  354. }, nil
  355. }
  356. // TOPIC [newtopic]
  357. type TopicCommand struct {
  358. BaseCommand
  359. channel string
  360. setTopic bool
  361. topic string
  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: args[0],
  372. }
  373. if len(args) > 1 {
  374. msg.setTopic = true
  375. msg.topic = 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 string
  406. changes ModeChanges
  407. }
  408. // MODE <nickname> *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
  409. func NewUserModeCommand(args []string) (Command, error) {
  410. cmd := &ModeCommand{
  411. nickname: args[0],
  412. changes: make(ModeChanges, 0),
  413. }
  414. for _, modeChange := range args[1:] {
  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 string
  472. changes ChannelModeChanges
  473. }
  474. // MODE <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
  475. func NewChannelModeCommand(args []string) (Command, error) {
  476. cmd := &ChannelModeCommand{
  477. channel: args[0],
  478. changes: make(ChannelModeChanges, 0),
  479. }
  480. args = args[1:]
  481. for len(args) > 0 {
  482. if len(args[0]) == 0 {
  483. args = args[1:]
  484. continue
  485. }
  486. modeArg := args[0]
  487. op := ModeOp(modeArg[0])
  488. if (op == Add) || (op == Remove) {
  489. modeArg = modeArg[1:]
  490. } else {
  491. op = List
  492. }
  493. skipArgs := 1
  494. for _, mode := range modeArg {
  495. change := &ChannelModeChange{
  496. mode: ChannelMode(mode),
  497. op: op,
  498. }
  499. switch change.mode {
  500. case Key, BanMask, ExceptMask, InviteMask, UserLimit,
  501. ChannelOperator, ChannelCreator, Voice:
  502. if len(args) > skipArgs {
  503. change.arg = args[skipArgs]
  504. skipArgs += 1
  505. }
  506. }
  507. cmd.changes = append(cmd.changes, change)
  508. }
  509. args = args[skipArgs:]
  510. }
  511. return cmd, nil
  512. }
  513. func (msg *ChannelModeCommand) String() string {
  514. return fmt.Sprintf("MODE(channel=%s, changes=%s)", msg.channel, msg.changes)
  515. }
  516. func NewModeCommand(args []string) (Command, error) {
  517. if len(args) == 0 {
  518. return nil, NotEnoughArgsError
  519. }
  520. if IsChannel(args[0]) {
  521. return NewChannelModeCommand(args)
  522. } else {
  523. return NewUserModeCommand(args)
  524. }
  525. }
  526. type WhoisCommand struct {
  527. BaseCommand
  528. target string
  529. masks []string
  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: target,
  546. masks: 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 string
  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 = 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 string
  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: 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 string
  621. sourceIP string
  622. destIP string
  623. sourcePort string
  624. destPort string
  625. hostname string // 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: args[0],
  636. sourceIP: args[1],
  637. destIP: args[2],
  638. sourcePort: args[3],
  639. destPort: args[4],
  640. hostname: LookupHostname(args[1]),
  641. }, nil
  642. }
  643. type AwayCommand struct {
  644. BaseCommand
  645. text string
  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 = args[0]
  655. cmd.away = true
  656. }
  657. return cmd, nil
  658. }
  659. type IsOnCommand struct {
  660. BaseCommand
  661. nicks []string
  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: args,
  672. }, nil
  673. }
  674. type MOTDCommand struct {
  675. BaseCommand
  676. target string
  677. }
  678. func NewMOTDCommand(args []string) (Command, error) {
  679. cmd := &MOTDCommand{}
  680. if len(args) > 0 {
  681. cmd.target = args[0]
  682. }
  683. return cmd, nil
  684. }
  685. type NoticeCommand struct {
  686. BaseCommand
  687. target string
  688. message string
  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: args[0],
  699. message: args[1],
  700. }, nil
  701. }
  702. type KickCommand struct {
  703. BaseCommand
  704. kicks map[string]string
  705. comment string
  706. }
  707. func (msg *KickCommand) Comment() string {
  708. if msg.comment == "" {
  709. return msg.Client().Nick()
  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 := strings.Split(args[0], ",")
  718. users := 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[string]string),
  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 = args[2]
  734. }
  735. return cmd, nil
  736. }
  737. type ListCommand struct {
  738. BaseCommand
  739. channels []string
  740. target string
  741. }
  742. func NewListCommand(args []string) (Command, error) {
  743. cmd := &ListCommand{}
  744. if len(args) > 0 {
  745. cmd.channels = strings.Split(args[0], ",")
  746. }
  747. if len(args) > 1 {
  748. cmd.target = args[1]
  749. }
  750. return cmd, nil
  751. }
  752. type NamesCommand struct {
  753. BaseCommand
  754. channels []string
  755. target string
  756. }
  757. func NewNamesCommand(args []string) (Command, error) {
  758. cmd := &NamesCommand{}
  759. if len(args) > 0 {
  760. cmd.channels = strings.Split(args[0], ",")
  761. }
  762. if len(args) > 1 {
  763. cmd.target = args[1]
  764. }
  765. return cmd, nil
  766. }
  767. type DebugCommand struct {
  768. BaseCommand
  769. subCommand string
  770. }
  771. func NewDebugCommand(args []string) (Command, error) {
  772. if len(args) == 0 {
  773. return nil, NotEnoughArgsError
  774. }
  775. return &DebugCommand{
  776. subCommand: strings.ToUpper(args[0]),
  777. }, nil
  778. }
  779. type VersionCommand struct {
  780. BaseCommand
  781. target string
  782. }
  783. func NewVersionCommand(args []string) (Command, error) {
  784. cmd := &VersionCommand{}
  785. if len(args) > 0 {
  786. cmd.target = args[0]
  787. }
  788. return cmd, nil
  789. }
  790. type InviteCommand struct {
  791. BaseCommand
  792. nickname string
  793. channel string
  794. }
  795. func NewInviteCommand(args []string) (Command, error) {
  796. if len(args) < 2 {
  797. return nil, NotEnoughArgsError
  798. }
  799. return &InviteCommand{
  800. nickname: args[0],
  801. channel: args[1],
  802. }, nil
  803. }
  804. type TimeCommand struct {
  805. BaseCommand
  806. target string
  807. }
  808. func NewTimeCommand(args []string) (Command, error) {
  809. cmd := &TimeCommand{}
  810. if len(args) > 0 {
  811. cmd.target = args[0]
  812. }
  813. return cmd, nil
  814. }
  815. type KillCommand struct {
  816. BaseCommand
  817. nickname string
  818. comment string
  819. }
  820. func NewKillCommand(args []string) (Command, error) {
  821. if len(args) < 2 {
  822. return nil, NotEnoughArgsError
  823. }
  824. return &KillCommand{
  825. nickname: args[0],
  826. comment: args[1],
  827. }, nil
  828. }
  829. type WhoWasCommand struct {
  830. BaseCommand
  831. nicknames []string
  832. count int64
  833. target string
  834. }
  835. func NewWhoWasCommand(args []string) (Command, error) {
  836. if len(args) < 1 {
  837. return nil, NotEnoughArgsError
  838. }
  839. cmd := &WhoWasCommand{
  840. nicknames: strings.Split(args[0], ","),
  841. }
  842. if len(args) > 1 {
  843. cmd.count, _ = strconv.ParseInt(args[1], 10, 64)
  844. }
  845. if len(args) > 2 {
  846. cmd.target = args[2]
  847. }
  848. return cmd, nil
  849. }