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 4 : static int build_messages_request(const HistoryPeer *peer, int32_t max_id,
24 : uint8_t *buf, size_t cap, size_t *out_len) {
25 4 : TlWriter w; tl_writer_init(&w);
26 4 : tl_write_uint32(&w, CRC_messages_readHistory);
27 4 : switch (peer->kind) {
28 3 : case HISTORY_PEER_SELF:
29 3 : tl_write_uint32(&w, TL_inputPeerSelf);
30 3 : 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 1 : case HISTORY_PEER_CHAT:
37 1 : tl_write_uint32(&w, TL_inputPeerChat);
38 1 : tl_write_int64 (&w, peer->peer_id);
39 1 : break;
40 0 : default:
41 0 : tl_writer_free(&w);
42 0 : return -1;
43 : }
44 4 : tl_write_int32(&w, max_id);
45 :
46 4 : int rc = -1;
47 4 : if (w.len <= cap) { memcpy(buf, w.data, w.len); *out_len = w.len; rc = 0; }
48 4 : tl_writer_free(&w);
49 4 : return rc;
50 : }
51 :
52 4 : static int build_channels_request(const HistoryPeer *peer, int32_t max_id,
53 : uint8_t *buf, size_t cap, size_t *out_len) {
54 4 : TlWriter w; tl_writer_init(&w);
55 4 : tl_write_uint32(&w, CRC_channels_readHistory);
56 4 : tl_write_uint32(&w, CRC_inputChannel);
57 4 : tl_write_int64 (&w, peer->peer_id);
58 4 : tl_write_int64 (&w, peer->access_hash);
59 4 : tl_write_int32 (&w, max_id);
60 :
61 4 : int rc = -1;
62 4 : if (w.len <= cap) { memcpy(buf, w.data, w.len); *out_len = w.len; rc = 0; }
63 4 : tl_writer_free(&w);
64 4 : return rc;
65 : }
66 :
67 9 : 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 9 : if (!cfg || !s || !t || !peer) return -1;
73 :
74 8 : uint8_t query[64]; size_t qlen = 0;
75 8 : int is_channel = (peer->kind == HISTORY_PEER_CHANNEL);
76 :
77 8 : int bc = is_channel
78 4 : ? build_channels_request(peer, max_id, query, sizeof(query), &qlen)
79 8 : : build_messages_request(peer, max_id, query, sizeof(query), &qlen);
80 8 : if (bc != 0) return -1;
81 :
82 8 : uint8_t resp[512]; size_t resp_len = 0;
83 8 : 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 8 : if (resp_len < 4) return -1;
88 :
89 : uint32_t top;
90 8 : memcpy(&top, resp, 4);
91 8 : if (top == TL_rpc_error) {
92 1 : if (err) rpc_parse_error(resp, resp_len, err);
93 1 : return -1;
94 : }
95 7 : if (is_channel) {
96 4 : if (top == TL_boolTrue) return 0;
97 1 : if (top == TL_boolFalse) {
98 1 : logger_log(LOG_WARN, "read_history: channel returned boolFalse");
99 1 : return -1;
100 : }
101 3 : } else if (top == CRC_messages_affectedMessages) {
102 3 : return 0;
103 : }
104 0 : logger_log(LOG_WARN, "read_history: unexpected top 0x%08x", top);
105 0 : return 0;
106 : }
|