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

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