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

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