Line data Source code
1 : /* SPDX-License-Identifier: GPL-3.0-or-later */
2 : /* Copyright 2026 Peter Csaszar */
3 :
4 : /**
5 : * @file domain/write/forward.c
6 : * @brief messages.forwardMessages (US-P5-06).
7 : */
8 :
9 : #include "domain/write/forward.h"
10 :
11 : #include "tl_serial.h"
12 : #include "tl_registry.h"
13 : #include "mtproto_rpc.h"
14 : #include "crypto.h"
15 : #include "logger.h"
16 :
17 : #include <string.h>
18 :
19 : #define CRC_messages_forwardMessages 0xc661bbc4u
20 :
21 6 : static int write_input_peer(TlWriter *w, const HistoryPeer *p) {
22 6 : switch (p->kind) {
23 3 : case HISTORY_PEER_SELF:
24 3 : tl_write_uint32(w, TL_inputPeerSelf); return 0;
25 3 : case HISTORY_PEER_USER:
26 3 : tl_write_uint32(w, TL_inputPeerUser);
27 3 : tl_write_int64 (w, p->peer_id);
28 3 : tl_write_int64 (w, p->access_hash); return 0;
29 0 : case HISTORY_PEER_CHAT:
30 0 : tl_write_uint32(w, TL_inputPeerChat);
31 0 : tl_write_int64 (w, p->peer_id); return 0;
32 0 : case HISTORY_PEER_CHANNEL:
33 0 : tl_write_uint32(w, TL_inputPeerChannel);
34 0 : tl_write_int64 (w, p->peer_id);
35 0 : tl_write_int64 (w, p->access_hash); return 0;
36 0 : default: return -1;
37 : }
38 : }
39 :
40 5 : int domain_forward_messages(const ApiConfig *cfg,
41 : MtProtoSession *s, Transport *t,
42 : const HistoryPeer *from,
43 : const HistoryPeer *to,
44 : const int32_t *ids, int n_ids,
45 : RpcError *err) {
46 5 : if (!cfg || !s || !t || !from || !to || !ids || n_ids <= 0 || n_ids > 100)
47 2 : return -1;
48 :
49 3 : TlWriter w; tl_writer_init(&w);
50 3 : tl_write_uint32(&w, CRC_messages_forwardMessages);
51 3 : tl_write_uint32(&w, 0); /* flags = 0 */
52 3 : if (write_input_peer(&w, from) != 0) { tl_writer_free(&w); return -1; }
53 3 : tl_write_uint32(&w, TL_vector); /* id vector */
54 3 : tl_write_uint32(&w, (uint32_t)n_ids);
55 8 : for (int i = 0; i < n_ids; i++) tl_write_int32(&w, ids[i]);
56 3 : tl_write_uint32(&w, TL_vector); /* random_id vector */
57 3 : tl_write_uint32(&w, (uint32_t)n_ids);
58 8 : for (int i = 0; i < n_ids; i++) {
59 : uint8_t rnd[8];
60 5 : int64_t rid = 0;
61 5 : if (crypto_rand_bytes(rnd, 8) == 0) memcpy(&rid, rnd, 8);
62 5 : tl_write_int64(&w, rid);
63 : }
64 3 : if (write_input_peer(&w, to) != 0) { tl_writer_free(&w); return -1; }
65 :
66 : uint8_t query[2048];
67 3 : if (w.len > sizeof(query)) { tl_writer_free(&w); return -1; }
68 3 : memcpy(query, w.data, w.len);
69 3 : size_t qlen = w.len;
70 3 : tl_writer_free(&w);
71 :
72 3 : uint8_t resp[4096]; size_t resp_len = 0;
73 3 : if (api_call(cfg, s, t, query, qlen, resp, sizeof(resp), &resp_len) != 0) {
74 0 : logger_log(LOG_ERROR, "forward: api_call failed");
75 0 : return -1;
76 : }
77 3 : if (resp_len < 4) return -1;
78 :
79 : uint32_t top;
80 3 : memcpy(&top, resp, 4);
81 3 : if (top == TL_rpc_error) {
82 0 : if (err) rpc_parse_error(resp, resp_len, err);
83 0 : return -1;
84 : }
85 3 : if (top == TL_updates || top == TL_updatesCombined
86 1 : || top == TL_updateShort) {
87 3 : return 0;
88 : }
89 0 : logger_log(LOG_WARN, "forward: unexpected top 0x%08x", top);
90 0 : return 0;
91 : }
|