From fb511b4df0ad1f2b6713228f6ef1490702b219be Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 21 Aug 2024 13:51:52 +0200 Subject: [PATCH] [MOD/ADD] Separate AS code, XMPP reactions removal --- Makefile | 4 +- src/AS.c | 971 ------------------------------- src/AS/Events.c | 93 +++ src/AS/Indicators.c | 119 ++++ src/AS/Media.c | 129 ++++ src/AS/Ping.c | 39 ++ src/AS/Profile.c | 138 +++++ src/AS/Register.c | 46 ++ src/AS/Relations.c | 81 +++ src/AS/Room.c | 352 +++++++++++ src/AS/Send.c | 48 ++ src/AS/State.c | 37 ++ src/XEP-0393.c | 7 + src/XMPPThread/ReListener.c | 2 - src/XMPPThread/Stanzas/Message.c | 128 ++-- src/include/AS.h | 18 +- 16 files changed, 1183 insertions(+), 1029 deletions(-) create mode 100644 src/AS/Events.c create mode 100644 src/AS/Indicators.c create mode 100644 src/AS/Media.c create mode 100644 src/AS/Ping.c create mode 100644 src/AS/Profile.c create mode 100644 src/AS/Register.c create mode 100644 src/AS/Relations.c create mode 100644 src/AS/Room.c create mode 100644 src/AS/Send.c create mode 100644 src/AS/State.c diff --git a/Makefile b/Makefile index bfff826..88cfb8d 100644 --- a/Makefile +++ b/Makefile @@ -26,8 +26,8 @@ AYAS=ayaya ETC=etc INCLUDES=src/include CC=cc -CFLAGS=-I$(SOURCE) -I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -DCODE=\"$(CODE)\" -O3 -s -Wall -Werror -LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -O3 -s +CFLAGS=-I$(SOURCE) -I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -DCODE=\"$(CODE)\" -O3 -g -Wall -Werror +LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -O3 -g AFLAGS=-C "$(ETC)/ayadoc/style.css" -p "$(NAME)" BINARY=parsee # ============================ Compilation ================================= diff --git a/src/AS.c b/src/AS.c index 81ce4a9..f9d1700 100644 --- a/src/AS.c +++ b/src/AS.c @@ -55,976 +55,5 @@ ASAuthenticateRequest(const ParseeConfig *data, HttpClientContext *ctx) HttpRequestHeader(ctx, "Authorization", bearer); Free(bearer); } -bool -ASRegisterUser(const ParseeConfig *conf, char *user) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - HttpStatus status; - if (!conf || !user) - { - return false; - } - /* Create user. We don't actually care about the value as we can - * masquerade, as long as it exists. */ - ctx = ParseeCreateRequest( - conf, - HTTP_POST, "/_matrix/client/v3/register" - ); - json = HashMapCreate(); - HashMapSet(json,"type",JsonValueString("m.login.application_service")); - - user = ParseeGetLocal(user); - HashMapSet(json,"username",JsonValueString(user)); - - ASAuthenticateRequest(conf, ctx); - status = ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); - - Free(user); - - return status == HTTP_OK; -} - -void -ASPing(const ParseeConfig *conf) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path; - if (!conf) - { - return; - } - - path = StrConcat(3, - "/_matrix/client/v1/appservice/", - "Parsee%20XMPP", - "/ping" - ); - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - HttpClientContextFree(ctx); - JsonFree(json); -} -void -ASInvite(const ParseeConfig *conf, char *id, char *invited) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *bridge; - if (!conf || !id || !invited) - { - return; - } - - bridge = StrConcat(4, - "@", conf->sender_localpart, - ":", conf->server_base - ); - path = StrConcat(5, - "/_matrix/client/v3/rooms/", id, "/invite", - "?user_id=", bridge - ); - Free(bridge); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - HashMapSet(json, "user_id", JsonValueString(invited)); - HashMapSet(json, "reason", JsonValueString("Pass over.")); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); -} -void -ASBan(const ParseeConfig *conf, char *id, char *banned) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *bridge; - if (!conf || !id || !banned) - { - return; - } - - bridge = StrConcat(4, - "@", conf->sender_localpart, - ":", conf->server_base - ); - path = StrConcat(5, - "/_matrix/client/v3/rooms/", id, "/ban", - "?user_id=", bridge - ); - Free(bridge); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - HashMapSet(json, "user_id", JsonValueString(banned)); - HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); -} -void -ASKick(const ParseeConfig *conf, char *id, char *banned) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *bridge; - if (!conf || !id || !banned) - { - return; - } - - bridge = StrConcat(4, - "@", conf->sender_localpart, - ":", conf->server_base - ); - path = StrConcat(5, - "/_matrix/client/v3/rooms/", id, "/kick", - "?user_id=", bridge - ); - Free(bridge); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - HashMapSet(json, "user_id", JsonValueString(banned)); - HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); -} -char * -ASJoin(const ParseeConfig *conf, char *id, char *masquerade) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *ret; - if (!conf || !id) - { - return NULL; - } - - if (!masquerade) - { - char *raw = StrConcat(4, - "@", conf->sender_localpart, - ":", conf->server_base - ); - masquerade = HttpUrlEncode(raw); - Free(raw); - } - else - { - masquerade = HttpUrlEncode(masquerade); - } - id = HttpUrlEncode(id); - path = StrConcat(5, - "/_matrix/client/v3/join/", id, "?", - "user_id=", masquerade - ); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - JsonFree(json); - - json = JsonDecode(HttpClientStream(ctx)); - ret = StrDuplicate(GrabString(json, 1, "room_id")); - JsonFree(json); - - HttpClientContextFree(ctx); - Free(masquerade); - Free(id); - - return ret; -} -void -ASLeave(const ParseeConfig *conf, char *id, char *masquerade) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path; - if (!conf || !id) - { - return; - } - - if (!masquerade) - { - char *raw = StrConcat(4, - "@", conf->sender_localpart, - ":", conf->server_base - ); - masquerade = HttpUrlEncode(raw); - Free(raw); - } - else - { - masquerade = HttpUrlEncode(masquerade); - } - id = HttpUrlEncode(id); - path = StrConcat(5, - "/_matrix/client/v3/rooms/", id, "/leave?", - "user_id=", masquerade - ); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - JsonFree(json); - - HttpClientContextFree(ctx); - Free(masquerade); - Free(id); -} -void -ASSetState(const ParseeConfig *conf, char *id, char *type, char *key, char *mask, HashMap *state) -{ - HttpClientContext *ctx = NULL; - char *path; - if (!conf || !id || !type || !mask || !state) - { - JsonFree(state); - return; - } - - path = StrConcat(9, - "/_matrix/client/v3/rooms/", id, "/state/", - type, "/", key, "?", "user_id=", mask - ); - - ctx = ParseeCreateRequest(conf, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, state); - - HttpClientContextFree(ctx); - JsonFree(state); -} -char * -ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) -{ - HttpClientContext *ctx = NULL; - char *path; - char *txn, *ret; - HashMap *reply; - if (!conf || !id || !type || !user || !c) - { - JsonFree(c); - return NULL; - } - - txn = StrRandom(16); - path = StrConcat(9, - "/_matrix/client/v3/rooms/", - id, "/send/", type, "/", txn, "?", - "user_id=", user - ); - Free(txn); - - ctx = ParseeCreateRequest(conf, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, c); - - reply = JsonDecode(HttpClientStream(ctx)); - ret = StrDuplicate(JsonValueAsString(HashMapGet(reply, "event_id"))); - JsonFree(reply); - - HttpClientContextFree(ctx); - JsonFree(c); - - return ret; -} -char * -ASCreateRoom(const ParseeConfig *conf, char *by, char *alias) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *id; - if (!conf || !by) - { - return NULL; - } - - path = StrConcat(3, - "/_matrix/client/v3/createRoom", - "?user_id=", by - ); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - if (alias) - { - char *trimmed = StrDuplicate(alias); - if (*alias == '#') - { - char *tmp, cb[2] = { 0 }; - alias++; - Free(trimmed); - trimmed = NULL; - - while (*alias && *alias != ':') - { - cb[0] = *alias; - tmp = trimmed; - trimmed = StrConcat(2, trimmed, cb); - Free(tmp); - alias ++; - } - } - HashMapSet(json, "room_alias_name", JsonValueString(trimmed)); - Free(trimmed); - } - HashMapSet(json, "visibility", JsonValueString("public")); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - JsonFree(json); - json = JsonDecode(HttpClientStream(ctx)); - id = StrDuplicate(JsonValueAsString(HashMapGet(json, "room_id"))); - HttpClientContextFree(ctx); - JsonFree(json); - - return id; -} -char * -ASCreateDM(const ParseeConfig *conf, char *by, char *with) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *id; - if (!conf || !by || !with) - { - return NULL; - } - - path = StrConcat(3, - "/_matrix/client/v3/createRoom", - "?user_id=", by - ); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - { - Array *invitees = ArrayCreate(); - - ArrayAdd(invitees, JsonValueString(with)); - HashMapSet(json, "invite", JsonValueArray(invitees)); - HashMapSet(json, "is_direct", JsonValueBoolean(true)); - } - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - JsonFree(json); - json = JsonDecode(HttpClientStream(ctx)); - id = StrDuplicate(JsonValueAsString(HashMapGet(json, "room_id"))); - HttpClientContextFree(ctx); - JsonFree(json); - - return id; -} -void -ASSetAvatar(const ParseeConfig *conf, char *user, char *mxc) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path; - if (!conf || !user || !mxc) - { - return; - } - - user = HttpUrlEncode(user); - path = StrConcat(6, - "/_matrix/client/v3/profile/", - user, "/avatar_url", "?", - "user_id=", user - ); - - json = HashMapCreate(); - HashMapSet(json, "avatar_url", JsonValueString(mxc)); - ctx = ParseeCreateRequest(conf, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); - Free(user); -} -void -ASSetName(const ParseeConfig *conf, char *user, char *name) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path; - if (!conf || !user || !name) - { - return; - } - - user = HttpUrlEncode(user); - path = StrConcat(6, - "/_matrix/client/v3/profile/", - user, "/displayname", "?", - "user_id=", user - ); - - json = HashMapCreate(); - HashMapSet(json, "displayname", JsonValueString(name)); - ctx = ParseeCreateRequest(conf, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); - Free(user); -} -HashMap * -ASFind(const ParseeConfig *c, char *room, char *event) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path, *user; - if (!c || !room || !event) - { - return NULL; - } - - user = StrConcat(4, "@", c->sender_localpart, ":", c->server_base); - path = StrConcat(7, - "/_matrix/client/v3/rooms/", - room, "/event/", event, "?", - "user_id=", user - ); - - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(path); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - json = JsonDecode(HttpClientStream(ctx)); - - HttpClientContextFree(ctx); - Free(user); - - return json; -} -char * -ASGetName(const ParseeConfig *c, char *room, char *user) -{ - HttpClientContext *ctx; - HashMap *reply; - char *path, *ret; - char *u2 = user; - if (!c || !user) - { - return NULL; - } - - if (!room) - { - user = HttpUrlEncode(user); - path = StrConcat(3, - "/_matrix/client/v3/profile/", user, "/displayname" - ); - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(user); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - reply = JsonDecode(HttpClientStream(ctx)); - - ret = StrDuplicate( - JsonValueAsString(HashMapGet(reply, "displayname")) - ); - HttpClientContextFree(ctx); - JsonFree(reply); - Free(path); - - if (!ret) - { - ret = StrDuplicate(u2); - } - return ret; - } - user = HttpUrlEncode(user); - room = HttpUrlEncode(room); - path = StrConcat(4, - "/_matrix/client/v3/rooms/", room, - "/state/m.room.member/", user - ); - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(user); - Free(room); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - reply = JsonDecode(HttpClientStream(ctx)); - - ret = StrDuplicate( - JsonValueAsString(HashMapGet(reply, "displayname")) - ); - HttpClientContextFree(ctx); - JsonFree(reply); - Free(path); - - if (!ret) - { - ret = StrDuplicate(u2); - } - return ret; -} -HashMap * -ASGetPL(const ParseeConfig *c, char *room) -{ - char *path; - HttpClientContext *ctx; - HashMap *reply; - if (!c || !room) - { - return NULL; - } - room = HttpUrlEncode(room); - path = StrConcat(4, - "/_matrix/client/v3/rooms/", room, - "/state/m.room.power_levels/", "" - ); - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(room); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - reply = JsonDecode(HttpClientStream(ctx)); - - HttpClientContextFree(ctx); - Free(path); - - return reply; -} -void -ASSetPL(const ParseeConfig *conf, char *id, HashMap *m) -{ - char *user; - if (!conf || !id || !m) - { - return; - } - user = StrConcat(4, - "@",conf->sender_localpart, - ":",conf->server_base - ); - ASSetState(conf, id, "m.room.power_levels", "", user, m); - Free(user); -} - -char * -ASUpload(const ParseeConfig *c, Stream *from, unsigned int size, char *mime) -{ - char *size_str, *path, *ret, *user; - int i; - HttpClientContext *ctx; - HashMap *reply; - if (!c || !from) - { - return NULL; - } - - size_str = StrInt(size); - user = StrConcat(4, "@",c->sender_localpart,":",c->server_base); - path = StrConcat(2, - "/_matrix/media/v3/upload?user_id=", user - ); - ctx = ParseeCreateRequest(c, HTTP_POST, path); - ASAuthenticateRequest(c, ctx); - if (size) - { - HttpRequestHeader(ctx, "Content-Length", size_str); - } - if (mime) - { - HttpRequestHeader(ctx, "Content-Type", mime); - } - HttpRequestSendHeaders(ctx); - - for (i = 0; i < size; i++) - { - int ch = StreamGetc(from); - if (ch == EOF) - { - break; - } - StreamPutc(HttpClientStream(ctx), ch); - } - HttpRequestSend(ctx); - reply = JsonDecode(HttpClientStream(ctx)); - ret = StrDuplicate( - JsonValueAsString(HashMapGet(reply, "content_uri")) - ); - if (!ret) - { - JsonEncode(reply, StreamStdout(), JSON_PRETTY); - StreamFlush(StreamStdout()); - } - HttpClientContextFree(ctx); - JsonFree(reply); - Free(size_str); - Free(path); - Free(user); - - return ret; -} -char * -ASReupload(const ParseeConfig *c, char *from, char **mime) -{ - Uri *uri; - HttpClientContext *ctx; - unsigned short port; - int size = 0, flags = HTTP_FLAG_NONE; - char *ret, *content_len; - - if (!c || !from) - { - return NULL; - } - - uri = UriParse(from); - if (!uri) - { - return NULL; - } - if (uri->port) - { - port = uri->port; - } - else if (StrEquals(uri->proto, "https")) - { - port = 443; - } - else - { - port = 80; - } - - if (StrEquals(uri->proto, "https")) - { - flags |= HTTP_FLAG_TLS; - } - - ctx = HttpRequest( - HTTP_GET, flags, port, uri->host, uri->path - ); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - if (mime) - { - *mime = HashMapGet(HttpResponseHeaders(ctx), "content-type"); - *mime = StrDuplicate(*mime); - } - - content_len = HashMapGet(HttpResponseHeaders(ctx), "content-length"); - if (content_len) - { - size = strtol(content_len, NULL, 10); - } - ret = ASUpload(c, HttpClientStream(ctx), size, mime ? *mime : NULL); - - HttpClientContextFree(ctx); - UriFree(uri); - return ret; -} -void -ASType(const ParseeConfig *c, char *user, char *room, bool status) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path; - if (!c || !user || !room) - { - return; - } - - user = HttpUrlEncode(user); - path = StrConcat(6, - "/_matrix/client/v3/rooms/", - room, "/typing/", user, - "?user_id=", user - ); - - json = HashMapCreate(); - HashMapSet(json, "typing", JsonValueBoolean(status)); - /* If someone types for 10 minutes straight, they got something weird man. */ - HashMapSet(json, "timeout", JsonValueBoolean(10 MINUTES)); - ctx = ParseeCreateRequest(c, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(c, ctx); - ParseeSetRequestJSON(ctx, json); - JsonFree(json); - - HttpClientContextFree(ctx); - Free(user); -} - -void -ASPresence(const ParseeConfig *c, char *user, char *room, char *ev) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path; - if (!c || !user || !room || !ev) - { - return; - } - - user = HttpUrlEncode(user); - room = HttpUrlEncode(room); - ev = HttpUrlEncode(ev); - path = StrConcat(6, - "/_matrix/client/v3/rooms/", - room, "/receipt/m.read/", ev, - "?user_id=", user - ); - - json = HashMapCreate(); - ctx = ParseeCreateRequest(c, HTTP_POST, path); - Free(path); - ASAuthenticateRequest(c, ctx); - ParseeSetRequestJSON(ctx, json); - JsonFree(json); - - HttpClientContextFree(ctx); - Free(user); - Free(room); - Free(ev); -} - -HashMap * -ASGetUserConfig(const ParseeConfig *c, char *user, char *key) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path; - if (!c || !key) - { - return NULL; - } - - if (!user) - { - char *raw = StrConcat(4, - "@", c->sender_localpart, - ":", c->server_base - ); - user = HttpUrlEncode(raw); - Free(raw); - } - else - { - user = HttpUrlEncode(user); - } - path = StrConcat(7, - "/_matrix/client/v3/user/", - user, "/account_data/", key, "?", - "user_id=", user - ); - - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(path); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - json = JsonDecode(HttpClientStream(ctx)); - - HttpClientContextFree(ctx); - Free(user); - - return json; -} -void -ASSetUserConfig(const ParseeConfig *c, char *user, char *key, HashMap *map) -{ - HttpClientContext *ctx = NULL; - char *path; - if (!c || !key || !map) - { - JsonFree(map); - return; - } - - if (!user) - { - char *raw = StrConcat(4, - "@", c->sender_localpart, - ":", c->server_base - ); - user = HttpUrlEncode(raw); - Free(raw); - } - else - { - user = HttpUrlEncode(user); - } - - path = StrConcat(7, - "/_matrix/client/v3/user/", - user, "/account_data/", key, "?", - "user_id=", user - ); - - ctx = ParseeCreateRequest(c, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(c, ctx); - ParseeSetRequestJSON(ctx, map); - - HttpClientContextFree(ctx); - Free(user); - JsonFree(map); - - return; -} -void -ASRedact(const ParseeConfig *c, char *room, char *user, char *e_id) -{ - HttpClientContext *ctx = NULL; - HashMap *request; - char *path, *txn; - if (!c || !room || !e_id) - { - return; - } - - if (!user) - { - char *raw = StrConcat(4, - "@", c->sender_localpart, - ":", c->server_base - ); - user = HttpUrlEncode(raw); - Free(raw); - } - else - { - user = HttpUrlEncode(user); - } - room = HttpUrlEncode(room); - e_id = HttpUrlEncode(e_id); - txn = StrRandom(16); - - path = StrConcat(9, - "/_matrix/client/v3/rooms/", - room, "/redact/", e_id, "/", txn, - "?", "user_id=", user - ); - - request = HashMapCreate(); - ctx = ParseeCreateRequest(c, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(c, ctx); - ParseeSetRequestJSON(ctx, request); - JsonFree(request); - - HttpClientContextFree(ctx); - Free(user); - Free(room); - Free(e_id); - Free(txn); - - return; -} -void -ASSetStatus(const ParseeConfig *c, char *user, UserStatus status, char *msg) -{ - HttpClientContext *ctx = NULL; - HashMap *request; - char *path; - char *status_str = NULL; - if (!c || !user) - { - return; - } - - switch (status) - { - case USER_STATUS_ONLINE: status_str = "online"; break; - case USER_STATUS_OFFLINE: status_str = "offline"; break; - case USER_STATUS_UNAVAILABLE: status_str = "unavailable"; break; - default: return; - } - - user = HttpUrlEncode(user); - path = StrConcat(5, - "/_matrix/client/v3/presence/",user,"/status", - "?user_id=", user - ); - Free(user); - - request = HashMapCreate(); - HashMapSet(request, "presence", JsonValueString(status_str)); - if (msg) - { - HashMapSet(request, "status_msg", JsonValueString(msg)); - } - - ctx = ParseeCreateRequest(c, HTTP_PUT, path); - ASAuthenticateRequest(c, ctx); - ParseeSetRequestJSON(ctx, request); - JsonFree(request); - - HttpClientContextFree(ctx); - Free(path); -} diff --git a/src/AS/Events.c b/src/AS/Events.c new file mode 100644 index 0000000..83ce147 --- /dev/null +++ b/src/AS/Events.c @@ -0,0 +1,93 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +HashMap * +ASFind(const ParseeConfig *c, char *room, char *event) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path, *user; + if (!c || !room || !event) + { + return NULL; + } + + user = StrConcat(4, "@", c->sender_localpart, ":", c->server_base); + path = StrConcat(7, + "/_matrix/client/v3/rooms/", + room, "/event/", event, "?", + "user_id=", user + ); + + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(path); + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + json = JsonDecode(HttpClientStream(ctx)); + + HttpClientContextFree(ctx); + Free(user); + + return json; +} + +void +ASRedact(const ParseeConfig *c, char *room, char *user, char *e_id) +{ + HttpClientContext *ctx = NULL; + HashMap *request; + char *path, *txn; + if (!c || !room || !e_id) + { + return; + } + + if (!user) + { + char *raw = StrConcat(4, + "@", c->sender_localpart, + ":", c->server_base + ); + user = HttpUrlEncode(raw); + Free(raw); + } + else + { + user = HttpUrlEncode(user); + } + room = HttpUrlEncode(room); + e_id = HttpUrlEncode(e_id); + txn = StrRandom(16); + + path = StrConcat(9, + "/_matrix/client/v3/rooms/", + room, "/redact/", e_id, "/", txn, + "?", "user_id=", user + ); + + request = HashMapCreate(); + ctx = ParseeCreateRequest(c, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(c, ctx); + ParseeSetRequestJSON(ctx, request); + JsonFree(request); + + HttpClientContextFree(ctx); + Free(user); + Free(room); + Free(e_id); + Free(txn); + + return; +} diff --git a/src/AS/Indicators.c b/src/AS/Indicators.c new file mode 100644 index 0000000..afe860a --- /dev/null +++ b/src/AS/Indicators.c @@ -0,0 +1,119 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +void +ASType(const ParseeConfig *c, char *user, char *room, bool status) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path; + if (!c || !user || !room) + { + return; + } + + user = HttpUrlEncode(user); + path = StrConcat(6, + "/_matrix/client/v3/rooms/", + room, "/typing/", user, + "?user_id=", user + ); + + json = HashMapCreate(); + HashMapSet(json, "typing", JsonValueBoolean(status)); + /* If someone types for 10 minutes straight, they got something weird man. */ + HashMapSet(json, "timeout", JsonValueBoolean(10 MINUTES)); + ctx = ParseeCreateRequest(c, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(c, ctx); + ParseeSetRequestJSON(ctx, json); + JsonFree(json); + + HttpClientContextFree(ctx); + Free(user); +} + +void +ASPresence(const ParseeConfig *c, char *user, char *room, char *ev) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path; + if (!c || !user || !room || !ev) + { + return; + } + + user = HttpUrlEncode(user); + room = HttpUrlEncode(room); + ev = HttpUrlEncode(ev); + path = StrConcat(6, + "/_matrix/client/v3/rooms/", + room, "/receipt/m.read/", ev, + "?user_id=", user + ); + + json = HashMapCreate(); + ctx = ParseeCreateRequest(c, HTTP_POST, path); + Free(path); + ASAuthenticateRequest(c, ctx); + ParseeSetRequestJSON(ctx, json); + JsonFree(json); + + HttpClientContextFree(ctx); + Free(user); + Free(room); + Free(ev); +} + +void +ASSetStatus(const ParseeConfig *c, char *user, UserStatus status, char *msg) +{ + HttpClientContext *ctx = NULL; + HashMap *request; + char *path; + char *status_str = NULL; + if (!c || !user) + { + return; + } + + switch (status) + { + case USER_STATUS_ONLINE: status_str = "online"; break; + case USER_STATUS_OFFLINE: status_str = "offline"; break; + case USER_STATUS_UNAVAILABLE: status_str = "unavailable"; break; + default: return; + } + + user = HttpUrlEncode(user); + path = StrConcat(5, + "/_matrix/client/v3/presence/",user,"/status", + "?user_id=", user + ); + Free(user); + + request = HashMapCreate(); + HashMapSet(request, "presence", JsonValueString(status_str)); + if (msg) + { + HashMapSet(request, "status_msg", JsonValueString(msg)); + } + + ctx = ParseeCreateRequest(c, HTTP_PUT, path); + ASAuthenticateRequest(c, ctx); + ParseeSetRequestJSON(ctx, request); + JsonFree(request); + + HttpClientContextFree(ctx); + Free(path); +} diff --git a/src/AS/Media.c b/src/AS/Media.c new file mode 100644 index 0000000..4e642e9 --- /dev/null +++ b/src/AS/Media.c @@ -0,0 +1,129 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +char * +ASUpload(const ParseeConfig *c, Stream *from, unsigned int size, char *mime) +{ + char *size_str, *path, *ret, *user; + int i; + HttpClientContext *ctx; + HashMap *reply; + if (!c || !from) + { + return NULL; + } + + size_str = StrInt(size); + user = StrConcat(4, "@",c->sender_localpart,":",c->server_base); + path = StrConcat(2, + "/_matrix/media/v3/upload?user_id=", user + ); + ctx = ParseeCreateRequest(c, HTTP_POST, path); + ASAuthenticateRequest(c, ctx); + if (size) + { + HttpRequestHeader(ctx, "Content-Length", size_str); + } + if (mime) + { + HttpRequestHeader(ctx, "Content-Type", mime); + } + HttpRequestSendHeaders(ctx); + + for (i = 0; i < size; i++) + { + int ch = StreamGetc(from); + if (ch == EOF) + { + break; + } + StreamPutc(HttpClientStream(ctx), ch); + } + HttpRequestSend(ctx); + reply = JsonDecode(HttpClientStream(ctx)); + ret = StrDuplicate( + JsonValueAsString(HashMapGet(reply, "content_uri")) + ); + if (!ret) + { + JsonEncode(reply, StreamStdout(), JSON_PRETTY); + StreamFlush(StreamStdout()); + } + HttpClientContextFree(ctx); + JsonFree(reply); + Free(size_str); + Free(path); + Free(user); + + return ret; +} +char * +ASReupload(const ParseeConfig *c, char *from, char **mime) +{ + Uri *uri; + HttpClientContext *ctx; + unsigned short port; + int size = 0, flags = HTTP_FLAG_NONE; + char *ret, *content_len; + + if (!c || !from) + { + return NULL; + } + + uri = UriParse(from); + if (!uri) + { + return NULL; + } + if (uri->port) + { + port = uri->port; + } + else if (StrEquals(uri->proto, "https")) + { + port = 443; + } + else + { + port = 80; + } + + if (StrEquals(uri->proto, "https")) + { + flags |= HTTP_FLAG_TLS; + } + + ctx = HttpRequest( + HTTP_GET, flags, port, uri->host, uri->path + ); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + if (mime) + { + *mime = HashMapGet(HttpResponseHeaders(ctx), "content-type"); + *mime = StrDuplicate(*mime); + } + + content_len = HashMapGet(HttpResponseHeaders(ctx), "content-length"); + if (content_len) + { + size = strtol(content_len, NULL, 10); + } + ret = ASUpload(c, HttpClientStream(ctx), size, mime ? *mime : NULL); + + HttpClientContextFree(ctx); + UriFree(uri); + return ret; +} + diff --git a/src/AS/Ping.c b/src/AS/Ping.c new file mode 100644 index 0000000..88ac7cb --- /dev/null +++ b/src/AS/Ping.c @@ -0,0 +1,39 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +void +ASPing(const ParseeConfig *conf) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path; + if (!conf) + { + return; + } + + path = StrConcat(3, + "/_matrix/client/v1/appservice/", + "Parsee%20XMPP", + "/ping" + ); + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + HttpClientContextFree(ctx); + JsonFree(json); +} diff --git a/src/AS/Profile.c b/src/AS/Profile.c new file mode 100644 index 0000000..73e9b4b --- /dev/null +++ b/src/AS/Profile.c @@ -0,0 +1,138 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +void +ASSetAvatar(const ParseeConfig *conf, char *user, char *mxc) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path; + if (!conf || !user || !mxc) + { + return; + } + + user = HttpUrlEncode(user); + path = StrConcat(6, + "/_matrix/client/v3/profile/", + user, "/avatar_url", "?", + "user_id=", user + ); + + json = HashMapCreate(); + HashMapSet(json, "avatar_url", JsonValueString(mxc)); + ctx = ParseeCreateRequest(conf, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); + Free(user); +} +void +ASSetName(const ParseeConfig *conf, char *user, char *name) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path; + if (!conf || !user || !name) + { + return; + } + + user = HttpUrlEncode(user); + path = StrConcat(6, + "/_matrix/client/v3/profile/", + user, "/displayname", "?", + "user_id=", user + ); + + json = HashMapCreate(); + HashMapSet(json, "displayname", JsonValueString(name)); + ctx = ParseeCreateRequest(conf, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); + Free(user); +} + +char * +ASGetName(const ParseeConfig *c, char *room, char *user) +{ + HttpClientContext *ctx; + HashMap *reply; + char *path, *ret; + char *u2 = user; + if (!c || !user) + { + return NULL; + } + + if (!room) + { + user = HttpUrlEncode(user); + path = StrConcat(3, + "/_matrix/client/v3/profile/", user, "/displayname" + ); + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(user); + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + reply = JsonDecode(HttpClientStream(ctx)); + + ret = StrDuplicate( + JsonValueAsString(HashMapGet(reply, "displayname")) + ); + HttpClientContextFree(ctx); + JsonFree(reply); + Free(path); + + if (!ret) + { + ret = StrDuplicate(u2); + } + return ret; + } + user = HttpUrlEncode(user); + room = HttpUrlEncode(room); + path = StrConcat(4, + "/_matrix/client/v3/rooms/", room, + "/state/m.room.member/", user + ); + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(user); + Free(room); + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + reply = JsonDecode(HttpClientStream(ctx)); + + ret = StrDuplicate( + JsonValueAsString(HashMapGet(reply, "displayname")) + ); + HttpClientContextFree(ctx); + JsonFree(reply); + Free(path); + + if (!ret) + { + ret = StrDuplicate(u2); + } + return ret; +} diff --git a/src/AS/Register.c b/src/AS/Register.c new file mode 100644 index 0000000..cbb8881 --- /dev/null +++ b/src/AS/Register.c @@ -0,0 +1,46 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +bool +ASRegisterUser(const ParseeConfig *conf, char *user) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + HttpStatus status; + if (!conf || !user) + { + return false; + } + + /* Create user. We don't actually care about the value as we can + * masquerade, as long as it exists. */ + ctx = ParseeCreateRequest( + conf, + HTTP_POST, "/_matrix/client/v3/register" + ); + json = HashMapCreate(); + + HashMapSet(json,"type",JsonValueString("m.login.application_service")); + + user = ParseeGetLocal(user); + HashMapSet(json,"username",JsonValueString(user)); + + ASAuthenticateRequest(conf, ctx); + status = ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); + + Free(user); + + return status == HTTP_OK; +} diff --git a/src/AS/Relations.c b/src/AS/Relations.c new file mode 100644 index 0000000..4809413 --- /dev/null +++ b/src/AS/Relations.c @@ -0,0 +1,81 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +Array * +ASGetRelations(const ParseeConfig *c, size_t n, char *room, char *event, char *type) +{ + HttpClientContext *ctx = NULL; + Array *ret, *chunk; + HashMap *json = NULL; + char *path; + char *user; + size_t i; + if (!c || !n || !room || !event) + { + return NULL; + } + + user = StrConcat(4, "@", c->sender_localpart, ":", c->server_base); + if (event) + { + path = StrConcat(6, + "/_matrix/client/v1/rooms/", room, + "/relations/", event, + "?user_id=", user + ); + } + else + { + path = StrConcat(4, + "/_matrix/client/v1/rooms/", room, + "/relations?user_id=", user + ); + } + Free(user); + + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(path); + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + + json = JsonDecode(HttpClientStream(ctx)); + ret = ArrayCreate(); + chunk = GrabArray(json, 1, "chunk"); + for (i = 0; i < ArraySize(chunk); i++) + { + HashMap *obj = JsonValueAsObject(ArrayGet(chunk, i)); + ArrayAdd(ret, JsonDuplicate(obj)); + } + + HttpClientContextFree(ctx); + JsonFree(json); + return ret; +} + +void +ASFreeRelations(Array *relations) +{ + size_t i; + if (!relations) + { + return; + } + + for (i = 0; i < ArraySize(relations); i++) + { + JsonFree(ArrayGet(relations, i)); + } + + ArrayFree(relations); +} diff --git a/src/AS/Room.c b/src/AS/Room.c new file mode 100644 index 0000000..3bc7cbf --- /dev/null +++ b/src/AS/Room.c @@ -0,0 +1,352 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +void +ASInvite(const ParseeConfig *conf, char *id, char *invited) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *bridge; + if (!conf || !id || !invited) + { + return; + } + + bridge = StrConcat(4, + "@", conf->sender_localpart, + ":", conf->server_base + ); + path = StrConcat(5, + "/_matrix/client/v3/rooms/", id, "/invite", + "?user_id=", bridge + ); + Free(bridge); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + HashMapSet(json, "user_id", JsonValueString(invited)); + HashMapSet(json, "reason", JsonValueString("Pass over.")); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); +} +void +ASBan(const ParseeConfig *conf, char *id, char *banned) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *bridge; + if (!conf || !id || !banned) + { + return; + } + + bridge = StrConcat(4, + "@", conf->sender_localpart, + ":", conf->server_base + ); + path = StrConcat(5, + "/_matrix/client/v3/rooms/", id, "/ban", + "?user_id=", bridge + ); + Free(bridge); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + HashMapSet(json, "user_id", JsonValueString(banned)); + HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); +} +void +ASKick(const ParseeConfig *conf, char *id, char *banned) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *bridge; + if (!conf || !id || !banned) + { + return; + } + + bridge = StrConcat(4, + "@", conf->sender_localpart, + ":", conf->server_base + ); + path = StrConcat(5, + "/_matrix/client/v3/rooms/", id, "/kick", + "?user_id=", bridge + ); + Free(bridge); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + HashMapSet(json, "user_id", JsonValueString(banned)); + HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); +} +char * +ASJoin(const ParseeConfig *conf, char *id, char *masquerade) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *ret; + if (!conf || !id) + { + return NULL; + } + + if (!masquerade) + { + char *raw = StrConcat(4, + "@", conf->sender_localpart, + ":", conf->server_base + ); + masquerade = HttpUrlEncode(raw); + Free(raw); + } + else + { + masquerade = HttpUrlEncode(masquerade); + } + id = HttpUrlEncode(id); + path = StrConcat(5, + "/_matrix/client/v3/join/", id, "?", + "user_id=", masquerade + ); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + JsonFree(json); + + json = JsonDecode(HttpClientStream(ctx)); + ret = StrDuplicate(GrabString(json, 1, "room_id")); + JsonFree(json); + + HttpClientContextFree(ctx); + Free(masquerade); + Free(id); + + return ret; +} +void +ASLeave(const ParseeConfig *conf, char *id, char *masquerade) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path; + if (!conf || !id) + { + return; + } + + if (!masquerade) + { + char *raw = StrConcat(4, + "@", conf->sender_localpart, + ":", conf->server_base + ); + masquerade = HttpUrlEncode(raw); + Free(raw); + } + else + { + masquerade = HttpUrlEncode(masquerade); + } + id = HttpUrlEncode(id); + path = StrConcat(5, + "/_matrix/client/v3/rooms/", id, "/leave?", + "user_id=", masquerade + ); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + JsonFree(json); + + HttpClientContextFree(ctx); + Free(masquerade); + Free(id); +} + +char * +ASCreateRoom(const ParseeConfig *conf, char *by, char *alias) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *id; + if (!conf || !by) + { + return NULL; + } + + path = StrConcat(3, + "/_matrix/client/v3/createRoom", + "?user_id=", by + ); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + if (alias) + { + char *trimmed = StrDuplicate(alias); + if (*alias == '#') + { + char *tmp, cb[2] = { 0 }; + alias++; + Free(trimmed); + trimmed = NULL; + + while (*alias && *alias != ':') + { + cb[0] = *alias; + tmp = trimmed; + trimmed = StrConcat(2, trimmed, cb); + Free(tmp); + alias ++; + } + } + HashMapSet(json, "room_alias_name", JsonValueString(trimmed)); + Free(trimmed); + } + HashMapSet(json, "visibility", JsonValueString("public")); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + JsonFree(json); + json = JsonDecode(HttpClientStream(ctx)); + id = StrDuplicate(JsonValueAsString(HashMapGet(json, "room_id"))); + HttpClientContextFree(ctx); + JsonFree(json); + + return id; +} +char * +ASCreateDM(const ParseeConfig *conf, char *by, char *with) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *id; + if (!conf || !by || !with) + { + return NULL; + } + + path = StrConcat(3, + "/_matrix/client/v3/createRoom", + "?user_id=", by + ); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + { + Array *invitees = ArrayCreate(); + + ArrayAdd(invitees, JsonValueString(with)); + HashMapSet(json, "invite", JsonValueArray(invitees)); + HashMapSet(json, "is_direct", JsonValueBoolean(true)); + } + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + JsonFree(json); + json = JsonDecode(HttpClientStream(ctx)); + id = StrDuplicate(JsonValueAsString(HashMapGet(json, "room_id"))); + HttpClientContextFree(ctx); + JsonFree(json); + + return id; +} + +HashMap * +ASGetPL(const ParseeConfig *c, char *room) +{ + char *path; + HttpClientContext *ctx; + HashMap *reply; + if (!c || !room) + { + return NULL; + } + room = HttpUrlEncode(room); + path = StrConcat(4, + "/_matrix/client/v3/rooms/", room, + "/state/m.room.power_levels/", "" + ); + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(room); + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + reply = JsonDecode(HttpClientStream(ctx)); + + HttpClientContextFree(ctx); + Free(path); + + return reply; +} +void +ASSetPL(const ParseeConfig *conf, char *id, HashMap *m) +{ + char *user; + if (!conf || !id || !m) + { + return; + } + user = StrConcat(4, + "@",conf->sender_localpart, + ":",conf->server_base + ); + ASSetState(conf, id, "m.room.power_levels", "", user, m); + Free(user); +} diff --git a/src/AS/Send.c b/src/AS/Send.c new file mode 100644 index 0000000..4032423 --- /dev/null +++ b/src/AS/Send.c @@ -0,0 +1,48 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +char * +ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) +{ + HttpClientContext *ctx = NULL; + char *path; + char *txn, *ret; + HashMap *reply; + if (!conf || !id || !type || !user || !c) + { + JsonFree(c); + return NULL; + } + + txn = StrRandom(16); + path = StrConcat(9, + "/_matrix/client/v3/rooms/", + id, "/send/", type, "/", txn, "?", + "user_id=", user + ); + Free(txn); + + ctx = ParseeCreateRequest(conf, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, c); + + reply = JsonDecode(HttpClientStream(ctx)); + ret = StrDuplicate(JsonValueAsString(HashMapGet(reply, "event_id"))); + JsonFree(reply); + + HttpClientContextFree(ctx); + JsonFree(c); + + return ret; +} + diff --git a/src/AS/State.c b/src/AS/State.c new file mode 100644 index 0000000..ef2ff14 --- /dev/null +++ b/src/AS/State.c @@ -0,0 +1,37 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + +void +ASSetState(const ParseeConfig *conf, char *id, char *type, char *key, char *mask, HashMap *state) +{ + HttpClientContext *ctx = NULL; + char *path; + if (!conf || !id || !type || !mask || !state) + { + JsonFree(state); + return; + } + + path = StrConcat(9, + "/_matrix/client/v3/rooms/", id, "/state/", + type, "/", key, "?", "user_id=", mask + ); + + ctx = ParseeCreateRequest(conf, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, state); + + HttpClientContextFree(ctx); + JsonFree(state); +} + diff --git a/src/XEP-0393.c b/src/XEP-0393.c index 8f3cef2..a90b4a1 100644 --- a/src/XEP-0393.c +++ b/src/XEP-0393.c @@ -80,6 +80,13 @@ DecodeQuote(StringRect rect, size_t *skip) ret = rect; ret.end_line--; + /* TODO: You can easily craft strings that conceal data( + * > Please mind the whitespace + * > hidden we're concealing data to Matrix + * > star in Well, you can still stare at the body and XML + * > four but that's for Nerds + * > seasons See, Touhou reference! + * concealing!) */ while ((ch = StrGet(&rect, lines - 1, shift_by)) && isspace(ch)) { shift_by++; diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index e66e1af..0641f42 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -52,7 +52,6 @@ XMPPDispatcher(void *argp) { XMLElement *stanza = RetrieveStanza(thread); - /* TODO: I've seen some spikes in some threads. */ if (!stanza) { UtilSleepMillis(5); @@ -153,7 +152,6 @@ ParseeXMPPThread(void *argp) pthread_mutex_init(&info.lock, NULL); /* ... and its readers. */ - /* TODO: Make that configurable. */ info.available_dispatchers = args->config->xmpp_threads; info.dispatchers = Malloc( sizeof(*info.dispatchers) * info.available_dispatchers diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 3c6949c..1b207b1 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -9,6 +9,62 @@ #include +static void +ProcessChatstates(ParseeData *args, XMLElement *stanza) +{ + char *from_matrix, *mroom_id; +#define CHAT_STATES "http://jabber.org/protocol/chatstates" + if (XMLookForTKV(stanza, "composing", "xmlns", CHAT_STATES)) + { + from_matrix = ParseeGetBridgedUser(args, stanza); + mroom_id = ParseeGetBridgedRoom(args, stanza); + + ASType(args->config, from_matrix, mroom_id, true); + + Free(from_matrix); + Free(mroom_id); + mroom_id = NULL; + from_matrix = NULL; + } + if (XMLookForTKV(stanza, "active", "xmlns", CHAT_STATES)) + { + char *latest = NULL; + from_matrix = ParseeGetBridgedUser(args, stanza); + mroom_id = ParseeGetBridgedRoom(args, stanza); + + latest = ParseeLookupHead(mroom_id); + + ASType(args->config, from_matrix, mroom_id, false); + ASPresence(args->config, from_matrix, mroom_id, latest); + + Free(from_matrix); + Free(latest); + Free(mroom_id); + mroom_id = NULL; + from_matrix = NULL; + } + if (XMLookForTKV(stanza, "paused", "xmlns", CHAT_STATES) || + XMLookForTKV(stanza, "received", "xmlns", "urn:xmpp:receipts") || + XMLookForTKV(stanza, "displayed", "xmlns", "urn:xmpp:chat-markers:0")) + { + /* TODO: Use stanza ID if possible */ + char *latest = NULL; + from_matrix = ParseeGetBridgedUser(args, stanza); + mroom_id = ParseeGetBridgedRoom(args, stanza); + + latest = ParseeLookupHead(mroom_id); + + ASPresence(args->config, from_matrix, mroom_id, latest); + + Free(from_matrix); + Free(latest); + Free(mroom_id); + mroom_id = NULL; + from_matrix = NULL; + + } +#undef CHAT_STATES +} bool MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { @@ -107,57 +163,7 @@ end_error: PEPManagerHandle(thr->info->pep_manager, stanza); /* TODO: Separate the chatstate processing code. */ -#define CHAT_STATES "http://jabber.org/protocol/chatstates" - if (XMLookForTKV(stanza, "composing", "xmlns", CHAT_STATES)) - { - from_matrix = ParseeGetBridgedUser(args, stanza); - mroom_id = ParseeGetBridgedRoom(args, stanza); - - ASType(args->config, from_matrix, mroom_id, true); - - Free(from_matrix); - Free(mroom_id); - mroom_id = NULL; - from_matrix = NULL; - } - if (XMLookForTKV(stanza, "active", "xmlns", CHAT_STATES)) - { - char *latest = NULL; - from_matrix = ParseeGetBridgedUser(args, stanza); - mroom_id = ParseeGetBridgedRoom(args, stanza); - - latest = ParseeLookupHead(mroom_id); - - ASType(args->config, from_matrix, mroom_id, false); - ASPresence(args->config, from_matrix, mroom_id, latest); - - Free(from_matrix); - Free(latest); - Free(mroom_id); - mroom_id = NULL; - from_matrix = NULL; - } - if (XMLookForTKV(stanza, "paused", "xmlns", CHAT_STATES) || - XMLookForTKV(stanza, "received", "xmlns", "urn:xmpp:receipts") || - XMLookForTKV(stanza, "displayed", "xmlns", "urn:xmpp:chat-markers:0")) - { - /* TODO: Use stanza ID if possible */ - char *latest = NULL; - from_matrix = ParseeGetBridgedUser(args, stanza); - mroom_id = ParseeGetBridgedRoom(args, stanza); - - latest = ParseeLookupHead(mroom_id); - - ASPresence(args->config, from_matrix, mroom_id, latest); - - Free(from_matrix); - Free(latest); - Free(mroom_id); - mroom_id = NULL; - from_matrix = NULL; - - } -#undef CHAT_STATES + ProcessChatstates(args, stanza); to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to")); decode_from = ParseeLookupJID(from); @@ -283,8 +289,28 @@ end_error: else if (reactions) { Array *react_child = reactions->children; + Array *to_redact; size_t reacts = ArraySize(react_child); event_id = ParseeGetReactedEvent(args, stanza); + + to_redact = ASGetRelations( + args->config, 30, mroom_id, event_id, + "m.reaction" + ); + for (i = 0; i < ArraySize(to_redact); i++) + { + HashMap *e = ArrayGet(to_redact, i); + char *e_sender = GrabString(e, 1, "sender"); + char *e_id = GrabString(e, 1, "event_id"); + if (!StrEquals(e_sender, encoded)) + { + continue; + } + + ASRedact(args->config, mroom_id, encoded, e_id); + } + ASFreeRelations(to_redact); + for (i = 0; i < reacts; i++) { XMLElement *reaction, *react_data; diff --git a/src/include/AS.h b/src/include/AS.h index cdb67c1..1d993e1 100644 --- a/src/include/AS.h +++ b/src/include/AS.h @@ -3,7 +3,8 @@ /*-* * Functions used to communicate with a Matrix server and execute actions * over HTTP(S)+JSON. This effectively serves as Parsee's Matrix SDK. - * TODO: Write my own RanSDK for KappaChat. + * TODO: Write my own RumiaSDK for the KappaChat project(not the client + * itself). * -------- * Writren-By: LDA */ @@ -156,6 +157,17 @@ extern char * ASUpload(const ParseeConfig *c, Stream *from, unsigned int size, c * See-Also: ASUpload */ extern char * ASReupload(const ParseeConfig *c, char *from, char **mime); -extern HashMap * ASGetUserConfig(const ParseeConfig *c, char *user, char *key); -extern void ASSetUserConfig(const ParseeConfig *c, char *u, char *key, HashMap *map); +/** Gets up to {n} relations to an event(with a specific type, optionally). + * ---------- + * Returns: A list of JSON objects[HEAP] + * Thrasher: ASFreeRelations + * See-Also: https://spec.matrix.org/v1.7/client-server-api/#get_matrixclientv1roomsroomidrelationseventid */ +extern Array * ASGetRelations(const ParseeConfig *c, size_t n, char *room, char *event, char *type); + +/** Destroys a relation list created by {ASGetRelations} + * ------------ + * Returns: NOTHING + * Thrashes: {relations} + * See-Also: ASGetRelations */ +extern void ASFreeRelations(Array *relations); #endif