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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  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. keys[i] = key
  285. }
  286. }
  287. for i, channel := range channels {
  288. msg.channels[NewName(channel)] = NewText(keys[i])
  289. }
  290. return msg, nil
  291. }
  292. // PART <channel> *( "," <channel> ) [ <Part Command> ]
  293. type PartCommand struct {
  294. BaseCommand
  295. channels []Name
  296. message Text
  297. }
  298. func (cmd *PartCommand) Message() Text {
  299. if cmd.message == "" {
  300. return cmd.Client().Nick().Text()
  301. }
  302. return cmd.message
  303. }
  304. func ParsePartCommand(args []string) (Command, error) {
  305. if len(args) < 1 {
  306. return nil, NotEnoughArgsError
  307. }
  308. msg := &PartCommand{
  309. channels: NewNames(strings.Split(args[0], ",")),
  310. }
  311. if len(args) > 1 {
  312. msg.message = NewText(args[1])
  313. }
  314. return msg, nil
  315. }
  316. // PRIVMSG <target> <message>
  317. type PrivMsgCommand struct {
  318. BaseCommand
  319. target Name
  320. message Text
  321. }
  322. func ParsePrivMsgCommand(args []string) (Command, error) {
  323. if len(args) < 2 {
  324. return nil, NotEnoughArgsError
  325. }
  326. return &PrivMsgCommand{
  327. target: NewName(args[0]),
  328. message: NewText(args[1]),
  329. }, nil
  330. }
  331. // TOPIC [newtopic]
  332. type TopicCommand struct {
  333. BaseCommand
  334. channel Name
  335. setTopic bool
  336. topic Text
  337. }
  338. func ParseTopicCommand(args []string) (Command, error) {
  339. if len(args) < 1 {
  340. return nil, NotEnoughArgsError
  341. }
  342. msg := &TopicCommand{
  343. channel: NewName(args[0]),
  344. }
  345. if len(args) > 1 {
  346. msg.setTopic = true
  347. msg.topic = NewText(args[1])
  348. }
  349. return msg, nil
  350. }
  351. type ModeChange struct {
  352. mode UserMode
  353. op ModeOp
  354. }
  355. func (change *ModeChange) String() string {
  356. return fmt.Sprintf("%s%s", change.op, change.mode)
  357. }
  358. type ModeChanges []*ModeChange
  359. func (changes ModeChanges) String() string {
  360. if len(changes) == 0 {
  361. return ""
  362. }
  363. op := changes[0].op
  364. str := changes[0].op.String()
  365. for _, change := range changes {
  366. if change.op == op {
  367. str += change.mode.String()
  368. } else {
  369. op = change.op
  370. str += " " + change.op.String()
  371. }
  372. }
  373. return str
  374. }
  375. type ModeCommand struct {
  376. BaseCommand
  377. nickname Name
  378. changes ModeChanges
  379. }
  380. // MODE <nickname> *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
  381. func ParseUserModeCommand(nickname Name, args []string) (Command, error) {
  382. cmd := &ModeCommand{
  383. nickname: nickname,
  384. changes: make(ModeChanges, 0),
  385. }
  386. for _, modeChange := range args {
  387. if len(modeChange) == 0 {
  388. continue
  389. }
  390. op := ModeOp(modeChange[0])
  391. if (op != Add) && (op != Remove) {
  392. return nil, ErrParseCommand
  393. }
  394. for _, mode := range modeChange[1:] {
  395. cmd.changes = append(cmd.changes, &ModeChange{
  396. mode: UserMode(mode),
  397. op: op,
  398. })
  399. }
  400. }
  401. return cmd, nil
  402. }
  403. type ChannelModeChange struct {
  404. mode ChannelMode
  405. op ModeOp
  406. arg string
  407. }
  408. func (change *ChannelModeChange) String() (str string) {
  409. if (change.op == Add) || (change.op == Remove) {
  410. str = change.op.String()
  411. }
  412. str += change.mode.String()
  413. if change.arg != "" {
  414. str += " " + change.arg
  415. }
  416. return
  417. }
  418. type ChannelModeChanges []*ChannelModeChange
  419. func (changes ChannelModeChanges) String() (str string) {
  420. if len(changes) == 0 {
  421. return
  422. }
  423. str = "+"
  424. if changes[0].op == Remove {
  425. str = "-"
  426. }
  427. for _, change := range changes {
  428. str += change.mode.String()
  429. }
  430. for _, change := range changes {
  431. if change.arg == "" {
  432. continue
  433. }
  434. str += " " + change.arg
  435. }
  436. return
  437. }
  438. type ChannelModeCommand struct {
  439. BaseCommand
  440. channel Name
  441. changes ChannelModeChanges
  442. }
  443. // MODE <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
  444. func ParseChannelModeCommand(channel Name, args []string) (Command, error) {
  445. cmd := &ChannelModeCommand{
  446. channel: channel,
  447. changes: make(ChannelModeChanges, 0),
  448. }
  449. for len(args) > 0 {
  450. if len(args[0]) == 0 {
  451. args = args[1:]
  452. continue
  453. }
  454. modeArg := args[0]
  455. op := ModeOp(modeArg[0])
  456. if (op == Add) || (op == Remove) {
  457. modeArg = modeArg[1:]
  458. } else {
  459. op = List
  460. }
  461. skipArgs := 1
  462. for _, mode := range modeArg {
  463. change := &ChannelModeChange{
  464. mode: ChannelMode(mode),
  465. op: op,
  466. }
  467. switch change.mode {
  468. case Key, BanMask, ExceptMask, InviteMask, UserLimit,
  469. ChannelOperator, ChannelCreator, Voice:
  470. if len(args) > skipArgs {
  471. change.arg = args[skipArgs]
  472. skipArgs += 1
  473. }
  474. }
  475. cmd.changes = append(cmd.changes, change)
  476. }
  477. args = args[skipArgs:]
  478. }
  479. return cmd, nil
  480. }
  481. func ParseModeCommand(args []string) (Command, error) {
  482. if len(args) == 0 {
  483. return nil, NotEnoughArgsError
  484. }
  485. name := NewName(args[0])
  486. if name.IsChannel() {
  487. return ParseChannelModeCommand(name, args[1:])
  488. } else {
  489. return ParseUserModeCommand(name, args[1:])
  490. }
  491. }
  492. type WhoisCommand struct {
  493. BaseCommand
  494. target Name
  495. masks []Name
  496. }
  497. // WHOIS [ <target> ] <mask> *( "," <mask> )
  498. func ParseWhoisCommand(args []string) (Command, error) {
  499. if len(args) < 1 {
  500. return nil, NotEnoughArgsError
  501. }
  502. var masks string
  503. var target string
  504. if len(args) > 1 {
  505. target = args[0]
  506. masks = args[1]
  507. } else {
  508. masks = args[0]
  509. }
  510. return &WhoisCommand{
  511. target: NewName(target),
  512. masks: NewNames(strings.Split(masks, ",")),
  513. }, nil
  514. }
  515. type WhoCommand struct {
  516. BaseCommand
  517. mask Name
  518. operatorOnly bool
  519. }
  520. // WHO [ <mask> [ "o" ] ]
  521. func ParseWhoCommand(args []string) (Command, error) {
  522. cmd := &WhoCommand{}
  523. if len(args) > 0 {
  524. cmd.mask = NewName(args[0])
  525. }
  526. if (len(args) > 1) && (args[1] == "o") {
  527. cmd.operatorOnly = true
  528. }
  529. return cmd, nil
  530. }
  531. type OperCommand struct {
  532. PassCommand
  533. name Name
  534. }
  535. func (msg *OperCommand) LoadPassword(server *Server) {
  536. msg.hash = server.operators[msg.name]
  537. }
  538. // OPER <name> <password>
  539. func ParseOperCommand(args []string) (Command, error) {
  540. if len(args) < 2 {
  541. return nil, NotEnoughArgsError
  542. }
  543. cmd := &OperCommand{
  544. name: NewName(args[0]),
  545. }
  546. cmd.password = []byte(args[1])
  547. return cmd, nil
  548. }
  549. type CapCommand struct {
  550. BaseCommand
  551. subCommand CapSubCommand
  552. capabilities CapabilitySet
  553. }
  554. func ParseCapCommand(args []string) (Command, error) {
  555. if len(args) < 1 {
  556. return nil, NotEnoughArgsError
  557. }
  558. cmd := &CapCommand{
  559. subCommand: CapSubCommand(strings.ToUpper(args[0])),
  560. capabilities: make(CapabilitySet),
  561. }
  562. if len(args) > 1 {
  563. strs := spacesExpr.Split(args[1], -1)
  564. for _, str := range strs {
  565. cmd.capabilities[Capability(str)] = true
  566. }
  567. }
  568. return cmd, nil
  569. }
  570. // HAPROXY support
  571. type ProxyCommand struct {
  572. BaseCommand
  573. net Name
  574. sourceIP Name
  575. destIP Name
  576. sourcePort Name
  577. destPort Name
  578. hostname Name // looked up in socket thread
  579. }
  580. func NewProxyCommand(hostname Name) *ProxyCommand {
  581. cmd := &ProxyCommand{
  582. hostname: hostname,
  583. }
  584. cmd.code = PROXY
  585. return cmd
  586. }
  587. func ParseProxyCommand(args []string) (Command, error) {
  588. if len(args) < 5 {
  589. return nil, NotEnoughArgsError
  590. }
  591. return &ProxyCommand{
  592. net: NewName(args[0]),
  593. sourceIP: NewName(args[1]),
  594. destIP: NewName(args[2]),
  595. sourcePort: NewName(args[3]),
  596. destPort: NewName(args[4]),
  597. hostname: LookupHostname(NewName(args[1])),
  598. }, nil
  599. }
  600. type AwayCommand struct {
  601. BaseCommand
  602. text Text
  603. }
  604. func ParseAwayCommand(args []string) (Command, error) {
  605. cmd := &AwayCommand{}
  606. if len(args) > 0 {
  607. cmd.text = NewText(args[0])
  608. }
  609. return cmd, nil
  610. }
  611. type IsOnCommand struct {
  612. BaseCommand
  613. nicks []Name
  614. }
  615. func ParseIsOnCommand(args []string) (Command, error) {
  616. if len(args) == 0 {
  617. return nil, NotEnoughArgsError
  618. }
  619. return &IsOnCommand{
  620. nicks: NewNames(args),
  621. }, nil
  622. }
  623. type MOTDCommand struct {
  624. BaseCommand
  625. target Name
  626. }
  627. func ParseMOTDCommand(args []string) (Command, error) {
  628. cmd := &MOTDCommand{}
  629. if len(args) > 0 {
  630. cmd.target = NewName(args[0])
  631. }
  632. return cmd, nil
  633. }
  634. type NoticeCommand struct {
  635. BaseCommand
  636. target Name
  637. message Text
  638. }
  639. func ParseNoticeCommand(args []string) (Command, error) {
  640. if len(args) < 2 {
  641. return nil, NotEnoughArgsError
  642. }
  643. return &NoticeCommand{
  644. target: NewName(args[0]),
  645. message: NewText(args[1]),
  646. }, nil
  647. }
  648. type KickCommand struct {
  649. BaseCommand
  650. kicks map[Name]Name
  651. comment Text
  652. }
  653. func (msg *KickCommand) Comment() Text {
  654. if msg.comment == "" {
  655. return msg.Client().Nick().Text()
  656. }
  657. return msg.comment
  658. }
  659. func ParseKickCommand(args []string) (Command, error) {
  660. if len(args) < 2 {
  661. return nil, NotEnoughArgsError
  662. }
  663. channels := NewNames(strings.Split(args[0], ","))
  664. users := NewNames(strings.Split(args[1], ","))
  665. if (len(channels) != len(users)) && (len(users) != 1) {
  666. return nil, NotEnoughArgsError
  667. }
  668. cmd := &KickCommand{
  669. kicks: make(map[Name]Name),
  670. }
  671. for index, channel := range channels {
  672. if len(users) == 1 {
  673. cmd.kicks[channel] = users[0]
  674. } else {
  675. cmd.kicks[channel] = users[index]
  676. }
  677. }
  678. if len(args) > 2 {
  679. cmd.comment = NewText(args[2])
  680. }
  681. return cmd, nil
  682. }
  683. type ListCommand struct {
  684. BaseCommand
  685. channels []Name
  686. target Name
  687. }
  688. func ParseListCommand(args []string) (Command, error) {
  689. cmd := &ListCommand{}
  690. if len(args) > 0 {
  691. cmd.channels = NewNames(strings.Split(args[0], ","))
  692. }
  693. if len(args) > 1 {
  694. cmd.target = NewName(args[1])
  695. }
  696. return cmd, nil
  697. }
  698. type NamesCommand struct {
  699. BaseCommand
  700. channels []Name
  701. target Name
  702. }
  703. func ParseNamesCommand(args []string) (Command, error) {
  704. cmd := &NamesCommand{}
  705. if len(args) > 0 {
  706. cmd.channels = NewNames(strings.Split(args[0], ","))
  707. }
  708. if len(args) > 1 {
  709. cmd.target = NewName(args[1])
  710. }
  711. return cmd, nil
  712. }
  713. type DebugCommand struct {
  714. BaseCommand
  715. subCommand Name
  716. }
  717. func ParseDebugCommand(args []string) (Command, error) {
  718. if len(args) == 0 {
  719. return nil, NotEnoughArgsError
  720. }
  721. return &DebugCommand{
  722. subCommand: NewName(strings.ToUpper(args[0])),
  723. }, nil
  724. }
  725. type VersionCommand struct {
  726. BaseCommand
  727. target Name
  728. }
  729. func ParseVersionCommand(args []string) (Command, error) {
  730. cmd := &VersionCommand{}
  731. if len(args) > 0 {
  732. cmd.target = NewName(args[0])
  733. }
  734. return cmd, nil
  735. }
  736. type InviteCommand struct {
  737. BaseCommand
  738. nickname Name
  739. channel Name
  740. }
  741. func ParseInviteCommand(args []string) (Command, error) {
  742. if len(args) < 2 {
  743. return nil, NotEnoughArgsError
  744. }
  745. return &InviteCommand{
  746. nickname: NewName(args[0]),
  747. channel: NewName(args[1]),
  748. }, nil
  749. }
  750. func ParseTheaterCommand(args []string) (Command, error) {
  751. if len(args) < 1 {
  752. return nil, NotEnoughArgsError
  753. } else if upperSubCmd := strings.ToUpper(args[0]); upperSubCmd == "IDENTIFY" && len(args) == 3 {
  754. return &TheaterIdentifyCommand{
  755. channel: NewName(args[1]),
  756. PassCommand: PassCommand{password: []byte(args[2])},
  757. }, nil
  758. } else if upperSubCmd == "PRIVMSG" && len(args) == 4 {
  759. return &TheaterPrivMsgCommand{
  760. channel: NewName(args[1]),
  761. asNick: NewName(args[2]),
  762. message: NewText(args[3]),
  763. }, nil
  764. } else if upperSubCmd == "ACTION" && len(args) == 4 {
  765. return &TheaterActionCommand{
  766. channel: NewName(args[1]),
  767. asNick: NewName(args[2]),
  768. action: NewCTCPText(args[3]),
  769. }, nil
  770. } else {
  771. return nil, ErrParseCommand
  772. }
  773. }
  774. type TimeCommand struct {
  775. BaseCommand
  776. target Name
  777. }
  778. func ParseTimeCommand(args []string) (Command, error) {
  779. cmd := &TimeCommand{}
  780. if len(args) > 0 {
  781. cmd.target = NewName(args[0])
  782. }
  783. return cmd, nil
  784. }
  785. type KillCommand struct {
  786. BaseCommand
  787. nickname Name
  788. comment Text
  789. }
  790. func ParseKillCommand(args []string) (Command, error) {
  791. if len(args) < 2 {
  792. return nil, NotEnoughArgsError
  793. }
  794. return &KillCommand{
  795. nickname: NewName(args[0]),
  796. comment: NewText(args[1]),
  797. }, nil
  798. }
  799. type WhoWasCommand struct {
  800. BaseCommand
  801. nicknames []Name
  802. count int64
  803. target Name
  804. }
  805. func ParseWhoWasCommand(args []string) (Command, error) {
  806. if len(args) < 1 {
  807. return nil, NotEnoughArgsError
  808. }
  809. cmd := &WhoWasCommand{
  810. nicknames: NewNames(strings.Split(args[0], ",")),
  811. }
  812. if len(args) > 1 {
  813. cmd.count, _ = strconv.ParseInt(args[1], 10, 64)
  814. }
  815. if len(args) > 2 {
  816. cmd.target = NewName(args[2])
  817. }
  818. return cmd, nil
  819. }
  820. func ParseOperNickCommand(args []string) (Command, error) {
  821. if len(args) < 2 {
  822. return nil, NotEnoughArgsError
  823. }
  824. return &OperNickCommand{
  825. target: NewName(args[0]),
  826. nick: NewName(args[1]),
  827. }, nil
  828. }