Line data Source code
1 : /* SPDX-License-Identifier: GPL-3.0-or-later */
2 : /* Copyright 2026 Peter Csaszar */
3 :
4 : /**
5 : * @file domain/write/read_history.c
6 : * @brief messages.readHistory + channels.readHistory (US-P5-04).
7 : */
8 :
9 : #include "domain/write/read_history.h"
10 :
11 : #include "tl_serial.h"
12 : #include "tl_registry.h"
13 : #include "mtproto_rpc.h"
14 : #include "logger.h"
15 :
16 : #include <string.h>
17 :
18 : #define CRC_messages_readHistory 0x0e306d3au
19 : #define CRC_channels_readHistory 0xcc104937u
20 : #define CRC_messages_affectedMessages TL_messages_affectedMessages
21 : #define CRC_inputChannel 0xf35aec28u
22 :
23 1 : static int build_messages_request(const HistoryPeer *peer, int32_t max_id,
24 : uint8_t *buf, size_t cap, size_t *out_len) {
25 1 : TlWriter w; tl_writer_init(&w);
26 1 : tl_write_uint32(&w, CRC_messages_readHistory);
27 1 : switch (peer->kind) {
28 1 : case HISTORY_PEER_SELF:
29 1 : tl_write_uint32(&w, TL_inputPeerSelf);
30 1 : break;
31 0 : case HISTORY_PEER_USER:
32 0 : tl_write_uint32(&w, TL_inputPeerUser);
33 0 : tl_write_int64 (&w, peer->peer_id);
34 0 : tl_write_int64 (&w, peer->access_hash);
35 0 : break;
36 0 : case HISTORY_PEER_CHAT:
37 0 : tl_write_uint32(&w, TL_inputPeerChat);
38 0 : tl_write_int64 (&w, peer->peer_id);
39 0 : break;
40 0 : default:
41 0 : tl_writer_free(&w);
42 0 : return -1;
43 : }
44 1 : tl_write_int32(&w, max_id);
45 :
46 1 : int rc = -1;
47 1 : if (w.len <= cap) { memcpy(buf, w.data, w.len); *out_len = w.len; rc = 0; }
48 1 : tl_writer_free(&w);
49 1 : return rc;
50 : }
51 :
52 1 : static int build_channels_request(const HistoryPeer *peer, int32_t max_id,
53 : uint8_t *buf, size_t cap, size_t *out_len) {
54 1 : TlWriter w; tl_writer_init(&w);
55 1 : tl_write_uint32(&w, CRC_channels_readHistory);
56 1 : tl_write_uint32(&w, CRC_inputChannel);
57 1 : tl_write_int64 (&w, peer->peer_id);
58 1 : tl_write_int64 (&w, peer->access_hash);
59 1 : tl_write_int32 (&w, max_id);
60 :
61 1 : int rc = -1;
62 1 : if (w.len <= cap) { memcpy(buf, w.data, w.len); *out_len = w.len; rc = 0; }
63 1 : tl_writer_free(&w);
64 1 : return rc;
65 : }
66 :
67 2 : int domain_mark_read(const ApiConfig *cfg,
68 : MtProtoSession *s, Transport *t,
69 : const HistoryPeer *peer,
70 : int32_t max_id,
71 : RpcError *err) {
72 2 : if (!cfg || !s || !t || !peer) return -1;
73 :
74 2 : uint8_t query[64]; size_t qlen = 0;
75 2 : int is_channel = (peer->kind == HISTORY_PEER_CHANNEL);
76 :
77 2 : int bc = is_channel
78 1 : ? build_channels_request(peer, max_id, query, sizeof(query), &qlen)
79 2 : : build_messages_request(peer, max_id, query, sizeof(query), &qlen);
80 2 : if (bc != 0) return -1;
81 :
82 2 : uint8_t resp[512]; size_t resp_len = 0;
83 2 : if (api_call(cfg, s, t, query, qlen, resp, sizeof(resp), &resp_len) != 0) {
84 0 : logger_log(LOG_ERROR, "read_history: api_call failed");
85 0 : return -1;
86 : }
87 2 : if (resp_len < 4) return -1;
88 :
89 : uint32_t top;
90 2 : memcpy(&top, resp, 4);
91 2 : if (top == TL_rpc_error) {
92 0 : if (err) rpc_parse_error(resp, resp_len, err);
93 0 : return -1;
94 : }
95 2 : if (is_channel) {
96 1 : if (top == TL_boolTrue) return 0;
97 0 : if (top == TL_boolFalse) {
98 0 : logger_log(LOG_WARN, "read_history: channel returned boolFalse");
99 0 : return -1;
100 : }
101 1 : } else if (top == CRC_messages_affectedMessages) {
102 1 : return 0;
103 : }
104 0 : logger_log(LOG_WARN, "read_history: unexpected top 0x%08x", top);
105 0 : return 0;
106 : }
|