summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/irc/main.go40
-rw-r--r--irc/events.go9
-rw-r--r--irc/states.go82
-rw-r--r--irc/tokens.go6
-rw-r--r--ui/ui.go6
5 files changed, 114 insertions, 29 deletions
diff --git a/cmd/irc/main.go b/cmd/irc/main.go
index 2e76c3a..61ee39f 100644
--- a/cmd/irc/main.go
+++ b/cmd/irc/main.go
@@ -59,6 +59,8 @@ func main() {
app.AddLine("home", "Connected to the server", time.Now())
case irc.SelfJoinEvent:
app.AddBuffer(ev.Channel)
+ case irc.SelfPartEvent:
+ app.RemoveBuffer(ev.Channel)
case irc.ChannelMessageEvent:
line := formatIRCMessage(ev.Nick, ev.Content)
app.AddLine(ev.Channel, line, ev.Time)
@@ -94,11 +96,14 @@ func main() {
case tcell.KeyBackspace2:
app.InputBackspace()
case tcell.KeyEnter:
- content := app.InputEnter()
- handleInput(app, &s, content)
+ buffer := app.CurrentBuffer()
+ input := app.InputEnter()
+ handleInput(&s, buffer, input)
case tcell.KeyRune:
app.InputRune(ev.Rune())
- s.Typing(app.CurrentBuffer())
+ if app.CurrentBuffer() != "home" && !strings.HasPrefix(app.Input(), "/") {
+ s.Typing(app.CurrentBuffer())
+ }
}
}
}
@@ -117,35 +122,44 @@ func parseCommand(s string) (command, args string) {
i := strings.IndexByte(s, ' ')
if i < 0 {
- i = len(s) - 1
+ i = len(s)
}
command = strings.ToUpper(s[1:i])
- args = s[i+1:]
+ args = strings.TrimLeft(s[i:], " ")
return
}
-func handleInput(app *ui.UI, s *irc.Session, content string) {
+func handleInput(s *irc.Session, buffer, content string) {
cmd, args := parseCommand(content)
switch cmd {
case "":
- ch := app.CurrentBuffer()
- if ch == "home" {
+ if buffer == "home" {
+ return
+ }
+
+ s.PrivMsg(buffer, args)
+ case "J", "JOIN":
+ s.Join(args)
+ case "PART":
+ if buffer == "home" {
return
}
- s.PrivMsg(ch, args)
+ if args == "" {
+ args = buffer
+ }
+
+ s.Part(args)
case "ME":
- ch := app.CurrentBuffer()
- if ch == "home" {
+ if buffer == "home" {
return
}
line := fmt.Sprintf("\x01ACTION %s\x01", args)
- s.PrivMsg(ch, line)
- default:
+ s.PrivMsg(buffer, line)
}
}
diff --git a/irc/events.go b/irc/events.go
index 2cd5214..c2af056 100644
--- a/irc/events.go
+++ b/irc/events.go
@@ -34,6 +34,15 @@ type UserJoinEvent struct {
ChannelEvent
}
+type SelfPartEvent struct {
+ ChannelEvent
+}
+
+type UserPartEvent struct {
+ UserEvent
+ ChannelEvent
+}
+
type SelfJoinEvent struct {
ChannelEvent
}
diff --git a/irc/states.go b/irc/states.go
index 177c68f..40ac308 100644
--- a/irc/states.go
+++ b/irc/states.go
@@ -84,16 +84,23 @@ type Channel struct {
type action interface{}
type (
+ actionJoin struct {
+ Channel string
+ }
+ actionPart struct {
+ Channel string
+ }
+
actionPrivMsg struct {
- To string
+ Channel string
Content string
}
actionTyping struct {
- To string
+ Channel string
}
actionTypingStop struct {
- To string
+ Channel string
}
)
@@ -137,9 +144,9 @@ type Session struct {
func NewSession(conn io.ReadWriteCloser, params SessionParams) (s Session, err error) {
s = Session{
conn: conn,
- msgs: make(chan Message, 10),
- acts: make(chan action, 10),
- evts: make(chan Event, 10),
+ msgs: make(chan Message, 128),
+ acts: make(chan action, 128),
+ evts: make(chan Event, 128),
typingStamps: map[string]time.Time{},
nick: params.Nickname,
lNick: strings.ToLower(params.Nickname),
@@ -205,17 +212,35 @@ func (s *Session) IsChannel(name string) bool {
return strings.IndexAny(name, "#&") == 0 // TODO compute CHANTYPES
}
-func (s *Session) PrivMsg(to, content string) {
- s.acts <- actionPrivMsg{to, content}
+func (s *Session) Join(channel string) {
+ s.acts <- actionJoin{channel}
+}
+
+func (s *Session) join(act actionJoin) (err error) {
+ err = s.send("JOIN %s\r\n", act.Channel)
+ return
+}
+
+func (s *Session) Part(channel string) {
+ s.acts <- actionPart{channel}
+}
+
+func (s *Session) part(act actionPart) (err error) {
+ err = s.send("PART %s\r\n", act.Channel)
+ return
+}
+
+func (s *Session) PrivMsg(channel, content string) {
+ s.acts <- actionPrivMsg{channel, content}
}
func (s *Session) privMsg(act actionPrivMsg) (err error) {
- err = s.send("PRIVMSG %s :%s\r\n", act.To, act.Content)
+ err = s.send("PRIVMSG %s :%s\r\n", act.Channel, act.Content)
return
}
-func (s *Session) Typing(to string) {
- s.acts <- actionTyping{to}
+func (s *Session) Typing(channel string) {
+ s.acts <- actionTyping{channel}
}
func (s *Session) typing(act actionTyping) (err error) {
@@ -223,13 +248,16 @@ func (s *Session) typing(act actionTyping) (err error) {
return
}
- to := strings.ToLower(act.To)
+ to := strings.ToLower(act.Channel)
+ now := time.Now()
- if t, ok := s.typingStamps[to]; ok && time.Now().Sub(t) < 3 {
+ if t, ok := s.typingStamps[to]; ok && now.Sub(t).Seconds() < 3.0 {
return
}
- err = s.send("@+typing=active TAGMSG %s\r\n", act.To)
+ s.typingStamps[to] = now
+
+ err = s.send("@+typing=active TAGMSG %s\r\n", act.Channel)
return
}
@@ -242,7 +270,7 @@ func (s *Session) typingStop(act actionTypingStop) (err error) {
return
}
- err = s.send("@+typing=done TAGMSG %s\r\n", act.To)
+ err = s.send("@+typing=done TAGMSG %s\r\n", act.Channel)
return
}
@@ -256,6 +284,10 @@ func (s *Session) run() {
select {
case act := <-s.acts:
switch act := act.(type) {
+ case actionJoin:
+ err = s.join(act)
+ case actionPart:
+ err = s.part(act)
case actionPrivMsg:
err = s.privMsg(act)
case actionTyping:
@@ -497,6 +529,19 @@ func (s *Session) handle(msg Message) (ev Event, err error) {
c.Members[lNick] = ""
ev = UserJoinEvent{ChannelEvent: channelEv, UserEvent: UserEvent{Nick: nick}}
}
+ case "PART":
+ nick, _, _ := FullMask(msg.Prefix)
+ lNick := strings.ToLower(nick)
+ channel := strings.ToLower(msg.Params[0])
+ channelEv := ChannelEvent{Channel: msg.Params[0]}
+
+ if lNick == s.lNick {
+ delete(s.channels, channel)
+ ev = SelfPartEvent{ChannelEvent: channelEv}
+ } else if c, ok := s.channels[channel]; ok {
+ delete(c.Members, lNick)
+ ev = UserPartEvent{ChannelEvent: channelEv, UserEvent: UserEvent{Nick: nick}}
+ }
case "353": // RPL_NAMREPLY
channel := strings.ToLower(msg.Params[2])
@@ -623,3 +668,10 @@ func (s *Session) send(format string, args ...interface{}) (err error) {
}
// */
+
+/*
+func (s *Session) send(format string, args ...interface{}) (err error) {
+ go fmt.Fprintf(s.conn, format, args...)
+ return
+}
+// */
diff --git a/irc/tokens.go b/irc/tokens.go
index 976207d..bbe7e8b 100644
--- a/irc/tokens.go
+++ b/irc/tokens.go
@@ -201,6 +201,12 @@ func (msg *Message) Validate() (err error) {
} else if msg.Prefix == "" {
err = errNoPrefix
}
+ case "PART":
+ if len(msg.Params) < 1 {
+ err = errNotEnoughParams
+ } else if msg.Prefix == "" {
+ err = errNoPrefix
+ }
case "353":
if len(msg.Params) < 4 {
err = errNotEnoughParams
diff --git a/ui/ui.go b/ui/ui.go
index 7bdf4a7..04d3f25 100644
--- a/ui/ui.go
+++ b/ui/ui.go
@@ -34,7 +34,7 @@ func New() (ui *UI, err error) {
ui.screen.Clear()
ui.screen.ShowCursor(0, h-2)
- ui.Events = make(chan tcell.Event)
+ ui.Events = make(chan tcell.Event, 128)
go func() {
for !ui.ShouldExit() {
ui.Events <- ui.screen.PollEvent()
@@ -125,6 +125,10 @@ func (ui *UI) AddLine(buffer string, line string, t time.Time) {
}
}
+func (ui *UI) Input() string {
+ return string(ui.textInput)
+}
+
func (ui *UI) InputRune(r rune) {
ui.textInput = append(ui.textInput, r)
ui.textCursor++