Skip to content

Commit e9568ab

Browse files
committed
chathistory: implement draft/chathistory-end tag (ircv3/ircv3-specifications#598)
When a CHATHISTORY (or TARGETS) response contains fewer messages than the requested limit, attach the draft/chathistory-end tag to the BATCH opener to signal end-of-pagination to the client. - Register a MessageTagHandler for draft/chathistory-end in the chathistory module, tied to the draft/chathistory capability so the tag is only delivered to capable clients - history_send_result() gains an end_of_pagination parameter; when true, the tag is attached to the 'BATCH +ID chathistory' opener - chathistory_targets() attaches the tag to the 'BATCH +ID draft/chathistory-targets' opener when the target count is below the requested limit - cmd_chathistory() counts logical head-messages in the result and sets end_of_pagination when the count is below filter->limit - Auto-playback callers (chanmodes/history.c, history.c) pass 0
1 parent 717c9cb commit e9568ab

5 files changed

Lines changed: 60 additions & 8 deletions

File tree

include/h.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1218,7 +1218,7 @@ extern HistoryResult *history_request(const char *object, HistoryFilter *filter)
12181218
extern int history_delete(const char *object, HistoryFilter *filter, int *rejected_deletes);
12191219
extern int history_destroy(const char *object);
12201220
extern int can_receive_history(Client *client);
1221-
extern void history_send_result(Client *client, HistoryResult *r);
1221+
extern void history_send_result(Client *client, HistoryResult *r, int end_of_pagination);
12221222
extern void free_history_result(HistoryResult *r);
12231223
extern void free_history_filter(HistoryFilter *f);
12241224
extern void special_delayed_unloading(void);

src/api-history-backend.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,11 +374,12 @@ static void history_send_result_multiline_fallback(Client *client, HistoryLogLin
374374
* @param client The client to send to.
375375
* @param r The history result retrieved via history_request().
376376
*/
377-
void history_send_result(Client *client, HistoryResult *r)
377+
void history_send_result(Client *client, HistoryResult *r, int end_of_pagination)
378378
{
379379
char batch[BATCHLEN+1];
380380
HistoryLogLine *l;
381381
int has_multiline;
382+
MessageTag *batch_open_mtags = NULL;
382383

383384
if (!can_receive_history(client))
384385
return;
@@ -388,7 +389,14 @@ void history_send_result(Client *client, HistoryResult *r)
388389
{
389390
/* Start a new batch */
390391
generate_batch_id(batch);
391-
sendto_one(client, NULL, ":%s BATCH +%s chathistory %s", me.name, batch, r->object);
392+
if (end_of_pagination)
393+
{
394+
batch_open_mtags = safe_alloc(sizeof(MessageTag));
395+
safe_strdup(batch_open_mtags->name, "draft/chathistory-end");
396+
}
397+
sendto_one(client, batch_open_mtags, ":%s BATCH +%s chathistory %s", me.name, batch, r->object);
398+
if (batch_open_mtags)
399+
free_message_tags(batch_open_mtags);
392400
}
393401

394402
has_multiline = HasCapability(client, "draft/multiline") && HasCapability(client, "batch");

src/modules/chanmodes/history.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ int history_join(Client *client, Channel *channel, MessageTag *mtags)
740740
r = history_request(channel->name, &filter);
741741
if (r)
742742
{
743-
history_send_result(client, r);
743+
history_send_result(client, r, 0);
744744
free_history_result(r);
745745
}
746746
}

src/modules/chathistory.c

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct ChatHistoryTarget {
2626

2727
/* Forward declarations */
2828
CMD_FUNC(cmd_chathistory);
29+
int chathistory_end_mtag_is_ok(Client *client, const char *name, const char *value);
2930

3031
/* Global variables */
3132
long CAP_CHATHISTORY = 0L;
@@ -35,13 +36,22 @@ long CAP_CHATHISTORY = 0L;
3536
MOD_INIT()
3637
{
3738
ClientCapabilityInfo c;
39+
ClientCapability *cap;
40+
MessageTagHandlerInfo mtag;
3841

3942
MARK_AS_OFFICIAL_MODULE(modinfo);
4043
CommandAdd(modinfo->handle, "CHATHISTORY", cmd_chathistory, MAXPARA, CMD_USER);
4144

4245
memset(&c, 0, sizeof(c));
4346
c.name = "draft/chathistory";
44-
ClientCapabilityAdd(modinfo->handle, &c, &CAP_CHATHISTORY);
47+
cap = ClientCapabilityAdd(modinfo->handle, &c, &CAP_CHATHISTORY);
48+
49+
memset(&mtag, 0, sizeof(mtag));
50+
mtag.name = "draft/chathistory-end";
51+
mtag.is_ok = chathistory_end_mtag_is_ok;
52+
mtag.clicap_handler = cap;
53+
MessageTagHandlerAdd(modinfo->handle, &mtag);
54+
4555
return MOD_SUCCESS;
4656
}
4757

@@ -57,6 +67,14 @@ MOD_UNLOAD()
5767
return MOD_SUCCESS;
5868
}
5969

70+
/** The draft/chathistory-end tag is server-generated only; reject it from clients */
71+
int chathistory_end_mtag_is_ok(Client *client, const char *name, const char *value)
72+
{
73+
if (IsServer(client))
74+
return 1;
75+
return 0;
76+
}
77+
6078
int chathistory_token(const char *str, char *token, char **store)
6179
{
6280
char request[BUFSIZE];
@@ -188,14 +206,30 @@ void chathistory_targets(Client *client, HistoryFilter *filter, int limit)
188206

189207
/* 2. Now send it to the client */
190208

209+
/* Count total matching targets to determine end-of-pagination */
210+
{
211+
ChatHistoryTarget *t;
212+
for (t = targets; t; t = t->next)
213+
sent++;
214+
}
215+
191216
batch[0] = '\0';
192217
if (HasCapability(client, "batch"))
193218
{
194219
/* Start a new batch */
220+
MessageTag *batch_open_mtags = NULL;
195221
generate_batch_id(batch);
196-
sendto_one(client, NULL, ":%s BATCH +%s draft/chathistory-targets", me.name, batch);
222+
if (sent < limit)
223+
{
224+
batch_open_mtags = safe_alloc(sizeof(MessageTag));
225+
safe_strdup(batch_open_mtags->name, "draft/chathistory-end");
226+
}
227+
sendto_one(client, batch_open_mtags, ":%s BATCH +%s draft/chathistory-targets", me.name, batch);
228+
if (batch_open_mtags)
229+
free_message_tags(batch_open_mtags);
197230
}
198231

232+
sent = 0;
199233
for (; targets; targets = targets_next)
200234
{
201235
targets_next = targets->next;
@@ -418,7 +452,17 @@ CMD_FUNC(cmd_chathistory)
418452
if (fakelag_ms > 5000)
419453
fakelag_ms = 5000;
420454
add_fake_lag(client, fakelag_ms);
421-
history_send_result(client, r);
455+
/* Count logical messages to determine end-of-pagination.
456+
* Each entry in r->log is a head message (multiline continuation
457+
* lines are linked via next_in_batch, not next).
458+
*/
459+
{
460+
HistoryLogLine *l;
461+
int count = 0;
462+
for (l = r->log; l; l = l->next)
463+
count++;
464+
history_send_result(client, r, count < filter->limit);
465+
}
422466
}
423467
}
424468

src/modules/history.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ CMD_FUNC(cmd_history)
130130

131131
if ((r = history_request(channel->name, &filter)))
132132
{
133-
history_send_result(client, r);
133+
history_send_result(client, r, 0);
134134
free_history_result(r);
135135
}
136136
}

0 commit comments

Comments
 (0)