Skip to content

Commit

Permalink
Merge pull request #1606 from slingamn/listcorrespondents.2
Browse files Browse the repository at this point in the history
fix #1592
  • Loading branch information
slingamn authored Apr 7, 2021
2 parents 2e9a0d4 + 18b6e2f commit b83b051
Show file tree
Hide file tree
Showing 12 changed files with 511 additions and 73 deletions.
11 changes: 3 additions & 8 deletions irc/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,7 @@ func (channel *Channel) autoReplayHistory(client *Client, rb *ResponseBuffer, sk
_, seq, _ := channel.server.GetHistorySequence(channel, client, "")
if seq != nil {
zncMax := channel.server.Config().History.ZNCMax
items, _, _ = seq.Between(history.Selector{Time: start}, history.Selector{Time: end}, zncMax)
items, _ = seq.Between(history.Selector{Time: start}, history.Selector{Time: end}, zncMax)
}
} else if !rb.session.HasHistoryCaps() {
var replayLimit int
Expand All @@ -937,7 +937,7 @@ func (channel *Channel) autoReplayHistory(client *Client, rb *ResponseBuffer, sk
if 0 < replayLimit {
_, seq, _ := channel.server.GetHistorySequence(channel, client, "")
if seq != nil {
items, _, _ = seq.Between(history.Selector{}, history.Selector{}, replayLimit)
items, _ = seq.Between(history.Selector{}, history.Selector{}, replayLimit)
}
}
}
Expand Down Expand Up @@ -1097,20 +1097,15 @@ func (channel *Channel) resumeAndAnnounce(session *Session) {

func (channel *Channel) replayHistoryForResume(session *Session, after time.Time, before time.Time) {
var items []history.Item
var complete bool
afterS, beforeS := history.Selector{Time: after}, history.Selector{Time: before}
_, seq, _ := channel.server.GetHistorySequence(channel, session.client, "")
if seq != nil {
items, complete, _ = seq.Between(afterS, beforeS, channel.server.Config().History.ZNCMax)
items, _ = seq.Between(afterS, beforeS, channel.server.Config().History.ZNCMax)
}
rb := NewResponseBuffer(session)
if len(items) != 0 {
channel.replayHistoryItems(rb, items, false)
}
if !complete && !session.resumeDetails.HistoryIncomplete {
// warn here if we didn't warn already
rb.Add(nil, histservService.prefix, "NOTICE", channel.Name(), session.client.t("Some additional message history may have been lost"))
}
rb.Send(true)
}

Expand Down
10 changes: 10 additions & 0 deletions irc/channelmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,3 +458,13 @@ func (cm *ChannelManager) ListPurged() (result []string) {
sort.Strings(result)
return
}

func (cm *ChannelManager) UnfoldName(cfname string) (result string) {
cm.RLock()
entry := cm.chans[cfname]
cm.RUnlock()
if entry != nil && entry.channel.IsLoaded() {
return entry.channel.Name()
}
return cfname
}
48 changes: 41 additions & 7 deletions irc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,7 @@ func (session *Session) playResume() {
}
_, privmsgSeq, _ := server.GetHistorySequence(nil, client, "*")
if privmsgSeq != nil {
privmsgs, _, _ := privmsgSeq.Between(history.Selector{}, history.Selector{}, config.History.ClientLength)
privmsgs, _ := privmsgSeq.Between(history.Selector{}, history.Selector{}, config.History.ClientLength)
for _, item := range privmsgs {
sender := server.clients.Get(NUHToNick(item.Nick))
if sender != nil {
Expand Down Expand Up @@ -1055,18 +1055,18 @@ func (session *Session) playResume() {
// replay direct PRIVSMG history
if !timestamp.IsZero() && privmsgSeq != nil {
after := history.Selector{Time: timestamp}
items, complete, _ := privmsgSeq.Between(after, history.Selector{}, config.History.ZNCMax)
items, _ := privmsgSeq.Between(after, history.Selector{}, config.History.ZNCMax)
if len(items) != 0 {
rb := NewResponseBuffer(session)
client.replayPrivmsgHistory(rb, items, "", complete)
client.replayPrivmsgHistory(rb, items, "")
rb.Send(true)
}
}

session.resumeDetails = nil
}

func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, target string, complete bool) {
func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, target string) {
var batchID string
details := client.Details()
nick := details.nick
Expand Down Expand Up @@ -1126,9 +1126,6 @@ func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.I
}

rb.EndNestedBatch(batchID)
if !complete {
rb.Add(nil, histservService.prefix, "NOTICE", nick, client.t("Some additional message history may have been lost"))
}
}

// IdleTime returns how long this client's been idle.
Expand Down Expand Up @@ -1934,6 +1931,43 @@ func (client *Client) addHistoryItem(target *Client, item history.Item, details,
return nil
}

func (client *Client) listTargets(start, end history.Selector, limit int) (results []history.TargetListing, err error) {
var base, extras []history.TargetListing
var chcfnames []string
for _, channel := range client.Channels() {
_, seq, err := client.server.GetHistorySequence(channel, client, "")
if seq == nil || err != nil {
continue
}
if seq.Ephemeral() {
items, err := seq.Between(history.Selector{}, history.Selector{}, 1)
if err == nil && len(items) != 0 {
extras = append(extras, history.TargetListing{
Time: items[0].Message.Time,
CfName: channel.NameCasefolded(),
})
}
} else {
chcfnames = append(chcfnames, channel.NameCasefolded())
}
}
persistentExtras, err := client.server.historyDB.ListChannels(chcfnames)
if err == nil && len(persistentExtras) != 0 {
extras = append(extras, persistentExtras...)
}

_, cSeq, err := client.server.GetHistorySequence(nil, client, "*")
if err == nil && cSeq != nil {
correspondents, err := cSeq.ListCorrespondents(start, end, limit)
if err == nil {
base = correspondents
}
}

results = history.MergeTargets(base, extras, start.Time, end.Time, limit)
return results, nil
}

func (client *Client) handleRegisterTimeout() {
client.Quit(fmt.Sprintf("Registration timeout: %v", RegisterTimeout), nil)
client.destroy(nil)
Expand Down
13 changes: 13 additions & 0 deletions irc/client_lookup_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,16 @@ func (clients *ClientManager) FindAll(userhost string) (set ClientSet) {

return set
}

// Determine the canonical / unfolded form of a nick, if a client matching it
// is present (or always-on).
func (clients *ClientManager) UnfoldNick(cfnick string) (nick string) {
clients.RLock()
c := clients.byNick[cfnick]
clients.RUnlock()
if c != nil {
return c.Nick()
} else {
return cfnick
}
}
57 changes: 37 additions & 20 deletions irc/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,27 +566,34 @@ func capHandler(server *Server, client *Client, msg ircmsg.Message, rb *Response
// e.g., CHATHISTORY #ircv3 BETWEEN timestamp=YYYY-MM-DDThh:mm:ss.sssZ timestamp=YYYY-MM-DDThh:mm:ss.sssZ + 100
func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) (exiting bool) {
var items []history.Item
unknown_command := false
var target string
var channel *Channel
var sequence history.Sequence
var err error
var listTargets bool
var targets []history.TargetListing
defer func() {
// errors are sent either without a batch, or in a draft/labeled-response batch as usual
if unknown_command {
rb.Add(nil, server.name, "FAIL", "CHATHISTORY", "UNKNOWN_COMMAND", utils.SafeErrorParam(msg.Params[0]), client.t("Unknown command"))
} else if err == utils.ErrInvalidParams {
if err == utils.ErrInvalidParams {
rb.Add(nil, server.name, "FAIL", "CHATHISTORY", "INVALID_PARAMS", msg.Params[0], client.t("Invalid parameters"))
} else if sequence == nil {
} else if !listTargets && sequence == nil {
rb.Add(nil, server.name, "FAIL", "CHATHISTORY", "INVALID_TARGET", utils.SafeErrorParam(target), client.t("Messages could not be retrieved"))
} else if err != nil {
rb.Add(nil, server.name, "FAIL", "CHATHISTORY", "MESSAGE_ERROR", msg.Params[0], client.t("Messages could not be retrieved"))
} else {
// successful responses are sent as a chathistory or history batch
if channel != nil {
if listTargets {
batchID := rb.StartNestedBatch("draft/chathistory-targets")
defer rb.EndNestedBatch(batchID)
for _, target := range targets {
name := server.UnfoldName(target.CfName)
rb.Add(nil, server.name, "CHATHISTORY", "TARGETS", name,
target.Time.Format(IRCv3TimestampFormat))
}
} else if channel != nil {
channel.replayHistoryItems(rb, items, false)
} else {
client.replayPrivmsgHistory(rb, items, target, true)
client.replayPrivmsgHistory(rb, items, target)
}
}
}()
Expand All @@ -598,6 +605,7 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
}
preposition := strings.ToLower(msg.Params[0])
target = msg.Params[1]
listTargets = (preposition == "targets")

parseQueryParam := func(param string) (msgid string, timestamp time.Time, err error) {
if param == "*" && (preposition == "before" || preposition == "between") {
Expand Down Expand Up @@ -632,24 +640,25 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
return
}

channel, sequence, err = server.GetHistorySequence(nil, client, target)
if err != nil || sequence == nil {
return
}

roundUp := func(endpoint time.Time) (result time.Time) {
return endpoint.Truncate(time.Millisecond).Add(time.Millisecond)
}

paramPos := 2
var start, end history.Selector
var limit int
switch preposition {
case "targets":
// use the same selector parsing as BETWEEN,
// except that we have no target so we have one fewer parameter
paramPos = 1
fallthrough
case "between":
start.Msgid, start.Time, err = parseQueryParam(msg.Params[2])
start.Msgid, start.Time, err = parseQueryParam(msg.Params[paramPos])
if err != nil {
return
}
end.Msgid, end.Time, err = parseQueryParam(msg.Params[3])
end.Msgid, end.Time, err = parseQueryParam(msg.Params[paramPos+1])
if err != nil {
return
}
Expand All @@ -662,7 +671,7 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
end.Time = roundUp(end.Time)
}
}
limit = parseHistoryLimit(4)
limit = parseHistoryLimit(paramPos + 2)
case "before", "after", "around":
start.Msgid, start.Time, err = parseQueryParam(msg.Params[2])
if err != nil {
Expand All @@ -689,14 +698,22 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
}
limit = parseHistoryLimit(3)
default:
unknown_command = true
err = utils.ErrInvalidParams
return
}

if preposition == "around" {
items, err = sequence.Around(start, limit)
if listTargets {
targets, err = client.listTargets(start, end, limit)
} else {
items, _, err = sequence.Between(start, end, limit)
channel, sequence, err = server.GetHistorySequence(nil, client, target)
if err != nil || sequence == nil {
return
}
if preposition == "around" {
items, err = sequence.Around(start, limit)
} else {
items, err = sequence.Between(start, end, limit)
}
}
return
}
Expand Down Expand Up @@ -1086,7 +1103,7 @@ func historyHandler(server *Server, client *Client, msg ircmsg.Message, rb *Resp
if channel != nil {
channel.replayHistoryItems(rb, items, false)
} else {
client.replayPrivmsgHistory(rb, items, "", true)
client.replayPrivmsgHistory(rb, items, "")
}
}
return false
Expand Down
Loading

0 comments on commit b83b051

Please sign in to comment.