1 | #include "mtxclient/http/client.hpp" |
2 | #include "mtx/log.hpp" |
3 | #include "mtxclient/http/client_impl.hpp" |
4 | |
5 | #include <mutex> |
6 | #include <thread> |
7 | |
8 | #include <nlohmann/json.hpp> |
9 | |
10 | #include <coeurl/client.hpp> |
11 | #include <coeurl/request.hpp> |
12 | #include <utility> |
13 | |
14 | #include "mtxclient/utils.hpp" |
15 | |
16 | #include "mtx/log.hpp" |
17 | #include "mtx/requests.hpp" |
18 | #include "mtx/responses.hpp" |
19 | |
20 | using namespace mtx::http; |
21 | |
22 | namespace mtx::http { |
23 | struct ClientPrivate |
24 | { |
25 | coeurl::Client client; |
26 | }; |
27 | |
28 | void |
29 | UIAHandler::next(const user_interactive::Auth &auth) const |
30 | { |
31 | next_(*this, auth); |
32 | } |
33 | } |
34 | |
35 | Client::Client(const std::string &server, uint16_t port) |
36 | : p{new ClientPrivate} |
37 | { |
38 | set_server(server); |
39 | set_port(port); |
40 | |
41 | p->client.set_verify_peer(true); |
42 | p->client.connection_timeout(t: 60); |
43 | } |
44 | |
45 | // call destuctor of work queue and ios first! |
46 | Client::~Client() { p.reset(); } |
47 | |
48 | void |
49 | Client::shutdown() |
50 | { |
51 | p->client.shutdown(); |
52 | } |
53 | |
54 | void |
55 | Client::alt_svc_cache_path(const std::string &path) |
56 | { |
57 | p->client.alt_svc_cache_path(path); |
58 | } |
59 | |
60 | coeurl::Headers |
61 | mtx::http::Client::(bool requires_auth) |
62 | { |
63 | coeurl::Headers ; |
64 | headers["User-Agent" ] = "mtxclient v0.9.2" ; |
65 | |
66 | if (requires_auth && !access_token_.empty()) |
67 | headers["Authorization" ] = "Bearer " + access_token(); |
68 | |
69 | return headers; |
70 | } |
71 | |
72 | std::string |
73 | mtx::http::Client::endpoint_to_url(const std::string &endpoint, const char *endpoint_namespace) |
74 | { |
75 | return protocol_ + "://" + server_ + ":" + std::to_string(val: port_) + endpoint_namespace + |
76 | endpoint; |
77 | } |
78 | |
79 | void |
80 | mtx::http::Client::(const std::string &endpoint, |
81 | const std::string &req, |
82 | mtx::http::TypeErasedCallback cb, |
83 | bool requires_auth, |
84 | const std::string &content_type) |
85 | { |
86 | p->client.post( |
87 | url: endpoint_to_url(endpoint), |
88 | request_body: req, |
89 | mimetype: content_type, |
90 | callback: [cb = std::move(cb)](const coeurl::Request &r) { |
91 | cb(r.response_headers(), r.response(), r.error_code(), r.response_code()); |
92 | }, |
93 | headers: prepare_headers(requires_auth)); |
94 | } |
95 | |
96 | void |
97 | mtx::http::Client::delete_(const std::string &endpoint, ErrCallback cb, bool requires_auth) |
98 | { |
99 | p->client.delete_( |
100 | url: endpoint_to_url(endpoint), |
101 | callback: [cb = std::move(cb)](const coeurl::Request &r) { |
102 | mtx::http::ClientError client_error; |
103 | if (r.error_code()) { |
104 | client_error.error_code = r.error_code(); |
105 | return cb(client_error); |
106 | } |
107 | |
108 | client_error.status_code = r.response_code(); |
109 | |
110 | // We only count 2xx status codes as success. |
111 | if (client_error.status_code < 200 || client_error.status_code >= 300) { |
112 | // The homeserver should return an error struct. |
113 | try { |
114 | nlohmann::json json_error = nlohmann::json::parse(i: r.response()); |
115 | client_error.matrix_error = json_error.get<mtx::errors::Error>(); |
116 | } catch (const nlohmann::json::exception &e) { |
117 | client_error.parse_error = |
118 | std::string(e.what()) + ": " + std::string(r.response()); |
119 | } |
120 | return cb(client_error); |
121 | } |
122 | return cb({}); |
123 | }, |
124 | headers: prepare_headers(requires_auth)); |
125 | } |
126 | |
127 | void |
128 | mtx::http::Client::(const std::string &endpoint, |
129 | const std::string &req, |
130 | mtx::http::TypeErasedCallback cb, |
131 | bool requires_auth) |
132 | { |
133 | p->client.put( |
134 | url: endpoint_to_url(endpoint), |
135 | request_body: req, |
136 | mimetype: "application/json" , |
137 | callback: [cb = std::move(cb)](const coeurl::Request &r) { |
138 | cb(r.response_headers(), r.response(), r.error_code(), r.response_code()); |
139 | }, |
140 | headers: prepare_headers(requires_auth)); |
141 | } |
142 | |
143 | void |
144 | mtx::http::Client::(const std::string &endpoint, |
145 | mtx::http::TypeErasedCallback cb, |
146 | bool requires_auth, |
147 | const std::string &endpoint_namespace, |
148 | int num_redirects) |
149 | { |
150 | p->client.get( |
151 | url: endpoint_to_url(endpoint, endpoint_namespace: endpoint_namespace.c_str()), |
152 | callback: [cb = std::move(cb)](const coeurl::Request &r) { |
153 | cb(r.response_headers(), r.response(), r.error_code(), r.response_code()); |
154 | }, |
155 | headers: prepare_headers(requires_auth), |
156 | max_redirects: num_redirects); |
157 | } |
158 | |
159 | void |
160 | Client::verify_certificates(bool enabled) |
161 | { |
162 | p->client.set_verify_peer(enabled); |
163 | } |
164 | |
165 | void |
166 | Client::set_server(const std::string &server) |
167 | { |
168 | std::string_view server_name = server; |
169 | std::uint16_t port = 443; |
170 | this->protocol_ = "https" ; |
171 | // Remove https prefix, if it exists |
172 | if (server_name.substr(pos: 0, n: 8) == "https://" ) { |
173 | server_name.remove_prefix(n: 8); |
174 | port = 443; |
175 | } |
176 | if (server_name.substr(pos: 0, n: 7) == "http://" ) { |
177 | server_name.remove_prefix(n: 7); |
178 | port = 80; |
179 | this->protocol_ = "http" ; |
180 | } |
181 | if (server_name.size() > 0 && server_name.back() == '/') |
182 | server_name.remove_suffix(n: 1); |
183 | |
184 | if (std::count(first: server_name.begin(), last: server_name.end(), value: ':') == 1) { |
185 | auto colon_offset = server_name.find(c: ':'); |
186 | server_ = std::string(server_name.substr(pos: 0, n: colon_offset)); |
187 | |
188 | auto tmp = std::string(server_name.substr(pos: colon_offset + 1)); |
189 | if (mtx::client::utils::is_number(s: tmp)) { |
190 | port_ = static_cast<std::uint16_t>(std::stoul(str: tmp)); |
191 | return; |
192 | } |
193 | } |
194 | |
195 | server_ = std::string(server_name); |
196 | port_ = port; |
197 | } |
198 | |
199 | void |
200 | Client::close(bool force) |
201 | { |
202 | p->client.close(force); |
203 | } |
204 | |
205 | // |
206 | // Client API endpoints |
207 | // |
208 | |
209 | void |
210 | Client::login(const std::string &user, |
211 | const std::string &password, |
212 | const std::string &device_name, |
213 | Callback<mtx::responses::Login> callback) |
214 | { |
215 | mtx::requests::Login req; |
216 | req.identifier = mtx::requests::login_identifier::User{.user: user}; |
217 | req.password = password; |
218 | req.initial_device_display_name = device_name; |
219 | |
220 | login(req, cb: std::move(callback)); |
221 | } |
222 | |
223 | void |
224 | Client::login(const std::string &user, |
225 | const std::string &password, |
226 | Callback<mtx::responses::Login> callback) |
227 | { |
228 | mtx::requests::Login req; |
229 | req.identifier = mtx::requests::login_identifier::User{.user: user}; |
230 | req.password = password; |
231 | |
232 | login(req, cb: std::move(callback)); |
233 | } |
234 | |
235 | void |
236 | Client::login(const mtx::requests::Login &req, Callback<mtx::responses::Login> callback) |
237 | { |
238 | post<mtx::requests::Login, mtx::responses::Login>( |
239 | endpoint: "/client/v3/login" , |
240 | req, |
241 | callback: [_this = shared_from_this(), |
242 | callback = std::move(callback)](const mtx::responses::Login &resp, RequestErr err) { |
243 | if (!err && resp.access_token.size()) { |
244 | _this->user_id_ = resp.user_id; |
245 | _this->device_id_ = resp.device_id; |
246 | _this->access_token_ = resp.access_token; |
247 | } |
248 | callback(resp, err); |
249 | }, |
250 | requires_auth: false); |
251 | } |
252 | |
253 | void |
254 | Client::get_login(Callback<mtx::responses::LoginFlows> cb) |
255 | { |
256 | get<mtx::responses::LoginFlows>( |
257 | endpoint: "/client/v3/login" , |
258 | callback: [cb = std::move(cb)](const mtx::responses::LoginFlows &res, HeaderFields, RequestErr err) { |
259 | cb(res, err); |
260 | }, |
261 | requires_auth: false); |
262 | } |
263 | |
264 | std::string |
265 | Client::login_sso_redirect(std::string redirectUrl, const std::string &idp) |
266 | { |
267 | const std::string idp_suffix = idp.empty() ? idp : ("/" + mtx::client::utils::url_encode(s: idp)); |
268 | return protocol_ + "://" + server() + ":" + std::to_string(val: port()) + |
269 | "/_matrix/client/v3/login/sso/redirect" + idp_suffix + "?" + |
270 | mtx::client::utils::query_params(params: {{"redirectUrl" , redirectUrl}}); |
271 | } |
272 | |
273 | void |
274 | Client::well_known(Callback<mtx::responses::WellKnown> callback) |
275 | { |
276 | get<mtx::responses::WellKnown>( |
277 | endpoint: "/matrix/client" , |
278 | callback: [cb = std::move(callback)]( |
279 | const mtx::responses::WellKnown &res, HeaderFields, RequestErr err) { cb(res, err); }, |
280 | requires_auth: false, |
281 | endpoint_namespace: "/.well-known" , |
282 | num_redirects: 30); |
283 | } |
284 | |
285 | void |
286 | Client::logout(Callback<mtx::responses::Logout> callback) |
287 | { |
288 | mtx::requests::Logout req; |
289 | |
290 | post<mtx::requests::Logout, mtx::responses::Logout>( |
291 | endpoint: "/client/v3/logout" , |
292 | req, |
293 | callback: [_this = shared_from_this(), |
294 | callback = std::move(callback)](const mtx::responses::Logout &res, RequestErr err) { |
295 | if (!err) { |
296 | // Clear the now invalid access token when logout is successful |
297 | _this->clear(); |
298 | } |
299 | // Pass up response and error to supplied callback |
300 | callback(res, err); |
301 | }); |
302 | } |
303 | |
304 | void |
305 | Client::notifications(uint64_t limit, |
306 | const std::string &from, |
307 | const std::string &only, |
308 | Callback<mtx::responses::Notifications> cb) |
309 | { |
310 | std::map<std::string, std::string> params; |
311 | params.emplace(args: "limit" , args: std::to_string(val: limit)); |
312 | |
313 | if (!from.empty()) { |
314 | params.emplace(args: "from" , args: from); |
315 | } |
316 | |
317 | if (!only.empty()) { |
318 | params.emplace(args: "only" , args: only); |
319 | } |
320 | |
321 | get<mtx::responses::Notifications>( |
322 | endpoint: "/client/v3/notifications?" + mtx::client::utils::query_params(params), |
323 | callback: [cb = std::move(cb)](const mtx::responses::Notifications &res, HeaderFields, RequestErr err) { |
324 | cb(res, err); |
325 | }); |
326 | } |
327 | |
328 | void |
329 | Client::get_pushrules(Callback<mtx::pushrules::GlobalRuleset> cb) |
330 | { |
331 | get<mtx::pushrules::GlobalRuleset>( |
332 | endpoint: "/client/v3/pushrules/" , |
333 | callback: [cb = std::move(cb)](const mtx::pushrules::GlobalRuleset &res, HeaderFields, RequestErr err) { |
334 | cb(res, err); |
335 | }); |
336 | } |
337 | |
338 | void |
339 | Client::get_pushrules(const std::string &scope, |
340 | const std::string &kind, |
341 | const std::string &ruleId, |
342 | Callback<mtx::pushrules::PushRule> cb) |
343 | { |
344 | get<mtx::pushrules::PushRule>( |
345 | endpoint: "/client/v3/pushrules/" + mtx::client::utils::url_encode(s: scope) + "/" + |
346 | mtx::client::utils::url_encode(s: kind) + "/" + mtx::client::utils::url_encode(s: ruleId), |
347 | callback: [cb = std::move(cb)](const mtx::pushrules::PushRule &res, HeaderFields, RequestErr err) { |
348 | cb(res, err); |
349 | }); |
350 | } |
351 | |
352 | void |
353 | Client::delete_pushrules(const std::string &scope, |
354 | const std::string &kind, |
355 | const std::string &ruleId, |
356 | ErrCallback cb) |
357 | { |
358 | delete_(endpoint: "/client/v3/pushrules/" + mtx::client::utils::url_encode(s: scope) + "/" + |
359 | mtx::client::utils::url_encode(s: kind) + "/" + mtx::client::utils::url_encode(s: ruleId), |
360 | cb: std::move(cb)); |
361 | } |
362 | |
363 | void |
364 | Client::put_pushrules(const std::string &scope, |
365 | const std::string &kind, |
366 | const std::string &ruleId, |
367 | const mtx::pushrules::PushRule &rule, |
368 | ErrCallback cb, |
369 | const std::string &before, |
370 | const std::string &after) |
371 | { |
372 | std::map<std::string, std::string> params; |
373 | |
374 | if (!before.empty()) |
375 | params.emplace(args: "before" , args: before); |
376 | |
377 | if (!after.empty()) |
378 | params.emplace(args: "after" , args: after); |
379 | |
380 | std::string path = "/client/v3/pushrules/" + mtx::client::utils::url_encode(s: scope) + "/" + |
381 | mtx::client::utils::url_encode(s: kind) + "/" + |
382 | mtx::client::utils::url_encode(s: ruleId); |
383 | if (!params.empty()) |
384 | path += "?" + mtx::client::utils::query_params(params); |
385 | put<mtx::pushrules::PushRule>(endpoint: path, req: rule, callback: std::move(cb)); |
386 | } |
387 | |
388 | void |
389 | Client::get_pushrules_enabled(const std::string &scope, |
390 | const std::string &kind, |
391 | const std::string &ruleId, |
392 | Callback<mtx::pushrules::Enabled> cb) |
393 | { |
394 | get<mtx::pushrules::Enabled>(endpoint: "/client/v3/pushrules/" + mtx::client::utils::url_encode(s: scope) + |
395 | "/" + mtx::client::utils::url_encode(s: kind) + "/" + |
396 | mtx::client::utils::url_encode(s: ruleId) + "/enabled" , |
397 | callback: [cb = std::move(cb)](const mtx::pushrules::Enabled &res, |
398 | HeaderFields, |
399 | RequestErr err) { cb(res, err); }); |
400 | } |
401 | |
402 | void |
403 | Client::put_pushrules_enabled(const std::string &scope, |
404 | const std::string &kind, |
405 | const std::string &ruleId, |
406 | bool enabled, |
407 | ErrCallback cb) |
408 | { |
409 | put<mtx::pushrules::Enabled>(endpoint: "/client/v3/pushrules/" + mtx::client::utils::url_encode(s: scope) + |
410 | "/" + mtx::client::utils::url_encode(s: kind) + "/" + |
411 | mtx::client::utils::url_encode(s: ruleId) + "/enabled" , |
412 | req: {.enabled: enabled}, |
413 | callback: std::move(cb)); |
414 | } |
415 | |
416 | void |
417 | Client::get_pushrules_actions(const std::string &scope, |
418 | const std::string &kind, |
419 | const std::string &ruleId, |
420 | Callback<mtx::pushrules::actions::Actions> cb) |
421 | { |
422 | get<mtx::pushrules::actions::Actions>( |
423 | endpoint: "/client/v3/pushrules/" + mtx::client::utils::url_encode(s: scope) + "/" + |
424 | mtx::client::utils::url_encode(s: kind) + "/" + mtx::client::utils::url_encode(s: ruleId) + |
425 | "/actions" , |
426 | callback: [cb = std::move(cb)](const mtx::pushrules::actions::Actions &res, |
427 | HeaderFields, |
428 | RequestErr err) { cb(res, err); }); |
429 | } |
430 | |
431 | void |
432 | Client::put_pushrules_actions(const std::string &scope, |
433 | const std::string &kind, |
434 | const std::string &ruleId, |
435 | const mtx::pushrules::actions::Actions &actions, |
436 | ErrCallback cb) |
437 | { |
438 | put<mtx::pushrules::actions::Actions>(endpoint: "/client/v3/pushrules/" + |
439 | mtx::client::utils::url_encode(s: scope) + "/" + |
440 | mtx::client::utils::url_encode(s: kind) + "/" + |
441 | mtx::client::utils::url_encode(s: ruleId) + "/actions" , |
442 | req: actions, |
443 | callback: std::move(cb)); |
444 | } |
445 | |
446 | void |
447 | Client::set_avatar_url(const std::string &avatar_url, ErrCallback callback) |
448 | { |
449 | mtx::requests::AvatarUrl req; |
450 | req.avatar_url = avatar_url; |
451 | |
452 | put<mtx::requests::AvatarUrl>( |
453 | endpoint: "/client/v3/profile/" + mtx::client::utils::url_encode(s: user_id_.to_string()) + "/avatar_url" , |
454 | req, |
455 | callback: std::move(callback)); |
456 | } |
457 | |
458 | void |
459 | Client::set_displayname(const std::string &displayname, ErrCallback callback) |
460 | { |
461 | mtx::requests::DisplayName req; |
462 | req.displayname = displayname; |
463 | |
464 | put<mtx::requests::DisplayName>( |
465 | endpoint: "/client/v3/profile/" + mtx::client::utils::url_encode(s: user_id_.to_string()) + "/displayname" , |
466 | req, |
467 | callback: std::move(callback)); |
468 | } |
469 | |
470 | void |
471 | Client::get_profile(const std::string &user_id, Callback<mtx::responses::Profile> callback) |
472 | { |
473 | get<mtx::responses::Profile>( |
474 | endpoint: "/client/v3/profile/" + mtx::client::utils::url_encode(s: user_id), |
475 | callback: [callback = std::move(callback)]( |
476 | const mtx::responses::Profile &res, HeaderFields, RequestErr err) { callback(res, err); }); |
477 | } |
478 | |
479 | void |
480 | Client::get_avatar_url(const std::string &user_id, Callback<mtx::responses::AvatarUrl> callback) |
481 | { |
482 | get<mtx::responses::AvatarUrl>( |
483 | endpoint: "/client/v3/profile/" + mtx::client::utils::url_encode(s: user_id) + "/avatar_url" , |
484 | callback: [callback = std::move(callback)](const mtx::responses::AvatarUrl &res, |
485 | HeaderFields, |
486 | RequestErr err) { callback(res, err); }); |
487 | } |
488 | |
489 | void |
490 | Client::get_tags(const std::string &room_id, Callback<mtx::events::account_data::Tags> cb) |
491 | { |
492 | get<mtx::events::account_data::Tags>( |
493 | endpoint: "/client/v3/user/" + mtx::client::utils::url_encode(s: user_id_.to_string()) + "/rooms/" + |
494 | mtx::client::utils::url_encode(s: room_id) + "/tags" , |
495 | callback: [cb = std::move(cb)](const mtx::events::account_data::Tags &res, |
496 | HeaderFields, |
497 | RequestErr err) { cb(res, err); }); |
498 | } |
499 | void |
500 | Client::put_tag(const std::string &room_id, |
501 | const std::string &tag_name, |
502 | const mtx::events::account_data::Tag &tag, |
503 | ErrCallback cb) |
504 | { |
505 | put<mtx::events::account_data::Tag>(endpoint: "/client/v3/user/" + |
506 | mtx::client::utils::url_encode(s: user_id_.to_string()) + |
507 | "/rooms/" + mtx::client::utils::url_encode(s: room_id) + |
508 | "/tags/" + mtx::client::utils::url_encode(s: tag_name), |
509 | req: tag, |
510 | callback: std::move(cb)); |
511 | } |
512 | void |
513 | Client::delete_tag(const std::string &room_id, const std::string &tag_name, ErrCallback cb) |
514 | { |
515 | delete_(endpoint: "/client/v3/user/" + mtx::client::utils::url_encode(s: user_id_.to_string()) + "/rooms/" + |
516 | mtx::client::utils::url_encode(s: room_id) + "/tags/" + |
517 | mtx::client::utils::url_encode(s: tag_name), |
518 | cb: std::move(cb)); |
519 | } |
520 | |
521 | void |
522 | Client::create_room(const mtx::requests::CreateRoom &room_options, |
523 | Callback<mtx::responses::CreateRoom> callback) |
524 | { |
525 | post<mtx::requests::CreateRoom, mtx::responses::CreateRoom>( |
526 | endpoint: "/client/v3/createRoom" , req: room_options, callback: std::move(callback)); |
527 | } |
528 | |
529 | void |
530 | Client::join_room(const std::string &room, Callback<mtx::responses::RoomId> callback) |
531 | { |
532 | join_room(room, via: {}, cb: std::move(callback)); |
533 | } |
534 | |
535 | void |
536 | Client::join_room(const std::string &room, |
537 | const std::vector<std::string> &via, |
538 | Callback<mtx::responses::RoomId> callback, |
539 | const std::string &reason) |
540 | { |
541 | using mtx::client::utils::url_encode; |
542 | std::string query; |
543 | if (!via.empty()) { |
544 | query = "?server_name=" + url_encode(s: via[0]); |
545 | for (size_t i = 1; i < via.size(); i++) { |
546 | query += "&server_name=" + url_encode(s: via[i]); |
547 | } |
548 | } |
549 | auto api_path = "/client/v3/join/" + url_encode(s: room) + query; |
550 | |
551 | auto body = nlohmann::json::object(); |
552 | if (!reason.empty()) |
553 | body["reason" ] = reason; |
554 | |
555 | post<std::string, mtx::responses::RoomId>(endpoint: api_path, req: body.dump(), callback: std::move(callback)); |
556 | } |
557 | |
558 | void |
559 | Client::knock_room(const std::string &room, |
560 | const std::vector<std::string> &via, |
561 | Callback<mtx::responses::RoomId> cb, |
562 | const std::string &reason) |
563 | { |
564 | using mtx::client::utils::url_encode; |
565 | std::string query; |
566 | if (!via.empty()) { |
567 | query = "?server_name=" + url_encode(s: via[0]); |
568 | for (size_t i = 1; i < via.size(); i++) { |
569 | query += "&server_name=" + url_encode(s: via[i]); |
570 | } |
571 | } |
572 | auto api_path = "/client/v3/knock/" + url_encode(s: room) + query; |
573 | |
574 | auto body = nlohmann::json::object(); |
575 | if (!reason.empty()) |
576 | body["reason" ] = reason; |
577 | |
578 | post<std::string, mtx::responses::RoomId>(endpoint: api_path, req: body.dump(), callback: std::move(cb)); |
579 | } |
580 | |
581 | void |
582 | Client::leave_room(const std::string &room_id, |
583 | Callback<mtx::responses::Empty> callback, |
584 | const std::string &reason) |
585 | { |
586 | auto api_path = "/client/v3/rooms/" + mtx::client::utils::url_encode(s: room_id) + "/leave" ; |
587 | |
588 | auto body = nlohmann::json::object(); |
589 | if (!reason.empty()) |
590 | body["reason" ] = reason; |
591 | |
592 | post<std::string, mtx::responses::Empty>(endpoint: api_path, req: body.dump(), callback: std::move(callback)); |
593 | } |
594 | |
595 | void |
596 | Client::invite_user(const std::string &room_id, |
597 | const std::string &user_id, |
598 | Callback<mtx::responses::RoomInvite> callback, |
599 | const std::string &reason) |
600 | { |
601 | mtx::requests::RoomMembershipChange req; |
602 | req.user_id = user_id; |
603 | req.reason = reason; |
604 | |
605 | auto api_path = "/client/v3/rooms/" + mtx::client::utils::url_encode(s: room_id) + "/invite" ; |
606 | |
607 | post<mtx::requests::RoomMembershipChange, mtx::responses::RoomInvite>( |
608 | endpoint: api_path, req, callback: std::move(callback)); |
609 | } |
610 | |
611 | void |
612 | Client::kick_user(const std::string &room_id, |
613 | const std::string &user_id, |
614 | Callback<mtx::responses::Empty> callback, |
615 | const std::string &reason) |
616 | { |
617 | mtx::requests::RoomMembershipChange req; |
618 | req.user_id = user_id; |
619 | req.reason = reason; |
620 | |
621 | auto api_path = "/client/v3/rooms/" + mtx::client::utils::url_encode(s: room_id) + "/kick" ; |
622 | |
623 | post<mtx::requests::RoomMembershipChange, mtx::responses::Empty>( |
624 | endpoint: api_path, req, callback: std::move(callback)); |
625 | } |
626 | |
627 | void |
628 | Client::ban_user(const std::string &room_id, |
629 | const std::string &user_id, |
630 | Callback<mtx::responses::Empty> callback, |
631 | const std::string &reason) |
632 | { |
633 | mtx::requests::RoomMembershipChange req; |
634 | req.user_id = user_id; |
635 | req.reason = reason; |
636 | |
637 | auto api_path = "/client/v3/rooms/" + mtx::client::utils::url_encode(s: room_id) + "/ban" ; |
638 | |
639 | post<mtx::requests::RoomMembershipChange, mtx::responses::Empty>( |
640 | endpoint: api_path, req, callback: std::move(callback)); |
641 | } |
642 | |
643 | void |
644 | Client::unban_user(const std::string &room_id, |
645 | const std::string &user_id, |
646 | Callback<mtx::responses::Empty> callback, |
647 | const std::string &reason) |
648 | { |
649 | mtx::requests::RoomMembershipChange req; |
650 | req.user_id = user_id; |
651 | req.reason = reason; |
652 | |
653 | auto api_path = "/client/v3/rooms/" + mtx::client::utils::url_encode(s: room_id) + "/unban" ; |
654 | |
655 | post<mtx::requests::RoomMembershipChange, mtx::responses::Empty>( |
656 | endpoint: api_path, req, callback: std::move(callback)); |
657 | } |
658 | |
659 | void |
660 | Client::sync(const SyncOpts &opts, Callback<mtx::responses::Sync> callback) |
661 | { |
662 | std::map<std::string, std::string> params; |
663 | |
664 | if (!opts.filter.empty()) |
665 | params.emplace(args: "filter" , args: opts.filter); |
666 | |
667 | if (!opts.since.empty()) |
668 | params.emplace(args: "since" , args: opts.since); |
669 | |
670 | if (opts.full_state) |
671 | params.emplace(args: "full_state" , args: "true" ); |
672 | |
673 | if (opts.set_presence) |
674 | params.emplace(args: "set_presence" , args: mtx::presence::to_string(state: opts.set_presence.value())); |
675 | |
676 | params.emplace(args: "timeout" , args: std::to_string(val: opts.timeout)); |
677 | |
678 | get<mtx::responses::Sync>( |
679 | endpoint: "/client/v3/sync?" + mtx::client::utils::query_params(params), |
680 | callback: [callback = std::move(callback)]( |
681 | const mtx::responses::Sync &res, HeaderFields, RequestErr err) { callback(res, err); }); |
682 | } |
683 | |
684 | void |
685 | Client::versions(Callback<mtx::responses::Versions> callback) |
686 | { |
687 | get<mtx::responses::Versions>( |
688 | endpoint: "/client/versions" , |
689 | callback: [callback = std::move(callback)]( |
690 | const mtx::responses::Versions &res, HeaderFields, RequestErr err) { callback(res, err); }); |
691 | } |
692 | |
693 | void |
694 | Client::capabilities(Callback<mtx::responses::capabilities::Capabilities> callback) |
695 | { |
696 | get<mtx::responses::capabilities::Capabilities>( |
697 | endpoint: "/client/v3/capabilities" , |
698 | callback: [callback = std::move(callback)](const mtx::responses::capabilities::Capabilities &res, |
699 | HeaderFields, |
700 | RequestErr err) { callback(res, err); }); |
701 | } |
702 | |
703 | void |
704 | Client::upload(const std::string &data, |
705 | const std::string &content_type, |
706 | const std::string &filename, |
707 | Callback<mtx::responses::ContentURI> cb) |
708 | { |
709 | std::map<std::string, std::string> params = {{"filename" , filename}}; |
710 | |
711 | const auto api_path = "/media/v3/upload?" + client::utils::query_params(params); |
712 | post<std::string, mtx::responses::ContentURI>( |
713 | endpoint: api_path, req: data, callback: std::move(cb), requires_auth: true, content_type); |
714 | } |
715 | |
716 | std::string |
717 | mtx::http::Client::mxc_to_download_url(const std::string &mxc_url) |
718 | { |
719 | auto url = mtx::client::utils::parse_mxc_url(url: mxc_url); |
720 | return endpoint_to_url(endpoint: "/media/v3/download/" + url.server + "/" + url.media_id); |
721 | } |
722 | |
723 | void |
724 | Client::download(const std::string &mxc_url, |
725 | std::function<void(const std::string &res, |
726 | const std::string &content_type, |
727 | const std::string &original_filename, |
728 | RequestErr err)> callback) |
729 | { |
730 | auto url = mtx::client::utils::parse_mxc_url(url: mxc_url); |
731 | download(server: url.server, media_id: url.media_id, cb: std::move(callback)); |
732 | } |
733 | |
734 | void |
735 | Client::get_thumbnail(const ThumbOpts &opts, Callback<std::string> callback, bool try_download) |
736 | { |
737 | std::map<std::string, std::string> params; |
738 | params.emplace(args: "width" , args: std::to_string(val: opts.width)); |
739 | params.emplace(args: "height" , args: std::to_string(val: opts.height)); |
740 | params.emplace(args: "method" , args: opts.method); |
741 | |
742 | auto mxc = mtx::client::utils::parse_mxc_url(url: opts.mxc_url); |
743 | const auto api_path = "/media/v3/thumbnail/" + mxc.server + "/" + mxc.media_id + "?" + |
744 | client::utils::query_params(params); |
745 | get<std::string>( |
746 | endpoint: api_path, |
747 | callback: [callback = std::move(callback), |
748 | try_download, |
749 | mxc = std::move(mxc), |
750 | _this = shared_from_this()](const std::string &res, HeaderFields, RequestErr err) { |
751 | if (err && try_download) { |
752 | const int status_code = static_cast<int>(err->status_code); |
753 | |
754 | if (status_code == 404) { |
755 | _this->download(server: mxc.server, |
756 | media_id: mxc.media_id, |
757 | cb: [callback](const std::string &res, |
758 | const std::string &, // content_type |
759 | const std::string &, // original_filename |
760 | RequestErr err) { callback(res, err); }); |
761 | return; |
762 | } |
763 | } |
764 | |
765 | callback(res, err); |
766 | }); |
767 | } |
768 | |
769 | void |
770 | Client::download(const std::string &server, |
771 | const std::string &media_id, |
772 | std::function<void(const std::string &res, |
773 | const std::string &content_type, |
774 | const std::string &original_filename, |
775 | RequestErr err)> callback) |
776 | { |
777 | const auto api_path = "/media/v3/download/" + server + "/" + media_id; |
778 | get<std::string>( |
779 | endpoint: api_path, |
780 | callback: [callback = |
781 | std::move(callback)](const std::string &res, HeaderFields fields, RequestErr err) { |
782 | std::string content_type, original_filename; |
783 | |
784 | if (fields) { |
785 | if (fields->find(x: "Content-Type" ) != fields->end()) |
786 | content_type = fields->at(k: "Content-Type" ); |
787 | if (fields->find(x: "Content-Disposition" ) != fields->end()) { |
788 | auto value = fields->at(k: "Content-Disposition" ); |
789 | |
790 | if (auto pos = value.find(s: "filename" ); pos != std::string::npos) { |
791 | if (auto start = value.find(c: '"', pos: pos); start != std::string::npos) { |
792 | auto end = value.find(c: '"', pos: start + 1); |
793 | original_filename = value.substr(pos: start + 1, n: end - start - 2); |
794 | } else if (start = value.find(c: '='); start != std::string::npos) { |
795 | original_filename = value.substr(pos: start + 1); |
796 | } |
797 | } |
798 | } |
799 | } |
800 | |
801 | callback(res, content_type, original_filename, err); |
802 | }); |
803 | } |
804 | |
805 | void |
806 | Client::start_typing(const std::string &room_id, uint64_t timeout, ErrCallback callback) |
807 | { |
808 | using mtx::client::utils::url_encode; |
809 | const auto api_path = |
810 | "/client/v3/rooms/" + url_encode(s: room_id) + "/typing/" + url_encode(s: user_id_.to_string()); |
811 | |
812 | mtx::requests::TypingNotification req; |
813 | req.typing = true; |
814 | req.timeout = timeout; |
815 | |
816 | put<mtx::requests::TypingNotification>(endpoint: api_path, req, callback: std::move(callback)); |
817 | } |
818 | |
819 | void |
820 | Client::stop_typing(const std::string &room_id, ErrCallback callback) |
821 | { |
822 | using mtx::client::utils::url_encode; |
823 | const auto api_path = |
824 | "/client/v3/rooms/" + url_encode(s: room_id) + "/typing/" + url_encode(s: user_id_.to_string()); |
825 | |
826 | mtx::requests::TypingNotification req; |
827 | req.typing = false; |
828 | |
829 | put<mtx::requests::TypingNotification>(endpoint: api_path, req, callback: std::move(callback)); |
830 | } |
831 | |
832 | void |
833 | Client::presence_status(const std::string &user_id, |
834 | Callback<mtx::events::presence::Presence> callback) |
835 | { |
836 | using mtx::client::utils::url_encode; |
837 | const auto api_path = "/client/v3/presence/" + url_encode(s: user_id) + "/status" ; |
838 | get<mtx::events::presence::Presence>( |
839 | endpoint: api_path, |
840 | callback: [callback = std::move(callback)](const mtx::events::presence::Presence &res, |
841 | HeaderFields, |
842 | RequestErr err) { callback(res, err); }); |
843 | } |
844 | void |
845 | Client::put_presence_status(mtx::presence::PresenceState state, |
846 | std::optional<std::string> status_msg, |
847 | ErrCallback cb) |
848 | { |
849 | using mtx::client::utils::url_encode; |
850 | const auto api_path = "/client/v3/presence/" + url_encode(s: user_id_.to_string()) + "/status" ; |
851 | |
852 | nlohmann::json body; |
853 | body["presence" ] = mtx::presence::to_string(state); |
854 | if (status_msg) |
855 | body["status_msg" ] = *status_msg; |
856 | |
857 | put<nlohmann::json>(endpoint: api_path, req: body, callback: std::move(cb)); |
858 | } |
859 | |
860 | void |
861 | Client::get_event(const std::string &room_id, |
862 | const std::string &event_id, |
863 | Callback<mtx::events::collections::TimelineEvents> callback) |
864 | { |
865 | using namespace mtx::client::utils; |
866 | const auto api_path = |
867 | "/client/v3/rooms/" + url_encode(s: room_id) + "/event/" + url_encode(s: event_id); |
868 | |
869 | get<mtx::events::collections::TimelineEvent>( |
870 | endpoint: api_path, |
871 | callback: [callback = std::move(callback)](const mtx::events::collections::TimelineEvent &res, |
872 | HeaderFields, |
873 | RequestErr err) { callback(res.data, err); }); |
874 | } |
875 | |
876 | void |
877 | Client::members(const std::string &room_id, |
878 | Callback<mtx::responses::Members> cb, |
879 | const std::string &at, |
880 | std::optional<mtx::events::state::Membership> membership, |
881 | std::optional<mtx::events::state::Membership> not_membership) |
882 | { |
883 | std::map<std::string, std::string> params; |
884 | |
885 | std::string query; |
886 | |
887 | if (!at.empty()) |
888 | params.emplace(args: "at" , args: at); |
889 | if (membership) |
890 | params.emplace(args: "membership" , args: events::state::membershipToString(membership: *membership)); |
891 | if (not_membership) |
892 | params.emplace(args: "not_membership" , args: events::state::membershipToString(membership: *not_membership)); |
893 | |
894 | const auto api_path = "/client/v3/rooms/" + mtx::client::utils::url_encode(s: room_id) + |
895 | "/members?" + client::utils::query_params(params); |
896 | |
897 | get<mtx::responses::Members>(endpoint: api_path, |
898 | callback: [cb = std::move(cb)](const mtx::responses::Members &res, |
899 | HeaderFields, |
900 | RequestErr err) { cb(res, err); }); |
901 | } |
902 | |
903 | void |
904 | Client::messages(const MessagesOpts &opts, Callback<mtx::responses::Messages> callback) |
905 | { |
906 | std::map<std::string, std::string> params; |
907 | |
908 | params.emplace(args: "dir" , args: to_string(dir: opts.dir)); |
909 | |
910 | if (!opts.from.empty()) |
911 | params.emplace(args: "from" , args: opts.from); |
912 | if (!opts.to.empty()) |
913 | params.emplace(args: "to" , args: opts.to); |
914 | if (opts.limit > 0) |
915 | params.emplace(args: "limit" , args: std::to_string(val: opts.limit)); |
916 | if (!opts.filter.empty()) |
917 | params.emplace(args: "filter" , args: opts.filter); |
918 | |
919 | const auto api_path = "/client/v3/rooms/" + mtx::client::utils::url_encode(s: opts.room_id) + |
920 | "/messages?" + client::utils::query_params(params); |
921 | |
922 | get<mtx::responses::Messages>( |
923 | endpoint: api_path, |
924 | callback: [callback = std::move(callback)]( |
925 | const mtx::responses::Messages &res, HeaderFields, RequestErr err) { callback(res, err); }); |
926 | } |
927 | |
928 | void |
929 | Client::upload_filter(const nlohmann::json &j, Callback<mtx::responses::FilterId> callback) |
930 | { |
931 | const auto api_path = |
932 | "/client/v3/user/" + mtx::client::utils::url_encode(s: user_id_.to_string()) + "/filter" ; |
933 | |
934 | post<nlohmann::json, mtx::responses::FilterId>(endpoint: api_path, req: j, callback: std::move(callback)); |
935 | } |
936 | |
937 | void |
938 | Client::read_event(const std::string &room_id, |
939 | const std::string &event_id, |
940 | ErrCallback callback, |
941 | bool hidden) |
942 | { |
943 | const auto api_path = |
944 | "/client/v3/rooms/" + mtx::client::utils::url_encode(s: room_id) + "/read_markers" ; |
945 | |
946 | nlohmann::json body = { |
947 | {"m.fully_read" , event_id}, |
948 | {"org.matrix.msc2285.read.private" , event_id}, |
949 | {"m.read.private" , event_id}, |
950 | }; |
951 | |
952 | if (!hidden) |
953 | body["m.read" ] = event_id; |
954 | |
955 | post<nlohmann::json, mtx::responses::Empty>( |
956 | endpoint: api_path, |
957 | req: body, |
958 | callback: [callback = std::move(callback)](const mtx::responses::Empty, RequestErr err) { |
959 | callback(err); |
960 | }); |
961 | } |
962 | |
963 | void |
964 | Client::redact_event(const std::string &room_id, |
965 | const std::string &event_id, |
966 | Callback<mtx::responses::EventId> callback, |
967 | const std::string &reason) |
968 | { |
969 | const auto api_path = "/client/v3/rooms/" + mtx::client::utils::url_encode(s: room_id) + |
970 | "/redact/" + mtx::client::utils::url_encode(s: event_id) + "/" + |
971 | mtx::client::utils::url_encode(s: mtx::client::utils::random_token()); |
972 | |
973 | nlohmann::json body = nlohmann::json::object(); |
974 | if (!reason.empty()) { |
975 | body["reason" ] = reason; |
976 | } |
977 | |
978 | put<nlohmann::json, mtx::responses::EventId>(endpoint: api_path, req: body, callback: std::move(callback)); |
979 | } |
980 | |
981 | void |
982 | Client::registration(const std::string &user, |
983 | const std::string &pass, |
984 | UIAHandler uia_handler, |
985 | Callback<mtx::responses::Register> cb, |
986 | const std::string &initial_device_display_name) |
987 | { |
988 | nlohmann::json req = {{"username" , user}, {"password" , pass}}; |
989 | |
990 | if (!initial_device_display_name.empty()) |
991 | req["initial_device_display_name" ] = initial_device_display_name; |
992 | |
993 | uia_handler.next_ = [this, req, cb = std::move(cb)](const UIAHandler &h, |
994 | const nlohmann::json &auth) { |
995 | auto request = req; |
996 | if (!auth.empty()) |
997 | request["auth" ] = auth; |
998 | |
999 | post<nlohmann::json, mtx::responses::Register>( |
1000 | endpoint: "/client/v3/register" , |
1001 | req: request, |
1002 | callback: [this, cb, h](auto &r, RequestErr e) { |
1003 | if (e && e->status_code == 401) { |
1004 | mtx::utils::log::log()->debug(fmt: "{}" , args: e); |
1005 | h.prompt(h, e->matrix_error.unauthorized); |
1006 | } else { |
1007 | if (!e && !r.access_token.empty()) { |
1008 | this->user_id_ = r.user_id; |
1009 | this->device_id_ = r.device_id; |
1010 | this->access_token_ = r.access_token; |
1011 | } |
1012 | cb(r, e); |
1013 | } |
1014 | }, |
1015 | requires_auth: false); |
1016 | }; |
1017 | |
1018 | uia_handler.next_(uia_handler, {}); |
1019 | } |
1020 | |
1021 | void |
1022 | Client::registration(Callback<mtx::responses::Register> cb) |
1023 | { |
1024 | post<nlohmann::json, mtx::responses::Register>( |
1025 | endpoint: "/client/v3/register" , req: nlohmann::json::object(), callback: std::move(cb), requires_auth: false); |
1026 | } |
1027 | |
1028 | void |
1029 | Client::registration_token_validity(const std::string token, |
1030 | Callback<mtx::responses::RegistrationTokenValidity> cb) |
1031 | { |
1032 | const auto api_path = "/client/v1/register/m.login.registration_token/validity?" + |
1033 | mtx::client::utils::query_params(params: {{"token" , token}}); |
1034 | |
1035 | get<mtx::responses::RegistrationTokenValidity>( |
1036 | endpoint: api_path, |
1037 | callback: [cb = std::move(cb)](const mtx::responses::RegistrationTokenValidity &res, |
1038 | HeaderFields, |
1039 | RequestErr err) { cb(res, err); }); |
1040 | } |
1041 | |
1042 | void |
1043 | Client::register_email_request_token(const requests::RequestEmailToken &r, |
1044 | Callback<mtx::responses::RequestToken> cb) |
1045 | { |
1046 | post(endpoint: "/client/v3/register/email/requestToken" , req: r, callback: std::move(cb)); |
1047 | } |
1048 | |
1049 | void |
1050 | Client::register_username_available(const std::string &username, |
1051 | Callback<mtx::responses::Available> cb) |
1052 | { |
1053 | get<mtx::responses::Available>( |
1054 | endpoint: "/client/v3/register/available?username=" + mtx::client::utils::url_encode(s: username), |
1055 | callback: [cb = std::move(cb)](const mtx::responses::Available &res, HeaderFields, RequestErr err) { |
1056 | cb(res, err); |
1057 | }); |
1058 | } |
1059 | |
1060 | void |
1061 | Client::verify_email_request_token(const requests::RequestEmailToken &r, |
1062 | Callback<mtx::responses::RequestToken> cb) |
1063 | { |
1064 | post(endpoint: "/client/v3/account/password/email/requestToken" , req: r, callback: std::move(cb)); |
1065 | } |
1066 | |
1067 | void |
1068 | Client::register_phone_request_token(const requests::RequestMSISDNToken &r, |
1069 | Callback<mtx::responses::RequestToken> cb) |
1070 | { |
1071 | post(endpoint: "/client/v3/register/msisdn/requestToken" , req: r, callback: std::move(cb)); |
1072 | } |
1073 | void |
1074 | Client::verify_phone_request_token(const requests::RequestMSISDNToken &r, |
1075 | Callback<mtx::responses::RequestToken> cb) |
1076 | { |
1077 | post(endpoint: "/client/v3/account/password/msisdn/requestToken" , req: r, callback: std::move(cb)); |
1078 | } |
1079 | |
1080 | void |
1081 | Client::validate_submit_token(const std::string &url, |
1082 | const requests::IdentitySubmitToken &r, |
1083 | Callback<mtx::responses::Success> cb) |
1084 | { |
1085 | // some dancing to send to an arbitrary, server provided url |
1086 | auto callback = prepare_callback<mtx::responses::Success>( |
1087 | callback: [cb = std::move(cb)](const mtx::responses::Success &res, HeaderFields, RequestErr err) { |
1088 | cb(res, err); |
1089 | }); |
1090 | p->client.post( |
1091 | url, |
1092 | request_body: nlohmann::json(r).dump(), |
1093 | mimetype: "application/json" , |
1094 | callback: [callback = std::move(callback)](const coeurl::Request &r) { |
1095 | callback(r.response_headers(), r.response(), r.error_code(), r.response_code()); |
1096 | }, |
1097 | headers: prepare_headers(requires_auth: false)); |
1098 | } |
1099 | |
1100 | void |
1101 | Client::send_state_event(const std::string &room_id, |
1102 | const std::string &event_type, |
1103 | const std::string &state_key, |
1104 | const nlohmann::json &payload, |
1105 | Callback<mtx::responses::EventId> callback) |
1106 | { |
1107 | const auto api_path = "/client/v3/rooms/" + mtx::client::utils::url_encode(s: room_id) + |
1108 | "/state/" + mtx::client::utils::url_encode(s: event_type) + "/" + |
1109 | mtx::client::utils::url_encode(s: state_key); |
1110 | |
1111 | put<nlohmann::json, mtx::responses::EventId>(endpoint: api_path, req: payload, callback: std::move(callback)); |
1112 | } |
1113 | |
1114 | void |
1115 | Client::send_to_device(const std::string &event_type, |
1116 | const std::string &txn_id, |
1117 | const nlohmann::json &body, |
1118 | ErrCallback callback) |
1119 | { |
1120 | const auto api_path = "/client/v3/sendToDevice/" + mtx::client::utils::url_encode(s: event_type) + |
1121 | "/" + mtx::client::utils::url_encode(s: txn_id); |
1122 | |
1123 | put<nlohmann::json>(endpoint: api_path, req: body, callback: std::move(callback)); |
1124 | } |
1125 | |
1126 | void |
1127 | Client::resolve_room_alias(const std::string &alias, Callback<mtx::responses::RoomId> cb) |
1128 | { |
1129 | const auto api_path = "/client/v3/directory/room/" + mtx::client::utils::url_encode(s: alias); |
1130 | |
1131 | get<mtx::responses::RoomId>(endpoint: api_path, |
1132 | callback: [cb = std::move(cb)](const mtx::responses::RoomId &res, |
1133 | HeaderFields, |
1134 | RequestErr err) { cb(res, err); }); |
1135 | } |
1136 | void |
1137 | Client::add_room_alias(const std::string &alias, const std::string &roomid, ErrCallback cb) |
1138 | { |
1139 | const auto api_path = "/client/v3/directory/room/" + mtx::client::utils::url_encode(s: alias); |
1140 | auto body = nlohmann::json::object(); |
1141 | body["room_id" ] = roomid; |
1142 | put<nlohmann::json>(endpoint: api_path, req: body, callback: std::move(cb)); |
1143 | } |
1144 | |
1145 | void |
1146 | Client::delete_room_alias(const std::string &alias, ErrCallback cb) |
1147 | { |
1148 | delete_(endpoint: "/client/v3/directory/room/" + mtx::client::utils::url_encode(s: alias), cb: std::move(cb)); |
1149 | } |
1150 | |
1151 | void |
1152 | Client::list_room_aliases(const std::string &room_id, Callback<mtx::responses::Aliases> cb) |
1153 | { |
1154 | const auto api_path = |
1155 | "/client/v3/rooms/" + mtx::client::utils::url_encode(s: room_id) + "/aliases" ; |
1156 | |
1157 | get<mtx::responses::Aliases>(endpoint: api_path, |
1158 | callback: [cb = std::move(cb)](const mtx::responses::Aliases &res, |
1159 | HeaderFields, |
1160 | RequestErr err) { cb(res, err); }); |
1161 | } |
1162 | |
1163 | void |
1164 | Client::get_room_visibility(const std::string &room_id, |
1165 | Callback<mtx::responses::PublicRoomVisibility> cb) |
1166 | { |
1167 | const auto api_path = |
1168 | "/client/v3/directory/list/room/" + mtx::client::utils::url_encode(s: room_id); |
1169 | |
1170 | get<mtx::responses::PublicRoomVisibility>( |
1171 | endpoint: api_path, |
1172 | callback: [cb = std::move(cb)](const mtx::responses::PublicRoomVisibility &res, |
1173 | HeaderFields, |
1174 | RequestErr err) { cb(res, err); }); |
1175 | } |
1176 | |
1177 | void |
1178 | Client::put_room_visibility(const std::string &room_id, |
1179 | const mtx::requests::PublicRoomVisibility &req, |
1180 | ErrCallback cb) |
1181 | { |
1182 | const auto api_path = |
1183 | "/client/v3/directory/list/room/" + mtx::client::utils::url_encode(s: room_id); |
1184 | put<mtx::requests::PublicRoomVisibility>(endpoint: api_path, req, callback: std::move(cb)); |
1185 | } |
1186 | |
1187 | void |
1188 | Client::post_public_rooms(const mtx::requests::PublicRooms &req, |
1189 | Callback<mtx::responses::PublicRooms> cb, |
1190 | const std::string &server) |
1191 | { |
1192 | std::string api_path = "/client/v3/publicRooms" ; |
1193 | |
1194 | if (!server.empty()) |
1195 | api_path += "?" + mtx::client::utils::query_params(params: {{"server" , server}}); |
1196 | post<mtx::requests::PublicRooms, mtx::responses::PublicRooms>(endpoint: api_path, req, callback: std::move(cb)); |
1197 | } |
1198 | |
1199 | void |
1200 | Client::get_public_rooms(Callback<mtx::responses::PublicRooms> cb, |
1201 | const std::string &server, |
1202 | size_t limit, |
1203 | const std::string &since) |
1204 | { |
1205 | std::string api_path = "/client/v3/publicRooms" ; |
1206 | |
1207 | std::map<std::string, std::string> params; |
1208 | if (!server.empty()) |
1209 | params["server" ] = server; |
1210 | if (limit > 0) |
1211 | params["limit" ] = std::to_string(val: limit); |
1212 | if (!since.empty()) |
1213 | params["since" ] = since; |
1214 | |
1215 | if (!params.empty()) |
1216 | api_path += "?" + mtx::client::utils::query_params(params); |
1217 | |
1218 | get<mtx::responses::PublicRooms>(endpoint: api_path, |
1219 | callback: [cb = std::move(cb)](const mtx::responses::PublicRooms &res, |
1220 | HeaderFields, |
1221 | RequestErr err) { cb(res, err); }); |
1222 | } |
1223 | |
1224 | void |
1225 | Client::get_hierarchy(const std::string &room_id, |
1226 | Callback<mtx::responses::HierarchyRooms> cb, |
1227 | const std::string &from, |
1228 | size_t limit, |
1229 | size_t max_depth, |
1230 | bool suggested_only) |
1231 | { |
1232 | std::string api_path = |
1233 | "/client/v1/rooms/" + mtx::client::utils::url_encode(s: room_id) + "/hierarchy" ; |
1234 | |
1235 | std::map<std::string, std::string> params; |
1236 | if (limit > 0) |
1237 | params["limit" ] = std::to_string(val: limit); |
1238 | if (max_depth > 0) |
1239 | params["max_depth" ] = std::to_string(val: max_depth); |
1240 | if (suggested_only) |
1241 | params["suggested_only" ] = "true" ; |
1242 | if (!from.empty()) |
1243 | params["from" ] = from; |
1244 | |
1245 | if (!params.empty()) |
1246 | api_path += "?" + mtx::client::utils::query_params(params); |
1247 | |
1248 | get<mtx::responses::HierarchyRooms>( |
1249 | endpoint: api_path, |
1250 | callback: [cb = std::move(cb)]( |
1251 | const mtx::responses::HierarchyRooms &res, HeaderFields, RequestErr err) { cb(res, err); }); |
1252 | } |
1253 | |
1254 | void |
1255 | Client::get_summary(const std::string &room_id, |
1256 | Callback<mtx::responses::PublicRoomsChunk> cb, |
1257 | std::vector<std::string> via) |
1258 | { |
1259 | std::string query; |
1260 | if (!via.empty()) { |
1261 | query = "?via=" + mtx::client::utils::url_encode(s: via[0]); |
1262 | for (size_t i = 1; i < via.size(); i++) { |
1263 | query += "&via=" + mtx::client::utils::url_encode(s: via[i]); |
1264 | } |
1265 | } |
1266 | std::string api_path = "/client/unstable/im.nheko.summary/rooms/" + |
1267 | mtx::client::utils::url_encode(s: room_id) + "/summary" + query; |
1268 | |
1269 | get<mtx::responses::PublicRoomsChunk>( |
1270 | endpoint: api_path, |
1271 | callback: [this, room_id, cb = std::move(cb)]( |
1272 | const mtx::responses::PublicRoomsChunk &res, HeaderFields, RequestErr err) { |
1273 | if (!err || !(err->status_code == 404 || err->status_code == 400)) |
1274 | cb(res, err); |
1275 | else if (!room_id.empty() && room_id[0] == '#') |
1276 | resolve_room_alias( |
1277 | alias: room_id, cb: [this, cb](const mtx::responses::RoomId &room, RequestErr err) { |
1278 | if (room.room_id.empty()) |
1279 | cb({}, err); |
1280 | else |
1281 | get_hierarchy( |
1282 | room_id: room.room_id, |
1283 | cb: [cb](const mtx::responses::HierarchyRooms &res, RequestErr err) { |
1284 | if (res.rooms.empty()) |
1285 | cb({}, err); |
1286 | else |
1287 | cb(res.rooms.front(), err); |
1288 | }, |
1289 | from: "" , |
1290 | limit: 1); |
1291 | }); |
1292 | else |
1293 | get_hierarchy( |
1294 | room_id, |
1295 | cb: [cb](const mtx::responses::HierarchyRooms &res, RequestErr err) { |
1296 | if (res.rooms.empty()) |
1297 | cb({}, err); |
1298 | else |
1299 | cb(res.rooms.front(), err); |
1300 | }, |
1301 | from: "" , |
1302 | limit: 1); |
1303 | }); |
1304 | } |
1305 | |
1306 | // |
1307 | // Device related endpoints |
1308 | // |
1309 | |
1310 | void |
1311 | Client::query_devices(Callback<mtx::responses::QueryDevices> cb) |
1312 | { |
1313 | get<mtx::responses::QueryDevices>(endpoint: "/client/v3/devices" , |
1314 | callback: [cb = std::move(cb)](const mtx::responses::QueryDevices &res, |
1315 | HeaderFields, |
1316 | RequestErr err) { cb(res, err); }); |
1317 | } |
1318 | |
1319 | void |
1320 | Client::get_device(const std::string &device_id, Callback<mtx::responses::Device> cb) |
1321 | { |
1322 | get<mtx::responses::Device>(endpoint: "/client/v3/devices/" + mtx::client::utils::url_encode(s: device_id), |
1323 | callback: [cb = std::move(cb)](const mtx::responses::Device &res, |
1324 | HeaderFields, |
1325 | RequestErr err) { cb(res, err); }); |
1326 | } |
1327 | |
1328 | void |
1329 | Client::set_device_name(const std::string &device_id, |
1330 | const std::string &display_name, |
1331 | ErrCallback callback) |
1332 | { |
1333 | mtx::requests::DeviceUpdate req; |
1334 | req.display_name = display_name; |
1335 | |
1336 | put<mtx::requests::DeviceUpdate>( |
1337 | endpoint: "/client/v3/devices/" + mtx::client::utils::url_encode(s: device_id), req, callback: std::move(callback)); |
1338 | } |
1339 | |
1340 | void |
1341 | Client::delete_device(const std::string &device_id, UIAHandler uia_handler, ErrCallback cb) |
1342 | { |
1343 | nlohmann::json req; |
1344 | req["devices" ] = {device_id}; |
1345 | |
1346 | uia_handler.next_ = [this, req, cb = std::move(cb)](const UIAHandler &h, |
1347 | const nlohmann::json &auth) { |
1348 | auto request = req; |
1349 | if (!auth.empty()) |
1350 | request["auth" ] = auth; |
1351 | |
1352 | post<nlohmann::json, mtx::responses::Empty>( |
1353 | endpoint: "/client/v3/delete_devices" , req: request, callback: [cb, h](auto &, RequestErr e) { |
1354 | if (e && e->status_code == 401 && !e->matrix_error.unauthorized.flows.empty()) |
1355 | h.prompt(h, e->matrix_error.unauthorized); |
1356 | else |
1357 | cb(e); |
1358 | }); |
1359 | }; |
1360 | |
1361 | uia_handler.next_(uia_handler, {}); |
1362 | } |
1363 | |
1364 | void |
1365 | Client::delete_devices(const std::vector<std::string> &device_ids, |
1366 | UIAHandler uia_handler, |
1367 | ErrCallback cb) |
1368 | { |
1369 | nlohmann::json req; |
1370 | req["devices" ] = device_ids; |
1371 | |
1372 | uia_handler.next_ = [this, req = std::move(req), cb = std::move(cb)]( |
1373 | const UIAHandler &h, const nlohmann::json &auth) { |
1374 | auto request = req; |
1375 | if (!auth.empty()) |
1376 | request["auth" ] = auth; |
1377 | |
1378 | post<nlohmann::json, mtx::responses::Empty>( |
1379 | endpoint: "/client/v3/delete_devices" , req: request, callback: [cb, h](auto &, RequestErr e) { |
1380 | if (e && e->status_code == 401 && !e->matrix_error.unauthorized.flows.empty()) |
1381 | h.prompt(h, e->matrix_error.unauthorized); |
1382 | else |
1383 | cb(e); |
1384 | }); |
1385 | }; |
1386 | |
1387 | uia_handler.next_(uia_handler, {}); |
1388 | } |
1389 | |
1390 | // |
1391 | // Encryption related endpoints |
1392 | // |
1393 | |
1394 | void |
1395 | Client::upload_keys(const mtx::requests::UploadKeys &req, |
1396 | Callback<mtx::responses::UploadKeys> callback) |
1397 | { |
1398 | post<mtx::requests::UploadKeys, mtx::responses::UploadKeys>( |
1399 | endpoint: "/client/v3/keys/upload" , req, callback: std::move(callback)); |
1400 | } |
1401 | |
1402 | void |
1403 | Client::keys_signatures_upload(const mtx::requests::KeySignaturesUpload &req, |
1404 | Callback<mtx::responses::KeySignaturesUpload> cb) |
1405 | { |
1406 | post<mtx::requests::KeySignaturesUpload, mtx::responses::KeySignaturesUpload>( |
1407 | endpoint: "/client/v3/keys/signatures/upload" , req, callback: std::move(cb)); |
1408 | } |
1409 | |
1410 | void |
1411 | Client::device_signing_upload(const mtx::requests::DeviceSigningUpload &deviceKeys, |
1412 | UIAHandler uia_handler, |
1413 | ErrCallback cb) |
1414 | { |
1415 | nlohmann::json req = deviceKeys; |
1416 | |
1417 | uia_handler.next_ = [this, req = std::move(req), cb = std::move(cb)]( |
1418 | const UIAHandler &h, const nlohmann::json &auth) { |
1419 | auto request = req; |
1420 | if (!auth.empty()) |
1421 | request["auth" ] = auth; |
1422 | |
1423 | post<nlohmann::json, mtx::responses::Empty>( |
1424 | endpoint: "/client/v3/keys/device_signing/upload" , req: request, callback: [cb, h](auto &, RequestErr e) { |
1425 | if (e && e->status_code == 401 && !e->matrix_error.unauthorized.flows.empty()) |
1426 | h.prompt(h, e->matrix_error.unauthorized); |
1427 | else |
1428 | cb(e); |
1429 | }); |
1430 | }; |
1431 | |
1432 | uia_handler.next_(uia_handler, {}); |
1433 | } |
1434 | |
1435 | void |
1436 | Client::query_keys(const mtx::requests::QueryKeys &req, |
1437 | Callback<mtx::responses::QueryKeys> callback) |
1438 | { |
1439 | post<mtx::requests::QueryKeys, mtx::responses::QueryKeys>( |
1440 | endpoint: "/client/v3/keys/query" , req, callback: std::move(callback)); |
1441 | } |
1442 | |
1443 | //! Claims one-time keys for use in pre-key messages. |
1444 | void |
1445 | Client::claim_keys(const mtx::requests::ClaimKeys &req, Callback<mtx::responses::ClaimKeys> cb) |
1446 | { |
1447 | post<mtx::requests::ClaimKeys, mtx::responses::ClaimKeys>( |
1448 | endpoint: "/client/v3/keys/claim" , req, callback: std::move(cb)); |
1449 | } |
1450 | |
1451 | void |
1452 | Client::key_changes(const std::string &from, |
1453 | const std::string &to, |
1454 | Callback<mtx::responses::KeyChanges> callback) |
1455 | { |
1456 | std::map<std::string, std::string> params; |
1457 | |
1458 | if (!from.empty()) |
1459 | params.emplace(args: "from" , args: from); |
1460 | |
1461 | if (!to.empty()) |
1462 | params.emplace(args: "to" , args: to); |
1463 | |
1464 | get<mtx::responses::KeyChanges>( |
1465 | endpoint: "/client/v3/keys/changes?" + mtx::client::utils::query_params(params), |
1466 | callback: [callback = std::move(callback)](const mtx::responses::KeyChanges &res, |
1467 | HeaderFields, |
1468 | RequestErr err) { callback(res, err); }); |
1469 | } |
1470 | |
1471 | // |
1472 | // Key backup endpoints |
1473 | // |
1474 | void |
1475 | Client::backup_version(Callback<mtx::responses::backup::BackupVersion> cb) |
1476 | { |
1477 | get<mtx::responses::backup::BackupVersion>( |
1478 | endpoint: "/client/v3/room_keys/version" , |
1479 | callback: [cb = std::move(cb)](const mtx::responses::backup::BackupVersion &res, |
1480 | HeaderFields, |
1481 | RequestErr err) { cb(res, err); }); |
1482 | } |
1483 | void |
1484 | Client::backup_version(const std::string &version, |
1485 | Callback<mtx::responses::backup::BackupVersion> cb) |
1486 | { |
1487 | get<mtx::responses::backup::BackupVersion>( |
1488 | endpoint: "/client/v3/room_keys/version/" + mtx::client::utils::url_encode(s: version), |
1489 | callback: [cb = std::move(cb)](const mtx::responses::backup::BackupVersion &res, |
1490 | HeaderFields, |
1491 | RequestErr err) { cb(res, err); }); |
1492 | } |
1493 | |
1494 | void |
1495 | Client::update_backup_version(const std::string &version, |
1496 | const mtx::responses::backup::BackupVersion &data, |
1497 | ErrCallback cb) |
1498 | { |
1499 | put<mtx::responses::backup::BackupVersion>(endpoint: "/client/v3/room_keys/version/" + |
1500 | mtx::client::utils::url_encode(s: version), |
1501 | req: data, |
1502 | callback: std::move(cb)); |
1503 | } |
1504 | |
1505 | void |
1506 | Client::post_backup_version(const std::string &algorithm, |
1507 | const std::string &auth_data, |
1508 | Callback<mtx::responses::Version> cb) |
1509 | { |
1510 | nlohmann::json req = {{"algorithm" , algorithm}, |
1511 | {"auth_data" , nlohmann::json::parse(i: auth_data)}}; |
1512 | post<nlohmann::json, mtx::responses::Version>( |
1513 | endpoint: "/client/v3/room_keys/version" , req, callback: std::move(cb)); |
1514 | } |
1515 | void |
1516 | Client::room_keys(const std::string &version, Callback<mtx::responses::backup::KeysBackup> cb) |
1517 | { |
1518 | get<mtx::responses::backup::KeysBackup>( |
1519 | endpoint: "/client/v3/room_keys/keys?" + mtx::client::utils::query_params(params: {{"version" , version}}), |
1520 | callback: [cb = std::move(cb)](const mtx::responses::backup::KeysBackup &res, |
1521 | HeaderFields, |
1522 | RequestErr err) { cb(res, err); }); |
1523 | } |
1524 | void |
1525 | Client::room_keys(const std::string &version, |
1526 | const std::string &room_id, |
1527 | Callback<mtx::responses::backup::RoomKeysBackup> cb) |
1528 | { |
1529 | get<mtx::responses::backup::RoomKeysBackup>( |
1530 | endpoint: "/client/v3/room_keys/keys/" + mtx::client::utils::url_encode(s: room_id) + "?" + |
1531 | mtx::client::utils::query_params(params: {{"version" , version}}), |
1532 | callback: [cb = std::move(cb)](const mtx::responses::backup::RoomKeysBackup &res, |
1533 | HeaderFields, |
1534 | RequestErr err) { cb(res, err); }); |
1535 | } |
1536 | void |
1537 | Client::room_keys(const std::string &version, |
1538 | const std::string &room_id, |
1539 | const std::string &session_id, |
1540 | Callback<mtx::responses::backup::SessionBackup> cb) |
1541 | { |
1542 | get<mtx::responses::backup::SessionBackup>( |
1543 | endpoint: "/client/v3/room_keys/keys/" + mtx::client::utils::url_encode(s: room_id) + "/" + |
1544 | mtx::client::utils::url_encode(s: session_id) + "?" + |
1545 | mtx::client::utils::query_params(params: {{"version" , version}}), |
1546 | callback: [cb = std::move(cb)](const mtx::responses::backup::SessionBackup &res, |
1547 | HeaderFields, |
1548 | RequestErr err) { cb(res, err); }); |
1549 | } |
1550 | |
1551 | void |
1552 | Client::put_room_keys(const std::string &version, |
1553 | const mtx::responses::backup::KeysBackup &keys, |
1554 | ErrCallback cb) |
1555 | { |
1556 | put(endpoint: "/client/v3/room_keys/keys?" + mtx::client::utils::query_params(params: {{"version" , version}}), |
1557 | req: keys, |
1558 | callback: std::move(cb)); |
1559 | } |
1560 | void |
1561 | Client::put_room_keys(const std::string &version, |
1562 | const std::string &room_id, |
1563 | const mtx::responses::backup::RoomKeysBackup &keys, |
1564 | ErrCallback cb) |
1565 | { |
1566 | put(endpoint: "/client/v3/room_keys/keys/" + mtx::client::utils::url_encode(s: room_id) + "?" + |
1567 | mtx::client::utils::query_params(params: {{"version" , version}}), |
1568 | req: keys, |
1569 | callback: std::move(cb)); |
1570 | } |
1571 | void |
1572 | Client::put_room_keys(const std::string &version, |
1573 | const std::string &room_id, |
1574 | const std::string &session_id, |
1575 | const mtx::responses::backup::SessionBackup &keys, |
1576 | ErrCallback cb) |
1577 | { |
1578 | put(endpoint: "/client/v3/room_keys/keys/" + mtx::client::utils::url_encode(s: room_id) + "/" + |
1579 | mtx::client::utils::url_encode(s: session_id) + "?" + |
1580 | mtx::client::utils::query_params(params: {{"version" , version}}), |
1581 | req: keys, |
1582 | callback: std::move(cb)); |
1583 | } |
1584 | |
1585 | //! Retrieve a specific secret |
1586 | void |
1587 | Client::secret_storage_secret(const std::string &secret_id, |
1588 | Callback<mtx::secret_storage::Secret> cb) |
1589 | { |
1590 | get<mtx::secret_storage::Secret>( |
1591 | endpoint: "/client/v3/user/" + mtx::client::utils::url_encode(s: user_id_.to_string()) + "/account_data/" + |
1592 | mtx::client::utils::url_encode(s: secret_id), |
1593 | callback: [cb = std::move(cb)](const mtx::secret_storage::Secret &res, HeaderFields, RequestErr err) { |
1594 | cb(res, err); |
1595 | }); |
1596 | } |
1597 | //! Retrieve information about a key |
1598 | void |
1599 | Client::secret_storage_key(const std::string &key_id, |
1600 | Callback<mtx::secret_storage::AesHmacSha2KeyDescription> cb) |
1601 | { |
1602 | get<mtx::secret_storage::AesHmacSha2KeyDescription>( |
1603 | endpoint: "/client/v3/user/" + mtx::client::utils::url_encode(s: user_id_.to_string()) + |
1604 | "/account_data/m.secret_storage.key." + mtx::client::utils::url_encode(s: key_id), |
1605 | callback: [cb = std::move(cb)](const mtx::secret_storage::AesHmacSha2KeyDescription &res, |
1606 | HeaderFields, |
1607 | RequestErr err) { cb(res, err); }); |
1608 | } |
1609 | |
1610 | //! Upload a specific secret |
1611 | void |
1612 | Client::upload_secret_storage_secret(const std::string &secret_id, |
1613 | const mtx::secret_storage::Secret &secret, |
1614 | ErrCallback cb) |
1615 | { |
1616 | put(endpoint: "/client/v3/user/" + mtx::client::utils::url_encode(s: user_id_.to_string()) + |
1617 | "/account_data/" + mtx::client::utils::url_encode(s: secret_id), |
1618 | req: secret, |
1619 | callback: std::move(cb)); |
1620 | } |
1621 | |
1622 | //! Upload information about a key |
1623 | void |
1624 | Client::upload_secret_storage_key(const std::string &key_id, |
1625 | const mtx::secret_storage::AesHmacSha2KeyDescription &desc, |
1626 | ErrCallback cb) |
1627 | { |
1628 | put(endpoint: "/client/v3/user/" + mtx::client::utils::url_encode(s: user_id_.to_string()) + |
1629 | "/account_data/m.secret_storage.key." + mtx::client::utils::url_encode(s: key_id), |
1630 | req: desc, |
1631 | callback: std::move(cb)); |
1632 | } |
1633 | |
1634 | void |
1635 | Client::set_secret_storage_default_key(const std::string &key_id, ErrCallback cb) |
1636 | { |
1637 | nlohmann::json key = {{"key" , key_id}}; |
1638 | put(endpoint: "/client/v3/user/" + mtx::client::utils::url_encode(s: user_id_.to_string()) + |
1639 | "/account_data/m.secret_storage.default_key" , |
1640 | req: key, |
1641 | callback: std::move(cb)); |
1642 | } |
1643 | |
1644 | void |
1645 | Client::enable_encryption(const std::string &room, Callback<mtx::responses::EventId> callback) |
1646 | { |
1647 | using namespace mtx::events; |
1648 | state::Encryption event; |
1649 | |
1650 | send_state_event<state::Encryption>(room_id: room, state_key: "" , payload: event, callback: std::move(callback)); |
1651 | } |
1652 | |
1653 | void |
1654 | Client::get_turn_server(Callback<mtx::responses::TurnServer> cb) |
1655 | { |
1656 | get<mtx::responses::TurnServer>(endpoint: "/client/v3/voip/turnServer" , |
1657 | callback: [cb = std::move(cb)](const mtx::responses::TurnServer &res, |
1658 | HeaderFields, |
1659 | RequestErr err) { cb(res, err); }); |
1660 | } |
1661 | |
1662 | void |
1663 | Client::set_pusher(const mtx::requests::SetPusher &req, Callback<mtx::responses::Empty> cb) |
1664 | { |
1665 | post<mtx::requests::SetPusher, mtx::responses::Empty>( |
1666 | endpoint: "/client/v3/pushers/set" , req, callback: std::move(cb)); |
1667 | } |
1668 | |
1669 | void |
1670 | Client::search_user_directory(const std::string &search_term, |
1671 | Callback<mtx::responses::Users> callback, |
1672 | int limit) |
1673 | { |
1674 | nlohmann::json req = {{"search_term" , search_term}}; |
1675 | if (limit >= 0) |
1676 | req["limit" ] = limit; |
1677 | post<nlohmann::json, mtx::responses::Users>( |
1678 | endpoint: "/client/v3/user_directory/search" , req, callback: std::move(callback)); |
1679 | } |
1680 | |
1681 | // Template instantiations for the various send functions |
1682 | |
1683 | #define MTXCLIENT_SEND_STATE_EVENT(Content) \ |
1684 | template void mtx::http::Client::send_state_event<mtx::events::Content>( \ |
1685 | const std::string &, \ |
1686 | const std::string &state_key, \ |
1687 | const mtx::events::Content &, \ |
1688 | Callback<mtx::responses::EventId> cb); \ |
1689 | template void mtx::http::Client::send_state_event<mtx::events::Content>( \ |
1690 | const std::string &, const mtx::events::Content &, Callback<mtx::responses::EventId> cb); \ |
1691 | template void mtx::http::Client::get_state_event<mtx::events::Content>( \ |
1692 | const std::string &room_id, \ |
1693 | const std::string &type, \ |
1694 | const std::string &state_key, \ |
1695 | Callback<mtx::events::Content> cb); \ |
1696 | template void mtx::http::Client::get_state_event<mtx::events::Content>( \ |
1697 | const std::string &room_id, \ |
1698 | const std::string &state_key, \ |
1699 | Callback<mtx::events::Content> cb); |
1700 | |
1701 | MTXCLIENT_SEND_STATE_EVENT(state::Aliases) |
1702 | MTXCLIENT_SEND_STATE_EVENT(state::Avatar) |
1703 | MTXCLIENT_SEND_STATE_EVENT(state::CanonicalAlias) |
1704 | MTXCLIENT_SEND_STATE_EVENT(state::Create) |
1705 | MTXCLIENT_SEND_STATE_EVENT(state::Encryption) |
1706 | MTXCLIENT_SEND_STATE_EVENT(state::GuestAccess) |
1707 | MTXCLIENT_SEND_STATE_EVENT(state::HistoryVisibility) |
1708 | MTXCLIENT_SEND_STATE_EVENT(state::JoinRules) |
1709 | MTXCLIENT_SEND_STATE_EVENT(state::Member) |
1710 | MTXCLIENT_SEND_STATE_EVENT(state::Name) |
1711 | MTXCLIENT_SEND_STATE_EVENT(state::PinnedEvents) |
1712 | MTXCLIENT_SEND_STATE_EVENT(state::PowerLevels) |
1713 | MTXCLIENT_SEND_STATE_EVENT(state::Tombstone) |
1714 | MTXCLIENT_SEND_STATE_EVENT(state::Topic) |
1715 | MTXCLIENT_SEND_STATE_EVENT(state::Widget) |
1716 | MTXCLIENT_SEND_STATE_EVENT(state::policy_rule::UserRule) |
1717 | MTXCLIENT_SEND_STATE_EVENT(state::policy_rule::RoomRule) |
1718 | MTXCLIENT_SEND_STATE_EVENT(state::policy_rule::ServerRule) |
1719 | MTXCLIENT_SEND_STATE_EVENT(state::space::Child) |
1720 | MTXCLIENT_SEND_STATE_EVENT(state::space::Parent) |
1721 | MTXCLIENT_SEND_STATE_EVENT(msc2545::ImagePack) |
1722 | |
1723 | #define MTXCLIENT_SEND_ROOM_MESSAGE(Content) \ |
1724 | template void mtx::http::Client::send_room_message<Content>( \ |
1725 | const std::string &, \ |
1726 | const std::string &, \ |
1727 | const Content &, \ |
1728 | Callback<mtx::responses::EventId> cb); \ |
1729 | template void mtx::http::Client::send_room_message<Content>( \ |
1730 | const std::string &, const Content &, Callback<mtx::responses::EventId> cb); |
1731 | |
1732 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Encrypted) |
1733 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::StickerImage) |
1734 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Reaction) |
1735 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Audio) |
1736 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Emote) |
1737 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::File) |
1738 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Image) |
1739 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Notice) |
1740 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Text) |
1741 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Video) |
1742 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Confetti) |
1743 | // MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationRequest) |
1744 | // MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationStart) |
1745 | // MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationReady) |
1746 | // MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationDone) |
1747 | // MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationAccept) |
1748 | // MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationCancel) |
1749 | // MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationKey) |
1750 | // MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationMac) |
1751 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::voip::CallInvite) |
1752 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::voip::CallCandidates) |
1753 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::voip::CallAnswer) |
1754 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::voip::CallHangUp) |
1755 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::voip::CallSelectAnswer) |
1756 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::voip::CallReject) |
1757 | MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::voip::CallNegotiate) |
1758 | |
1759 | #define MTXCLIENT_SEND_TO_DEVICE(Content) \ |
1760 | template void mtx::http::Client::send_to_device<Content>( \ |
1761 | const std::string &txid, \ |
1762 | const std::map<mtx::identifiers::User, std::map<std::string, Content>> &messages, \ |
1763 | ErrCallback callback); |
1764 | |
1765 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::RoomKey) |
1766 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::ForwardedRoomKey) |
1767 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyRequest) |
1768 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::OlmEncrypted) |
1769 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::Encrypted) |
1770 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::Dummy) |
1771 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationRequest) |
1772 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationStart) |
1773 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationReady) |
1774 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationDone) |
1775 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationAccept) |
1776 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationCancel) |
1777 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationKey) |
1778 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationMac) |
1779 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::SecretSend) |
1780 | MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::SecretRequest) |
1781 | |
1782 | #define MTXCLIENT_ACCOUNT_DATA(Payload) \ |
1783 | template void mtx::http::Client::put_room_account_data<Payload>(const std::string &room_id, \ |
1784 | const std::string &type, \ |
1785 | const Payload &payload, \ |
1786 | ErrCallback cb); \ |
1787 | template void mtx::http::Client::put_room_account_data<Payload>( \ |
1788 | const std::string &room_id, const Payload &payload, ErrCallback cb); \ |
1789 | template void mtx::http::Client::put_account_data<Payload>( \ |
1790 | const std::string &type, const Payload &payload, ErrCallback cb); \ |
1791 | template void mtx::http::Client::put_account_data<Payload>(const Payload &payload, \ |
1792 | ErrCallback cb); \ |
1793 | template void mtx::http::Client::get_room_account_data<Payload>( \ |
1794 | const std::string &room_id, const std::string &type, Callback<Payload> payload); \ |
1795 | template void mtx::http::Client::get_room_account_data<Payload>(const std::string &room_id, \ |
1796 | Callback<Payload> cb); \ |
1797 | template void mtx::http::Client::get_account_data<Payload>(const std::string &type, \ |
1798 | Callback<Payload> payload); \ |
1799 | template void mtx::http::Client::get_account_data<Payload>(Callback<Payload> cb); |
1800 | |
1801 | MTXCLIENT_ACCOUNT_DATA(mtx::events::msc2545::ImagePack) |
1802 | MTXCLIENT_ACCOUNT_DATA(mtx::events::msc2545::ImagePackRooms) |
1803 | MTXCLIENT_ACCOUNT_DATA(mtx::events::account_data::nheko_extensions::HiddenEvents) |
1804 | MTXCLIENT_ACCOUNT_DATA(mtx::events::account_data::Tags) |
1805 | MTXCLIENT_ACCOUNT_DATA(mtx::events::account_data::Direct) |
1806 | |