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

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